From 6ed78e393423ac1243bfda630f5e156843cd74c5 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Thu, 10 Feb 2022 23:11:19 +0100 Subject: [PATCH 001/244] Inicia el repositorio --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3e04751d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +workdir +**/target +**/log/*.log +Cargo.lock From 13a408ce611b613daa869c1b8057c7daec7892de Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Thu, 10 Feb 2022 23:12:53 +0100 Subject: [PATCH 002/244] =?UTF-8?q?A=C3=B1ade=20el=20servidor=20web=20acti?= =?UTF-8?q?x-web?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 35 +++++++++++++++++++++++++++++++++++ STARTER.Cargo.toml | 14 ++++++++++++++ src/core/mod.rs | 3 +++ src/core/server/main.rs | 17 +++++++++++++++++ src/core/server/mod.rs | 4 ++++ src/lib.rs | 3 +++ src/main.rs | 6 ++++++ tests/health_check.rs | 9 +++++++++ tests/main.rs | 1 + 9 files changed, 92 insertions(+) create mode 100644 Cargo.toml create mode 100644 STARTER.Cargo.toml create mode 100644 src/core/mod.rs create mode 100644 src/core/server/main.rs create mode 100644 src/core/server/mod.rs create mode 100644 src/lib.rs create mode 100644 src/main.rs create mode 100644 tests/health_check.rs create mode 100644 tests/main.rs diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..e29ba8be --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "pagetop" +version = "0.0.0" +edition = "2021" + +authors = [ + "Manuel Cillero " +] +description = """\ + PageTop es un proyecto personal para aprender Rust. Incluye algunos de los \ + crates más estables y populares para desarrollar soluciones web modulares, \ + extensibles y configurables. También es un sistema para la gestión de \ + contenidos web.\ +""" +homepage = "https://suitepro.cillero.es/projects/pagetop" +repository = "https://gitlab.com/manuelcillero/pagetop" +license = "MIT" + +keywords = [ + "web", "cms", "framework", "frontend", "ssr" +] +categories = [ + "web-programming", "development-tools", "gui" +] + +[dependencies] +actix-web = "4.0.0-rc.3" + +[lib] +name = "pagetop" +path = "src/lib.rs" + +[[bin]] +name = "pagetop" +path = "src/main.rs" diff --git a/STARTER.Cargo.toml b/STARTER.Cargo.toml new file mode 100644 index 00000000..4795fde9 --- /dev/null +++ b/STARTER.Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "app" +version = "0.1.0" +edition = "2021" + +# Ver más claves y sus definiciones en +# https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +pagetop = { path = "pagetop" } +actix-web = "4.0.0-rc.3" + +[[bin]] +name = "app" diff --git a/src/core/mod.rs b/src/core/mod.rs new file mode 100644 index 00000000..fc3e282f --- /dev/null +++ b/src/core/mod.rs @@ -0,0 +1,3 @@ +pub use actix_web::dev::Server; + +pub mod server; diff --git a/src/core/server/main.rs b/src/core/server/main.rs new file mode 100644 index 00000000..022d32d1 --- /dev/null +++ b/src/core/server/main.rs @@ -0,0 +1,17 @@ +use crate::core::{server, Server}; + +async fn greet(req: server::HttpRequest) -> impl server::Responder { + let name = req.match_info().get("name").unwrap_or("World"); + format!("Hello {}!", &name) +} + +pub fn run() -> Result { + let server = server::HttpServer::new(|| { + server::App::new() + .route("/", server::web::get().to(greet)) + .route("/{name}", server::web::get().to(greet)) + }) + .bind("127.0.0.1:8000")? + .run(); + Ok(server) +} diff --git a/src/core/server/mod.rs b/src/core/server/mod.rs new file mode 100644 index 00000000..f293ee80 --- /dev/null +++ b/src/core/server/mod.rs @@ -0,0 +1,4 @@ +pub use actix_web::{web, App, HttpRequest, HttpServer, Responder}; + +mod main; +pub use main::run; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..48a67efc --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +pub mod core; + +pub use actix_web::main; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 00000000..db2a29bc --- /dev/null +++ b/src/main.rs @@ -0,0 +1,6 @@ +use pagetop::core::server; + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + server::run()?.await +} diff --git a/tests/health_check.rs b/tests/health_check.rs new file mode 100644 index 00000000..4ae6653e --- /dev/null +++ b/tests/health_check.rs @@ -0,0 +1,9 @@ +fn spawn_app() { + let server = pagetop::core::server::run().expect("Failed to bind address"); + let _ = tokio::spawn(server); +} + +#[tokio::test] +async fn health_check_works() { + spawn_app(); +} diff --git a/tests/main.rs b/tests/main.rs new file mode 100644 index 00000000..f56eeca6 --- /dev/null +++ b/tests/main.rs @@ -0,0 +1 @@ +mod health_check; From e1ea1499885ac4624b199758a2bbbb64799e588b Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Thu, 10 Feb 2022 23:15:50 +0100 Subject: [PATCH 003/244] =?UTF-8?q?A=C3=B1ade=20Sycamore=20para=20render?= =?UTF-8?q?=20de=20HTML=20con=20reactividad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 1 + src/core/server/main.rs | 15 +++++++++++---- src/core/server/mod.rs | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e29ba8be..168ee872 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ categories = [ [dependencies] actix-web = "4.0.0-rc.3" +sycamore = { version = "0.8.0-beta.2", features = ["ssr"] } [lib] name = "pagetop" diff --git a/src/core/server/main.rs b/src/core/server/main.rs index 022d32d1..6a54d243 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -1,15 +1,22 @@ use crate::core::{server, Server}; -async fn greet(req: server::HttpRequest) -> impl server::Responder { - let name = req.match_info().get("name").unwrap_or("World"); - format!("Hello {}!", &name) +async fn greet() -> impl server::Responder { + "Hello!" +} + +async fn greet_with_param(req: server::HttpRequest) -> server::HttpResponse { + let name: String = req.match_info().get("name").unwrap_or("World").into(); + server::HttpResponse::Ok() + .body(sycamore::render_to_string(|ctx| sycamore::view! { ctx, + p { "Hello " (name) "!" } + })) } pub fn run() -> Result { let server = server::HttpServer::new(|| { server::App::new() .route("/", server::web::get().to(greet)) - .route("/{name}", server::web::get().to(greet)) + .route("/{name}", server::web::get().to(greet_with_param)) }) .bind("127.0.0.1:8000")? .run(); diff --git a/src/core/server/mod.rs b/src/core/server/mod.rs index f293ee80..a1210ce3 100644 --- a/src/core/server/mod.rs +++ b/src/core/server/mod.rs @@ -1,4 +1,4 @@ -pub use actix_web::{web, App, HttpRequest, HttpServer, Responder}; +pub use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer, Responder}; mod main; pub use main::run; From 4e23523e80fdbc18c8d9e5a2adee009e1663e0a6 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Thu, 10 Feb 2022 23:58:22 +0100 Subject: [PATCH 004/244] =?UTF-8?q?A=C3=B1ade=20una=20arquitectura=20escal?= =?UTF-8?q?able=20basada=20en=20m=C3=B3dulos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 4 +++- src/core/all.rs | 7 ++++++ src/core/mod.rs | 6 +++++ src/core/module/api.rs | 14 ++++++++++++ src/core/module/mod.rs | 2 ++ src/core/server/main.rs | 22 ++++++------------ src/core/server/mod.rs | 2 +- src/core/state.rs | 16 +++++++++++++ src/lib.rs | 4 ++++ src/main.rs | 50 +++++++++++++++++++++++++++++++++++++++-- 10 files changed, 108 insertions(+), 19 deletions(-) create mode 100644 src/core/all.rs create mode 100644 src/core/module/api.rs create mode 100644 src/core/module/mod.rs create mode 100644 src/core/state.rs diff --git a/Cargo.toml b/Cargo.toml index 168ee872..1b07ae3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.0" +version = "0.1.0" edition = "2021" authors = [ @@ -24,6 +24,8 @@ categories = [ ] [dependencies] +once_cell = "1.9.0" + actix-web = "4.0.0-rc.3" sycamore = { version = "0.8.0-beta.2", features = ["ssr"] } diff --git a/src/core/all.rs b/src/core/all.rs new file mode 100644 index 00000000..4067a838 --- /dev/null +++ b/src/core/all.rs @@ -0,0 +1,7 @@ +use crate::core::{server, state}; + +pub fn modules(cfg: &mut server::web::ServiceConfig) { + for m in state::MODULES.read().unwrap().iter() { + m.configure_module(cfg); + } +} diff --git a/src/core/mod.rs b/src/core/mod.rs index fc3e282f..3c6040c9 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,3 +1,9 @@ pub use actix_web::dev::Server; +mod state; +pub use state::register_module; + +mod all; + +pub mod module; pub mod server; diff --git a/src/core/module/api.rs b/src/core/module/api.rs new file mode 100644 index 00000000..37c84786 --- /dev/null +++ b/src/core/module/api.rs @@ -0,0 +1,14 @@ +use crate::core::server; + +/// Modules must implement this trait. +pub trait Module: Send + Sync { + fn name(&self) -> String; + + fn description(&self) -> String { + "".to_string() + } + + #[allow(unused_variables)] + fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { + } +} diff --git a/src/core/module/mod.rs b/src/core/module/mod.rs new file mode 100644 index 00000000..a8f85139 --- /dev/null +++ b/src/core/module/mod.rs @@ -0,0 +1,2 @@ +mod api; +pub use api::Module; diff --git a/src/core/server/main.rs b/src/core/server/main.rs index 6a54d243..457bb652 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -1,22 +1,14 @@ -use crate::core::{server, Server}; +use crate::core::{Server, all, server}; -async fn greet() -> impl server::Responder { - "Hello!" -} +pub fn run(bootstrap: Option) -> Result { + // Call application bootstrap. + if bootstrap != None { + let _ = &(bootstrap.unwrap())(); + } -async fn greet_with_param(req: server::HttpRequest) -> server::HttpResponse { - let name: String = req.match_info().get("name").unwrap_or("World").into(); - server::HttpResponse::Ok() - .body(sycamore::render_to_string(|ctx| sycamore::view! { ctx, - p { "Hello " (name) "!" } - })) -} - -pub fn run() -> Result { let server = server::HttpServer::new(|| { server::App::new() - .route("/", server::web::get().to(greet)) - .route("/{name}", server::web::get().to(greet_with_param)) + .configure(&all::modules) }) .bind("127.0.0.1:8000")? .run(); diff --git a/src/core/server/mod.rs b/src/core/server/mod.rs index a1210ce3..d39c1d4d 100644 --- a/src/core/server/mod.rs +++ b/src/core/server/mod.rs @@ -1,4 +1,4 @@ -pub use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer, Responder}; +pub use actix_web::{App, HttpRequest, HttpResponse, HttpServer, Responder, web}; mod main; pub use main::run; diff --git a/src/core/state.rs b/src/core/state.rs new file mode 100644 index 00000000..6ded57b8 --- /dev/null +++ b/src/core/state.rs @@ -0,0 +1,16 @@ +use crate::Lazy; +use crate::core::module::Module; + +use std::sync::RwLock; + +// ----------------------------------------------------------------------------- +// Registered modules. +// ----------------------------------------------------------------------------- + +pub static MODULES: Lazy>> = Lazy::new(|| { + RwLock::new(vec![]) +}); + +pub fn register_module(m: &'static (dyn Module + 'static)) { + MODULES.write().unwrap().push(m); +} diff --git a/src/lib.rs b/src/lib.rs index 48a67efc..01361a13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,7 @@ +// Global. + +pub use once_cell::sync::Lazy; + pub mod core; pub use actix_web::main; diff --git a/src/main.rs b/src/main.rs index db2a29bc..c1545d0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,52 @@ -use pagetop::core::server; +use pagetop::core::module::Module; +use pagetop::core::{register_module, server}; + +struct Greet; +impl Module for Greet { + fn name(&self) -> String { + "Hello".to_string() + } + + fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { + cfg.service( + server::web::resource("/") + .route(server::web::get().to(greet)) + ); + } +} + +async fn greet() -> impl server::Responder { + "Hello!" +} + +struct GreetWithParam; +impl Module for GreetWithParam { + fn name(&self) -> String { + "Hello World!".to_string() + } + + fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { + cfg.service( + server::web::resource("/{name}") + .route(server::web::get().to(greet_with_param)) + ); + } +} + +async fn greet_with_param(req: server::HttpRequest) -> server::HttpResponse { + let name: String = req.match_info().get("name").unwrap_or("World").into(); + server::HttpResponse::Ok() + .body(sycamore::render_to_string(|ctx| sycamore::view! { ctx, + p { "Hello " (name) "!" } + })) +} + +fn bootstrap() { + register_module(&Greet); + register_module(&GreetWithParam); +} #[pagetop::main] async fn main() -> std::io::Result<()> { - server::run()?.await + server::run(Some(bootstrap))?.await } From 96884cbbc0590119f6e4ecb646ca578e2451ed36 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Sat, 12 Feb 2022 10:14:36 +0100 Subject: [PATCH 005/244] =?UTF-8?q?A=C3=B1ade=20carga=20de=20ajustes=20de?= =?UTF-8?q?=20configuraci=C3=B3n=20globales?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 7 ++- STARTER.Cargo.toml | 2 +- config/default.toml | 2 + config/settings.default.toml | 9 +++ src/config/mod.rs | 5 ++ src/config/settings.rs | 103 +++++++++++++++++++++++++++++++++++ src/core/module/api.rs | 2 +- src/core/server/main.rs | 9 ++- src/core/state.rs | 2 +- src/lib.rs | 8 ++- src/main.rs | 5 +- tests/health_check.rs | 4 +- 12 files changed, 146 insertions(+), 12 deletions(-) create mode 100644 config/default.toml create mode 100644 config/settings.default.toml create mode 100644 src/config/mod.rs create mode 100644 src/config/settings.rs diff --git a/Cargo.toml b/Cargo.toml index 1b07ae3a..67ed8c44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,15 +24,18 @@ categories = [ ] [dependencies] +doc-comment = "0.3.3" once_cell = "1.9.0" +config_rs = { package = "config", version = "0.11.0", features = ["toml"] } actix-web = "4.0.0-rc.3" sycamore = { version = "0.8.0-beta.2", features = ["ssr"] } +tokio = { version = "1.16", features = ["macros", "rt-multi-thread"] } +serde = { version = "1.0", features = ["derive"] } + [lib] name = "pagetop" -path = "src/lib.rs" [[bin]] name = "pagetop" -path = "src/main.rs" diff --git a/STARTER.Cargo.toml b/STARTER.Cargo.toml index 4795fde9..13ef591d 100644 --- a/STARTER.Cargo.toml +++ b/STARTER.Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] pagetop = { path = "pagetop" } -actix-web = "4.0.0-rc.3" +tokio = { version = "1.16", features = ["macros", "rt-multi-thread"] } [[bin]] name = "app" diff --git a/config/default.toml b/config/default.toml new file mode 100644 index 00000000..429d6da5 --- /dev/null +++ b/config/default.toml @@ -0,0 +1,2 @@ +[app] +name = "PageTop Essence" diff --git a/config/settings.default.toml b/config/settings.default.toml new file mode 100644 index 00000000..cef2d7cf --- /dev/null +++ b/config/settings.default.toml @@ -0,0 +1,9 @@ +[app] +name = "PageTop Application" +description = "Developed with the amazing PageTop framework." + +[webserver] +# Configuración opcional del servidor web. +# Usar bind_address = "" para deshabilitar el servidor web. +bind_address = "localhost" +bind_port = 8088 diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 00000000..afefaf4f --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1,5 @@ +/// Nombre del directorio donde se encuentra la configuración. +pub const CONFIG_DIR: &'static str = "config"; + +mod settings; +pub use crate::config::settings::{CONFIG, SETTINGS}; diff --git a/src/config/settings.rs b/src/config/settings.rs new file mode 100644 index 00000000..ffb316f6 --- /dev/null +++ b/src/config/settings.rs @@ -0,0 +1,103 @@ +use crate::Lazy; +use crate::config::CONFIG_DIR; + +use config_rs::{Config, File}; +use serde::Deserialize; + +use std::env; + +/// Carga los ajustes globales "clave = valor" al arrancar la aplicación. +pub static CONFIG: Lazy = Lazy::new(|| { + // Establece el modo de ejecución según el valor de la variable de entorno + // PAGETOP_RUN_MODE. Asume "default" por defecto. + let run_mode = env::var("PAGETOP_RUN_MODE").unwrap_or("default".into()); + + // Inicializa los ajustes. + let mut settings = Config::default(); + + // Lee los ajustes combinando los archivos de configuración disponibles y + // asigna el modo de ejecución. + settings + .merge( + File::with_name( + &format!("{}/{}.toml", CONFIG_DIR, "common") + ).required(false)).unwrap() + .merge( + File::with_name( + &format!("{}/{}.toml", CONFIG_DIR, run_mode) + ).required(false)).unwrap() + .merge( + File::with_name( + &format!("{}/{}.toml", CONFIG_DIR, "local") + ).required(false)).unwrap() + .set("app.run_mode", run_mode).unwrap(); + + settings +}); + +#[macro_export] +/// Usar esta macro para obtener el valor de cualquier ajuste global, donde +/// clave y valor son cadenas de caracteres. Devuelve la cadena vacía si no +/// encuentra un ajuste para la clave. +macro_rules! config_get { + ( $key:expr ) => { + $crate::config::CONFIG.get_str($key).unwrap_or("".to_string()) + }; +} + +#[macro_export] +/// Carga los ajustes específicos de tu módulo o aplicación en una estructura +/// similar a [`SETTINGS`] con tipos de variables seguros. Genera un *panic!* +/// en caso de asignaciones no válidas. +macro_rules! config_map { + ( $COMMENT:expr, $CONF:ident, $TYPE:tt $(, $key:expr => $value:expr)* ) => { + $crate::doc_comment! { + concat!($COMMENT), + + pub static $CONF: $crate::Lazy<$TYPE> = $crate::Lazy::new(|| { + let mut settings = $crate::config::CONFIG.clone(); + $( + settings.set_default($key, $value).unwrap(); + )* + match settings.try_into() { + Ok(c) => c, + Err(e) => panic!("Error parsing settings: {}", e), + } + }); + } + }; +} + +#[derive(Debug, Deserialize)] +pub struct App { + pub name : String, + pub description : String, + pub run_mode : String, +} + +#[derive(Debug, Deserialize)] +pub struct Webserver { + pub bind_address : String, + pub bind_port : u16, +} + +#[derive(Debug, Deserialize)] +pub struct Settings { + pub app : App, + pub webserver : Webserver, +} + +config_map!(r#" +Ajustes globales y valores por defecto para las secciones *\[app\]* y +*\[webserver\]* específicas de PageTop. +"#, + SETTINGS, Settings, + + // [app] + "app.name" => "PageTop Application", + "app.description" => "Developed with the amazing PageTop framework.", + + // [webserver] + "webserver.bind_address" => "localhost", + "webserver.bind_port" => 8088 +); diff --git a/src/core/module/api.rs b/src/core/module/api.rs index 37c84786..bbbdb5eb 100644 --- a/src/core/module/api.rs +++ b/src/core/module/api.rs @@ -1,6 +1,6 @@ use crate::core::server; -/// Modules must implement this trait. +/// Los módulos deben implementar este *trait*. pub trait Module: Send + Sync { fn name(&self) -> String; diff --git a/src/core/server/main.rs b/src/core/server/main.rs index 457bb652..3f5a7d90 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -1,16 +1,21 @@ +use crate::config::SETTINGS; use crate::core::{Server, all, server}; pub fn run(bootstrap: Option) -> Result { - // Call application bootstrap. + // Ejecuta la función de inicio específica para la aplicación. if bootstrap != None { let _ = &(bootstrap.unwrap())(); } + // Inicializa el servidor web. let server = server::HttpServer::new(|| { server::App::new() .configure(&all::modules) }) - .bind("127.0.0.1:8000")? + .bind(format!("{}:{}", + &SETTINGS.webserver.bind_address, + &SETTINGS.webserver.bind_port + ))? .run(); Ok(server) } diff --git a/src/core/state.rs b/src/core/state.rs index 6ded57b8..5535c3b6 100644 --- a/src/core/state.rs +++ b/src/core/state.rs @@ -4,7 +4,7 @@ use crate::core::module::Module; use std::sync::RwLock; // ----------------------------------------------------------------------------- -// Registered modules. +// Módulos registrados. // ----------------------------------------------------------------------------- pub static MODULES: Lazy>> = Lazy::new(|| { diff --git a/src/lib.rs b/src/lib.rs index 01361a13..15be4ce1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,11 @@ // Global. +pub use doc_comment::doc_comment; pub use once_cell::sync::Lazy; -pub mod core; +// ----------------------------------------------------------------------------- +// APIs públicas. +// ----------------------------------------------------------------------------- -pub use actix_web::main; +pub mod config; // Gestión de la configuración. +pub mod core; // Servidor web y sistemas para Temas, Módulos y Respuestas. diff --git a/src/main.rs b/src/main.rs index c1545d0a..4d3e46b9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use pagetop::config_get; use pagetop::core::module::Module; use pagetop::core::{register_module, server}; @@ -16,7 +17,7 @@ impl Module for Greet { } async fn greet() -> impl server::Responder { - "Hello!" + format!("Hello from {}!", config_get!("app.name")) } struct GreetWithParam; @@ -46,7 +47,7 @@ fn bootstrap() { register_module(&GreetWithParam); } -#[pagetop::main] +#[tokio::main] async fn main() -> std::io::Result<()> { server::run(Some(bootstrap))?.await } diff --git a/tests/health_check.rs b/tests/health_check.rs index 4ae6653e..0c309bea 100644 --- a/tests/health_check.rs +++ b/tests/health_check.rs @@ -1,5 +1,7 @@ +use pagetop::core::server; + fn spawn_app() { - let server = pagetop::core::server::run().expect("Failed to bind address"); + let server = server::run(None).expect("Failed to bind address"); let _ = tokio::spawn(server); } From 0e3300dc90dd344cba9e4af6299f2f09145aa4a2 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Sun, 13 Feb 2022 09:12:12 +0100 Subject: [PATCH 006/244] =?UTF-8?q?A=C3=B1ade=20traducci=C3=B3n=20de=20tex?= =?UTF-8?q?tos=20con=20plantillas=20Fluent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 4 ++ config/settings.default.toml | 2 + src/base/mod.rs | 3 ++ .../homepage/locales/en-US/homepage.ftl | 4 ++ .../homepage/locales/es-ES/homepage.ftl | 4 ++ src/base/module/homepage/mod.rs | 39 ++++++++++++++ src/base/module/mod.rs | 1 + src/config/settings.rs | 4 +- src/core/server/main.rs | 9 +++- src/lib.rs | 5 ++ src/locale/mod.rs | 47 +++++++++++++++++ src/macros/mod.rs | 19 +++++++ src/main.rs | 51 +------------------ src/prelude.rs | 10 ++++ 14 files changed, 149 insertions(+), 53 deletions(-) create mode 100644 src/base/mod.rs create mode 100644 src/base/module/homepage/locales/en-US/homepage.ftl create mode 100644 src/base/module/homepage/locales/es-ES/homepage.ftl create mode 100644 src/base/module/homepage/mod.rs create mode 100644 src/base/module/mod.rs create mode 100644 src/locale/mod.rs create mode 100644 src/macros/mod.rs create mode 100644 src/prelude.rs diff --git a/Cargo.toml b/Cargo.toml index 67ed8c44..0b8836ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,10 @@ doc-comment = "0.3.3" once_cell = "1.9.0" config_rs = { package = "config", version = "0.11.0", features = ["toml"] } + +fluent-templates = "0.6.1" +unic-langid = "0.9.0" + actix-web = "4.0.0-rc.3" sycamore = { version = "0.8.0-beta.2", features = ["ssr"] } diff --git a/config/settings.default.toml b/config/settings.default.toml index cef2d7cf..dbbf8355 100644 --- a/config/settings.default.toml +++ b/config/settings.default.toml @@ -1,6 +1,8 @@ [app] name = "PageTop Application" description = "Developed with the amazing PageTop framework." +# Idioma (localización) predeterminado. +language = "en-US" [webserver] # Configuración opcional del servidor web. diff --git a/src/base/mod.rs b/src/base/mod.rs new file mode 100644 index 00000000..fadf78f5 --- /dev/null +++ b/src/base/mod.rs @@ -0,0 +1,3 @@ +//! Temas, Módulos y Componentes base. + +pub mod module; diff --git a/src/base/module/homepage/locales/en-US/homepage.ftl b/src/base/module/homepage/locales/en-US/homepage.ftl new file mode 100644 index 00000000..380b29ee --- /dev/null +++ b/src/base/module/homepage/locales/en-US/homepage.ftl @@ -0,0 +1,4 @@ +module_name = Default homepage +module_desc = Displays a default homepage when none is configured. + +greeting = Hello { $name }! diff --git a/src/base/module/homepage/locales/es-ES/homepage.ftl b/src/base/module/homepage/locales/es-ES/homepage.ftl new file mode 100644 index 00000000..46571c42 --- /dev/null +++ b/src/base/module/homepage/locales/es-ES/homepage.ftl @@ -0,0 +1,4 @@ +module_name = Página de inicio predeterminada +module_desc = Muestra una página de inicio predeterminada cuando no hay ninguna configurada. + +greeting = Hola { $name }! diff --git a/src/base/module/homepage/mod.rs b/src/base/module/homepage/mod.rs new file mode 100644 index 00000000..637659cd --- /dev/null +++ b/src/base/module/homepage/mod.rs @@ -0,0 +1,39 @@ +use crate::prelude::*; + +localize!("en-US", "src/base/module/homepage/locales"); + +pub struct HomepageModule; + +impl Module for HomepageModule { + fn name(&self) -> String { + l("module_name") + } + + fn description(&self) -> String { + l("module_desc") + } + + fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { + cfg.service( + server::web::resource("/") + .route(server::web::get().to(greet)) + ); + cfg.service( + server::web::resource("/{name}") + .route(server::web::get().to(greet_with_param)) + ); + } +} + +async fn greet() -> impl server::Responder { + t("greeting", &args!["name" => config_get!("app.name")]) +} + +async fn greet_with_param(req: server::HttpRequest) -> server::HttpResponse { + let name: String = req.match_info().get("name").unwrap_or("World").into(); + let args = args!["name" => name]; + server::HttpResponse::Ok() + .body(sycamore::render_to_string(|ctx| sycamore::view! { ctx, + p { (t("greeting", &args)) } + })) +} diff --git a/src/base/module/mod.rs b/src/base/module/mod.rs new file mode 100644 index 00000000..070e5b82 --- /dev/null +++ b/src/base/module/mod.rs @@ -0,0 +1 @@ +pub mod homepage; diff --git a/src/config/settings.rs b/src/config/settings.rs index ffb316f6..88c5805d 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -72,6 +72,7 @@ macro_rules! config_map { pub struct App { pub name : String, pub description : String, + pub language : String, pub run_mode : String, } @@ -88,7 +89,7 @@ pub struct Settings { } config_map!(r#" -Ajustes globales y valores por defecto para las secciones *\[app\]* y +Ajustes globales y valores predeterminados para las secciones *\[app\]* y *\[webserver\]* específicas de PageTop. "#, SETTINGS, Settings, @@ -96,6 +97,7 @@ Ajustes globales y valores por defecto para las secciones *\[app\]* y // [app] "app.name" => "PageTop Application", "app.description" => "Developed with the amazing PageTop framework.", + "app.language" => "en-US", // [webserver] "webserver.bind_address" => "localhost", diff --git a/src/core/server/main.rs b/src/core/server/main.rs index 3f5a7d90..49e78a65 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -1,12 +1,17 @@ +use crate::base; use crate::config::SETTINGS; -use crate::core::{Server, all, server}; +use crate::core::{Server, all, register_module, server}; pub fn run(bootstrap: Option) -> Result { - // Ejecuta la función de inicio específica para la aplicación. + // Ejecuta la función de arranque de la aplicación. if bootstrap != None { let _ = &(bootstrap.unwrap())(); } + // Registra la página de inicio de PageTop como último módulo. + // Así, la función de arranque de la aplicación podría sobrecargarlo. + register_module(&base::module::homepage::HomepageModule); + // Inicializa el servidor web. let server = server::HttpServer::new(|| { server::App::new() diff --git a/src/lib.rs b/src/lib.rs index 15be4ce1..87e80aac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,5 +7,10 @@ pub use once_cell::sync::Lazy; // APIs públicas. // ----------------------------------------------------------------------------- +pub mod macros; // Macros útiles. pub mod config; // Gestión de la configuración. +pub mod locale; // Localización. pub mod core; // Servidor web y sistemas para Temas, Módulos y Respuestas. +pub mod base; // Temas, Módulos y Componentes base. + +pub mod prelude; // Re-exporta recursos comunes. diff --git a/src/locale/mod.rs b/src/locale/mod.rs new file mode 100644 index 00000000..21fd7bd1 --- /dev/null +++ b/src/locale/mod.rs @@ -0,0 +1,47 @@ +use crate::Lazy; +use crate::config::SETTINGS; + +use unic_langid::LanguageIdentifier; + +pub use fluent_templates::{static_loader as static_locale, Loader as Locale}; +pub use fluent_templates; +pub use fluent_templates::fluent_bundle::FluentValue; + +/// Almacena el Identificador de Idioma Unicode ([Unicode Language Identifier] +/// (https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier)) de +/// la aplicación, obtenido de `SETTINGS.app.language`. +pub static LANGID: Lazy = Lazy::new(|| { + SETTINGS.app.language.parse().expect("Failed to parse.") +}); + +#[macro_export] +/// Permite integrar fácilmente localización en tus temas y módulos. +macro_rules! localize { + ( $DEF_LANGID:literal, $locales:literal $(, $core_locales:literal)? ) => { + use $crate::locale::*; + + static_locale! { + static LOCALES = { + locales: $locales, + $( core_locales: $core_locales, )? + fallback_language: $DEF_LANGID, + + // Elimina las marcas Unicode que delimitan los argumentos. + customise: |bundle| bundle.set_use_isolating(false), + }; + } + + #[allow(dead_code)] + pub fn l(key: &str) -> String { + LOCALES.lookup(&LANGID, key) + } + + #[allow(dead_code)] + pub fn t( + key: &str, + args: &std::collections::HashMap + ) -> String { + LOCALES.lookup_with_args(&LANGID, key, args) + } + }; +} diff --git a/src/macros/mod.rs b/src/macros/mod.rs new file mode 100644 index 00000000..ef3c05d5 --- /dev/null +++ b/src/macros/mod.rs @@ -0,0 +1,19 @@ +#[macro_export] +/// Macro para construir grupos de pares clave-valor. +/// +/// ``` +/// let args = args![ +/// "userName" => "Roberto", +/// "photoCount" => 3, +/// "userGender" => "male" +/// ]; +/// ``` +macro_rules! args { + ( $($key:expr => $value:expr),* ) => {{ + let mut a = std::collections::HashMap::new(); + $( + a.insert(String::from($key), $value.into()); + )* + a + }}; +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 4d3e46b9..96cee3df 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,53 +1,4 @@ -use pagetop::config_get; -use pagetop::core::module::Module; -use pagetop::core::{register_module, server}; - -struct Greet; -impl Module for Greet { - fn name(&self) -> String { - "Hello".to_string() - } - - fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { - cfg.service( - server::web::resource("/") - .route(server::web::get().to(greet)) - ); - } -} - -async fn greet() -> impl server::Responder { - format!("Hello from {}!", config_get!("app.name")) -} - -struct GreetWithParam; -impl Module for GreetWithParam { - fn name(&self) -> String { - "Hello World!".to_string() - } - - fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { - cfg.service( - server::web::resource("/{name}") - .route(server::web::get().to(greet_with_param)) - ); - } -} - -async fn greet_with_param(req: server::HttpRequest) -> server::HttpResponse { - let name: String = req.match_info().get("name").unwrap_or("World").into(); - server::HttpResponse::Ok() - .body(sycamore::render_to_string(|ctx| sycamore::view! { ctx, - p { "Hello " (name) "!" } - })) -} - -fn bootstrap() { - register_module(&Greet); - register_module(&GreetWithParam); -} - #[tokio::main] async fn main() -> std::io::Result<()> { - server::run(Some(bootstrap))?.await + pagetop::core::server::run(None)?.await } diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 00000000..43370939 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,10 @@ +//! Re-exporta recursos comunes. + +pub use crate::args; +pub use crate::config_get; +pub use crate::localize; + +pub use crate::core::module::*; + +pub use crate::core::server; +pub use crate::core::register_module; From 24e773c17b78e7232be52593c99942837219237c Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Sun, 13 Feb 2022 20:11:33 +0100 Subject: [PATCH 007/244] =?UTF-8?q?A=C3=B1ade=20composici=C3=B3n=20de=20p?= =?UTF-8?q?=C3=A1ginas=20basada=20en=20componentes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 7 +- STARTER.Cargo.toml | 6 +- config/default.toml | 1 + config/settings.default.toml | 2 + src/base/component/chunck.rs | 77 ++++++ src/base/component/container.rs | 103 +++++++ src/base/component/mod.rs | 2 + src/base/mod.rs | 2 + .../homepage/locales/en-US/homepage.ftl | 2 +- .../homepage/locales/es-ES/homepage.ftl | 2 +- src/base/module/homepage/mod.rs | 24 +- src/base/theme/minimal/mod.rs | 9 + src/base/theme/mod.rs | 1 + src/config/settings.rs | 2 + src/core/all.rs | 6 + src/core/mod.rs | 4 + src/core/response/mod.rs | 1 + src/core/response/page/assets.rs | 258 ++++++++++++++++++ src/core/response/page/component.rs | 34 +++ src/core/response/page/container.rs | 33 +++ src/core/response/page/mod.rs | 12 + src/core/response/page/page.rs | 172 ++++++++++++ src/core/server/main.rs | 5 +- src/core/server/mod.rs | 4 +- src/core/state.rs | 46 ++++ src/core/theme/api.rs | 84 ++++++ src/core/theme/mod.rs | 4 + src/locale/mod.rs | 10 + src/main.rs | 2 +- src/prelude.rs | 11 +- 30 files changed, 895 insertions(+), 31 deletions(-) create mode 100644 src/base/component/chunck.rs create mode 100644 src/base/component/container.rs create mode 100644 src/base/component/mod.rs create mode 100644 src/base/theme/minimal/mod.rs create mode 100644 src/base/theme/mod.rs create mode 100644 src/core/response/mod.rs create mode 100644 src/core/response/page/assets.rs create mode 100644 src/core/response/page/component.rs create mode 100644 src/core/response/page/container.rs create mode 100644 src/core/response/page/mod.rs create mode 100644 src/core/response/page/page.rs create mode 100644 src/core/theme/api.rs create mode 100644 src/core/theme/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 0b8836ad..db5f7be9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,10 +32,11 @@ config_rs = { package = "config", version = "0.11.0", features = ["toml"] } fluent-templates = "0.6.1" unic-langid = "0.9.0" -actix-web = "4.0.0-rc.3" -sycamore = { version = "0.8.0-beta.2", features = ["ssr"] } +actix-web = "3.3.3" +maud = { version = "0.23.0", features = ["actix-web"] } +sycamore = { version = "0.7.1", features = ["ssr"] } +downcast-rs = "1.2.0" -tokio = { version = "1.16", features = ["macros", "rt-multi-thread"] } serde = { version = "1.0", features = ["derive"] } [lib] diff --git a/STARTER.Cargo.toml b/STARTER.Cargo.toml index 13ef591d..1db51f3d 100644 --- a/STARTER.Cargo.toml +++ b/STARTER.Cargo.toml @@ -8,7 +8,5 @@ edition = "2021" [dependencies] pagetop = { path = "pagetop" } -tokio = { version = "1.16", features = ["macros", "rt-multi-thread"] } - -[[bin]] -name = "app" +actix-web = "3.3.3" +maud = { version = "0.23.0" } diff --git a/config/default.toml b/config/default.toml index 429d6da5..f96d1a7d 100644 --- a/config/default.toml +++ b/config/default.toml @@ -1,2 +1,3 @@ [app] name = "PageTop Essence" +language = "es-ES" diff --git a/config/settings.default.toml b/config/settings.default.toml index dbbf8355..c726c44e 100644 --- a/config/settings.default.toml +++ b/config/settings.default.toml @@ -3,6 +3,8 @@ name = "PageTop Application" description = "Developed with the amazing PageTop framework." # Idioma (localización) predeterminado. language = "en-US" +# Tema predeterminado. +theme = "Minimal" [webserver] # Configuración opcional del servidor web. diff --git a/src/base/component/chunck.rs b/src/base/component/chunck.rs new file mode 100644 index 00000000..29c62918 --- /dev/null +++ b/src/base/component/chunck.rs @@ -0,0 +1,77 @@ +use crate::prelude::*; + +pub struct Chunck { + renderable: fn() -> bool, + weight : i8, + markup : Vec, + template : String, +} + +impl PageComponent for Chunck { + + fn prepare() -> Self { + Chunck { + renderable: always, + weight : 0, + markup : Vec::new(), + template : "default".to_string(), + } + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> i8 { + self.weight + } + + fn default_render(&self, _: &mut PageAssets) -> Markup { + html! { + @for markup in self.markup.iter() { + (*markup) + } + } + } +} + +impl Chunck { + + // Chunck BUILDER. + + pub fn markup(markup: Markup) -> Self { + let mut chunck = Chunck::prepare(); + chunck.markup.push(markup); + chunck + } + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn add_markup(mut self, markup: Markup) -> Self { + self.markup.push(markup); + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.template = template.to_string(); + self + } + + // Chunck GETTERS. + + pub fn template(&self) -> &str { + self.template.as_str() + } +} + +fn always() -> bool { + true +} diff --git a/src/base/component/container.rs b/src/base/component/container.rs new file mode 100644 index 00000000..58a0caac --- /dev/null +++ b/src/base/component/container.rs @@ -0,0 +1,103 @@ +use crate::prelude::*; + +enum ContainerType { Column, Row, Wrapper } + +pub struct Container { + renderable: fn() -> bool, + weight : i8, + id : String, + container : ContainerType, + components: PageContainer, + template : String, +} + +impl PageComponent for Container { + + fn prepare() -> Self { + Container { + renderable: always, + weight : 0, + id : "".to_string(), + container : ContainerType::Wrapper, + components: PageContainer::new(), + template : "default".to_string(), + } + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> i8 { + self.weight + } + + fn default_render(&self, assets: &mut PageAssets) -> Markup { + let classes = match self.container { + ContainerType::Wrapper => "wrapper", + ContainerType::Row => "row", + ContainerType::Column => "col", + }; + html! { + div class=(classes) { + (self.components.render(assets)) + } + } + } +} + +impl Container { + + // Container BUILDER. + + pub fn row() -> Self { + let mut grid = Container::prepare(); + grid.container = ContainerType::Row; + grid + } + + pub fn column() -> Self { + let mut grid = Container::prepare(); + grid.container = ContainerType::Column; + grid + } + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_id(mut self, id: &str) -> Self { + self.id = id.to_string(); + self + } + + pub fn add(mut self, component: impl PageComponent) -> Self { + self.components.add(component); + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.template = template.to_string(); + self + } + + // Grid GETTERS. + + pub fn id(&self) -> &str { + self.id.as_str() + } + + pub fn template(&self) -> &str { + self.template.as_str() + } +} + +fn always() -> bool { + true +} diff --git a/src/base/component/mod.rs b/src/base/component/mod.rs new file mode 100644 index 00000000..c12fb175 --- /dev/null +++ b/src/base/component/mod.rs @@ -0,0 +1,2 @@ +pub mod container; +pub mod chunck; diff --git a/src/base/mod.rs b/src/base/mod.rs index fadf78f5..f40d2d0e 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -1,3 +1,5 @@ //! Temas, Módulos y Componentes base. +pub mod theme; pub mod module; +pub mod component; diff --git a/src/base/module/homepage/locales/en-US/homepage.ftl b/src/base/module/homepage/locales/en-US/homepage.ftl index 380b29ee..7008c35a 100644 --- a/src/base/module/homepage/locales/en-US/homepage.ftl +++ b/src/base/module/homepage/locales/en-US/homepage.ftl @@ -1,4 +1,4 @@ module_name = Default homepage module_desc = Displays a default homepage when none is configured. -greeting = Hello { $name }! +greetings = Hello { $name }! diff --git a/src/base/module/homepage/locales/es-ES/homepage.ftl b/src/base/module/homepage/locales/es-ES/homepage.ftl index 46571c42..7af7b370 100644 --- a/src/base/module/homepage/locales/es-ES/homepage.ftl +++ b/src/base/module/homepage/locales/es-ES/homepage.ftl @@ -1,4 +1,4 @@ module_name = Página de inicio predeterminada module_desc = Muestra una página de inicio predeterminada cuando no hay ninguna configurada. -greeting = Hola { $name }! +greetings = ¡Hola { $name }! diff --git a/src/base/module/homepage/mod.rs b/src/base/module/homepage/mod.rs index 637659cd..4133f6ba 100644 --- a/src/base/module/homepage/mod.rs +++ b/src/base/module/homepage/mod.rs @@ -14,26 +14,16 @@ impl Module for HomepageModule { } fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { - cfg.service( - server::web::resource("/") - .route(server::web::get().to(greet)) - ); - cfg.service( - server::web::resource("/{name}") - .route(server::web::get().to(greet_with_param)) - ); + cfg.service(server::web::resource("/").to(home)); + cfg.service(server::web::resource("/{name}").to(home)); } } -async fn greet() -> impl server::Responder { - t("greeting", &args!["name" => config_get!("app.name")]) -} - -async fn greet_with_param(req: server::HttpRequest) -> server::HttpResponse { +async fn home(req: server::HttpRequest) -> server::Result { let name: String = req.match_info().get("name").unwrap_or("World").into(); - let args = args!["name" => name]; - server::HttpResponse::Ok() - .body(sycamore::render_to_string(|ctx| sycamore::view! { ctx, - p { (t("greeting", &args)) } + Page::prepare() + .add_to("content", Chunck::markup(html! { + h1 { (t("greetings", &args![ "name" => name])) } })) + .render() } diff --git a/src/base/theme/minimal/mod.rs b/src/base/theme/minimal/mod.rs new file mode 100644 index 00000000..ea1ea1f4 --- /dev/null +++ b/src/base/theme/minimal/mod.rs @@ -0,0 +1,9 @@ +use crate::prelude::*; + +pub struct MinimalTheme; + +impl Theme for MinimalTheme { + fn name(&self) -> &str { + "Minimal" + } +} diff --git a/src/base/theme/mod.rs b/src/base/theme/mod.rs new file mode 100644 index 00000000..b272be88 --- /dev/null +++ b/src/base/theme/mod.rs @@ -0,0 +1 @@ +pub mod minimal; diff --git a/src/config/settings.rs b/src/config/settings.rs index 88c5805d..3c9a7853 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -73,6 +73,7 @@ pub struct App { pub name : String, pub description : String, pub language : String, + pub theme : String, pub run_mode : String, } @@ -98,6 +99,7 @@ Ajustes globales y valores predeterminados para las secciones *\[app\]* y "app.name" => "PageTop Application", "app.description" => "Developed with the amazing PageTop framework.", "app.language" => "en-US", + "app.theme" => "Minimal", // [webserver] "webserver.bind_address" => "localhost", diff --git a/src/core/all.rs b/src/core/all.rs index 4067a838..716dac9b 100644 --- a/src/core/all.rs +++ b/src/core/all.rs @@ -1,5 +1,11 @@ use crate::core::{server, state}; +pub fn themes(cfg: &mut server::web::ServiceConfig) { + for t in state::THEMES.read().unwrap().iter() { + t.configure_theme(cfg); + } +} + pub fn modules(cfg: &mut server::web::ServiceConfig) { for m in state::MODULES.read().unwrap().iter() { m.configure_module(cfg); diff --git a/src/core/mod.rs b/src/core/mod.rs index 3c6040c9..de375c10 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,9 +1,13 @@ pub use actix_web::dev::Server; mod state; +pub use state::register_theme; pub use state::register_module; +pub use state::add_component_to; mod all; +pub mod theme; pub mod module; +pub mod response; pub mod server; diff --git a/src/core/response/mod.rs b/src/core/response/mod.rs new file mode 100644 index 00000000..79d28612 --- /dev/null +++ b/src/core/response/mod.rs @@ -0,0 +1 @@ +pub mod page; diff --git a/src/core/response/page/assets.rs b/src/core/response/page/assets.rs new file mode 100644 index 00000000..d36c870e --- /dev/null +++ b/src/core/response/page/assets.rs @@ -0,0 +1,258 @@ +use crate::core::theme::{Markup, PreEscaped, html}; + +// ----------------------------------------------------------------------------- +// Favicon. +// ----------------------------------------------------------------------------- + +pub struct Favicon(Vec); + +impl Favicon { + pub fn new() -> Self { + Favicon(Vec::new()) + } + + pub fn with_icon(self, image: &str) -> Self { + self.add_item("icon", image, "", "") + } + + pub fn with_icon_for_sizes(self, image: &str, sizes: &str) -> Self { + self.add_item("icon", image, sizes, "") + } + + pub fn with_apple_touch_icon(self, image: &str, sizes: &str) -> Self { + self.add_item("apple-touch-icon", image, sizes, "") + } + + pub fn with_mask_icon(self, image: &str, color: &str) -> Self { + self.add_item("mask-icon", image, "", color) + } + + pub fn with_manifest(self, file: &str) -> Self { + self.add_item("manifest", file, "", "") + } + + pub fn with_theme_color(mut self, color: &str) -> Self { + self.0.push(format!( + "", color + )); + self + } + + pub fn with_ms_tile_color(mut self, color: &str) -> Self { + self.0.push(format!( + "", color + )); + self + } + + pub fn with_ms_tile_image(mut self, image: &str) -> Self { + self.0.push(format!( + "", image + )); + self + } + + fn add_item( + mut self, + rel : &str, + source: &str, + sizes : &str, + color : &str + ) -> Self { + let mut link: String = format!(" format!("{} type=\"image/gif\"", link), + ".ico" => format!("{} type=\"image/x-icon\"", link), + ".jpg" => format!("{} type=\"image/jpg\"", link), + ".png" => format!("{} type=\"image/png\"", link), + ".svg" => format!("{} type=\"image/svg+xml\"", link), + _ => link + }; + } + if !sizes.is_empty() { + link = format!("{} sizes=\"{}\"", link, sizes); + } + if !color.is_empty() { + link = format!("{} color=\"{}\"", link, color); + } + self.0.push(format!("{} href=\"{}\">", link, source)); + self + } + + fn render(&self) -> Markup { + html! { + @for item in &self.0 { + (PreEscaped(item)) + } + } + } +} + +// ----------------------------------------------------------------------------- +// StyleSheet. +// ----------------------------------------------------------------------------- + +pub struct StyleSheet { + source: &'static str, + weight: i8, +} +impl StyleSheet { + pub fn source(s: &'static str) -> Self { + StyleSheet { + source: s, + weight: 0, + } + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn weight(self) -> i8 { + self.weight + } + + fn render(&self) -> Markup { + html! { + link rel="stylesheet" href=(self.source); + } + } +} + +// ----------------------------------------------------------------------------- +// JavaScript. +// ----------------------------------------------------------------------------- + +#[derive(PartialEq)] +pub enum JSMode { Async, Defer, Normal } + +pub struct JavaScript { + source: &'static str, + weight: i8, + mode : JSMode, +} +impl JavaScript { + pub fn source(s: &'static str) -> Self { + JavaScript { + source: s, + weight: 0, + mode : JSMode::Defer, + } + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_mode(mut self, mode: JSMode) -> Self { + self.mode = mode; + self + } + + pub fn weight(self) -> i8 { + self.weight + } + + fn render(&self) -> Markup { + html! { + script type="text/javascript" + src=(self.source) + async[self.mode == JSMode::Async] + defer[self.mode == JSMode::Defer] + {}; + } + } +} + +// ----------------------------------------------------------------------------- +// Page assets. +// ----------------------------------------------------------------------------- + +pub struct Assets { + favicon : Option, + metadata : Vec<(String, String)>, + stylesheets: Vec, + javascripts: Vec, + seqid_count: u16, +} + +impl Assets { + pub fn new() -> Self { + Assets { + favicon : None, + metadata : Vec::new(), + stylesheets: Vec::new(), + javascripts: Vec::new(), + seqid_count: 0, + } + } + + pub fn with_favicon(&mut self, favicon: Favicon) -> &mut Self { + self.favicon = Some(favicon); + self + } + + pub fn add_metadata(&mut self, name: String, content: String) -> &mut Self { + self.metadata.push((name, content)); + self + } + + pub fn add_stylesheet(&mut self, css: StyleSheet) -> &mut Self { + match self.stylesheets.iter().position(|x| x.source == css.source) { + Some(index) => if self.stylesheets[index].weight > css.weight { + self.stylesheets.remove(index); + self.stylesheets.push(css); + }, + _ => self.stylesheets.push(css) + } + self + } + + pub fn add_javascript(&mut self, js: JavaScript) -> &mut Self { + match self.javascripts.iter().position(|x| x.source == js.source) { + Some(index) => if self.javascripts[index].weight > js.weight { + self.javascripts.remove(index); + self.javascripts.push(js); + }, + _ => self.javascripts.push(js) + } + self + } + + pub fn render(&mut self) -> Markup { + let ordered_css = &mut self.stylesheets; + ordered_css.sort_by_key(|o| o.weight); + + let ordered_js = &mut self.javascripts; + ordered_js.sort_by_key(|o| o.weight); + + html! { + @match &self.favicon { + Some(favicon) => (favicon.render()), + None => "", + } + @for (name, content) in &self.metadata { + meta name=(name) content=(content) {} + } + @for css in ordered_css { + (css.render()) + } + @for js in ordered_js { + (js.render()) + } + } + } + + // Assets GETTERS. + + pub fn seqid(&mut self, id: &str) -> String { + if id.is_empty() { + self.seqid_count += 1; + return format!("seqid-{}", self.seqid_count); + } + id.to_string() + } +} diff --git a/src/core/response/page/component.rs b/src/core/response/page/component.rs new file mode 100644 index 00000000..097d960f --- /dev/null +++ b/src/core/response/page/component.rs @@ -0,0 +1,34 @@ +use crate::core::theme::{Markup, html}; +use crate::core::response::page::PageAssets; + +use downcast_rs::{Downcast, impl_downcast}; + +use std::any::type_name; + +pub trait Component: Downcast + Send + Sync { + + fn prepare() -> Self where Self: Sized; + + fn qualified_name(&self) -> &str { + type_name::() + } + + fn description(&self) -> &str { + "" + } + + fn is_renderable(&self) -> bool { + true + } + + fn weight(&self) -> i8 { + 0 + } + + #[allow(unused_variables)] + fn default_render(&self, assets: &mut PageAssets) -> Markup { + html! {} + } +} + +impl_downcast!(Component); diff --git a/src/core/response/page/container.rs b/src/core/response/page/container.rs new file mode 100644 index 00000000..c9d2e13b --- /dev/null +++ b/src/core/response/page/container.rs @@ -0,0 +1,33 @@ +use crate::core::theme::{Markup, html}; +use crate::core::response::page::{PageAssets, PageComponent, render_component}; + +use std::sync::Arc; + +#[derive(Clone)] +pub struct Container(Vec>); + +impl Container { + pub fn new() -> Self { + Container(Vec::new()) + } + + pub fn new_with(component: impl PageComponent) -> Self { + let mut container = Container::new(); + container.add(component); + container + } + + pub fn add(&mut self, component: impl PageComponent) { + self.0.push(Arc::new(component)); + } + + pub fn render(&self, assets: &mut PageAssets) -> Markup { + let mut components = self.0.clone(); + components.sort_by_key(|c| c.weight()); + html! { + @for c in components.iter() { + (render_component(&**c, assets)) + } + } + } +} \ No newline at end of file diff --git a/src/core/response/page/mod.rs b/src/core/response/page/mod.rs new file mode 100644 index 00000000..881e0df3 --- /dev/null +++ b/src/core/response/page/mod.rs @@ -0,0 +1,12 @@ +pub mod assets; +pub use assets::Assets as PageAssets; + +mod component; +pub use component::Component as PageComponent; + +mod container; +pub use container::Container as PageContainer; + +mod page; +pub use page::Page; +pub use page::render_component; diff --git a/src/core/response/page/page.rs b/src/core/response/page/page.rs new file mode 100644 index 00000000..add4c64d --- /dev/null +++ b/src/core/response/page/page.rs @@ -0,0 +1,172 @@ +use crate::config::SETTINGS; +use crate::core::server; +use crate::core::state::{COMPONENTS, THEME}; +use crate::core::theme::{DOCTYPE, Markup, html}; +use crate::core::response::page::{PageAssets, PageComponent, PageContainer}; + +use std::borrow::Cow; +use std::collections::HashMap; + +pub enum TextDirection { LeftToRight, RightToLeft, Auto } + +pub struct Page<'a> { + language : &'a str, + title : &'a str, + direction : &'a str, + description : &'a str, + body_classes: Cow<'a, str>, + assets : PageAssets, + regions : HashMap<&'a str, PageContainer>, + template : &'a str, +} + +impl<'a> Page<'a> { + + pub fn prepare() -> Self { + Page { + language : &SETTINGS.app.language[..2], + title : &SETTINGS.app.name, + direction : "ltr", + description : "", + body_classes: "body".into(), + assets : PageAssets::new(), + regions : COMPONENTS.read().unwrap().clone(), + template : "default", + } + } + + // Page BUILDER. + + pub fn with_language(&mut self, language: &'a str) -> &mut Self { + self.language = language; + self + } + + pub fn with_title(&mut self, title: &'a str) -> &mut Self { + self.title = title; + self + } + + pub fn with_direction(&mut self, dir: TextDirection) -> &mut Self { + self.direction = match dir { + TextDirection::LeftToRight => "ltr", + TextDirection::RightToLeft => "rtl", + _ => "auto" + }; + self + } + + pub fn with_description(&mut self, description: &'a str) -> &mut Self { + self.description = description; + self + } + + pub fn with_body_classes(&mut self, body_classes: &'a str) -> &mut Self { + self.body_classes = body_classes.into(); + self + } + + pub fn add_body_classes(&mut self, body_classes: &'a str) -> &mut Self { + self.body_classes = String::from( + format!("{} {}", self.body_classes, body_classes).trim() + ).into(); + self + } + + pub fn add_to( + &mut self, + region: &'a str, + component: impl PageComponent + ) -> &mut Self { + if let Some(regions) = self.regions.get_mut(region) { + regions.add(component); + } else { + self.regions.insert(region, PageContainer::new_with(component)); + } + self + } + + pub fn using_template(&mut self, template: &'a str) -> &mut Self { + self.template = template; + self + } + + // Page GETTERS. + + pub fn language(&self) -> &str { + self.language + } + + pub fn title(&self) -> &str { + self.title + } + + pub fn direction(&self) -> TextDirection { + match self.direction { + "ltr" => TextDirection::LeftToRight, + "rtl" => TextDirection::RightToLeft, + _ => TextDirection::Auto + } + } + + pub fn description(&self) -> &str { + self.description + } + + pub fn body_classes(&self) -> &str { + if self.body_classes.is_empty() { + return "body"; + } + &self.body_classes + } + + pub fn assets(&mut self) -> &mut PageAssets { + &mut self.assets + } + + pub fn template(&self) -> &str { + self.template + } + + // Page RENDER. + + pub fn render(&mut self) -> server::Result { + // Acciones del tema antes de renderizar la página. + THEME.before_render_page(self); + + // Primero, renderizar el cuerpo. + let body = THEME.render_page_body(self); + + // Luego, renderizar la cabecera. + let head = THEME.render_page_head(self); + + // Finalmente, renderizar la página. + return Ok(html! { + (DOCTYPE) + html lang=(self.language) dir=(self.direction) { + (head) + (body) + } + }) + } + + pub fn render_region(&mut self, region: &str) -> Markup { + match self.regions.get_mut(region) { + Some(components) => components.render(&mut self.assets), + None => html! {} + } + } +} + +pub fn render_component( + component: &dyn PageComponent, + assets: &mut PageAssets +) -> Markup { + match component.is_renderable() { + true => match THEME.render_component(component, assets) { + Some(markup) => markup, + None => component.default_render(assets) + }, + false => html! {} + } +} diff --git a/src/core/server/main.rs b/src/core/server/main.rs index 49e78a65..ea0deafc 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -8,13 +8,14 @@ pub fn run(bootstrap: Option) -> Result { let _ = &(bootstrap.unwrap())(); } - // Registra la página de inicio de PageTop como último módulo. - // Así, la función de arranque de la aplicación podría sobrecargarlo. + // Registra el módulo para la página de inicio de PageTop. + // Al ser el último, puede sobrecargarse en la función de arranque. register_module(&base::module::homepage::HomepageModule); // Inicializa el servidor web. let server = server::HttpServer::new(|| { server::App::new() + .configure(&all::themes) .configure(&all::modules) }) .bind(format!("{}:{}", diff --git a/src/core/server/mod.rs b/src/core/server/mod.rs index d39c1d4d..713a7ae6 100644 --- a/src/core/server/mod.rs +++ b/src/core/server/mod.rs @@ -1,4 +1,6 @@ -pub use actix_web::{App, HttpRequest, HttpResponse, HttpServer, Responder, web}; +pub use actix_web::{ + App, HttpRequest, HttpResponse, HttpServer, Responder, Result, web +}; mod main; pub use main::run; diff --git a/src/core/state.rs b/src/core/state.rs index 5535c3b6..69b6a4de 100644 --- a/src/core/state.rs +++ b/src/core/state.rs @@ -1,7 +1,35 @@ use crate::Lazy; +use crate::config::SETTINGS; +use crate::core::theme::Theme; use crate::core::module::Module; +use crate::core::response::page::{PageComponent, PageContainer}; +use crate::base; use std::sync::RwLock; +use std::collections::HashMap; + +// ----------------------------------------------------------------------------- +// Temas registrados. +// ----------------------------------------------------------------------------- + +pub static THEMES: Lazy>> = Lazy::new(|| { + RwLock::new(vec![ + &base::theme::minimal::MinimalTheme, + ]) +}); + +pub static THEME: Lazy<&dyn Theme> = Lazy::new(|| { + for t in THEMES.read().unwrap().iter() { + if t.name().to_lowercase() == SETTINGS.app.theme.to_lowercase() { + return *t; + } + } + &base::theme::minimal::MinimalTheme +}); + +pub fn register_theme(t: &'static (dyn Theme + 'static)) { + THEMES.write().unwrap().push(t); +} // ----------------------------------------------------------------------------- // Módulos registrados. @@ -14,3 +42,21 @@ pub static MODULES: Lazy>> = Lazy::new(|| { pub fn register_module(m: &'static (dyn Module + 'static)) { MODULES.write().unwrap().push(m); } + +// ----------------------------------------------------------------------------- +// Componentes globales. +// ----------------------------------------------------------------------------- + +pub static COMPONENTS: Lazy>> = Lazy::new( + || { RwLock::new(HashMap::new()) } +); + +#[allow(dead_code)] +pub fn add_component_to(region: &'static str, component: impl PageComponent) { + let mut hmap = COMPONENTS.write().unwrap(); + if let Some(regions) = hmap.get_mut(region) { + regions.add(component); + } else { + hmap.insert(region, PageContainer::new_with(component)); + } +} diff --git a/src/core/theme/api.rs b/src/core/theme/api.rs new file mode 100644 index 00000000..26d71552 --- /dev/null +++ b/src/core/theme/api.rs @@ -0,0 +1,84 @@ +use crate::core::server; +use crate::core::theme::{Markup, html}; +use crate::core::response::page::{Page, PageAssets, PageComponent}; + +/// Los temas deben implementar este "trait". +pub trait Theme: Send + Sync { + fn name(&self) -> &str; + + fn description(&self) -> &str { + "" + } + + #[allow(unused_variables)] + fn configure_theme(&self, cfg: &mut server::web::ServiceConfig) { + } + + #[allow(unused_variables)] + fn before_render_page(&self, page: &mut Page) { + } + + fn render_page_head(&self, page: &mut Page) -> Markup { + let viewport = "width=device-width, initial-scale=1, shrink-to-fit=no"; + let description = page.description(); + html! { + head { + meta charset="utf-8"; + + meta http-equiv="X-UA-Compatible" content="IE=edge"; + meta name="viewport" content=(viewport); + @if !description.is_empty() { + meta name="description" content=(description); + } + + title { (page.title()) } + + (page.assets().render()) + } + } + } + + fn render_page_body(&self, page: &mut Page) -> Markup { + html! { + body id="body" class=(page.body_classes()) { + @match page.template() { + "admin" => { + @for region in &["top-menu", "side-menu", "content"] { + #(region) { + (page.render_region(region)) + } + } + }, + _ => { + #content { + (page.render_region("content")) + } + } + } + } + } + } + + #[allow(unused_variables)] + fn render_component( + &self, + component: &dyn PageComponent, + assets: &mut PageAssets + ) -> Option { + None + /* + Cómo usarlo: + + match component.type_name() { + "Block" => { + let block = component.downcast_mut::().unwrap(); + match block.template() { + "default" => Some(block_default(block)), + _ => None + } + }, + _ => None + } + */ + } +} diff --git a/src/core/theme/mod.rs b/src/core/theme/mod.rs new file mode 100644 index 00000000..9b908257 --- /dev/null +++ b/src/core/theme/mod.rs @@ -0,0 +1,4 @@ +pub use maud::{DOCTYPE, Markup, PreEscaped, html}; + +mod api; +pub use api::Theme; diff --git a/src/locale/mod.rs b/src/locale/mod.rs index 21fd7bd1..6e64cc8f 100644 --- a/src/locale/mod.rs +++ b/src/locale/mod.rs @@ -43,5 +43,15 @@ macro_rules! localize { ) -> String { LOCALES.lookup_with_args(&LANGID, key, args) } + + #[allow(dead_code)] + pub fn e( + key: &str, + args: &std::collections::HashMap + ) -> crate::core::theme::PreEscaped { + crate::core::theme::PreEscaped( + LOCALES.lookup_with_args(&LANGID, key, args) + ) + } }; } diff --git a/src/main.rs b/src/main.rs index 96cee3df..8559a909 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -#[tokio::main] +#[actix_web::main] async fn main() -> std::io::Result<()> { pagetop::core::server::run(None)?.await } diff --git a/src/prelude.rs b/src/prelude.rs index 43370939..c74bb379 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,10 +1,19 @@ //! Re-exporta recursos comunes. pub use crate::args; -pub use crate::config_get; pub use crate::localize; +pub use crate::core::theme::*; + pub use crate::core::module::*; +pub use crate::core::response::page::*; +pub use crate::core::response::page::assets::*; + pub use crate::core::server; +pub use crate::core::register_theme; pub use crate::core::register_module; +pub use crate::core::add_component_to; + +pub use crate::base::component::container::Container; +pub use crate::base::component::chunck::Chunck; From 5d2901d32ad38e8c1bf17380e2b9350057d84237 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Mon, 14 Feb 2022 19:36:16 +0100 Subject: [PATCH 008/244] =?UTF-8?q?A=C3=B1ade=20un=20r=C3=B3tulo=20opciona?= =?UTF-8?q?l=20al=20arrancar=20la=20aplicaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 1 + config/settings.default.toml | 2 + resources/slant.flf | 1295 +++++++++++++++++++++++++++++++++ resources/small.flf | 1097 ++++++++++++++++++++++++++++ resources/speed.flf | 1301 ++++++++++++++++++++++++++++++++++ resources/starwars.flf | 719 +++++++++++++++++++ src/config/settings.rs | 20 +- src/core/server/main.rs | 18 + 8 files changed, 4444 insertions(+), 9 deletions(-) create mode 100644 resources/slant.flf create mode 100644 resources/small.flf create mode 100644 resources/speed.flf create mode 100644 resources/starwars.flf diff --git a/Cargo.toml b/Cargo.toml index db5f7be9..1a36650e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ categories = [ [dependencies] doc-comment = "0.3.3" once_cell = "1.9.0" +figlet-rs = "0.1.3" config_rs = { package = "config", version = "0.11.0", features = ["toml"] } diff --git a/config/settings.default.toml b/config/settings.default.toml index c726c44e..0a446896 100644 --- a/config/settings.default.toml +++ b/config/settings.default.toml @@ -5,6 +5,8 @@ description = "Developed with the amazing PageTop framework." language = "en-US" # Tema predeterminado. theme = "Minimal" +# Rótulo al inicio: "Off", "Slant", "Small", "Speed" or "Starwars". +startup_banner = "Small" [webserver] # Configuración opcional del servidor web. diff --git a/resources/slant.flf b/resources/slant.flf new file mode 100644 index 00000000..ea27b6ed --- /dev/null +++ b/resources/slant.flf @@ -0,0 +1,1295 @@ +flf2a$ 6 5 16 15 10 0 18319 +Slant by Glenn Chappell 3/93 -- based on Standard +Includes ISO Latin-1 +figlet release 2.1 -- 12 Aug 1994 +Permission is hereby given to modify this font, as long as the +modifier's name is placed on a comment line. + +Modified by Paul Burton 12/96 to include new parameter +supported by FIGlet and FIGWin. May also be slightly modified for better use +of new full-width/kern/smush alternatives, but default output is NOT changed. + + $$@ + $$ @ + $$ @ + $$ @ + $$ @ +$$ @@ + __@ + / /@ + / / @ + /_/ @ +(_) @ + @@ + _ _ @ +( | )@ +|/|/ @ + $ @ +$ @ + @@ + __ __ @ + __/ // /_@ + /_ _ __/@ +/_ _ __/ @ + /_//_/ @ + @@ + __@ + _/ /@ + / __/@ + (_ ) @ +/ _/ @ +/_/ @@ + _ __@ + (_)_/_/@ + _/_/ @ + _/_/_ @ +/_/ (_) @ + @@ + ___ @ + ( _ ) @ + / __ \/|@ +/ /_/ < @ +\____/\/ @ + @@ + _ @ + ( )@ + |/ @ + $ @ +$ @ + @@ + __@ + _/_/@ + / / @ + / / @ +/ / @ +|_| @@ + _ @ + | |@ + / /@ + / / @ + _/_/ @ +/_/ @@ + @ + __/|_@ + | /@ +/_ __| @ + |/ @ + @@ + @ + __ @ + __/ /_@ +/_ __/@ + /_/ @ + @@ + @ + @ + @ + _ @ +( )@ +|/ @@ + @ + @ + ______@ +/_____/@ + $ @ + @@ + @ + @ + @ + _ @ +(_)@ + @@ + __@ + _/_/@ + _/_/ @ + _/_/ @ +/_/ @ + @@ + ____ @ + / __ \@ + / / / /@ +/ /_/ / @ +\____/ @ + @@ + ___@ + < /@ + / / @ + / / @ +/_/ @ + @@ + ___ @ + |__ \@ + __/ /@ + / __/ @ +/____/ @ + @@ + _____@ + |__ /@ + /_ < @ + ___/ / @ +/____/ @ + @@ + __ __@ + / // /@ + / // /_@ +/__ __/@ + /_/ @ + @@ + ______@ + / ____/@ + /___ \ @ + ____/ / @ +/_____/ @ + @@ + _____@ + / ___/@ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ + _____@ +/__ /@ + / / @ + / / @ +/_/ @ + @@ + ____ @ + ( __ )@ + / __ |@ +/ /_/ / @ +\____/ @ + @@ + ____ @ + / __ \@ + / /_/ /@ + \__, / @ +/____/ @ + @@ + @ + _ @ + (_)@ + _ @ +(_) @ + @@ + @ + _ @ + (_)@ + _ @ +( ) @ +|/ @@ + __@ + / /@ +/ / @ +\ \ @ + \_\@ + @@ + @ + _____@ + /____/@ +/____/ @ + $ @ + @@ +__ @ +\ \ @ + \ \@ + / /@ +/_/ @ + @@ + ___ @ + /__ \@ + / _/@ + /_/ @ +(_) @ + @@ + ______ @ + / ____ \@ + / / __ `/@ +/ / /_/ / @ +\ \__,_/ @ + \____/ @@ + ___ @ + / |@ + / /| |@ + / ___ |@ +/_/ |_|@ + @@ + ____ @ + / __ )@ + / __ |@ + / /_/ / @ +/_____/ @ + @@ + ______@ + / ____/@ + / / @ +/ /___ @ +\____/ @ + @@ + ____ @ + / __ \@ + / / / /@ + / /_/ / @ +/_____/ @ + @@ + ______@ + / ____/@ + / __/ @ + / /___ @ +/_____/ @ + @@ + ______@ + / ____/@ + / /_ @ + / __/ @ +/_/ @ + @@ + ______@ + / ____/@ + / / __ @ +/ /_/ / @ +\____/ @ + @@ + __ __@ + / / / /@ + / /_/ / @ + / __ / @ +/_/ /_/ @ + @@ + ____@ + / _/@ + / / @ + _/ / @ +/___/ @ + @@ + __@ + / /@ + __ / / @ +/ /_/ / @ +\____/ @ + @@ + __ __@ + / //_/@ + / ,< @ + / /| | @ +/_/ |_| @ + @@ + __ @ + / / @ + / / @ + / /___@ +/_____/@ + @@ + __ ___@ + / |/ /@ + / /|_/ / @ + / / / / @ +/_/ /_/ @ + @@ + _ __@ + / | / /@ + / |/ / @ + / /| / @ +/_/ |_/ @ + @@ + ____ @ + / __ \@ + / / / /@ +/ /_/ / @ +\____/ @ + @@ + ____ @ + / __ \@ + / /_/ /@ + / ____/ @ +/_/ @ + @@ + ____ @ + / __ \@ + / / / /@ +/ /_/ / @ +\___\_\ @ + @@ + ____ @ + / __ \@ + / /_/ /@ + / _, _/ @ +/_/ |_| @ + @@ + _____@ + / ___/@ + \__ \ @ + ___/ / @ +/____/ @ + @@ + ______@ + /_ __/@ + / / @ + / / @ +/_/ @ + @@ + __ __@ + / / / /@ + / / / / @ +/ /_/ / @ +\____/ @ + @@ + _ __@ +| | / /@ +| | / / @ +| |/ / @ +|___/ @ + @@ + _ __@ +| | / /@ +| | /| / / @ +| |/ |/ / @ +|__/|__/ @ + @@ + _ __@ + | |/ /@ + | / @ + / | @ +/_/|_| @ + @@ +__ __@ +\ \/ /@ + \ / @ + / / @ +/_/ @ + @@ + _____@ +/__ /@ + / / @ + / /__@ +/____/@ + @@ + ___@ + / _/@ + / / @ + / / @ + / / @ +/__/ @@ +__ @ +\ \ @ + \ \ @ + \ \ @ + \_\@ + @@ + ___@ + / /@ + / / @ + / / @ + _/ / @ +/__/ @@ + //|@ + |/||@ + $ @ + $ @ +$ @ + @@ + @ + @ + @ + @ + ______@ +/_____/@@ + _ @ + ( )@ + V @ + $ @ +$ @ + @@ + @ + ____ _@ + / __ `/@ +/ /_/ / @ +\__,_/ @ + @@ + __ @ + / /_ @ + / __ \@ + / /_/ /@ +/_.___/ @ + @@ + @ + _____@ + / ___/@ +/ /__ @ +\___/ @ + @@ + __@ + ____/ /@ + / __ / @ +/ /_/ / @ +\__,_/ @ + @@ + @ + ___ @ + / _ \@ +/ __/@ +\___/ @ + @@ + ____@ + / __/@ + / /_ @ + / __/ @ +/_/ @ + @@ + @ + ____ _@ + / __ `/@ + / /_/ / @ + \__, / @ +/____/ @@ + __ @ + / /_ @ + / __ \@ + / / / /@ +/_/ /_/ @ + @@ + _ @ + (_)@ + / / @ + / / @ +/_/ @ + @@ + _ @ + (_)@ + / / @ + / / @ + __/ / @ +/___/ @@ + __ @ + / /__@ + / //_/@ + / ,< @ +/_/|_| @ + @@ + __@ + / /@ + / / @ + / / @ +/_/ @ + @@ + @ + ____ ___ @ + / __ `__ \@ + / / / / / /@ +/_/ /_/ /_/ @ + @@ + @ + ____ @ + / __ \@ + / / / /@ +/_/ /_/ @ + @@ + @ + ____ @ + / __ \@ +/ /_/ /@ +\____/ @ + @@ + @ + ____ @ + / __ \@ + / /_/ /@ + / .___/ @ +/_/ @@ + @ + ____ _@ + / __ `/@ +/ /_/ / @ +\__, / @ + /_/ @@ + @ + _____@ + / ___/@ + / / @ +/_/ @ + @@ + @ + _____@ + / ___/@ + (__ ) @ +/____/ @ + @@ + __ @ + / /_@ + / __/@ +/ /_ @ +\__/ @ + @@ + @ + __ __@ + / / / /@ +/ /_/ / @ +\__,_/ @ + @@ + @ + _ __@ +| | / /@ +| |/ / @ +|___/ @ + @@ + @ + _ __@ +| | /| / /@ +| |/ |/ / @ +|__/|__/ @ + @@ + @ + _ __@ + | |/_/@ + _> < @ +/_/|_| @ + @@ + @ + __ __@ + / / / /@ + / /_/ / @ + \__, / @ +/____/ @@ + @ + ____@ +/_ /@ + / /_@ +/___/@ + @@ + __@ + _/_/@ + _/_/ @ +< < @ +/ / @ +\_\ @@ + __@ + / /@ + / / @ + / / @ + / / @ +/_/ @@ + _ @ + | |@ + / /@ + _>_>@ + _/_/ @ +/_/ @@ + /\//@ + //\/ @ + $ @ + $ @ +$ @ + @@ + _ _ @ + (_)(_)@ + / _ | @ + / __ | @ +/_/ |_| @ + @@ + _ _ @ + (_)_(_)@ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ + _ _ @ + (_) (_)@ + / / / / @ +/ /_/ / @ +\____/ @ + @@ + _ _ @ + (_)_(_)@ + / __ `/ @ +/ /_/ / @ +\__,_/ @ + @@ + _ _ @ + (_)_(_)@ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ + _ _ @ + (_) (_)@ + / / / / @ +/ /_/ / @ +\__,_/ @ + @@ + ____ @ + / __ \@ + / / / /@ + / /_| | @ + / //__/ @ +/_/ @@ +160 NO-BREAK SPACE + $$@ + $$ @ + $$ @ + $$ @ + $$ @ +$$ @@ +161 INVERTED EXCLAMATION MARK + _ @ + (_)@ + / / @ + / / @ +/_/ @ + @@ +162 CENT SIGN + __@ + __/ /@ + / ___/@ +/ /__ @ +\ _/ @ +/_/ @@ +163 POUND SIGN + ____ @ + / ,__\@ + __/ /_ @ + _/ /___ @ +(_,____/ @ + @@ +164 CURRENCY SIGN + /|___/|@ + | __ / @ + / /_/ / @ + /___ | @ +|/ |/ @ + @@ +165 YEN SIGN + ____@ + _| / /@ + /_ __/@ +/_ __/ @ + /_/ @ + @@ +166 BROKEN BAR + __@ + / /@ + /_/ @ + __ @ + / / @ +/_/ @@ +167 SECTION SIGN + __ @ + _/ _)@ + / | | @ + | || | @ + | |_/ @ +(__/ @@ +168 DIAERESIS + _ _ @ + (_) (_)@ + $ $ @ + $ $ @ +$ $ @ + @@ +169 COPYRIGHT SIGN + ______ @ + / _____\ @ + / / ___/ |@ + / / /__ / @ +| \___/ / @ + \______/ @@ +170 FEMININE ORDINAL INDICATOR + ___ _@ + / _ `/@ + _\_,_/ @ +/____/ @ + $ @ + @@ +171 LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + ____@ + / / /@ +/ / / @ +\ \ \ @ + \_\_\@ + @@ +172 NOT SIGN + @ + ______@ +/___ /@ + /_/ @ + $ @ + @@ +173 SOFT HYPHEN + @ + @ + _____@ +/____/@ + $ @ + @@ +174 REGISTERED SIGN + ______ @ + / ___ \ @ + / / _ \ |@ + / / , _/ / @ +| /_/|_| / @ + \______/ @@ +175 MACRON + ______@ +/_____/@ + $ @ + $ @ +$ @ + @@ +176 DEGREE SIGN + ___ @ + / _ \@ +/ // /@ +\___/ @ + $ @ + @@ +177 PLUS-MINUS SIGN + __ @ + __/ /_@ + /_ __/@ + __/_/_ @ +/_____/ @ + @@ +178 SUPERSCRIPT TWO + ___ @ + |_ |@ + / __/ @ +/____/ @ + $ @ + @@ +179 SUPERSCRIPT THREE + ____@ + |_ /@ + _/_ < @ +/____/ @ + $ @ + @@ +180 ACUTE ACCENT + __@ + /_/@ + $ @ + $ @ +$ @ + @@ +181 MICRO SIGN + @ + __ __@ + / / / /@ + / /_/ / @ + / ._,_/ @ +/_/ @@ +182 PILCROW SIGN + _______@ + / _ /@ +/ (/ / / @ +\_ / / @ + /_/_/ @ + @@ +183 MIDDLE DOT + @ + _ @ +(_)@ + $ @ +$ @ + @@ +184 CEDILLA + @ + @ + @ + @ + _ @ +/_)@@ +185 SUPERSCRIPT ONE + ___@ + < /@ + / / @ +/_/ @ +$ @ + @@ +186 MASCULINE ORDINAL INDICATOR + ___ @ + / _ \@ + _\___/@ +/____/ @ + $ @ + @@ +187 RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +____ @ +\ \ \ @ + \ \ \@ + / / /@ +/_/_/ @ + @@ +188 VULGAR FRACTION ONE QUARTER + ___ __ @ + < / _/_/ @ + / /_/_/___@ +/_//_// / /@ + /_/ /_ _/@ + /_/ @@ +189 VULGAR FRACTION ONE HALF + ___ __ @ + < / _/_/__ @ + / /_/_/|_ |@ +/_//_/ / __/ @ + /_/ /____/ @ + @@ +190 VULGAR FRACTION THREE QUARTERS + ____ __ @ + |_ / _/_/ @ + _/_ < _/_/___@ +/____//_// / /@ + /_/ /_ _/@ + /_/ @@ +191 INVERTED QUESTION MARK + _ @ + (_)@ + _/ / @ +/ _/_ @ +\___/ @ + @@ +192 LATIN CAPITAL LETTER A WITH GRAVE + __ @ + _\_\@ + / _ |@ + / __ |@ +/_/ |_|@ + @@ +193 LATIN CAPITAL LETTER A WITH ACUTE + __@ + _/_/@ + / _ |@ + / __ |@ +/_/ |_|@ + @@ +194 LATIN CAPITAL LETTER A WITH CIRCUMFLEX + //|@ + _|/||@ + / _ | @ + / __ | @ +/_/ |_| @ + @@ +195 LATIN CAPITAL LETTER A WITH TILDE + /\//@ + _//\/ @ + / _ | @ + / __ | @ +/_/ |_| @ + @@ +196 LATIN CAPITAL LETTER A WITH DIAERESIS + _ _ @ + (_)(_)@ + / _ | @ + / __ | @ +/_/ |_| @ + @@ +197 LATIN CAPITAL LETTER A WITH RING ABOVE + (())@ + / |@ + / /| |@ + / ___ |@ +/_/ |_|@ + @@ +198 LATIN CAPITAL LETTER AE + __________@ + / ____/@ + / /| __/ @ + / __ /___ @ +/_/ /_____/ @ + @@ +199 LATIN CAPITAL LETTER C WITH CEDILLA + ______@ + / ____/@ + / / @ +/ /___ @ +\____/ @ + /_) @@ +200 LATIN CAPITAL LETTER E WITH GRAVE + __ @ + _\_\@ + / __/@ + / _/ @ +/___/ @ + @@ +201 LATIN CAPITAL LETTER E WITH ACUTE + __@ + _/_/@ + / __/@ + / _/ @ +/___/ @ + @@ +202 LATIN CAPITAL LETTER E WITH CIRCUMFLEX + //|@ + _|/||@ + / __/ @ + / _/ @ +/___/ @ + @@ +203 LATIN CAPITAL LETTER E WITH DIAERESIS + _ _ @ + (_)(_)@ + / __/ @ + / _/ @ +/___/ @ + @@ +204 LATIN CAPITAL LETTER I WITH GRAVE + __ @ + _\_\@ + / _/@ + _/ / @ +/___/ @ + @@ +205 LATIN CAPITAL LETTER I WITH ACUTE + __@ + _/_/@ + / _/@ + _/ / @ +/___/ @ + @@ +206 LATIN CAPITAL LETTER I WITH CIRCUMFLEX + //|@ + _|/||@ + / _/ @ + _/ / @ +/___/ @ + @@ +207 LATIN CAPITAL LETTER I WITH DIAERESIS + _ _ @ + (_)(_)@ + / _/ @ + _/ / @ +/___/ @ + @@ +208 LATIN CAPITAL LETTER ETH + ____ @ + / __ \@ + __/ /_/ /@ +/_ __/ / @ + /_____/ @ + @@ +209 LATIN CAPITAL LETTER N WITH TILDE + /\//@ + _//\/ @ + / |/ / @ + / / @ +/_/|_/ @ + @@ +210 LATIN CAPITAL LETTER O WITH GRAVE + __ @ + __\_\@ + / __ \@ +/ /_/ /@ +\____/ @ + @@ +211 LATIN CAPITAL LETTER O WITH ACUTE + __@ + __/_/@ + / __ \@ +/ /_/ /@ +\____/ @ + @@ +212 LATIN CAPITAL LETTER O WITH CIRCUMFLEX + //|@ + _|/||@ + / __ \@ +/ /_/ /@ +\____/ @ + @@ +213 LATIN CAPITAL LETTER O WITH TILDE + /\//@ + _//\/ @ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ +214 LATIN CAPITAL LETTER O WITH DIAERESIS + _ _ @ + (_)_(_)@ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ +215 MULTIPLICATION SIGN + @ + @ + /|/|@ + > < @ +|/|/ @ + @@ +216 LATIN CAPITAL LETTER O WITH STROKE + _____ @ + / _// \@ + / //// /@ +/ //// / @ +\_//__/ @ + @@ +217 LATIN CAPITAL LETTER U WITH GRAVE + __ @ + __\_\_@ + / / / /@ +/ /_/ / @ +\____/ @ + @@ +218 LATIN CAPITAL LETTER U WITH ACUTE + __ @ + __/_/_@ + / / / /@ +/ /_/ / @ +\____/ @ + @@ +219 LATIN CAPITAL LETTER U WITH CIRCUMFLEX + //| @ + _|/||_@ + / / / /@ +/ /_/ / @ +\____/ @ + @@ +220 LATIN CAPITAL LETTER U WITH DIAERESIS + _ _ @ + (_) (_)@ + / / / / @ +/ /_/ / @ +\____/ @ + @@ +221 LATIN CAPITAL LETTER Y WITH ACUTE + __ @ +__/_/_@ +\ \/ /@ + \ / @ + /_/ @ + @@ +222 LATIN CAPITAL LETTER THORN + __ @ + / /_ @ + / __ \@ + / ____/@ +/_/ @ + @@ +223 LATIN SMALL LETTER SHARP S + ____ @ + / __ \@ + / / / /@ + / /_| | @ + / //__/ @ +/_/ @@ +224 LATIN SMALL LETTER A WITH GRAVE + __ @ + __\_\_@ + / __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +225 LATIN SMALL LETTER A WITH ACUTE + __ @ + __/_/_@ + / __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +226 LATIN SMALL LETTER A WITH CIRCUMFLEX + //| @ + _|/||_@ + / __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +227 LATIN SMALL LETTER A WITH TILDE + /\//@ + _//\/_@ + / __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +228 LATIN SMALL LETTER A WITH DIAERESIS + _ _ @ + (_)_(_)@ + / __ `/ @ +/ /_/ / @ +\__,_/ @ + @@ +229 LATIN SMALL LETTER A WITH RING ABOVE + __ @ + __(())@ + / __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +230 LATIN SMALL LETTER AE + @ + ____ ___ @ + / __ ` _ \@ +/ /_/ __/@ +\__,_____/ @ + @@ +231 LATIN SMALL LETTER C WITH CEDILLA + @ + _____@ + / ___/@ +/ /__ @ +\___/ @ +/_) @@ +232 LATIN SMALL LETTER E WITH GRAVE + __ @ + _\_\@ + / _ \@ +/ __/@ +\___/ @ + @@ +233 LATIN SMALL LETTER E WITH ACUTE + __@ + _/_/@ + / _ \@ +/ __/@ +\___/ @ + @@ +234 LATIN SMALL LETTER E WITH CIRCUMFLEX + //|@ + _|/||@ + / _ \ @ +/ __/ @ +\___/ @ + @@ +235 LATIN SMALL LETTER E WITH DIAERESIS + _ _ @ + (_)(_)@ + / _ \ @ +/ __/ @ +\___/ @ + @@ +236 LATIN SMALL LETTER I WITH GRAVE + __ @ + \_\@ + / / @ + / / @ +/_/ @ + @@ +237 LATIN SMALL LETTER I WITH ACUTE + __@ + /_/@ + / / @ + / / @ +/_/ @ + @@ +238 LATIN SMALL LETTER I WITH CIRCUMFLEX + //|@ + |/||@ + / / @ + / / @ +/_/ @ + @@ +239 LATIN SMALL LETTER I WITH DIAERESIS + _ _ @ + (_)_(_)@ + / / @ + / / @ +/_/ @ + @@ +240 LATIN SMALL LETTER ETH + || @ + =||=@ + ___ || @ +/ __` | @ +\____/ @ + @@ +241 LATIN SMALL LETTER N WITH TILDE + /\//@ + _//\/ @ + / __ \ @ + / / / / @ +/_/ /_/ @ + @@ +242 LATIN SMALL LETTER O WITH GRAVE + __ @ + __\_\@ + / __ \@ +/ /_/ /@ +\____/ @ + @@ +243 LATIN SMALL LETTER O WITH ACUTE + __@ + __/_/@ + / __ \@ +/ /_/ /@ +\____/ @ + @@ +244 LATIN SMALL LETTER O WITH CIRCUMFLEX + //|@ + _|/||@ + / __ \@ +/ /_/ /@ +\____/ @ + @@ +245 LATIN SMALL LETTER O WITH TILDE + /\//@ + _//\/ @ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ +246 LATIN SMALL LETTER O WITH DIAERESIS + _ _ @ + (_)_(_)@ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ +247 DIVISION SIGN + @ + _ @ + __(_)_@ +/_____/@ + (_) @ + @@ +248 LATIN SMALL LETTER O WITH STROKE + @ + _____ @ + / _// \@ +/ //// /@ +\_//__/ @ + @@ +249 LATIN SMALL LETTER U WITH GRAVE + __ @ + __\_\_@ + / / / /@ +/ /_/ / @ +\__,_/ @ + @@ +250 LATIN SMALL LETTER U WITH ACUTE + __ @ + __/_/_@ + / / / /@ +/ /_/ / @ +\__,_/ @ + @@ +251 LATIN SMALL LETTER U WITH CIRCUMFLEX + //| @ + _|/||_@ + / / / /@ +/ /_/ / @ +\__,_/ @ + @@ +252 LATIN SMALL LETTER U WITH DIAERESIS + _ _ @ + (_) (_)@ + / / / / @ +/ /_/ / @ +\__,_/ @ + @@ +253 LATIN SMALL LETTER Y WITH ACUTE + __ @ + __/_/_@ + / / / /@ + / /_/ / @ + \__, / @ +/____/ @@ +254 LATIN SMALL LETTER THORN + __ @ + / /_ @ + / __ \@ + / /_/ /@ + / .___/ @ +/_/ @@ +255 LATIN SMALL LETTER Y WITH DIAERESIS + _ _ @ + (_) (_)@ + / / / / @ + / /_/ / @ + \__, / @ +/____/ @@ diff --git a/resources/small.flf b/resources/small.flf new file mode 100644 index 00000000..d2a2c49c --- /dev/null +++ b/resources/small.flf @@ -0,0 +1,1097 @@ +flf2a$ 5 4 13 15 10 0 22415 +Small by Glenn Chappell 4/93 -- based on Standard +Includes ISO Latin-1 +figlet release 2.1 -- 12 Aug 1994 +Permission is hereby given to modify this font, as long as the +modifier's name is placed on a comment line. + +Modified by Paul Burton 12/96 to include new parameter +supported by FIGlet and FIGWin. May also be slightly modified for better use +of new full-width/kern/smush alternatives, but default output is NOT changed. + + $@ + $@ + $@ + $@ + $@@ + _ @ + | |@ + |_|@ + (_)@ + @@ + _ _ @ + ( | )@ + V V @ + $ @ + @@ + _ _ @ + _| | |_ @ + |_ . _|@ + |_ _|@ + |_|_| @@ + @ + ||_@ + (_-<@ + / _/@ + || @@ + _ __ @ + (_)/ / @ + / /_ @ + /_/(_)@ + @@ + __ @ + / _|___ @ + > _|_ _|@ + \_____| @ + @@ + _ @ + ( )@ + |/ @ + $ @ + @@ + __@ + / /@ + | | @ + | | @ + \_\@@ + __ @ + \ \ @ + | |@ + | |@ + /_/ @@ + @ + _/\_@ + > <@ + \/ @ + @@ + _ @ + _| |_ @ + |_ _|@ + |_| @ + @@ + @ + @ + _ @ + ( )@ + |/ @@ + @ + ___ @ + |___|@ + $ @ + @@ + @ + @ + _ @ + (_)@ + @@ + __@ + / /@ + / / @ + /_/ @ + @@ + __ @ + / \ @ + | () |@ + \__/ @ + @@ + _ @ + / |@ + | |@ + |_|@ + @@ + ___ @ + |_ )@ + / / @ + /___|@ + @@ + ____@ + |__ /@ + |_ \@ + |___/@ + @@ + _ _ @ + | | | @ + |_ _|@ + |_| @ + @@ + ___ @ + | __|@ + |__ \@ + |___/@ + @@ + __ @ + / / @ + / _ \@ + \___/@ + @@ + ____ @ + |__ |@ + / / @ + /_/ @ + @@ + ___ @ + ( _ )@ + / _ \@ + \___/@ + @@ + ___ @ + / _ \@ + \_, /@ + /_/ @ + @@ + _ @ + (_)@ + _ @ + (_)@ + @@ + _ @ + (_)@ + _ @ + ( )@ + |/ @@ + __@ + / /@ + < < @ + \_\@ + @@ + @ + ___ @ + |___|@ + |___|@ + @@ + __ @ + \ \ @ + > >@ + /_/ @ + @@ + ___ @ + |__ \@ + /_/@ + (_) @ + @@ + ____ @ + / __ \ @ + / / _` |@ + \ \__,_|@ + \____/ @@ + _ @ + /_\ @ + / _ \ @ + /_/ \_\@ + @@ + ___ @ + | _ )@ + | _ \@ + |___/@ + @@ + ___ @ + / __|@ + | (__ @ + \___|@ + @@ + ___ @ + | \ @ + | |) |@ + |___/ @ + @@ + ___ @ + | __|@ + | _| @ + |___|@ + @@ + ___ @ + | __|@ + | _| @ + |_| @ + @@ + ___ @ + / __|@ + | (_ |@ + \___|@ + @@ + _ _ @ + | || |@ + | __ |@ + |_||_|@ + @@ + ___ @ + |_ _|@ + | | @ + |___|@ + @@ + _ @ + _ | |@ + | || |@ + \__/ @ + @@ + _ __@ + | |/ /@ + | ' < @ + |_|\_\@ + @@ + _ @ + | | @ + | |__ @ + |____|@ + @@ + __ __ @ + | \/ |@ + | |\/| |@ + |_| |_|@ + @@ + _ _ @ + | \| |@ + | .` |@ + |_|\_|@ + @@ + ___ @ + / _ \ @ + | (_) |@ + \___/ @ + @@ + ___ @ + | _ \@ + | _/@ + |_| @ + @@ + ___ @ + / _ \ @ + | (_) |@ + \__\_\@ + @@ + ___ @ + | _ \@ + | /@ + |_|_\@ + @@ + ___ @ + / __|@ + \__ \@ + |___/@ + @@ + _____ @ + |_ _|@ + | | @ + |_| @ + @@ + _ _ @ + | | | |@ + | |_| |@ + \___/ @ + @@ + __ __@ + \ \ / /@ + \ V / @ + \_/ @ + @@ + __ __@ + \ \ / /@ + \ \/\/ / @ + \_/\_/ @ + @@ + __ __@ + \ \/ /@ + > < @ + /_/\_\@ + @@ + __ __@ + \ \ / /@ + \ V / @ + |_| @ + @@ + ____@ + |_ /@ + / / @ + /___|@ + @@ + __ @ + | _|@ + | | @ + | | @ + |__|@@ + __ @ + \ \ @ + \ \ @ + \_\@ + @@ + __ @ + |_ |@ + | |@ + | |@ + |__|@@ + /\ @ + |/\|@ + $ @ + $ @ + @@ + @ + @ + @ + ___ @ + |___|@@ + _ @ + ( )@ + \|@ + $ @ + @@ + @ + __ _ @ + / _` |@ + \__,_|@ + @@ + _ @ + | |__ @ + | '_ \@ + |_.__/@ + @@ + @ + __ @ + / _|@ + \__|@ + @@ + _ @ + __| |@ + / _` |@ + \__,_|@ + @@ + @ + ___ @ + / -_)@ + \___|@ + @@ + __ @ + / _|@ + | _|@ + |_| @ + @@ + @ + __ _ @ + / _` |@ + \__, |@ + |___/ @@ + _ @ + | |_ @ + | ' \ @ + |_||_|@ + @@ + _ @ + (_)@ + | |@ + |_|@ + @@ + _ @ + (_)@ + | |@ + _/ |@ + |__/ @@ + _ @ + | |__@ + | / /@ + |_\_\@ + @@ + _ @ + | |@ + | |@ + |_|@ + @@ + @ + _ __ @ + | ' \ @ + |_|_|_|@ + @@ + @ + _ _ @ + | ' \ @ + |_||_|@ + @@ + @ + ___ @ + / _ \@ + \___/@ + @@ + @ + _ __ @ + | '_ \@ + | .__/@ + |_| @@ + @ + __ _ @ + / _` |@ + \__, |@ + |_|@@ + @ + _ _ @ + | '_|@ + |_| @ + @@ + @ + ___@ + (_-<@ + /__/@ + @@ + _ @ + | |_ @ + | _|@ + \__|@ + @@ + @ + _ _ @ + | || |@ + \_,_|@ + @@ + @ + __ __@ + \ V /@ + \_/ @ + @@ + @ + __ __ __@ + \ V V /@ + \_/\_/ @ + @@ + @ + __ __@ + \ \ /@ + /_\_\@ + @@ + @ + _ _ @ + | || |@ + \_, |@ + |__/ @@ + @ + ___@ + |_ /@ + /__|@ + @@ + __@ + / /@ + _| | @ + | | @ + \_\@@ + _ @ + | |@ + | |@ + | |@ + |_|@@ + __ @ + \ \ @ + | |_@ + | | @ + /_/ @@ + /\/|@ + |/\/ @ + $ @ + $ @ + @@ + _ _ @ + (_)(_)@ + /--\ @ + /_/\_\@ + @@ + _ _ @ + (_)(_)@ + / __ \@ + \____/@ + @@ + _ _ @ + (_) (_)@ + | |_| |@ + \___/ @ + @@ + _ _ @ + (_)(_)@ + / _` |@ + \__,_|@ + @@ + _ _ @ + (_)_(_)@ + / _ \ @ + \___/ @ + @@ + _ _ @ + (_)(_)@ + | || |@ + \_,_|@ + @@ + ___ @ + / _ \@ + | |< <@ + | ||_/@ + |_| @@ +160 NO-BREAK SPACE + $@ + $@ + $@ + $@ + $@@ +161 INVERTED EXCLAMATION MARK + _ @ + (_)@ + | |@ + |_|@ + @@ +162 CENT SIGN + @ + || @ + / _)@ + \ _)@ + || @@ +163 POUND SIGN + __ @ + _/ _\ @ + |_ _|_ @ + (_,___|@ + @@ +164 CURRENCY SIGN + /\_/\@ + \ . /@ + / _ \@ + \/ \/@ + @@ +165 YEN SIGN + __ __ @ + \ V / @ + |__ __|@ + |__ __|@ + |_| @@ +166 BROKEN BAR + _ @ + | |@ + |_|@ + | |@ + |_|@@ +167 SECTION SIGN + __ @ + / _)@ + /\ \ @ + \ \/ @ + (__/ @@ +168 DIAERESIS + _ _ @ + (_)(_)@ + $ $ @ + $ $ @ + @@ +169 COPYRIGHT SIGN + ____ @ + / __ \ @ + / / _| \@ + \ \__| /@ + \____/ @@ +170 FEMININE ORDINAL INDICATOR + __ _ @ + / _` |@ + \__,_|@ + |____|@ + @@ +171 LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + ____@ + / / /@ + < < < @ + \_\_\@ + @@ +172 NOT SIGN + ____ @ + |__ |@ + |_|@ + $ @ + @@ +173 SOFT HYPHEN + @ + __ @ + |__|@ + $ @ + @@ +174 REGISTERED SIGN + ____ @ + / __ \ @ + / | -) \@ + \ ||\\ /@ + \____/ @@ +175 MACRON + ___ @ + |___|@ + $ @ + $ @ + @@ +176 DEGREE SIGN + _ @ + /.\@ + \_/@ + $ @ + @@ +177 PLUS-MINUS SIGN + _ @ + _| |_ @ + |_ _|@ + _|_|_ @ + |_____|@@ +178 SUPERSCRIPT TWO + __ @ + |_ )@ + /__|@ + $ @ + @@ +179 SUPERSCRIPT THREE + ___@ + |_ /@ + |__)@ + $ @ + @@ +180 ACUTE ACCENT + __@ + /_/@ + $ @ + $ @ + @@ +181 MICRO SIGN + @ + _ _ @ + | || |@ + | .,_|@ + |_| @@ +182 PILCROW SIGN + ____ @ + / |@ + \_ | |@ + |_|_|@ + @@ +183 MIDDLE DOT + @ + _ @ + (_)@ + $ @ + @@ +184 CEDILLA + @ + @ + @ + _ @ + )_)@@ +185 SUPERSCRIPT ONE + _ @ + / |@ + |_|@ + $ @ + @@ +186 MASCULINE ORDINAL INDICATOR + ___ @ + / _ \@ + \___/@ + |___|@ + @@ +187 RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + ____ @ + \ \ \ @ + > > >@ + /_/_/ @ + @@ +188 VULGAR FRACTION ONE QUARTER + _ __ @ + / |/ /__ @ + |_/ /_' |@ + /_/ |_|@ + @@ +189 VULGAR FRACTION ONE HALF + _ __ @ + / |/ /_ @ + |_/ /_ )@ + /_//__|@ + @@ +190 VULGAR FRACTION THREE QUARTERS + ___ __ @ + |_ // /__ @ + |__) /_' |@ + /_/ |_|@ + @@ +191 INVERTED QUESTION MARK + _ @ + (_) @ + / /_ @ + \___|@ + @@ +192 LATIN CAPITAL LETTER A WITH GRAVE + __ @ + \_\ @ + /--\ @ + /_/\_\@ + @@ +193 LATIN CAPITAL LETTER A WITH ACUTE + __ @ + /_/ @ + /--\ @ + /_/\_\@ + @@ +194 LATIN CAPITAL LETTER A WITH CIRCUMFLEX + /\ @ + |/\| @ + /--\ @ + /_/\_\@ + @@ +195 LATIN CAPITAL LETTER A WITH TILDE + /\/|@ + |/\/ @ + /--\ @ + /_/\_\@ + @@ +196 LATIN CAPITAL LETTER A WITH DIAERESIS + _ _ @ + (_)(_)@ + /--\ @ + /_/\_\@ + @@ +197 LATIN CAPITAL LETTER A WITH RING ABOVE + __ @ + (()) @ + /--\ @ + /_/\_\@ + @@ +198 LATIN CAPITAL LETTER AE + ____ @ + /, __|@ + / _ _| @ + /_/|___|@ + @@ +199 LATIN CAPITAL LETTER C WITH CEDILLA + ___ @ + / __|@ + | (__ @ + \___|@ + )_) @@ +200 LATIN CAPITAL LETTER E WITH GRAVE + __ @ + \_\@ + | -<@ + |__<@ + @@ +201 LATIN CAPITAL LETTER E WITH ACUTE + __@ + /_/@ + | -<@ + |__<@ + @@ +202 LATIN CAPITAL LETTER E WITH CIRCUMFLEX + /\ @ + |/\|@ + | -<@ + |__<@ + @@ +203 LATIN CAPITAL LETTER E WITH DIAERESIS + _ _ @ + (_)(_)@ + | -< @ + |__< @ + @@ +204 LATIN CAPITAL LETTER I WITH GRAVE + __ @ + \_\ @ + |_ _|@ + |___|@ + @@ +205 LATIN CAPITAL LETTER I WITH ACUTE + __ @ + /_/ @ + |_ _|@ + |___|@ + @@ +206 LATIN CAPITAL LETTER I WITH CIRCUMFLEX + //\ @ + |/_\|@ + |_ _|@ + |___|@ + @@ +207 LATIN CAPITAL LETTER I WITH DIAERESIS + _ _ @ + (_)_(_)@ + |_ _| @ + |___| @ + @@ +208 LATIN CAPITAL LETTER ETH + ____ @ + | __ \ @ + |_ _|) |@ + |____/ @ + @@ +209 LATIN CAPITAL LETTER N WITH TILDE + /\/|@ + |/\/ @ + | \| |@ + |_|\_|@ + @@ +210 LATIN CAPITAL LETTER O WITH GRAVE + __ @ + \_\_ @ + / __ \@ + \____/@ + @@ +211 LATIN CAPITAL LETTER O WITH ACUTE + __ @ + _/_/ @ + / __ \@ + \____/@ + @@ +212 LATIN CAPITAL LETTER O WITH CIRCUMFLEX + /\ @ + |/\| @ + / __ \@ + \____/@ + @@ +213 LATIN CAPITAL LETTER O WITH TILDE + /\/|@ + |/\/ @ + / __ \@ + \____/@ + @@ +214 LATIN CAPITAL LETTER O WITH DIAERESIS + _ _ @ + (_)(_)@ + / __ \@ + \____/@ + @@ +215 MULTIPLICATION SIGN + @ + /\/\@ + > <@ + \/\/@ + @@ +216 LATIN CAPITAL LETTER O WITH STROKE + ____ @ + / _//\ @ + | (//) |@ + \//__/ @ + @@ +217 LATIN CAPITAL LETTER U WITH GRAVE + __ @ + _\_\_ @ + | |_| |@ + \___/ @ + @@ +218 LATIN CAPITAL LETTER U WITH ACUTE + __ @ + _/_/_ @ + | |_| |@ + \___/ @ + @@ +219 LATIN CAPITAL LETTER U WITH CIRCUMFLEX + //\ @ + |/ \| @ + | |_| |@ + \___/ @ + @@ +220 LATIN CAPITAL LETTER U WITH DIAERESIS + _ _ @ + (_) (_)@ + | |_| |@ + \___/ @ + @@ +221 LATIN CAPITAL LETTER Y WITH ACUTE + __ @ + _/_/_@ + \ V /@ + |_| @ + @@ +222 LATIN CAPITAL LETTER THORN + _ @ + | |_ @ + | -_)@ + |_| @ + @@ +223 LATIN SMALL LETTER SHARP S + ___ @ + / _ \@ + | |< <@ + | ||_/@ + |_| @@ +224 LATIN SMALL LETTER A WITH GRAVE + __ @ + \_\_ @ + / _` |@ + \__,_|@ + @@ +225 LATIN SMALL LETTER A WITH ACUTE + __ @ + _/_/ @ + / _` |@ + \__,_|@ + @@ +226 LATIN SMALL LETTER A WITH CIRCUMFLEX + /\ @ + |/\| @ + / _` |@ + \__,_|@ + @@ +227 LATIN SMALL LETTER A WITH TILDE + /\/|@ + |/\/ @ + / _` |@ + \__,_|@ + @@ +228 LATIN SMALL LETTER A WITH DIAERESIS + _ _ @ + (_)(_)@ + / _` |@ + \__,_|@ + @@ +229 LATIN SMALL LETTER A WITH RING ABOVE + __ @ + (()) @ + / _` |@ + \__,_|@ + @@ +230 LATIN SMALL LETTER AE + @ + __ ___ @ + / _` -_)@ + \__,___|@ + @@ +231 LATIN SMALL LETTER C WITH CEDILLA + @ + __ @ + / _|@ + \__|@ + )_)@@ +232 LATIN SMALL LETTER E WITH GRAVE + __ @ + \_\ @ + / -_)@ + \___|@ + @@ +233 LATIN SMALL LETTER E WITH ACUTE + __ @ + /_/ @ + / -_)@ + \___|@ + @@ +234 LATIN SMALL LETTER E WITH CIRCUMFLEX + //\ @ + |/_\|@ + / -_)@ + \___|@ + @@ +235 LATIN SMALL LETTER E WITH DIAERESIS + _ _ @ + (_)_(_)@ + / -_) @ + \___| @ + @@ +236 LATIN SMALL LETTER I WITH GRAVE + __ @ + \_\@ + | |@ + |_|@ + @@ +237 LATIN SMALL LETTER I WITH ACUTE + __@ + /_/@ + | |@ + |_|@ + @@ +238 LATIN SMALL LETTER I WITH CIRCUMFLEX + //\ @ + |/_\|@ + | | @ + |_| @ + @@ +239 LATIN SMALL LETTER I WITH DIAERESIS + _ _ @ + (_)_(_)@ + | | @ + |_| @ + @@ +240 LATIN SMALL LETTER ETH + \\/\ @ + \/\\ @ + / _` |@ + \___/ @ + @@ +241 LATIN SMALL LETTER N WITH TILDE + /\/| @ + |/\/ @ + | ' \ @ + |_||_|@ + @@ +242 LATIN SMALL LETTER O WITH GRAVE + __ @ + \_\ @ + / _ \@ + \___/@ + @@ +243 LATIN SMALL LETTER O WITH ACUTE + __ @ + /_/ @ + / _ \@ + \___/@ + @@ +244 LATIN SMALL LETTER O WITH CIRCUMFLEX + //\ @ + |/_\|@ + / _ \@ + \___/@ + @@ +245 LATIN SMALL LETTER O WITH TILDE + /\/|@ + |/\/ @ + / _ \@ + \___/@ + @@ +246 LATIN SMALL LETTER O WITH DIAERESIS + _ _ @ + (_)_(_)@ + / _ \ @ + \___/ @ + @@ +247 DIVISION SIGN + _ @ + (_) @ + |___|@ + (_) @ + @@ +248 LATIN SMALL LETTER O WITH STROKE + @ + ___ @ + / //\@ + \//_/@ + @@ +249 LATIN SMALL LETTER U WITH GRAVE + __ @ + \_\_ @ + | || |@ + \_,_|@ + @@ +250 LATIN SMALL LETTER U WITH ACUTE + __ @ + _/_/ @ + | || |@ + \_,_|@ + @@ +251 LATIN SMALL LETTER U WITH CIRCUMFLEX + /\ @ + |/\| @ + | || |@ + \_,_|@ + @@ +252 LATIN SMALL LETTER U WITH DIAERESIS + _ _ @ + (_)(_)@ + | || |@ + \_,_|@ + @@ +253 LATIN SMALL LETTER Y WITH ACUTE + __ @ + _/_/ @ + | || |@ + \_, |@ + |__/ @@ +254 LATIN SMALL LETTER THORN + _ @ + | |__ @ + | '_ \@ + | .__/@ + |_| @@ +255 LATIN SMALL LETTER Y WITH DIAERESIS + _ _ @ + (_)(_)@ + | || |@ + \_, |@ + |__/ @@ diff --git a/resources/speed.flf b/resources/speed.flf new file mode 100644 index 00000000..d294c52f --- /dev/null +++ b/resources/speed.flf @@ -0,0 +1,1301 @@ +flf2a$ 6 5 16 15 16 +Speed by Claude Martins 2/95 -- based on Slant +Includes ISO Latin-1 +figlet release 2.1 -- 12 Aug 1994 +Permission is hereby given to modify this font, as long as the +modifier's name is placed on a comment line. + +Explanation of first line: +flf2 - "magic number" for file identification +a - should always be `a', for now +$ - the "hardblank" -- prints as a blank, but can't be smushed +6 - height of a character +5 - height of a character, not including descenders +14 - max line length (excluding comment lines) + a fudge factor +15 - default smushmode for this font +16 - number of comment lines + + $$@ + $$ @ + $$ @ + $$ @ + $$ @ +$$ @@ +______@ +___ /@ +__ / @ + /_/ @ +(_) @ + @@ +___ _ @ +_( | )@ +_|/|/ @ + $ @ + $ @ + @@ +_______ __ @ +____/ // /_@ +_ _ _ __/@ +/_ _ __/ @ + /_//_/ @ + @@ +_______@ +____/ /@ +__ __/@ +_(_ ) @ +/ _/ @ +/_/ @@ +____ __@ +__(_)_/_/@ +____/_/ @ +__/_/_ @ +/_/ (_) @ + @@ +______ @ +__( _ ) @ +_ __ \/|@ +/ /_/ < @ +\____/\/ @ + @@ +___ @ +_( )@ +_|/ @ + $ @ +$ @ + @@ +_______@ +____/_/@ +__ / @ +_ / @ +/ / @ +|_| @@ +______ @ +____| |@ +____ /@ +___ / @ +__/_/ @ +/_/ @@ +_____ @ +____/|_@ +_| /@ +/_ __| @ + |/ @ + @@ + @ +______ @ +___/ /_@ +/_ __/@ + /_/ @ + @@ + @ + @ + @ +___ @ +_( )@ +_|/ @@ + @ + @ +________@ +_/_____/@ + $ @ + @@ + @ + @ + @ +___ @ +_(_)@ + @@ +_________@ +______/_/@ +____/_/ @ +__/_/ @ +/_/ @ + @@ +_______ @ +__ __ \@ +_ / / /@ +/ /_/ / @ +\____/ @ + @@ +______@ +__< /@ +__ / @ +_ / @ +/_/ @ + @@ +______ @ +__|__ \@ +____/ /@ +_ __/ @ +/____/ @ + @@ +________@ +__|__ /@ +___/_ < @ +____/ / @ +/____/ @ + @@ +_____ __@ +__ // /@ +_ // /_@ +/__ __/@ + /_/ @ + @@ +__________@ +___ ____/@ +______ \ @ + ____/ / @ +/_____/ @ + @@ +________@ +__ ___/@ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +______@ +/__ /@ +__ / @ +_ / @ +/_/ @ + @@ +_______ @ +__( __ )@ +_ __ |@ +/ /_/ / @ +\____/ @ + @@ +_______ @ +__ __ \@ +_ /_/ /@ +_\__, / @ +/____/ @ + @@ + @ +_____ @ +___(_)@ +___ @ +_(_) @ + @@ + @ +_____ @ +___(_)@ +___ @ +_( ) @ +_|/ @@ +____@ +_ /@ +/ / @ +\ \ @ + \_\@ + @@ + @ +_______@ +_ ____/@ +/____/ @ + $ @ + @@ +___ @ +__ \ @ +___ \@ +__ /@ +_/_/ @ + @@ +_____ @ +_ __ \@ +__/ _/@ +_/_/ @ +(_) @ + @@ +_________ @ +__ ____ \@ +_ / __ `/@ +/ / /_/ / @ +\ \__,_/ @ + \____/ @@ +_______ @ +___ |@ +__ /| |@ +_ ___ |@ +/_/ |_|@ + @@ +________ @ +___ __ )@ +__ __ |@ +_ /_/ / @ +/_____/ @ + @@ +_________@ +__ ____/@ +_ / @ +/ /___ @ +\____/ @ + @@ +________ @ +___ __ \@ +__ / / /@ +_ /_/ / @ +/_____/ @ + @@ +__________@ +___ ____/@ +__ __/ @ +_ /___ @ +/_____/ @ + @@ +__________@ +___ ____/@ +__ /_ @ +_ __/ @ +/_/ @ + @@ +_________@ +__ ____/@ +_ / __ @ +/ /_/ / @ +\____/ @ + @@ +______ __@ +___ / / /@ +__ /_/ / @ +_ __ / @ +/_/ /_/ @ + @@ +________@ +____ _/@ + __ / @ +__/ / @ +/___/ @ + @@ +_________@ +______ /@ +___ _ / @ +/ /_/ / @ +\____/ @ + @@ +______ __@ +___ //_/@ +__ ,< @ +_ /| | @ +/_/ |_| @ + @@ +______ @ +___ / @ +__ / @ +_ /___@ +/_____/@ + @@ +______ ___@ +___ |/ /@ +__ /|_/ / @ +_ / / / @ +/_/ /_/ @ + @@ +_____ __@ +___ | / /@ +__ |/ / @ +_ /| / @ +/_/ |_/ @ + @@ +_______ @ +__ __ \@ +_ / / /@ +/ /_/ / @ +\____/ @ + @@ +________ @ +___ __ \@ +__ /_/ /@ +_ ____/ @ +/_/ @ + @@ +_______ @ +__ __ \@ +_ / / /@ +/ /_/ / @ +\___\_\ @ + @@ +________ @ +___ __ \@ +__ /_/ /@ +_ _, _/ @ +/_/ |_| @ + @@ +________@ +__ ___/@ +_____ \ @ +____/ / @ +/____/ @ + @@ +________@ +___ __/@ +__ / @ +_ / @ +/_/ @ + @@ +_____ __@ +__ / / /@ +_ / / / @ +/ /_/ / @ +\____/ @ + @@ +___ __@ +__ | / /@ +__ | / / @ +__ |/ / @ +_____/ @ + @@ +___ __@ +__ | / /@ +__ | /| / / @ +__ |/ |/ / @ +____/|__/ @ + @@ +____ __@ +__ |/ /@ +__ / @ +_ | @ +/_/|_| @ + @@ +__ __@ +_ \/ /@ +__ / @ +_ / @ +/_/ @ + @@ +______@ +___ /@ +__ / @ +_ /__@ +/____/@ + @@ +________@ +____ _/@ +___ / @ +__ / @ +_ / @ +/__/ @@ +___ @ +__ \ @ +___ \ @ +____ \ @ +______\@ + @@ +________@ +____/ /@ +____ / @ +___ / @ +__/ / @ +/__/ @@ +_ //|@ +_|/||@ + $ @ + $ @ +$ @ + @@ + @ + @ + @ + @ +________@ +_/_____/@@ +___ @ +_( )@ +__V @ + $ @ +$ @ + @@ + @ +______ _@ +_ __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +______ @ +___ /_ @ +__ __ \@ +_ /_/ /@ +/_.___/ @ + @@ + @ +_______@ +_ ___/@ +/ /__ @ +\___/ @ + @@ +_________@ +______ /@ +_ __ / @ +/ /_/ / @ +\__,_/ @ + @@ + @ +_____ @ +_ _ \@ +/ __/@ +\___/ @ + @@ +________@ +___ __/@ +__ /_ @ +_ __/ @ +/_/ @ + @@ + @ +_______ _@ +__ __ `/@ +_ /_/ / @ +_\__, / @ +/____/ @@ +______ @ +___ /_ @ +__ __ \@ +_ / / /@ +/_/ /_/ @ + @@ +_____ @ +___(_)@ +__ / @ +_ / @ +/_/ @ + @@ +________ @ +______(_)@ +_____ / @ +____ / @ +___ / @ +/___/ @@ +______ @ +___ /__@ +__ //_/@ +_ ,< @ +/_/|_| @ + @@ +______@ +___ /@ +__ / @ +_ / @ +/_/ @ + @@ + @ +_______ ___ @ +__ __ `__ \@ +_ / / / / /@ +/_/ /_/ /_/ @ + @@ + @ +_______ @ +__ __ \@ +_ / / /@ +/_/ /_/ @ + @@ + @ +______ @ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ + @ +________ @ +___ __ \@ +__ /_/ /@ +_ .___/ @ +/_/ @@ + @ +______ _@ +_ __ `/@ +/ /_/ / @ +\__, / @ + /_/ @@ + @ +________@ +__ ___/@ +_ / @ +/_/ @ + @@ + @ +________@ +__ ___/@ +_(__ ) @ +/____/ @ + @@ +_____ @ +__ /_@ +_ __/@ +/ /_ @ +\__/ @ + @@ + @ +____ __@ +_ / / /@ +/ /_/ / @ +\__,_/ @ + @@ + @ +___ __@ +__ | / /@ +__ |/ / @ +_____/ @ + @@ + @ +___ __@ +__ | /| / /@ +__ |/ |/ / @ +____/|__/ @ + @@ + @ +____ __@ +__ |/_/@ +__> < @ +/_/|_| @ + @@ + @ +_____ __@ +__ / / /@ +_ /_/ / @ +_\__, / @ +/____/ @@ + @ +______@ +___ /@ +__ /_@ +_____/@ + @@ +_______@ +____/_/@ +__/_/ @ +< < @ +/ / @ +\_\ @@ +_______@ +____ /@ +___ / @ +__ / @ +_ / @ +/_/ @@ +____ _ @ +____| |@ +____/ /@ +____>_>@ +__/_/ @ +/_/ @@ +__/\//@ +_//\/ @ + $ @ + $ @ +$ @ + @@ +_____ _ @ +___(_)(_)@ +__ _ | @ +_ __ | @ +/_/ |_| @ + @@ +____ _ @ +__(_)_(_)@ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +____ _ @ +__(_) (_)@ +_ / / / @ +/ /_/ / @ +\____/ @ + @@ +____ _ @ +__(_)_(_)@ +_ __ `/ @ +/ /_/ / @ +\__,_/ @ + @@ +____ _ @ +__(_)_(_)@ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +____ _ @ +__(_) (_)@ +_ / / / @ +/ /_/ / @ +\__,_/ @ + @@ +_________ @ +____ __ \@ +___ / / /@ +__ /_| | @ +_ //__/ @ +/_/ @@ +160 + $$@ + $$ @ + $$ @ + $$ @ + $$ @ +$$ @@ +161 +_____ @ +___(_)@ +__ / @ +_ / @ +/_/ @ + @@ +162 +_______@ +____/ /@ +_ ___/@ +/ /__ @ +\ _/ @ +/_/ @@ +163 +_________ @ +____ ,__\@ +___/ /_ @ +__/ /___ @ +(_,____/ @ + @@ +164 +___ /|___/|@ +___| __ / @ +__ /_/ / @ +_ ___ | @ +|/ |/ @ + @@ +165 +___ ____@ +___| / /@ +_ _ __/@ +/_ __/ @ + /_/ @ + @@ +166 +_______@ +____ /@ +_____/ @ +____ @ +_ / @ +/_/ @@ +167 +_______ @ +____/ _)@ +__ | | @ +_| || | @ +_| |_/ @ +(__/ @@ +168 +___ _ @ +_(_) (_)@ + $ $ @ + $ $ @ +$ $ @ + @@ +169 +__________ @ +___ _____\ @ +__ / ___/ |@ +_ / /__ / @ +| \___/ / @ + \______/ @@ +170 +______ _@ +__ _ `/@ +__\_,_/ @ +/____/ @ + $ @ + @@ +171 +______@ +_ / /@ +/ / / @ +\ \ \ @ + \_\_\@ + @@ +172 + @ +________@ +_/___ /@ + /_/ @ + $ @ + @@ +173 + @ + @ +_______@ +_/____/@ + $ @ + @@ +174 +__________ @ +___ ___ \ @ +__ / _ \ |@ +_ / , _/ / @ +| /_/|_| / @ + \______/ @@ +175 +________@ +_/_____/@ + $ @ + $ @ + $ @ + @@ +176 +_____ @ +_ _ \@ +/ // /@ +\___/ @ + $ @ + @@ +177 +________ @ +_____/ /_@ +____ __/@ +___/_/_ @ +/_____/ @ + @@ +178 +__ ___ @ +__|_ |@ +_ __/ @ +/____/ @ + $ @ + @@ +179 +__ ____@ +__|_ /@ +__/_ < @ +/____/ @ + $ @ + @@ +180 +____@ +_/_/@ + $ @ + $ @ +$ @ + @@ +181 + @ +______ __@ +___ / / /@ +__ /_/ / @ +_ ._,_/ @ +/_/ @@ +182 +_________@ +_ _ /@ +/ (/ / / @ +\_ / / @ + /_/_/ @ + @@ +183 + @ +___ @ +_(_)@ + $ @ + $ @ + @@ +184 + @ + @ + @ + @ +___ @ +_/_)@@ +185 +_____@ +_< /@ +_ / @ +/_/ @ +$ @ + @@ +186 +______ @ +__ _ \@ +__\___/@ +/____/ @ + $ @ + @@ +187 +_____ @ +__ \ \ @ +___ \ \@ +__ / /@ +___/_/ @ + @@ +188 +_____ __ @ +_< / _/_/ @ +_/ /_/_/___@ +/_//_// / /@ + /_/ /_ _/@ + /_/ @@ +189 +_____ __ @ +_< / _/_/__ @ +_/ /_/_/|_ |@ +/_//_/ / __/ @ + /_/ /____/ @ + @@ +190 +__ ____ __ @ +__|_ / _/_/ @ +__/_ < _/_/___@ +/____//_// / /@ + /_/ /_ _/@ + /_/ @@ +191 +___ _ @ +___(_)@ +__ / @ +/ _/_ @ +\___/ @ + @@ +192 +______ @ +____\_\@ +__ _ |@ +_ __ |@ +/_/ |_|@ + @@ +193 +_______@ +____/_/@ +__ _ |@ +_ __ |@ +/_/ |_|@ + @@ +194 +____ //|@ +____|/||@ +__ _ | @ +_ __ | @ +/_/ |_| @ + @@ +195 +_____/\//@ +____//\/ @ +__ _ | @ +_ __ | @ +/_/ |_| @ + @@ +196 +_____ _ @ +___(_)(_)@ +__ _ | @ +_ __ | @ +/_/ |_| @ + @@ +197 +____(())@ +___ |@ +__ /| |@ +_ ___ |@ +/_/ |_|@ + @@ +198 +______________@ +___ ____/@ +__ /| __/ @ +_ __ /___ @ +/_/ /_____/ @ + @@ +199 +_________@ +__ ____/@ +_ / @ +/ /___ @ +\____/ @ + /_) @@ +200 +______ @ +____\_\@ +__ __/@ +_ _/ @ +/___/ @ + @@ +201 +_______@ +____/_/@ +__ __/@ +_ _/ @ +/___/ @ + @@ +202 +____ //|@ +____|/||@ +__ __/ @ +_ _/ @ +/___/ @ + @@ +203 +_____ _ @ +___(_)(_)@ +__ __/ @ +_ _/ @ +/___/ @ + @@ +204 +______ @ +____\_\@ +__ _/@ +__/ / @ +/___/ @ + @@ +205 +_______@ +____/_/@ +__ _/@ +__/ / @ +/___/ @ + @@ +206 +____ //|@ +____|/||@ +__ _/ @ +__/ / @ +/___/ @ + @@ +207 +_____ _ @ +___(_)(_)@ +__ _/ @ +__/ / @ +/___/ @ + @@ +208 +_________ @ +____ __ \@ +___ /_/ /@ +/_ __/ / @ + /_____/ @ + @@ +209 +_____/\//@ +____//\/ @ +__ |/ / @ +_ / @ +/_/|_/ @ + @@ +210 +______ @ +____\_\@ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ +211 +_______@ +____/_/@ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ +212 +___ //|@ +___|/||@ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ +213 +____/\//@ +___//\/ @ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +214 +____ _ @ +__(_)_(_)@ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +215 + @ +__ @ +_/|/|@ + > < @ +|/|/ @ + @@ +216 +________ @ +__ _// \@ +_ //// /@ +/ //// / @ +\_//__/ @ + @@ +217 +______ @ +____\_\_@ +_ / / /@ +/ /_/ / @ +\____/ @ + @@ +218 +_______ @ +____/_/_@ +_ / / /@ +/ /_/ / @ +\____/ @ + @@ +219 +___ //| @ +___|/||_@ +_ / / /@ +/ /_/ / @ +\____/ @ + @@ +220 +____ _ @ +__(_) (_)@ +_ / / / @ +/ /_/ / @ +\____/ @ + @@ +221 +______ @ +___/_/_@ +__ \/ /@ +___ / @ +__/_/ @ + @@ +222 +______ @ +___ /_ @ +__ __ \@ +_ ____/@ +/_/ @ + @@ +223 +_________ @ +____ __ \@ +___ / / /@ +__ /_| | @ +_ //__/ @ +/_/ @@ +224 +______ @ +____\_\_@ +_ __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +225 +_______ @ +____/_/_@ +_ __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +226 +___ //| @ +___|/||_@ +_ __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +227 +____/\//@ +___//\/_@ +_ __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +228 +____ _ @ +__(_)_(_)@ +_ __ `/ @ +/ /_/ / @ +\__,_/ @ + @@ +229 +_______ @ +____(())@ +_ __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +230 + @ +______ ___ @ +_ __ ` _ \@ +/ /_/ __/@ +\__,_____/ @ + @@ +231 + @ +_______@ +_ ___/@ +/ /__ @ +\___/ @ +/_) @@ +232 +_____ @ +___\_\@ +_ _ \@ +/ __/@ +\___/ @ + @@ +233 +______@ +___/_/@ +_ _ \@ +/ __/@ +\___/ @ + @@ +234 +___ //|@ +___|/||@ +_ _ \ @ +/ __/ @ +\___/ @ + @@ +235 +____ _ @ +__(_)(_)@ +_ _ \ @ +/ __/ @ +\___/ @ + @@ +236 +_____ @ +___\_\@ +__ / @ +_ / @ +/_/ @ + @@ +237 +______@ +___/_/@ +__ / @ +_ / @ +/_/ @ + @@ +238 +___ //|@ +___|/||@ +__ / @ +_ / @ +/_/ @ + @@ +239 +_ _ _ @ +_(_)_(_)@ +__/ / @ +_ / @ +/_/ @ + @@ +240 +____ || @ +____=||=@ +____ || @ +/ __` | @ +\____/ @ + @@ +241 +_____/\//@ +____//\/ @ +__ __ \ @ +_ / / / @ +/_/ /_/ @ + @@ +242 +______ @ +____\_\@ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ +243 +_______@ +____/_/@ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ +244 +___ //|@ +___|/||@ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ +245 +____/\//@ +___//\/ @ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +246 +____ _ @ +__(_)_(_)@ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +247 + @ +_____ @ +___(_)_@ +/_____/@ + (_) @ + @@ +248 + @ +_______ @ +_ _// \@ +/ //// /@ +\_//__/ @ + @@ +249 +______ @ +____\_\_@ +_ / / /@ +/ /_/ / @ +\__,_/ @ + @@ +250 +_______ @ +____/_/_@ +_ / / /@ +/ /_/ / @ +\__,_/ @ + @@ +251 +___ //| @ +___|/||_@ +_ / / /@ +/ /_/ / @ +\__,_/ @ + @@ +252 +____ _ @ +__(_) (_)@ +_ / / / @ +/ /_/ / @ +\__,_/ @ + @@ +253 +________ @ +_____/_/_@ +__ / / /@ +_ /_/ / @ +_\__, / @ +/____/ @@ +254 +_______ @ +____ /_ @ +___ __ \@ +__ /_/ /@ +_ .___/ @ +/_/ @@ +255 +_____ _ @ +___(_) (_)@ +__ / / / @ +_ /_/ / @ +_\__, / @ +/____/ @@ diff --git a/resources/starwars.flf b/resources/starwars.flf new file mode 100644 index 00000000..6ea55f02 --- /dev/null +++ b/resources/starwars.flf @@ -0,0 +1,719 @@ +flf2a$ 7 6 22 15 4 +starwars.flf by Ryan Youck (youck@cs.uregina.ca) Dec 25/1994 +I am not responsible for use of this font +Based on Big.flf by Glenn Chappell + +$ $@ +$ $@ +$ $@ +$ $@ +$ $@ +$ $@ +$ $@@ + __ $@ +| |$@ +| |$@ +| |$@ +|__|$@ +(__)$@ + $@@ + _ _ @ +( | )@ + V V @ + $ @ + $ @ + $ @ + @@ + _ _ @ + _| || |_$@ +|_ __ _|@ + _| || |_ @ +|_ __ _|@ + |_||_| $@ + @@ + __,--,_.@ + / |@ + | (----`@ + \ \ $@ +.----) | $@ +|_ __/ $@ + '--' $@@ + _ ___$ @ + / \ / /$ @ +( o ) / / $ @ + \_/ / / _$ @ + / / / \ @ + / / ( o )@ + /__/ \_/ @@ + @ + ___ @ + ( _ ) $@ + / _ \/\@ +| (_> <@ + \___/\/@ + $@@ + __ @ +(_ )@ + |/ @ + $ @ + $ @ + $ @ + @@ + ___@ + / /@ +| |$@ +| |$@ +| |$@ +| |$@ + \__\@@ +___ @ +\ \ @ + | |@ + | |@ + | |@ + | |@ +/__/ @@ + _ @ + /\| |/\ @ + \ ` ' /$@ +|_ _|@ + / , . \$@ + \/|_|\/ @ + @@ + @ + _ @ + _| |_$@ +|_ _|@ + |_| $@ + $ @ + @@ + @ + @ + $ @ + $ @ + __ @ +(_ )@ + |/ @@ + @ + @ + ______ @ +|______|@ + $ @ + $ @ + @@ + @ + @ + @ + $ @ + __ @ +(__)@ + @@ + ___@ + / /@ + / / @ + / /$ @ + / /$ @ +/__/$ @ + @@ + ___ $@ + / _ \ $@ +| | | |$@ +| | | |$@ +| |_| |$@ + \___/ $@ + $@@ + __ $@ +/_ |$@ + | |$@ + | |$@ + | |$@ + |_|$@ + $@@ + ___ $@ +|__ \ $@ + $) |$@ + / / $@ + / /_ $@ +|____|$@ + $@@ + ____ $@ +|___ \ $@ + __) |$@ + |__ < $@ + ___) |$@ +|____/ $@ + $@@ + _ _ $@ +| || | $@ +| || |_ $@ +|__ _|$@ + | | $@ + |_| $@ + $@@ + _____ $@ +| ____|$@ +| |__ $@ +|___ \ $@ + ___) |$@ +|____/ $@ + $@@ + __ $@ + / / $@ + / /_ $@ +| '_ \ $@ +| (_) |$@ + \___/ $@ + $@@ + ______ $@ +|____ |$@ + $/ / $@ + / / $@ + / / $@ + /_/ $@ + $@@ + ___ $@ + / _ \ $@ +| (_) |$@ + > _ < $@ +| (_) |$@ + \___/ $@ + $@@ + ___ $@ + / _ \ $@ +| (_) |$@ + \__, |$@ + / / $@ + /_/ $@ + $@@ + @ + _ @ +(_)@ + $ @ + _ @ +(_)@ + @@ + @ + _ @ +(_)@ + $ @ + _ @ +( )@ +|/ @@ + ___@ + / /@ + / /$@ +< <$ @ + \ \$@ + \__\@ + @@ + @ + ______ @ +|______|@ + ______ @ +|______|@ + @ + @@ +___ @ +\ \$ @ + \ \ @ + > >@ + / / @ +/__/$ @ + @@ + ______ $@ +| \ $@ +`----) |$@ + / / $@ + |__| $@ + __ $@ + (__) $@@ + ____ @ + / __ \ @ + / / _` |@ +| | (_| |@ + \ \__,_|@ + \____/ @ + @@ + ___ $ @ + / \ $ @ + / ^ \$ @ + / /_\ \$ @ + / _____ \$ @ +/__/ \__\$@ + $@@ +.______ $@ +| _ \ $@ +| |_) |$@ +| _ < $@ +| |_) |$@ +|______/ $@ + $@@ + ______$@ + / |@ +| ,----'@ +| | $@ +| `----.@ + \______|@ + $@@ + _______ $@ +| \$@ +| .--. |@ +| | | |@ +| '--' |@ +|_______/$@ + $@@ + _______ @ +| ____|@ +| |__ $@ +| __| $@ +| |____ @ +|_______|@ + @@ + _______ @ +| ____|@ +| |__ $@ +| __| $@ +| | $ @ +|__| @ + @@ + _______ @ + / _____|@ +| | __ $@ +| | |_ |$@ +| |__| |$@ + \______|$@ + $@@ + __ __ $@ +| | | |$@ +| |__| |$@ +| __ |$@ +| | | |$@ +|__| |__|$@ + $@@ + __ $@ +| |$@ +| |$@ +| |$@ +| |$@ +|__|$@ + $@@ + __ $@ + | |$@ + | |$@ +.--. | |$@ +| `--' |$@ + \______/ $@ + $@@ + __ ___$@ +| |/ /$@ +| ' / $@ +| < $@ +| . \ $@ +|__|\__\$@ + $@@ + __ $@ +| | $@ +| | $@ +| | $@ +| `----.@ +|_______|@ + $@@ +.___ ___.$@ +| \/ |$@ +| \ / |$@ +| |\/| |$@ +| | | |$@ +|__| |__|$@ + $@@ +.__ __.$@ +| \ | |$@ +| \| |$@ +| . ` |$@ +| |\ |$@ +|__| \__|$@ + $@@ + ______ $@ + / __ \ $@ +| | | |$@ +| | | |$@ +| `--' |$@ + \______/ $@ + $@@ +.______ $@ +| _ \ $@ +| |_) |$@ +| ___/ $@ +| | $ @ +| _| $ @ + $ @@ + ______ $ @ + / __ \ $ @ +| | | | $ @ +| | | | $ @ +| `--' '--. @ + \_____\_____\@ + $ @@ +.______ $ @ +| _ \ $ @ +| |_) | $ @ +| / $ @ +| |\ \----.@ +| _| `._____|@ + $@@ + _______.@ + / |@ + | (----`@ + \ \ $@ +.----) | $@ +|_______/ $@ + $@@ +.___________.@ +| |@ +`---| |----`@ + | | $ @ + | | $ @ + |__| $ @ + $ @@ + __ __ $@ +| | | |$@ +| | | |$@ +| | | |$@ +| `--' |$@ + \______/ $@ + $@@ +____ ____$@ +\ \ / /$@ + \ \/ /$ @ + \ /$ @ + \ /$ @ + \__/$ @ + $ @@ +____ __ ____$@ +\ \ / \ / /$@ + \ \/ \/ /$ @ + \ /$ @ + \ /\ /$ @ + \__/ \__/$ @ + $ @@ +___ ___$@ +\ \ / /$@ + \ V / $@ + > < $@ + / . \ $@ +/__/ \__\$@ + $@@ +____ ____$@ +\ \ / /$@ + \ \/ /$ @ + \_ _/$ @ + | |$ @ + |__|$ @ + $ @@ + ________ $@ +| / $@ +`---/ / $@ + / / $@ + / /----.@ + /________|@ + $@@ + ____ @ +| |@ +| |-`@ +| | $@ +| | $@ +| |-.@ +|____|@@ +___ @ +\ \ $ @ + \ \$ @ + \ \$ @ + \ \$@ + \__\@ + @@ + ____ @ +| |@ +`-| |@ + | |@ + | |@ +.-| |@ +|____|@@ + ___ @ + / \ @ +/--^--\@ + $@ + $@ + $@ + $@@ + @ + @ + @ + $ @ + $ @ + ______ @ +|______|@@ + __ @ +( _)@ + \| @ + $ @ + $ @ + $ @ + @@ + ___ $ @ + / \ $ @ + / ^ \$ @ + / /_\ \$ @ + / _____ \$ @ +/__/ \__\$@ + $@@ +.______ $@ +| _ \ $@ +| |_) |$@ +| _ < $@ +| |_) |$@ +|______/ $@ + $@@ + ______$@ + / |@ +| ,----'@ +| | $@ +| `----.@ + \______|@ + $@@ + _______ $@ +| \$@ +| .--. |@ +| | | |@ +| '--' |@ +|_______/$@ + $@@ + _______ @ +| ____|@ +| |__ $@ +| __| $@ +| |____ @ +|_______|@ + @@ + _______ @ +| ____|@ +| |__ $@ +| __| $@ +| | $ @ +|__| @ + @@ + _______ @ + / _____|@ +| | __ $@ +| | |_ |$@ +| |__| |$@ + \______|$@ + $@@ + __ __ $@ +| | | |$@ +| |__| |$@ +| __ |$@ +| | | |$@ +|__| |__|$@ + $@@ + __ $@ +| |$@ +| |$@ +| |$@ +| |$@ +|__|$@ + $@@ + __ $@ + | |$@ + | |$@ +.--. | |$@ +| `--' |$@ + \______/ $@ + $@@ + __ ___$@ +| |/ /$@ +| ' / $@ +| < $@ +| . \ $@ +|__|\__\$@ + $@@ + __ $@ +| | $@ +| | $@ +| | $@ +| `----.@ +|_______|@ + $@@ +.___ ___.$@ +| \/ |$@ +| \ / |$@ +| |\/| |$@ +| | | |$@ +|__| |__|$@ + $@@ +.__ __.$@ +| \ | |$@ +| \| |$@ +| . ` |$@ +| |\ |$@ +|__| \__|$@ + $@@ + ______ $@ + / __ \ $@ +| | | |$@ +| | | |$@ +| `--' |$@ + \______/ $@ + $@@ +.______ $@ +| _ \ $@ +| |_) |$@ +| ___/ $@ +| | $ @ +| _| $ @ + $ @@ + ______ $ @ + / __ \ $ @ +| | | | $ @ +| | | | $ @ +| `--' '--. @ + \_____\_____\@ + $ @@ +.______ $ @ +| _ \ $ @ +| |_) | $ @ +| / $ @ +| |\ \----.@ +| _| `._____|@ + $@@ + _______.@ + / |@ + | (----`@ + \ \ $@ +.----) | $@ +|_______/ $@ + $@@ +.___________.@ +| |@ +`---| |----`@ + | | $ @ + | | $ @ + |__| $ @ + $ @@ + __ __ $@ +| | | |$@ +| | | |$@ +| | | |$@ +| `--' |$@ + \______/ $@ + $@@ +____ ____$@ +\ \ / /$@ + \ \/ /$ @ + \ /$ @ + \ /$ @ + \__/$ @ + $ @@ +____ __ ____$@ +\ \ / \ / /$@ + \ \/ \/ /$ @ + \ /$ @ + \ /\ /$ @ + \__/ \__/$ @ + $ @@ +___ ___$@ +\ \ / /$@ + \ V / $@ + > < $@ + / . \ $@ +/__/ \__\$@ + $@@ +____ ____$@ +\ \ / /$@ + \ \/ /$ @ + \_ _/$ @ + | |$ @ + |__|$ @ + $ @@ + ________ $@ +| / $@ +`---/ / $@ + / / $@ + / /----.@ + /________|@ + $@@ + ___@ + / /@ + | |$@ +/ /$ @ +\ \$ @ + | |$@ + \__\@@ + __ $@ +| |$@ +| |$@ +| |$@ +| |$@ +| |$@ +|__|$@@ +___ @ +\ \$ @ + | | @ + \ \@ + / /@ + | | @ +/__/$ @@ + __ _ @ + / \/ |@ +|_/\__/ @ + $ @ + $ @ + $ @ + @@ + _ _ @ + (_)_(_) @ + / \ @ + / _ \ @ + / ___ \ @ +/_/ \_\@ + @@ + _ _ @ +(_)_(_)@ + / _ \ @ +| | | |@ +| |_| |@ + \___/ @ + @@ + _ _ @ +(_) (_)@ +| | | |@ +| | | |@ +| |_| |@ + \___/ @ + @@ + _ _ @ +(_) (_)@ + __ _ @ + / _` |@ +| (_| |@ + \__,_|@ + @@ + _ _ @ +(_) (_)@ + ___ @ + / _ \ @ +| (_) |@ + \___/ @ + @@ + _ _ @ +(_) (_)@ + _ _ @ +| | | |@ +| |_| |@ + \__,_|@ + @@ + ___ @ + / _ \ @ +| | ) |@ +| |< < @ +| | ) |@ +| ||_/ @ +|_| @@ diff --git a/src/config/settings.rs b/src/config/settings.rs index 3c9a7853..40723e3e 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -70,23 +70,24 @@ macro_rules! config_map { #[derive(Debug, Deserialize)] pub struct App { - pub name : String, - pub description : String, - pub language : String, - pub theme : String, - pub run_mode : String, + pub name : String, + pub description : String, + pub language : String, + pub theme : String, + pub startup_banner: String, + pub run_mode : String, } #[derive(Debug, Deserialize)] pub struct Webserver { - pub bind_address : String, - pub bind_port : u16, + pub bind_address : String, + pub bind_port : u16, } #[derive(Debug, Deserialize)] pub struct Settings { - pub app : App, - pub webserver : Webserver, + pub app : App, + pub webserver : Webserver, } config_map!(r#" @@ -100,6 +101,7 @@ Ajustes globales y valores predeterminados para las secciones *\[app\]* y "app.description" => "Developed with the amazing PageTop framework.", "app.language" => "en-US", "app.theme" => "Minimal", + "app.startup_banner" => "Small", // [webserver] "webserver.bind_address" => "localhost", diff --git a/src/core/server/main.rs b/src/core/server/main.rs index ea0deafc..c9271df5 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -12,6 +12,24 @@ pub fn run(bootstrap: Option) -> Result { // Al ser el último, puede sobrecargarse en la función de arranque. register_module(&base::module::homepage::HomepageModule); + // Si el arranque ha ido bien imprime un rótulo opcional de bienvenida. + if SETTINGS.app.startup_banner.to_lowercase() != "off" { + let figfont = figlet_rs::FIGfont::from_content( + match SETTINGS.app.startup_banner.to_lowercase().as_str() { + "slant" => include_str!("../../../resources/slant.flf"), + "small" => include_str!("../../../resources/small.flf"), + "speed" => include_str!("../../../resources/speed.flf"), + "starwars" => include_str!("../../../resources/starwars.flf"), + _ => include_str!("../../../resources/small.flf") + } + ).unwrap(); + println!("\n{} {}\n\n Powered by PageTop {}\n", + figfont.convert(&SETTINGS.app.name).unwrap(), + &SETTINGS.app.description, + env!("CARGO_PKG_VERSION") + ); + } + // Inicializa el servidor web. let server = server::HttpServer::new(|| { server::App::new() From cb557f4a867cc8ac0afd7f5e3ce6196d2bd20d47 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Mon, 14 Feb 2022 22:52:41 +0100 Subject: [PATCH 009/244] =?UTF-8?q?A=C3=B1ade=20seguimiento=20de=20la=20tr?= =?UTF-8?q?aza=20de=20ejecuci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 6 +++++ config/settings.default.toml | 5 +++- src/config/settings.rs | 2 ++ src/core/server/main.rs | 52 ++++++++++++++++++++++++++++-------- src/lib.rs | 1 + src/prelude.rs | 2 ++ src/trace/mod.rs | 1 + 7 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 src/trace/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 1a36650e..4c98cc21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,12 @@ figlet-rs = "0.1.3" config_rs = { package = "config", version = "0.11.0", features = ["toml"] } +tracing = "0.1" +tracing-log = "0.1" +tracing-subscriber = { version = "0.3", features = ["registry", "env-filter"] } +tracing-bunyan-formatter = "0.3" +tracing-actix-web = "0.2" + fluent-templates = "0.6.1" unic-langid = "0.9.0" diff --git a/config/settings.default.toml b/config/settings.default.toml index 0a446896..3d6d0b40 100644 --- a/config/settings.default.toml +++ b/config/settings.default.toml @@ -5,8 +5,11 @@ description = "Developed with the amazing PageTop framework." language = "en-US" # Tema predeterminado. theme = "Minimal" -# Rótulo al inicio: "Off", "Slant", "Small", "Speed" or "Starwars". +# Rótulo al inicio: "Off", "Slant", "Small", "Speed" o "Starwars". startup_banner = "Small" +# Traza de la ejecución: "Error", "Warn", "Info", "Debug" o "Trace". +# Ejemplos: "Error,actix_server::builder=Info,tracing_actix_web=Debug". +tracing = "Info" [webserver] # Configuración opcional del servidor web. diff --git a/src/config/settings.rs b/src/config/settings.rs index 40723e3e..3ac39634 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -75,6 +75,7 @@ pub struct App { pub language : String, pub theme : String, pub startup_banner: String, + pub tracing : String, pub run_mode : String, } @@ -102,6 +103,7 @@ Ajustes globales y valores predeterminados para las secciones *\[app\]* y "app.language" => "en-US", "app.theme" => "Minimal", "app.startup_banner" => "Small", + "app.tracing" => "Info", // [webserver] "webserver.bind_address" => "localhost", diff --git a/src/core/server/main.rs b/src/core/server/main.rs index c9271df5..a0ebc59e 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -1,18 +1,30 @@ -use crate::base; +use crate::{base, trace}; use crate::config::SETTINGS; use crate::core::{Server, all, register_module, server}; +use tracing::subscriber::set_global_default; +use tracing_subscriber::{EnvFilter, Registry}; +use tracing_subscriber::layer::SubscriberExt; +use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; +use tracing_log::LogTracer; +use tracing_actix_web::TracingLogger; + pub fn run(bootstrap: Option) -> Result { - // Ejecuta la función de arranque de la aplicación. - if bootstrap != None { - let _ = &(bootstrap.unwrap())(); - } + // Inicia el seguimiento de la traza de ejecución de la aplicación. + let env_filter = EnvFilter::try_new(String::from(&SETTINGS.app.tracing)) + .unwrap_or(EnvFilter::new(String::from("Info"))); + let formatting_layer = BunyanFormattingLayer::new( + String::from(&SETTINGS.app.name), + std::io::stdout + ); + let subscriber = Registry::default() + .with(env_filter) + .with(JsonStorageLayer) + .with(formatting_layer); + LogTracer::init().expect("Failed to set logger"); + set_global_default(subscriber).expect("Failed to set subscriber"); - // Registra el módulo para la página de inicio de PageTop. - // Al ser el último, puede sobrecargarse en la función de arranque. - register_module(&base::module::homepage::HomepageModule); - - // Si el arranque ha ido bien imprime un rótulo opcional de bienvenida. + // Imprime el rótulo (opcional) de bienvenida. if SETTINGS.app.startup_banner.to_lowercase() != "off" { let figfont = figlet_rs::FIGfont::from_content( match SETTINGS.app.startup_banner.to_lowercase().as_str() { @@ -20,7 +32,13 @@ pub fn run(bootstrap: Option) -> Result { "small" => include_str!("../../../resources/small.flf"), "speed" => include_str!("../../../resources/speed.flf"), "starwars" => include_str!("../../../resources/starwars.flf"), - _ => include_str!("../../../resources/small.flf") + _ => { + trace::warn!( + ">>> FIGfont \"{}\" not found for banner. Using \"{}\"", + SETTINGS.app.startup_banner, "Small" + ); + include_str!("../../../resources/small.flf") + } } ).unwrap(); println!("\n{} {}\n\n Powered by PageTop {}\n", @@ -30,9 +48,21 @@ pub fn run(bootstrap: Option) -> Result { ); } + // Ejecuta la función de inicio de la aplicación. + if bootstrap != None { + trace::debug!("Calling application bootstrap"); + let _ = &(bootstrap.unwrap())(); + } + + // Registra el módulo para la página de inicio de PageTop. + // Al ser el último, puede sobrecargarse en la función de arranque. + register_module(&base::module::homepage::HomepageModule); + + // Inicializa el servidor web. let server = server::HttpServer::new(|| { server::App::new() + .wrap(TracingLogger) .configure(&all::themes) .configure(&all::modules) }) diff --git a/src/lib.rs b/src/lib.rs index 87e80aac..c72b36f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ pub use once_cell::sync::Lazy; pub mod macros; // Macros útiles. pub mod config; // Gestión de la configuración. +pub mod trace; // Seguimiento de la traza de ejecución. pub mod locale; // Localización. pub mod core; // Servidor web y sistemas para Temas, Módulos y Respuestas. pub mod base; // Temas, Módulos y Componentes base. diff --git a/src/prelude.rs b/src/prelude.rs index c74bb379..8ae92907 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -3,6 +3,8 @@ pub use crate::args; pub use crate::localize; +pub use crate::trace; + pub use crate::core::theme::*; pub use crate::core::module::*; diff --git a/src/trace/mod.rs b/src/trace/mod.rs new file mode 100644 index 00000000..f4af4116 --- /dev/null +++ b/src/trace/mod.rs @@ -0,0 +1 @@ +pub use tracing::{debug, error, info, trace, warn}; From 1d438dff57c32bc00d831162bd2924169138c4bf Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Wed, 16 Feb 2022 00:33:35 +0100 Subject: [PATCH 010/244] =?UTF-8?q?Mejora=20la=20funcionalidad=20de=20la?= =?UTF-8?q?=20traza=20de=20ejecuci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 1 + config/settings.default.toml | 10 +++++++- src/config/settings.rs | 21 +++++++++++++---- src/core/server/main.rs | 45 ++++++++++++++++++++++++++++-------- src/lib.rs | 2 +- 5 files changed, 64 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4c98cc21..8eb88ee2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ config_rs = { package = "config", version = "0.11.0", features = ["toml"] } tracing = "0.1" tracing-log = "0.1" +tracing-appender = "0.2" tracing-subscriber = { version = "0.3", features = ["registry", "env-filter"] } tracing-bunyan-formatter = "0.3" tracing-actix-web = "0.2" diff --git a/config/settings.default.toml b/config/settings.default.toml index 3d6d0b40..1df46f5c 100644 --- a/config/settings.default.toml +++ b/config/settings.default.toml @@ -7,9 +7,17 @@ language = "en-US" theme = "Minimal" # Rótulo al inicio: "Off", "Slant", "Small", "Speed" o "Starwars". startup_banner = "Small" -# Traza de la ejecución: "Error", "Warn", "Info", "Debug" o "Trace". + +[log] +# Traza de ejecución: "Error", "Warn", "Info", "Debug" o "Trace". # Ejemplos: "Error,actix_server::builder=Info,tracing_actix_web=Debug". tracing = "Info" +# En terminal ("Stdout") o archivos "Daily", "Hourly", "Minutely" o "Endless". +rolling = "Daily" +# Directorio para los archivos de traza (si rolling != "Stdout"). +path = "log" +# Prefijo para los archivos de traza (si rolling != "Stdout"). +prefix = "tracing.log" [webserver] # Configuración opcional del servidor web. diff --git a/src/config/settings.rs b/src/config/settings.rs index 3ac39634..4d791763 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -75,10 +75,17 @@ pub struct App { pub language : String, pub theme : String, pub startup_banner: String, - pub tracing : String, pub run_mode : String, } +#[derive(Debug, Deserialize)] +pub struct Log { + pub tracing : String, + pub rolling : String, + pub path : String, + pub prefix : String, +} + #[derive(Debug, Deserialize)] pub struct Webserver { pub bind_address : String, @@ -88,12 +95,13 @@ pub struct Webserver { #[derive(Debug, Deserialize)] pub struct Settings { pub app : App, + pub log : Log, pub webserver : Webserver, } config_map!(r#" -Ajustes globales y valores predeterminados para las secciones *\[app\]* y -*\[webserver\]* específicas de PageTop. +Ajustes globales y valores predeterminados para las secciones *\[app\]*, +*\[log\]* y *\[webserver\]* específicas de PageTop. "#, SETTINGS, Settings, @@ -103,7 +111,12 @@ Ajustes globales y valores predeterminados para las secciones *\[app\]* y "app.language" => "en-US", "app.theme" => "Minimal", "app.startup_banner" => "Small", - "app.tracing" => "Info", + + // [log] + "log.tracing" => "Info", + "log.rolling" => "Daily", + "log.path" => "log", + "log.prefix" => "tracing.log", // [webserver] "webserver.bind_address" => "localhost", diff --git a/src/core/server/main.rs b/src/core/server/main.rs index a0ebc59e..0884201e 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -2,27 +2,54 @@ use crate::{base, trace}; use crate::config::SETTINGS; use crate::core::{Server, all, register_module, server}; -use tracing::subscriber::set_global_default; +use tracing_log::LogTracer; use tracing_subscriber::{EnvFilter, Registry}; use tracing_subscriber::layer::SubscriberExt; +use tracing::subscriber::set_global_default; use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; -use tracing_log::LogTracer; use tracing_actix_web::TracingLogger; pub fn run(bootstrap: Option) -> Result { - // Inicia el seguimiento de la traza de ejecución de la aplicación. - let env_filter = EnvFilter::try_new(String::from(&SETTINGS.app.tracing)) - .unwrap_or(EnvFilter::new(String::from("Info"))); + // Inicia la traza de ejecución de la aplicación. + let env_filter = EnvFilter::try_new(&SETTINGS.log.tracing) + .unwrap_or(EnvFilter::new("Info")); + + let rolling = SETTINGS.log.rolling.to_lowercase(); + let (non_blocking, _guard) = match rolling.as_str() { + "stdout" => tracing_appender::non_blocking( + std::io::stdout() + ), + _ => tracing_appender::non_blocking({ + let path = &SETTINGS.log.path; + let prefix = &SETTINGS.log.prefix; + match rolling.as_str() { + "daily" => tracing_appender::rolling::daily(path, prefix), + "hourly" => tracing_appender::rolling::hourly(path, prefix), + "minutely" => tracing_appender::rolling::minutely(path, prefix), + "endless" => tracing_appender::rolling::never(path, prefix), + _ => { + println!( + "Rolling value \"{}\" not valid. Using \"daily\"", + rolling + ); + tracing_appender::rolling::daily(path, prefix) + } + } + }) + }; let formatting_layer = BunyanFormattingLayer::new( String::from(&SETTINGS.app.name), - std::io::stdout + non_blocking ); + let subscriber = Registry::default() .with(env_filter) .with(JsonStorageLayer) .with(formatting_layer); - LogTracer::init().expect("Failed to set logger"); - set_global_default(subscriber).expect("Failed to set subscriber"); + + set_global_default(subscriber).expect("Unable to setup subscriber!"); + + LogTracer::init().expect("Unable to setup log tracer!"); // Imprime el rótulo (opcional) de bienvenida. if SETTINGS.app.startup_banner.to_lowercase() != "off" { @@ -34,7 +61,7 @@ pub fn run(bootstrap: Option) -> Result { "starwars" => include_str!("../../../resources/starwars.flf"), _ => { trace::warn!( - ">>> FIGfont \"{}\" not found for banner. Using \"{}\"", + "FIGfont \"{}\" not found for banner. Using \"{}\"", SETTINGS.app.startup_banner, "Small" ); include_str!("../../../resources/small.flf") diff --git a/src/lib.rs b/src/lib.rs index c72b36f9..327379a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ pub use once_cell::sync::Lazy; pub mod macros; // Macros útiles. pub mod config; // Gestión de la configuración. -pub mod trace; // Seguimiento de la traza de ejecución. +pub mod trace; // Traza de ejecución. pub mod locale; // Localización. pub mod core; // Servidor web y sistemas para Temas, Módulos y Respuestas. pub mod base; // Temas, Módulos y Componentes base. From d38df3a5b65918747a30dc92fdf28768aa1f6f34 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Sun, 20 Feb 2022 23:01:11 +0100 Subject: [PATCH 011/244] =?UTF-8?q?A=C3=B1ade=20m=C3=B3dulo=20User=20y=20c?= =?UTF-8?q?omponentes=20para=20formularios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/settings.default.toml | 3 +- src/base/component/chunck.rs | 8 +- src/base/component/container.rs | 4 +- src/base/component/form/button.rs | 174 +++++++++ src/base/component/form/date.rs | 264 +++++++++++++ src/base/component/form/form.rs | 152 ++++++++ src/base/component/form/hidden.rs | 110 ++++++ src/base/component/form/input.rs | 346 ++++++++++++++++++ src/base/component/form/mod.rs | 11 + src/base/component/mod.rs | 9 +- .../homepage/locales/en-US/homepage.ftl | 19 +- .../homepage/locales/es-ES/homepage.ftl | 19 +- src/base/module/homepage/mod.rs | 55 ++- src/base/module/mod.rs | 1 + .../module/user/locales/en-US/homepage.ftl | 8 + .../module/user/locales/es-ES/homepage.ftl | 8 + src/base/module/user/mod.rs | 47 +++ src/core/server/main.rs | 3 + src/core/state.rs | 4 +- src/macros/mod.rs | 2 +- src/prelude.rs | 7 +- 21 files changed, 1228 insertions(+), 26 deletions(-) create mode 100644 src/base/component/form/button.rs create mode 100644 src/base/component/form/date.rs create mode 100644 src/base/component/form/form.rs create mode 100644 src/base/component/form/hidden.rs create mode 100644 src/base/component/form/input.rs create mode 100644 src/base/component/form/mod.rs create mode 100644 src/base/module/user/locales/en-US/homepage.ftl create mode 100644 src/base/module/user/locales/es-ES/homepage.ftl create mode 100644 src/base/module/user/mod.rs diff --git a/config/settings.default.toml b/config/settings.default.toml index 1df46f5c..53a2c693 100644 --- a/config/settings.default.toml +++ b/config/settings.default.toml @@ -20,7 +20,6 @@ path = "log" prefix = "tracing.log" [webserver] -# Configuración opcional del servidor web. -# Usar bind_address = "" para deshabilitar el servidor web. +# Configuración del servidor web. bind_address = "localhost" bind_port = 8088 diff --git a/src/base/component/chunck.rs b/src/base/component/chunck.rs index 29c62918..8d4e956f 100644 --- a/src/base/component/chunck.rs +++ b/src/base/component/chunck.rs @@ -37,14 +37,12 @@ impl PageComponent for Chunck { impl Chunck { - // Chunck BUILDER. - pub fn markup(markup: Markup) -> Self { - let mut chunck = Chunck::prepare(); - chunck.markup.push(markup); - chunck + Chunck::prepare().add_markup(markup) } + // Chunck BUILDER. + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { self.renderable = renderable; self diff --git a/src/base/component/container.rs b/src/base/component/container.rs index 58a0caac..dfb1a010 100644 --- a/src/base/component/container.rs +++ b/src/base/component/container.rs @@ -48,8 +48,6 @@ impl PageComponent for Container { impl Container { - // Container BUILDER. - pub fn row() -> Self { let mut grid = Container::prepare(); grid.container = ContainerType::Row; @@ -62,6 +60,8 @@ impl Container { grid } + // Container BUILDER. + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { self.renderable = renderable; self diff --git a/src/base/component/form/button.rs b/src/base/component/form/button.rs new file mode 100644 index 00000000..440ccf93 --- /dev/null +++ b/src/base/component/form/button.rs @@ -0,0 +1,174 @@ +use crate::prelude::*; + +enum ButtonType {Button, Reset, Submit} + +pub struct Button { + renderable : fn() -> bool, + weight : i8, + button_type: ButtonType, + name : Option, + value : Option, + autofocus : Option, + disabled : Option, + template : String, +} + +impl PageComponent for Button { + + fn prepare() -> Self { + Button { + renderable : always, + weight : 0, + button_type: ButtonType::Button, + name : None, + value : None, + autofocus : None, + disabled : None, + template : "default".to_string(), + } + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> i8 { + self.weight + } + + fn default_render(&self, _: &mut PageAssets) -> Markup { + let (button_type, button_class) = match &self.button_type { + ButtonType::Button => ("button", "btn btn-primary form-button"), + ButtonType::Reset => ("reset", "btn btn-primary form-reset" ), + ButtonType::Submit => ("submit", "btn btn-primary form-submit") + }; + let id_item = match &self.name { + Some(name) => Some(format!("edit-{}", name)), + _ => None + }; + html! { + button + type=(button_type) + id=[&id_item] + class=(button_class) + name=[&self.name] + value=[&self.value] + autofocus=[&self.autofocus] + disabled=[&self.disabled] + { + @match &self.value { + Some(value) => (value), + _ => "" + }; + } + } + } +} + +impl Button { + + pub fn button(value: &str) -> Self { + Button::prepare().with_value(value) + } + + pub fn reset(value: &str) -> Self { + let mut button = Button::prepare().with_value(value); + button.button_type = ButtonType::Reset; + button + } + + pub fn submit(value: &str) -> Self { + let mut button = Button::prepare().with_value(value); + button.button_type = ButtonType::Submit; + button + } + + // Button BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_name(mut self, name: &str) -> Self { + self.name = if name.is_empty() { + None + } else { + Some(name.replace(" ", "_")) + }; + self + } + + pub fn with_value(mut self, value: &str) -> Self { + self.value = if value.is_empty() { + None + } else { + Some(value.to_string()) + }; + self + } + + pub fn autofocus(mut self, toggle: bool) -> Self { + self.autofocus = match toggle { + true => Some("autofocus".to_string()), + false => None + }; + self + } + + pub fn disabled(mut self, toggle: bool) -> Self { + self.disabled = match toggle { + true => Some("disabled".to_string()), + false => None + }; + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.template = template.to_string(); + self + } + + // Button GETTERS. + + pub fn name(&self) -> &str { + match &self.name { + Some(name) => name.as_str(), + _ => "" + } + } + + pub fn value(&self) -> &str { + match &self.value { + Some(value) => value.as_str(), + _ => "" + } + } + + pub fn has_autofocus(&self) -> bool { + match &self.autofocus { + Some(_) => true, + _ => false + } + } + + pub fn is_disabled(&self) -> bool { + match &self.disabled { + Some(_) => true, + _ => false + } + } + + pub fn template(&self) -> &str { + self.template.as_str() + } +} + +fn always() -> bool { + true +} diff --git a/src/base/component/form/date.rs b/src/base/component/form/date.rs new file mode 100644 index 00000000..e1e33be0 --- /dev/null +++ b/src/base/component/form/date.rs @@ -0,0 +1,264 @@ +use crate::prelude::*; + +pub struct Date { + renderable : fn() -> bool, + weight : i8, + name : Option, + value : Option, + label : String, + placeholder : Option, + autofocus : Option, + autocomplete: Option, + disabled : Option, + readonly : Option, + required : Option, + help_text : String, + template : String, +} + +impl PageComponent for Date { + + fn prepare() -> Self { + Date { + renderable : always, + weight : 0, + name : None, + value : None, + label : "".to_string(), + placeholder : None, + autofocus : None, + autocomplete: None, + disabled : None, + readonly : None, + required : None, + help_text : "".to_string(), + template : "default".to_string(), + } + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> i8 { + self.weight + } + + fn default_render(&self, _: &mut PageAssets) -> Markup { + let (class_item, id_item) = match &self.name { + Some(name) => ( + format!("form-item form-item-{} form-type-date", name), + Some(format!("edit-{}", name)) + ), + None => ( + "form-item form-type-date".to_string(), + None + ) + }; + html! { + div class=(class_item) { + @if !self.label.is_empty() { + label class="form-label" for=[&id_item] { + (self.label) " " + @if self.required != None { + span + class="form-required" + title="Este campo es obligatorio." + { + "*" + } " " + } + } + } + input + type="date" + id=[&id_item] + class="form-control" + name=[&self.name] + value=[&self.value] + placeholder=[&self.placeholder] + autofocus=[&self.autofocus] + autocomplete=[&self.autocomplete] + readonly=[&self.readonly] + required=[&self.required] + disabled=[&self.disabled]; + @if !self.help_text.is_empty() { + div class="form-text" { + (self.help_text) + } + } + } + } + } +} + +impl Date { + + // Date BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_name(mut self, name: &str) -> Self { + self.name = if name.is_empty() { + None + } else { + Some(name.replace(" ", "_")) + }; + self + } + + pub fn with_value(mut self, value: &str) -> Self { + self.value = if value.is_empty() { + None + } else { + Some(value.to_string()) + }; + self + } + + pub fn with_label(mut self, label: &str) -> Self { + self.label = label.to_string(); + self + } + + pub fn with_placeholder(mut self, placeholder: &str) -> Self { + self.placeholder = if placeholder.is_empty() { + None + } else { + Some(placeholder.to_string()) + }; + self + } + + pub fn autofocus(mut self, toggle: bool) -> Self { + self.autofocus = match toggle { + true => Some("autofocus".to_string()), + false => None + }; + self + } + + pub fn autocomplete(mut self, toggle: bool) -> Self { + self.autocomplete = match toggle { + true => None, + false => Some("off".to_string()) + }; + self + } + + pub fn disabled(mut self, toggle: bool) -> Self { + self.disabled = match toggle { + true => Some("disabled".to_string()), + false => None + }; + self + } + + pub fn readonly(mut self, toggle: bool) -> Self { + self.readonly = match toggle { + true => Some("readonly".to_string()), + false => None + }; + self + } + + pub fn required(mut self, toggle: bool) -> Self { + self.required = match toggle { + true => Some("required".to_string()), + false => None + }; + self + } + + pub fn with_help_text(mut self, help_text: &str) -> Self { + self.help_text = help_text.to_string(); + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.template = template.to_string(); + self + } + + // Date GETTERS. + + pub fn name(&self) -> &str { + match &self.name { + Some(name) => name.as_str(), + _ => "" + } + } + + pub fn value(&self) -> &str { + match &self.value { + Some(value) => value.as_str(), + _ => "" + } + } + + pub fn label(&self) -> &str { + self.label.as_str() + } + + pub fn placeholder(&self) -> &str { + match &self.placeholder { + Some(placeholder) => placeholder.as_str(), + _ => "" + } + } + + pub fn has_autofocus(&self) -> bool { + match &self.autofocus { + Some(_) => true, + _ => false + } + } + + pub fn has_autocomplete(&self) -> bool { + match &self.autocomplete { + Some(_) => false, + _ => true + } + } + + pub fn is_disabled(&self) -> bool { + match &self.disabled { + Some(_) => true, + _ => false + } + } + + pub fn is_readonly(&self) -> bool { + match &self.readonly { + Some(_) => true, + _ => false + } + } + + pub fn is_required(&self) -> bool { + match &self.required { + Some(_) => true, + _ => false + } + } + + pub fn help_text(&self) -> &str { + self.help_text.as_str() + } + + pub fn template(&self) -> &str { + self.template.as_str() + } +} + +fn always() -> bool { + true +} diff --git a/src/base/component/form/form.rs b/src/base/component/form/form.rs new file mode 100644 index 00000000..519587e0 --- /dev/null +++ b/src/base/component/form/form.rs @@ -0,0 +1,152 @@ +use crate::prelude::*; + +pub enum FormMethod {Get, Post} + +pub struct Form { + renderable: fn() -> bool, + weight : i8, + id : Option, + action : Option, + method : FormMethod, + charset : Option, + elements : PageContainer, + template : String, +} + +impl PageComponent for Form { + + fn prepare() -> Self { + Form { + renderable: always, + weight : 0, + id : None, + action : None, + method : FormMethod::Post, + charset : Some("UTF-8".to_string()), + elements : PageContainer::new(), + template : "default".to_string(), + } + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> i8 { + self.weight + } + + fn default_render(&self, assets: &mut PageAssets) -> Markup { + let method = match self.method { + FormMethod::Get => None, + FormMethod::Post => Some("post".to_string()) + }; + html! { + form + id=[&self.id] + action=[&self.action] + method=[method] + accept-charset=[&self.charset] + { + div { + (self.elements.render(assets)) + } + } + } + } +} + +impl Form { + + // Form BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_id(mut self, id: &str) -> Self { + self.id = if id.is_empty() { + None + } else { + Some(id.replace(" ", "_")) + }; + self + } + + pub fn with_action(mut self, action: &str) -> Self { + self.action = if action.is_empty() { + None + } else { + Some(action.to_string()) + }; + self + } + + pub fn with_method(mut self, method: FormMethod) -> Self { + self.method = method; + self + } + + pub fn with_charset(mut self, charset: &str) -> Self { + self.charset = if charset.is_empty() { + None + } else { + Some(charset.to_string()) + }; + self + } + + pub fn add(mut self, element: impl PageComponent) -> Self { + self.elements.add(element); + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.template = template.to_string(); + self + } + + // Form GETTERS. + + pub fn id(&self) -> &str { + match &self.id { + Some(id) => id.as_str(), + _ => "" + } + } + + pub fn action(&self) -> &str { + match &self.action { + Some(action) => action.as_str(), + _ => "" + } + } + + pub fn method(&self) -> &str { + match &self.method { + FormMethod::Get => "get", + FormMethod::Post => "post" + } + } + + pub fn charset(&self) -> &str { + match &self.charset { + Some(charset) => charset.as_str(), + _ => "" + } + } + + pub fn template(&self) -> &str { + self.template.as_str() + } +} + +fn always() -> bool { + true +} diff --git a/src/base/component/form/hidden.rs b/src/base/component/form/hidden.rs new file mode 100644 index 00000000..a95cfc77 --- /dev/null +++ b/src/base/component/form/hidden.rs @@ -0,0 +1,110 @@ +use crate::prelude::*; + +pub struct Hidden { + renderable : fn() -> bool, + weight : i8, + name : Option, + value : Option, + template : String, +} + +impl PageComponent for Hidden { + + fn prepare() -> Self { + Hidden { + renderable : always, + weight : 0, + name : None, + value : None, + template : "default".to_string(), + } + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> i8 { + self.weight + } + + fn default_render(&self, _: &mut PageAssets) -> Markup { + let id_item = match &self.name { + Some(name) => Some(format!("value-{}", name)), + _ => None + }; + html! { + input + type="hidden" + id=[&id_item] + name=[&self.name] + value=[&self.value]; + } + } +} + +impl Hidden { + + pub fn set(name: &str, value: &str) -> Self { + Hidden::prepare().with_name(name).with_value(value) + } + + // Hidden BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_name(mut self, name: &str) -> Self { + self.name = if name.is_empty() { + None + } else { + Some(name.replace(" ", "_")) + }; + self + } + + pub fn with_value(mut self, value: &str) -> Self { + self.value = if value.is_empty() { + None + } else { + Some(value.to_string()) + }; + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.template = template.to_string(); + self + } + + // Hidden GETTERS. + + pub fn name(&self) -> &str { + match &self.name { + Some(name) => name.as_str(), + _ => "" + } + } + + pub fn value(&self) -> &str { + match &self.value { + Some(value) => value.as_str(), + _ => "" + } + } + + pub fn template(&self) -> &str { + self.template.as_str() + } +} + +fn always() -> bool { + true +} diff --git a/src/base/component/form/input.rs b/src/base/component/form/input.rs new file mode 100644 index 00000000..d4ec8930 --- /dev/null +++ b/src/base/component/form/input.rs @@ -0,0 +1,346 @@ +use crate::prelude::*; + +enum InputType {Email, Password, Search, Telephone, Textfield, Url} + +pub struct Input { + renderable : fn() -> bool, + weight : i8, + input_type : InputType, + name : Option, + value : Option, + label : String, + size : Option, + minlength : Option, + maxlength : Option, + placeholder : Option, + autofocus : Option, + autocomplete: Option, + disabled : Option, + readonly : Option, + required : Option, + help_text : String, + template : String, +} + +impl PageComponent for Input { + + fn prepare() -> Self { + Input { + renderable : always, + weight : 0, + input_type : InputType::Textfield, + name : None, + value : None, + label : "".to_string(), + size : Some(60), + minlength : None, + maxlength : Some(128), + placeholder : None, + autofocus : None, + autocomplete: None, + disabled : None, + readonly : None, + required : None, + help_text : "".to_string(), + template : "default".to_string(), + } + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> i8 { + self.weight + } + + fn default_render(&self, _: &mut PageAssets) -> Markup { + let (input_type, class_type) = match &self.input_type { + InputType::Email => ("email", "form-type-email"), + InputType::Password => ("password", "form-type-password"), + InputType::Search => ("search", "form-type-search"), + InputType::Telephone => ("tel", "form-type-telephone"), + InputType::Textfield => ("text", "form-type-textfield"), + InputType::Url => ("url", "form-type-url") + }; + let (class_item, id_item) = match &self.name { + Some(name) => ( + format!("form-item form-item-{} {}", name, class_type), + Some(format!("edit-{}", name)) + ), + None => ( + format!("form-item {}", class_type), + None + ) + }; + html! { + div class=(class_item) { + @if !self.label.is_empty() { + label class="form-label" for=[&id_item] { + (self.label) " " + @if self.required != None { + span + class="form-required" + title="Este campo es obligatorio." + { + "*" + } " " + } + } + } + input + type=(input_type) + id=[&id_item] + class="form-control" + name=[&self.name] + value=[&self.value] + size=[self.size] + minlength=[self.minlength] + maxlength=[self.maxlength] + placeholder=[&self.placeholder] + autofocus=[&self.autofocus] + autocomplete=[&self.autocomplete] + readonly=[&self.readonly] + required=[&self.required] + disabled=[&self.disabled]; + @if !self.help_text.is_empty() { + div class="form-text" { + (self.help_text) + } + } + } + } + } +} + +impl Input { + + pub fn textfield() -> Self { + Input::prepare() + } + + pub fn password() -> Self { + let mut input = Input::prepare(); + input.input_type = InputType::Password; + input + } + + pub fn search() -> Self { + let mut input = Input::prepare(); + input.input_type = InputType::Search; + input + } + + pub fn email() -> Self { + let mut input = Input::prepare(); + input.input_type = InputType::Email; + input + } + + pub fn telephone() -> Self { + let mut input = Input::prepare(); + input.input_type = InputType::Telephone; + input + } + + pub fn url() -> Self { + let mut input = Input::prepare(); + input.input_type = InputType::Url; + input + } + + // Input BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_name(mut self, name: &str) -> Self { + self.name = if name.is_empty() { + None + } else { + Some(name.replace(" ", "_")) + }; + self + } + + pub fn with_value(mut self, value: &str) -> Self { + self.value = if value.is_empty() { + None + } else { + Some(value.to_string()) + }; + self + } + + pub fn with_label(mut self, label: &str) -> Self { + self.label = label.to_string(); + self + } + + pub fn with_size(mut self, size: Option) -> Self { + self.size = size; + self + } + + pub fn with_minlength(mut self, minlength: Option) -> Self { + self.minlength = minlength; + self + } + + pub fn with_maxlength(mut self, maxlength: Option) -> Self { + self.maxlength = maxlength; + self + } + + pub fn with_placeholder(mut self, placeholder: &str) -> Self { + self.placeholder = if placeholder.is_empty() { + None + } else { + Some(placeholder.to_string()) + }; + self + } + + pub fn autofocus(mut self, toggle: bool) -> Self { + self.autofocus = match toggle { + true => Some("autofocus".to_string()), + false => None + }; + self + } + + pub fn autocomplete(mut self, toggle: bool) -> Self { + self.autocomplete = match toggle { + true => None, + false => Some("off".to_string()) + }; + self + } + + pub fn disabled(mut self, toggle: bool) -> Self { + self.disabled = match toggle { + true => Some("disabled".to_string()), + false => None + }; + self + } + + pub fn readonly(mut self, toggle: bool) -> Self { + self.readonly = match toggle { + true => Some("readonly".to_string()), + false => None + }; + self + } + + pub fn required(mut self, toggle: bool) -> Self { + self.required = match toggle { + true => Some("required".to_string()), + false => None + }; + self + } + + pub fn with_help_text(mut self, help_text: &str) -> Self { + self.help_text = help_text.to_string(); + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.template = template.to_string(); + self + } + + // Input GETTERS. + + pub fn name(&self) -> &str { + match &self.name { + Some(name) => name.as_str(), + _ => "" + } + } + + pub fn value(&self) -> &str { + match &self.value { + Some(value) => value.as_str(), + _ => "" + } + } + + pub fn label(&self) -> &str { + self.label.as_str() + } + + pub fn size(&self) -> Option { + self.size + } + + pub fn minlength(&self) -> Option { + self.minlength + } + + pub fn maxlength(&self) -> Option { + self.maxlength + } + + pub fn placeholder(&self) -> &str { + match &self.placeholder { + Some(placeholder) => placeholder.as_str(), + _ => "" + } + } + + pub fn has_autofocus(&self) -> bool { + match &self.autofocus { + Some(_) => true, + _ => false + } + } + + pub fn has_autocomplete(&self) -> bool { + match &self.autocomplete { + Some(_) => false, + _ => true + } + } + + pub fn is_disabled(&self) -> bool { + match &self.disabled { + Some(_) => true, + _ => false + } + } + + pub fn is_readonly(&self) -> bool { + match &self.readonly { + Some(_) => true, + _ => false + } + } + + pub fn is_required(&self) -> bool { + match &self.required { + Some(_) => true, + _ => false + } + } + + pub fn help_text(&self) -> &str { + self.help_text.as_str() + } + + pub fn template(&self) -> &str { + self.template.as_str() + } +} + +fn always() -> bool { + true +} diff --git a/src/base/component/form/mod.rs b/src/base/component/form/mod.rs new file mode 100644 index 00000000..4e10d476 --- /dev/null +++ b/src/base/component/form/mod.rs @@ -0,0 +1,11 @@ +mod form; +pub use form::{Form, FormMethod}; + +mod input; +pub use input::Input; +mod hidden; +pub use hidden::Hidden; +mod date; +pub use date::Date; +mod button; +pub use button::Button; diff --git a/src/base/component/mod.rs b/src/base/component/mod.rs index c12fb175..07c16cf7 100644 --- a/src/base/component/mod.rs +++ b/src/base/component/mod.rs @@ -1,2 +1,7 @@ -pub mod container; -pub mod chunck; +mod container; +pub use container::Container; +mod chunck; +pub use chunck::Chunck; + +pub mod form; +pub use form::{Form, FormMethod}; diff --git a/src/base/module/homepage/locales/en-US/homepage.ftl b/src/base/module/homepage/locales/en-US/homepage.ftl index 7008c35a..ec401e64 100644 --- a/src/base/module/homepage/locales/en-US/homepage.ftl +++ b/src/base/module/homepage/locales/en-US/homepage.ftl @@ -1,4 +1,21 @@ module_name = Default homepage module_desc = Displays a default homepage when none is configured. -greetings = Hello { $name }! +page_title = Hello world! + +text_welcome = This page is used to test the proper operation of { $app } after installation. This web solution is powered by { $pagetop }. If you can read this page, it means that the PageTop server is working properly, but has not yet been configured. + +title_normal_user = Just visiting? +text1_normal_user = If you are a normal user of this web site and don't know what this page is about, this probably means that the site is either experiencing problems or is undergoing routine maintenance. +text2_normal_user = If the problem persists, please contact your system administrator. + +title_about_pagetop = About PageTop +text1_about_pagetop = PageTop defines an interface for the most stable and popular Rust packages to build modular, extensible and configurable web solutions. +text2_about_pagetop = For information on PageTop please visit the "PageTop website". + +title_promo_pagetop = Promoting PageTop +text1_promo_pagetop = You are free to use the image below on applications powered by { $pagetop }. Thanks for using PageTop! + +title_report_problems = Reporting Problems +text1_report_problems = Please use the GitLab tool to report bugs in PageTop. However, check "existing bug reports" before reporting a new bug. +text2_report_problems = Please report bugs specific to modules (such as admin, and others) to respective packages, not to PageTop itself. diff --git a/src/base/module/homepage/locales/es-ES/homepage.ftl b/src/base/module/homepage/locales/es-ES/homepage.ftl index 7af7b370..dee1df47 100644 --- a/src/base/module/homepage/locales/es-ES/homepage.ftl +++ b/src/base/module/homepage/locales/es-ES/homepage.ftl @@ -1,4 +1,21 @@ module_name = Página de inicio predeterminada module_desc = Muestra una página de inicio predeterminada cuando no hay ninguna configurada. -greetings = ¡Hola { $name }! +page_title = ¡Hola mundo! + +text_welcome = Esta página se utiliza para probar el correcto funcionamiento de { $app } después de la instalación. Esta solución web funciona con { $pagetop }. Si puede leer esta página, significa que el servidor PageTop funciona correctamente, pero aún no se ha configurado. + +title_normal_user = ¿Sólo de visita? +text1_normal_user = Si usted es un usuario normal de este sitio web y no sabe de qué trata esta página, probablemente significa que el sitio está experimentando problemas o está pasando por un mantenimiento de rutina. +text2_normal_user = Si el problema persiste, póngase en contacto con el administrador del sistema. + +title_about_pagetop = Sobre PageTop +text1_about_pagetop = PageTop define una interfaz para los paquetes Rust más estables y populares para crear soluciones web modulares, extensibles y configurables. +text2_about_pagetop = Para obtener información sobre PageTop, visite el "sitio web de PageTop". + +title_promo_pagetop = Promociona PageTop +text1_promo_pagetop = Puede usar la siguiente imagen en aplicaciones desarrolladas sobre { $pagetop }. ¡Gracias por usar PageTop! + +title_report_problems = Informando Problemas +text1_report_problems = Utilice la herramienta GitLab para informar errores en PageTop. Sin embargo, verifique los "informes de errores existentes" antes de informar de un nuevo error. +text2_report_problems = Informe los errores específicos de los módulos (como admin y otros) a los paquetes respectivos, no a PageTop en sí. diff --git a/src/base/module/homepage/mod.rs b/src/base/module/homepage/mod.rs index 4133f6ba..2e4164d0 100644 --- a/src/base/module/homepage/mod.rs +++ b/src/base/module/homepage/mod.rs @@ -14,16 +14,57 @@ impl Module for HomepageModule { } fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { - cfg.service(server::web::resource("/").to(home)); - cfg.service(server::web::resource("/{name}").to(home)); + cfg.route("/", server::web::get().to(home)); } } -async fn home(req: server::HttpRequest) -> server::Result { - let name: String = req.match_info().get("name").unwrap_or("World").into(); +async fn home() -> server::Result { Page::prepare() - .add_to("content", Chunck::markup(html! { - h1 { (t("greetings", &args![ "name" => name])) } - })) + .with_title( + l("page_title").as_str() + ) + .add_to("content", Container::prepare() + .with_id("welcome") + .add(Chunck::markup(html! { + h1 { (l("page_title")) } + p { (e("text_welcome", &args![ + "app" => format!("{}", &SETTINGS.app.name), + "pagetop" => "PageTop" + ])) } + })) + ) + .add_to("content", Container::prepare() + .add(Container::row() + .add(Container::column() + .with_id("visitors") + .add(Chunck::markup(html! { + h2 { (l("title_normal_user")) } + p { (l("text1_normal_user")) } + p { (l("text2_normal_user")) } + }))) + .add(Container::column() + .with_id("pagetop") + .add(Chunck::markup(html! { + h2 { (l("title_about_pagetop")) } + p { (l("text1_about_pagetop")) } + p { (l("text2_about_pagetop")) } + + h2 { (l("title_promo_pagetop")) } + p { (e("text1_promo_pagetop", &args![ + "pagetop" => + "PageTop" + ])) } + })) + ) + ) + ) + .add_to("content", Container::prepare() + .with_id("reporting") + .add(Chunck::markup(html! { + h2 { (l("title_report_problems")) } + p { (l("text1_report_problems")) } + p { (l("text2_report_problems")) } + })) + ) .render() } diff --git a/src/base/module/mod.rs b/src/base/module/mod.rs index 070e5b82..dd90a79f 100644 --- a/src/base/module/mod.rs +++ b/src/base/module/mod.rs @@ -1 +1,2 @@ pub mod homepage; +pub mod user; diff --git a/src/base/module/user/locales/en-US/homepage.ftl b/src/base/module/user/locales/en-US/homepage.ftl new file mode 100644 index 00000000..e6ad0e91 --- /dev/null +++ b/src/base/module/user/locales/en-US/homepage.ftl @@ -0,0 +1,8 @@ +module_name = User +module_desc = Manages the user registration and login system. + +username = User name +password = Password +username_help = Enter your { $app } username. +password_help = Enter the password that accompanies your username. +login = Log in diff --git a/src/base/module/user/locales/es-ES/homepage.ftl b/src/base/module/user/locales/es-ES/homepage.ftl new file mode 100644 index 00000000..68f1c889 --- /dev/null +++ b/src/base/module/user/locales/es-ES/homepage.ftl @@ -0,0 +1,8 @@ +module_name = Usuario +module_desc = Gestion el registro de usuarios y el sistema de accesos. + +username = Nombre de usuario +password = Contraseña +username_help = Introduzca su nombre de usuario en { $app }. +password_help = Introduzca la contraseña asociada a su nombre de usuario. +login = Iniciar sesión diff --git a/src/base/module/user/mod.rs b/src/base/module/user/mod.rs new file mode 100644 index 00000000..61d50ca1 --- /dev/null +++ b/src/base/module/user/mod.rs @@ -0,0 +1,47 @@ +use crate::prelude::*; + +localize!("en-US", "src/base/module/user/locales"); + +pub struct UserModule; + +impl Module for UserModule { + fn name(&self) -> String { + l("module_name") + } + + fn description(&self) -> String { + l("module_desc") + } + + fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { + cfg.route("/user/login", server::web::get().to(login)); + } +} + +fn form_login() -> impl PageComponent { + Form::prepare() + .with_id("user-login") + .add(form::Input::textfield() + .with_name("name") + .with_label(l("username").as_str()) + .with_help_text(t("username_help", &args![ + "app" => SETTINGS.app.name.to_string() + ]).as_str()) + .autofocus(true) + ) + .add(form::Input::password() + .with_name("pass") + .with_label(l("password").as_str()) + .with_help_text(l("password_help").as_str()) + ) + .add(form::Button::submit(l("login").as_str())) +} + +async fn login() -> server::Result { + Page::prepare() + .with_title( + "Identificación del usuario" + ) + .add_to("content", form_login()) + .render() +} diff --git a/src/core/server/main.rs b/src/core/server/main.rs index 0884201e..b915743e 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -9,6 +9,8 @@ use tracing::subscriber::set_global_default; use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; use tracing_actix_web::TracingLogger; +use actix_web::middleware::normalize; + pub fn run(bootstrap: Option) -> Result { // Inicia la traza de ejecución de la aplicación. let env_filter = EnvFilter::try_new(&SETTINGS.log.tracing) @@ -90,6 +92,7 @@ pub fn run(bootstrap: Option) -> Result { let server = server::HttpServer::new(|| { server::App::new() .wrap(TracingLogger) + .wrap(normalize::NormalizePath::new(normalize::TrailingSlash::Trim)) .configure(&all::themes) .configure(&all::modules) }) diff --git a/src/core/state.rs b/src/core/state.rs index 69b6a4de..88936bfd 100644 --- a/src/core/state.rs +++ b/src/core/state.rs @@ -36,7 +36,9 @@ pub fn register_theme(t: &'static (dyn Theme + 'static)) { // ----------------------------------------------------------------------------- pub static MODULES: Lazy>> = Lazy::new(|| { - RwLock::new(vec![]) + RwLock::new(vec![ + &base::module::user::UserModule, + ]) }); pub fn register_module(m: &'static (dyn Module + 'static)) { diff --git a/src/macros/mod.rs b/src/macros/mod.rs index ef3c05d5..88ab3f90 100644 --- a/src/macros/mod.rs +++ b/src/macros/mod.rs @@ -16,4 +16,4 @@ macro_rules! args { )* a }}; -} \ No newline at end of file +} diff --git a/src/prelude.rs b/src/prelude.rs index 8ae92907..b4b62b18 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,9 +1,9 @@ //! Re-exporta recursos comunes. pub use crate::args; -pub use crate::localize; - +pub use crate::config::SETTINGS; pub use crate::trace; +pub use crate::localize; pub use crate::core::theme::*; @@ -17,5 +17,4 @@ pub use crate::core::register_theme; pub use crate::core::register_module; pub use crate::core::add_component_to; -pub use crate::base::component::container::Container; -pub use crate::base::component::chunck::Chunck; +pub use crate::base::component::*; From 7f8b94eafeed18d67fff522c8a01fb8c38500df9 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Mon, 21 Feb 2022 00:28:22 +0100 Subject: [PATCH 012/244] =?UTF-8?q?A=C3=B1ade=20soporte=20nativo=20a=20Boo?= =?UTF-8?q?tstrap=20con=20un=20nuevo=20tema?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CREDITS.md | 15 + Cargo.toml | 5 + build.rs | 31 ++ config/settings.default.toml | 2 +- resources/assets/js/jquery.min.js | 2 + resources/assets/js/jquery.min.map | 1 + src/base/component/container.rs | 2 +- src/base/module/user/mod.rs | 5 +- src/base/theme/aliner/assets/css/styles.css | 343 ++++++++++++++++++ src/base/theme/aliner/mod.rs | 28 ++ .../bootsier/assets/css/bootstrap.min.css | 7 + .../bootsier/assets/css/bootstrap.min.css.map | 1 + .../theme/bootsier/assets/fonts/nunito.css | 70 ++++ .../assets/fonts/nunito/cyrillic_400.woff2 | Bin 0 -> 11248 bytes .../assets/fonts/nunito/cyrillic_700.woff2 | Bin 0 -> 11208 bytes .../fonts/nunito/cyrillic_ext_400.woff2 | Bin 0 -> 15308 bytes .../fonts/nunito/cyrillic_ext_700.woff2 | Bin 0 -> 15164 bytes .../assets/fonts/nunito/latin_400.woff2 | Bin 0 -> 18972 bytes .../assets/fonts/nunito/latin_700.woff2 | Bin 0 -> 19088 bytes .../assets/fonts/nunito/latin_ext_400.woff2 | Bin 0 -> 18380 bytes .../assets/fonts/nunito/latin_ext_700.woff2 | Bin 0 -> 18416 bytes .../assets/fonts/nunito/vietnamese_400.woff2 | Bin 0 -> 7568 bytes .../assets/fonts/nunito/vietnamese_700.woff2 | Bin 0 -> 7596 bytes .../theme/bootsier/assets/images/caution.png | Bin 0 -> 12481 bytes .../assets/js/bootstrap.bundle.min.js | 7 + .../assets/js/bootstrap.bundle.min.js.map | 1 + .../theme/bootsier/assets/js/bootstrap.min.js | 7 + .../bootsier/assets/js/bootstrap.min.js.map | 1 + .../theme/bootsier/locales/en-US/bootsier.ftl | 5 + .../theme/bootsier/locales/es-ES/bootsier.ftl | 5 + src/base/theme/bootsier/mod.rs | 82 +++++ src/base/theme/mod.rs | 2 + src/config/settings.rs | 2 +- src/core/response/page/assets.rs | 16 + src/core/server/mod.rs | 2 +- src/core/state.rs | 4 +- src/core/theme/api.rs | 12 + 37 files changed, 652 insertions(+), 6 deletions(-) create mode 100644 CREDITS.md create mode 100644 build.rs create mode 100644 resources/assets/js/jquery.min.js create mode 100644 resources/assets/js/jquery.min.map create mode 100644 src/base/theme/aliner/assets/css/styles.css create mode 100644 src/base/theme/aliner/mod.rs create mode 100644 src/base/theme/bootsier/assets/css/bootstrap.min.css create mode 100644 src/base/theme/bootsier/assets/css/bootstrap.min.css.map create mode 100644 src/base/theme/bootsier/assets/fonts/nunito.css create mode 100644 src/base/theme/bootsier/assets/fonts/nunito/cyrillic_400.woff2 create mode 100644 src/base/theme/bootsier/assets/fonts/nunito/cyrillic_700.woff2 create mode 100644 src/base/theme/bootsier/assets/fonts/nunito/cyrillic_ext_400.woff2 create mode 100644 src/base/theme/bootsier/assets/fonts/nunito/cyrillic_ext_700.woff2 create mode 100644 src/base/theme/bootsier/assets/fonts/nunito/latin_400.woff2 create mode 100644 src/base/theme/bootsier/assets/fonts/nunito/latin_700.woff2 create mode 100644 src/base/theme/bootsier/assets/fonts/nunito/latin_ext_400.woff2 create mode 100644 src/base/theme/bootsier/assets/fonts/nunito/latin_ext_700.woff2 create mode 100644 src/base/theme/bootsier/assets/fonts/nunito/vietnamese_400.woff2 create mode 100644 src/base/theme/bootsier/assets/fonts/nunito/vietnamese_700.woff2 create mode 100644 src/base/theme/bootsier/assets/images/caution.png create mode 100644 src/base/theme/bootsier/assets/js/bootstrap.bundle.min.js create mode 100644 src/base/theme/bootsier/assets/js/bootstrap.bundle.min.js.map create mode 100644 src/base/theme/bootsier/assets/js/bootstrap.min.js create mode 100644 src/base/theme/bootsier/assets/js/bootstrap.min.js.map create mode 100644 src/base/theme/bootsier/locales/en-US/bootsier.ftl create mode 100644 src/base/theme/bootsier/locales/es-ES/bootsier.ftl create mode 100644 src/base/theme/bootsier/mod.rs diff --git a/CREDITS.md b/CREDITS.md new file mode 100644 index 00000000..bd737e27 --- /dev/null +++ b/CREDITS.md @@ -0,0 +1,15 @@ +# FIGfonts + +PageTop utiliza el paquete [figlet-rs](https://crates.io/crates/figlet-rs) de +*yuanbohan* para mostrar al inicio un rótulo con el nombre de la aplicación +usando [FIGlet](http://www.figlet.org/). Las fuentes incluidas en `resources` +son: + +* [slant.flf](http://www.figlet.org/fontdb_example.cgi?font=slant.flf) + por *Glenn Chappell*. +* [small.flf](http://www.figlet.org/fontdb_example.cgi?font=small.flf) + por *Glenn Chappell*, usado por defecto. +* [speed.flf](http://www.figlet.org/fontdb_example.cgi?font=speed.flf) + por *Claude Martins*. +* [starwars.flf](http://www.figlet.org/fontdb_example.cgi?font=starwars.flf) + por *Ryan Youck*. diff --git a/Cargo.toml b/Cargo.toml index 8eb88ee2..7b4ac161 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,12 +41,17 @@ fluent-templates = "0.6.1" unic-langid = "0.9.0" actix-web = "3.3.3" +actix-web-static-files = "3.0.5" + maud = { version = "0.23.0", features = ["actix-web"] } sycamore = { version = "0.7.1", features = ["ssr"] } downcast-rs = "1.2.0" serde = { version = "1.0", features = ["derive"] } +[build-dependencies] +actix-web-static-files = "3.0.5" + [lib] name = "pagetop" diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..75aee1d5 --- /dev/null +++ b/build.rs @@ -0,0 +1,31 @@ +use actix_web_static_files::resource_dir; + +use std::env; +use std::path::Path; + +fn main() { + resource_dir("./resources/assets") + .with_generated_filename( + Path::new(env::var("OUT_DIR").unwrap().as_str()) + .join("assets.rs") + ) + .with_generated_fn("assets") + .build() + .unwrap(); + + resource_dir("./src/base/theme/aliner/assets") + .with_generated_filename( + Path::new(env::var("OUT_DIR").unwrap().as_str()) + .join("aliner.rs") + ) + .build() + .unwrap(); + + resource_dir("./src/base/theme/bootsier/assets") + .with_generated_filename( + Path::new(env::var("OUT_DIR").unwrap().as_str()) + .join("bootsier.rs") + ) + .build() + .unwrap(); +} diff --git a/config/settings.default.toml b/config/settings.default.toml index 53a2c693..aea77e5e 100644 --- a/config/settings.default.toml +++ b/config/settings.default.toml @@ -4,7 +4,7 @@ description = "Developed with the amazing PageTop framework." # Idioma (localización) predeterminado. language = "en-US" # Tema predeterminado. -theme = "Minimal" +theme = "Bootsier" # Rótulo al inicio: "Off", "Slant", "Small", "Speed" o "Starwars". startup_banner = "Small" diff --git a/resources/assets/js/jquery.min.js b/resources/assets/js/jquery.min.js new file mode 100644 index 00000000..c4c6022f --- /dev/null +++ b/resources/assets/js/jquery.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0"," ","+","~","preFilter","excess","unquoted","nodeNameSelector","pattern","operator","check","result","what","_argument","simple","forward","ofType","_context","xml","uniqueCache","outerCache","nodeIndex","start","parent","useCache","lastChild","uniqueID","pseudo","args","setFilters","idx","matched","not","matcher","unmatched","has","lang","elemLang","hash","location","root","focus","activeElement","hasFocus","href","tabIndex","enabled","checked","selected","selectedIndex","empty","header","button","_matchIndexes","lt","gt","radio","checkbox","file","password","image","submit","reset","tokens","combinator","base","skip","checkNonElements","doneName","oldCache","newCache","elementMatcher","matchers","condense","newUnmatched","mapped","setMatcher","postFilter","postFinder","postSelector","temp","preMap","postMap","preexisting","contexts","multipleContexts","matcherIn","matcherOut","matcherFromTokens","checkContext","leadingRelative","implicitRelative","matchContext","matchAnyContext","filters","parseOnly","soFar","preFilters","cached","elementMatchers","setMatchers","bySet","byElement","superMatcher","outermost","matchedCount","setMatched","contextBackup","dirrunsUnique","token","compiled","_name","defaultValue","unique","isXMLDoc","escapeSelector","until","truncate","is","siblings","n","rneedsContext","rsingleTag","winnow","qualifier","self","rootjQuery","parseHTML","ready","rparentsprev","guaranteedUnique","children","contents","prev","sibling","targets","l","closest","index","prevAll","add","addBack","parents","parentsUntil","nextAll","nextUntil","prevUntil","contentDocument","content","reverse","rnothtmlwhite","Identity","v","Thrower","ex","adoptValue","resolve","reject","noValue","method","promise","fail","then","Callbacks","object","_","flag","firing","memory","fired","locked","queue","firingIndex","fire","once","stopOnFalse","remove","disable","lock","fireWith","Deferred","func","tuples","state","always","deferred","catch","pipe","fns","newDefer","tuple","returned","progress","notify","onFulfilled","onRejected","onProgress","maxDepth","depth","special","that","mightThrow","TypeError","notifyWith","resolveWith","process","exceptionHook","stackTrace","rejectWith","getStackHook","setTimeout","stateString","when","singleValue","remaining","resolveContexts","resolveValues","primary","updateFunc","rerrorNames","stack","console","warn","message","readyException","readyList","completed","removeEventListener","readyWait","wait","readyState","doScroll","access","chainable","emptyGet","raw","bulk","_key","rmsPrefix","rdashAlpha","fcamelCase","_all","letter","toUpperCase","camelCase","string","acceptData","owner","Data","uid","defineProperty","configurable","set","data","prop","hasData","dataPriv","dataUser","rbrace","rmultiDash","dataAttr","JSON","parse","removeData","_data","_removeData","dequeue","startLength","hooks","_queueHooks","stop","setter","clearQueue","count","defer","pnum","source","rcssNum","cssExpand","isAttached","composed","getRootNode","isHiddenWithinTree","style","display","css","adjustCSS","valueParts","tween","adjusted","scale","maxIterations","currentValue","initial","unit","cssNumber","initialInUnit","defaultDisplayMap","showHide","show","values","body","hide","toggle","div","rcheckableType","rtagName","rscriptType","createDocumentFragment","checkClone","cloneNode","noCloneChecked","option","wrapMap","thead","col","tr","td","_default","getAll","setGlobalEval","refElements","tbody","tfoot","colgroup","caption","th","optgroup","buildFragment","scripts","selection","ignored","wrap","attached","fragment","nodes","htmlPrefilter","createTextNode","rtypenamespace","returnTrue","returnFalse","expectSync","err","safeActiveElement","on","types","one","origFn","event","off","leverageNative","notAsync","saved","isTrigger","delegateType","stopPropagation","stopImmediatePropagation","preventDefault","trigger","Event","handleObjIn","eventHandle","events","t","handleObj","handlers","namespaces","origType","elemData","create","handle","triggered","dispatch","bindType","delegateCount","setup","mappedTypes","origCount","teardown","removeEvent","nativeEvent","handlerQueue","fix","delegateTarget","preDispatch","isPropagationStopped","currentTarget","isImmediatePropagationStopped","rnamespace","postDispatch","matchedHandlers","matchedSelectors","addProp","hook","enumerable","originalEvent","writable","load","noBubble","click","beforeunload","returnValue","props","isDefaultPrevented","defaultPrevented","relatedTarget","timeStamp","now","isSimulated","altKey","bubbles","cancelable","changedTouches","ctrlKey","detail","eventPhase","metaKey","pageX","pageY","shiftKey","view","char","charCode","keyCode","buttons","clientX","clientY","offsetX","offsetY","pointerId","pointerType","screenX","screenY","targetTouches","toElement","touches","which","blur","mouseenter","mouseleave","pointerenter","pointerleave","orig","related","rnoInnerhtml","rchecked","rcleanScript","manipulationTarget","disableScript","restoreScript","cloneCopyEvent","dest","udataOld","udataCur","domManip","collection","hasScripts","iNoClone","valueIsFunction","html","_evalUrl","keepData","cleanData","dataAndEvents","deepDataAndEvents","srcElements","destElements","inPage","detach","append","prepend","insertBefore","before","after","replaceWith","replaceChild","appendTo","prependTo","insertAfter","replaceAll","original","insert","rnumnonpx","getStyles","opener","getComputedStyle","swap","old","rboxStyle","curCSS","computed","width","minWidth","maxWidth","getPropertyValue","pixelBoxStyles","addGetHookIf","conditionFn","hookFn","computeStyleTests","container","cssText","divStyle","pixelPositionVal","reliableMarginLeftVal","roundPixelMeasures","marginLeft","right","pixelBoxStylesVal","boxSizingReliableVal","position","scrollboxSizeVal","offsetWidth","measure","round","parseFloat","reliableTrDimensionsVal","backgroundClip","clearCloneStyle","boxSizingReliable","pixelPosition","reliableMarginLeft","scrollboxSize","reliableTrDimensions","table","trChild","trStyle","height","parseInt","borderTopWidth","borderBottomWidth","offsetHeight","cssPrefixes","emptyStyle","vendorProps","finalPropName","final","cssProps","capName","vendorPropName","rdisplayswap","rcustomProp","cssShow","visibility","cssNormalTransform","letterSpacing","fontWeight","setPositiveNumber","subtract","max","boxModelAdjustment","dimension","box","isBorderBox","styles","computedVal","extra","delta","ceil","getWidthOrHeight","valueIsBorderBox","offsetProp","getClientRects","Tween","easing","cssHooks","opacity","animationIterationCount","columnCount","fillOpacity","flexGrow","flexShrink","gridArea","gridColumn","gridColumnEnd","gridColumnStart","gridRow","gridRowEnd","gridRowStart","lineHeight","order","orphans","widows","zIndex","zoom","origName","isCustomProp","setProperty","isFinite","getBoundingClientRect","scrollboxSizeBuggy","left","margin","padding","border","prefix","suffix","expand","expanded","parts","propHooks","run","percent","eased","duration","pos","step","fx","scrollTop","scrollLeft","linear","p","swing","cos","PI","fxNow","inProgress","opt","rfxtypes","rrun","schedule","hidden","requestAnimationFrame","interval","tick","createFxNow","genFx","includeWidth","createTween","animation","Animation","tweeners","properties","stopped","prefilters","currentTime","startTime","tweens","opts","specialEasing","originalProperties","originalOptions","gotoEnd","propFilter","bind","complete","timer","anim","*","tweener","oldfire","propTween","restoreDisplay","isBox","dataShow","unqueued","overflow","overflowX","overflowY","prefilter","speed","speeds","fadeTo","to","animate","optall","doAnimation","finish","stopQueue","timers","cssFn","slideDown","slideUp","slideToggle","fadeIn","fadeOut","fadeToggle","slow","fast","delay","time","timeout","clearTimeout","checkOn","optSelected","radioValue","boolHook","removeAttr","nType","attrHooks","attrNames","getter","lowercaseName","rfocusable","rclickable","stripAndCollapse","getClass","classesToArray","removeProp","propFix","tabindex","for","class","addClass","classes","curValue","clazz","finalValue","removeClass","toggleClass","stateVal","isValidValue","classNames","hasClass","rreturn","valHooks","optionSet","focusin","rfocusMorph","stopPropagationCallback","onlyHandlers","bubbleType","ontype","lastElement","eventPath","parentWindow","simulate","triggerHandler","attaches","rquery","parseXML","parserErrorElem","DOMParser","parseFromString","rbracket","rCRLF","rsubmitterTypes","rsubmittable","buildParams","traditional","param","s","valueOrFunction","encodeURIComponent","serialize","serializeArray","r20","rhash","rantiCache","rheaders","rnoContent","rprotocol","transports","allTypes","originAnchor","addToPrefiltersOrTransports","structure","dataTypeExpression","dataType","dataTypes","inspectPrefiltersOrTransports","jqXHR","inspected","seekingTransport","inspect","prefilterOrFactory","dataTypeOrTransport","ajaxExtend","flatOptions","ajaxSettings","active","lastModified","etag","url","isLocal","protocol","processData","async","contentType","accepts","json","responseFields","converters","* text","text html","text json","text xml","ajaxSetup","settings","ajaxPrefilter","ajaxTransport","ajax","transport","cacheURL","responseHeadersString","responseHeaders","timeoutTimer","urlAnchor","fireGlobals","uncached","callbackContext","globalEventContext","completeDeferred","statusCode","requestHeaders","requestHeadersNames","strAbort","getResponseHeader","getAllResponseHeaders","setRequestHeader","overrideMimeType","mimeType","status","abort","statusText","finalText","crossDomain","host","hasContent","ifModified","headers","beforeSend","success","send","nativeStatusText","responses","isSuccess","response","modified","ct","finalDataType","firstDataType","ajaxHandleResponses","conv2","current","conv","dataFilter","throws","ajaxConvert","getJSON","getScript","text script","wrapAll","firstElementChild","wrapInner","htmlIsFunction","unwrap","visible","xhr","XMLHttpRequest","xhrSuccessStatus","0","1223","xhrSupported","cors","errorCallback","open","username","xhrFields","onload","onerror","onabort","ontimeout","onreadystatechange","responseType","responseText","binary","scriptAttrs","charset","scriptCharset","evt","oldCallbacks","rjsonp","jsonp","jsonpCallback","originalSettings","callbackName","overwritten","responseContainer","jsonProp","createHTMLDocument","implementation","keepScripts","parsed","params","animated","offset","setOffset","curPosition","curLeft","curCSSTop","curTop","curOffset","curCSSLeft","curElem","using","rect","win","pageYOffset","pageXOffset","offsetParent","parentOffset","scrollTo","Height","Width","","defaultExtra","funcName","unbind","delegate","undelegate","hover","fnOver","fnOut","proxy","holdReady","hold","parseJSON","isNumeric","isNaN","trim","define","amd","_jQuery","_$","$","noConflict"],"mappings":";CAaA,SAAYA,EAAQC,GAEnB,aAEuB,iBAAXC,QAAiD,iBAAnBA,OAAOC,QAShDD,OAAOC,QAAUH,EAAOI,SACvBH,EAASD,GAAQ,GACjB,SAAUK,GACT,IAAMA,EAAED,SACP,MAAM,IAAIE,MAAO,4CAElB,OAAOL,EAASI,IAGlBJ,EAASD,GAtBX,CA0BuB,oBAAXO,OAAyBA,OAASC,KAAM,SAAUD,EAAQE,GAMtE,aAEA,IAAIC,EAAM,GAENC,EAAWC,OAAOC,eAElBC,EAAQJ,EAAII,MAEZC,EAAOL,EAAIK,KAAO,SAAUC,GAC/B,OAAON,EAAIK,KAAKE,KAAMD,IACnB,SAAUA,GACb,OAAON,EAAIQ,OAAOC,MAAO,GAAIH,IAI1BI,EAAOV,EAAIU,KAEXC,EAAUX,EAAIW,QAEdC,EAAa,GAEbC,EAAWD,EAAWC,SAEtBC,EAASF,EAAWG,eAEpBC,EAAaF,EAAOD,SAEpBI,EAAuBD,EAAWT,KAAML,QAExCgB,EAAU,GAEVC,EAAa,SAAqBC,GASpC,MAAsB,mBAARA,GAA8C,iBAAjBA,EAAIC,UAC1B,mBAAbD,EAAIE,MAIVC,EAAW,SAAmBH,GAChC,OAAc,MAAPA,GAAeA,IAAQA,EAAIvB,QAIhCH,EAAWG,EAAOH,SAIjB8B,EAA4B,CAC/BC,MAAM,EACNC,KAAK,EACLC,OAAO,EACPC,UAAU,GAGX,SAASC,EAASC,EAAMC,EAAMC,GAG7B,IAAIC,EAAGC,EACNC,GAHDH,EAAMA,GAAOtC,GAGC0C,cAAe,UAG7B,GADAD,EAAOE,KAAOP,EACTC,EACJ,IAAME,KAAKT,GAYVU,EAAMH,EAAME,IAAOF,EAAKO,cAAgBP,EAAKO,aAAcL,KAE1DE,EAAOI,aAAcN,EAAGC,GAI3BF,EAAIQ,KAAKC,YAAaN,GAASO,WAAWC,YAAaR,GAIzD,SAASS,EAAQxB,GAChB,OAAY,MAAPA,EACGA,EAAM,GAIQ,iBAARA,GAAmC,mBAARA,EACxCR,EAAYC,EAASN,KAAMa,KAAW,gBAC/BA,EAQT,IACCyB,EAAU,QAGVC,EAAS,SAAUC,EAAUC,GAI5B,OAAO,IAAIF,EAAOG,GAAGC,KAAMH,EAAUC,IA0VvC,SAASG,EAAa/B,GAMrB,IAAIgC,IAAWhC,GAAO,WAAYA,GAAOA,EAAIgC,OAC5C3B,EAAOmB,EAAQxB,GAEhB,OAAKD,EAAYC,KAASG,EAAUH,KAIpB,UAATK,GAA+B,IAAX2B,GACR,iBAAXA,GAAgC,EAATA,GAAgBA,EAAS,KAAOhC,GArWhE0B,EAAOG,GAAKH,EAAOO,UAAY,CAG9BC,OAAQT,EAERU,YAAaT,EAGbM,OAAQ,EAERI,QAAS,WACR,OAAOpD,EAAMG,KAAMT,OAKpB2D,IAAK,SAAUC,GAGd,OAAY,MAAPA,EACGtD,EAAMG,KAAMT,MAIb4D,EAAM,EAAI5D,KAAM4D,EAAM5D,KAAKsD,QAAWtD,KAAM4D,IAKpDC,UAAW,SAAUC,GAGpB,IAAIC,EAAMf,EAAOgB,MAAOhE,KAAKyD,cAAeK,GAM5C,OAHAC,EAAIE,WAAajE,KAGV+D,GAIRG,KAAM,SAAUC,GACf,OAAOnB,EAAOkB,KAAMlE,KAAMmE,IAG3BC,IAAK,SAAUD,GACd,OAAOnE,KAAK6D,UAAWb,EAAOoB,IAAKpE,KAAM,SAAUqE,EAAMlC,GACxD,OAAOgC,EAAS1D,KAAM4D,EAAMlC,EAAGkC,OAIjC/D,MAAO,WACN,OAAON,KAAK6D,UAAWvD,EAAMK,MAAOX,KAAMsE,aAG3CC,MAAO,WACN,OAAOvE,KAAKwE,GAAI,IAGjBC,KAAM,WACL,OAAOzE,KAAKwE,IAAK,IAGlBE,KAAM,WACL,OAAO1E,KAAK6D,UAAWb,EAAO2B,KAAM3E,KAAM,SAAU4E,EAAOzC,GAC1D,OAASA,EAAI,GAAM,MAIrB0C,IAAK,WACJ,OAAO7E,KAAK6D,UAAWb,EAAO2B,KAAM3E,KAAM,SAAU4E,EAAOzC,GAC1D,OAAOA,EAAI,MAIbqC,GAAI,SAAUrC,GACb,IAAI2C,EAAM9E,KAAKsD,OACdyB,GAAK5C,GAAMA,EAAI,EAAI2C,EAAM,GAC1B,OAAO9E,KAAK6D,UAAgB,GAALkB,GAAUA,EAAID,EAAM,CAAE9E,KAAM+E,IAAQ,KAG5DC,IAAK,WACJ,OAAOhF,KAAKiE,YAAcjE,KAAKyD,eAKhC7C,KAAMA,EACNqE,KAAM/E,EAAI+E,KACVC,OAAQhF,EAAIgF,QAGblC,EAAOmC,OAASnC,EAAOG,GAAGgC,OAAS,WAClC,IAAIC,EAASC,EAAMzD,EAAK0D,EAAMC,EAAaC,EAC1CC,EAASnB,UAAW,IAAO,GAC3BnC,EAAI,EACJmB,EAASgB,UAAUhB,OACnBoC,GAAO,EAsBR,IAnBuB,kBAAXD,IACXC,EAAOD,EAGPA,EAASnB,UAAWnC,IAAO,GAC3BA,KAIsB,iBAAXsD,GAAwBpE,EAAYoE,KAC/CA,EAAS,IAILtD,IAAMmB,IACVmC,EAASzF,KACTmC,KAGOA,EAAImB,EAAQnB,IAGnB,GAAqC,OAA9BiD,EAAUd,UAAWnC,IAG3B,IAAMkD,KAAQD,EACbE,EAAOF,EAASC,GAIF,cAATA,GAAwBI,IAAWH,IAKnCI,GAAQJ,IAAUtC,EAAO2C,cAAeL,KAC1CC,EAAcK,MAAMC,QAASP,MAC/B1D,EAAM6D,EAAQJ,GAIbG,EADID,IAAgBK,MAAMC,QAASjE,GAC3B,GACI2D,GAAgBvC,EAAO2C,cAAe/D,GAG1CA,EAFA,GAIT2D,GAAc,EAGdE,EAAQJ,GAASrC,EAAOmC,OAAQO,EAAMF,EAAOF,SAGzBQ,IAATR,IACXG,EAAQJ,GAASC,IAOrB,OAAOG,GAGRzC,EAAOmC,OAAQ,CAGdY,QAAS,UAAahD,EAAUiD,KAAKC,UAAWC,QAAS,MAAO,IAGhEC,SAAS,EAETC,MAAO,SAAUC,GAChB,MAAM,IAAIvG,MAAOuG,IAGlBC,KAAM,aAENX,cAAe,SAAUrE,GACxB,IAAIiF,EAAOC,EAIX,SAAMlF,GAAgC,oBAAzBP,EAASN,KAAMa,QAI5BiF,EAAQpG,EAAUmB,KASK,mBADvBkF,EAAOxF,EAAOP,KAAM8F,EAAO,gBAAmBA,EAAM9C,cACfvC,EAAWT,KAAM+F,KAAWrF,IAGlEsF,cAAe,SAAUnF,GACxB,IAAI+D,EAEJ,IAAMA,KAAQ/D,EACb,OAAO,EAER,OAAO,GAKRoF,WAAY,SAAU1E,EAAMoD,EAASlD,GACpCH,EAASC,EAAM,CAAEH,MAAOuD,GAAWA,EAAQvD,OAASK,IAGrDgC,KAAM,SAAU5C,EAAK6C,GACpB,IAAIb,EAAQnB,EAAI,EAEhB,GAAKkB,EAAa/B,IAEjB,IADAgC,EAAShC,EAAIgC,OACLnB,EAAImB,EAAQnB,IACnB,IAAgD,IAA3CgC,EAAS1D,KAAMa,EAAKa,GAAKA,EAAGb,EAAKa,IACrC,WAIF,IAAMA,KAAKb,EACV,IAAgD,IAA3C6C,EAAS1D,KAAMa,EAAKa,GAAKA,EAAGb,EAAKa,IACrC,MAKH,OAAOb,GAIRqF,UAAW,SAAUzG,EAAK0G,GACzB,IAAI7C,EAAM6C,GAAW,GAarB,OAXY,MAAP1G,IACCmD,EAAajD,OAAQF,IACzB8C,EAAOgB,MAAOD,EACE,iBAAR7D,EACN,CAAEA,GAAQA,GAGZU,EAAKH,KAAMsD,EAAK7D,IAIX6D,GAGR8C,QAAS,SAAUxC,EAAMnE,EAAKiC,GAC7B,OAAc,MAAPjC,GAAe,EAAIW,EAAQJ,KAAMP,EAAKmE,EAAMlC,IAKpD6B,MAAO,SAAUO,EAAOuC,GAKvB,IAJA,IAAIhC,GAAOgC,EAAOxD,OACjByB,EAAI,EACJ5C,EAAIoC,EAAMjB,OAEHyB,EAAID,EAAKC,IAChBR,EAAOpC,KAAQ2E,EAAQ/B,GAKxB,OAFAR,EAAMjB,OAASnB,EAERoC,GAGRI,KAAM,SAAUb,EAAOK,EAAU4C,GAShC,IARA,IACCC,EAAU,GACV7E,EAAI,EACJmB,EAASQ,EAAMR,OACf2D,GAAkBF,EAIX5E,EAAImB,EAAQnB,KACAgC,EAAUL,EAAO3B,GAAKA,KAChB8E,GACxBD,EAAQpG,KAAMkD,EAAO3B,IAIvB,OAAO6E,GAIR5C,IAAK,SAAUN,EAAOK,EAAU+C,GAC/B,IAAI5D,EAAQ6D,EACXhF,EAAI,EACJ4B,EAAM,GAGP,GAAKV,EAAaS,GAEjB,IADAR,EAASQ,EAAMR,OACPnB,EAAImB,EAAQnB,IAGL,OAFdgF,EAAQhD,EAAUL,EAAO3B,GAAKA,EAAG+E,KAGhCnD,EAAInD,KAAMuG,QAMZ,IAAMhF,KAAK2B,EAGI,OAFdqD,EAAQhD,EAAUL,EAAO3B,GAAKA,EAAG+E,KAGhCnD,EAAInD,KAAMuG,GAMb,OAAO5G,EAAMwD,IAIdqD,KAAM,EAINhG,QAASA,IAGa,mBAAXiG,SACXrE,EAAOG,GAAIkE,OAAOC,UAAapH,EAAKmH,OAAOC,WAI5CtE,EAAOkB,KAAM,uEAAuEqD,MAAO,KAC1F,SAAUC,EAAInC,GACbvE,EAAY,WAAauE,EAAO,KAAQA,EAAKoC,gBAmB/C,IAAIC,EAWJ,SAAY3H,GACZ,IAAIoC,EACHf,EACAuG,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAGAC,EACAxI,EACAyI,EACAC,EACAC,EACAC,EACAxB,EACAyB,EAGA1C,EAAU,SAAW,EAAI,IAAI2C,KAC7BC,EAAe5I,EAAOH,SACtBgJ,EAAU,EACVC,EAAO,EACPC,EAAaC,KACbC,EAAaD,KACbE,EAAgBF,KAChBG,EAAyBH,KACzBI,EAAY,SAAUC,EAAGC,GAIxB,OAHKD,IAAMC,IACVlB,GAAe,GAET,GAIRnH,EAAS,GAAOC,eAChBf,EAAM,GACNoJ,EAAMpJ,EAAIoJ,IACVC,EAAarJ,EAAIU,KACjBA,EAAOV,EAAIU,KACXN,EAAQJ,EAAII,MAIZO,EAAU,SAAU2I,EAAMnF,GAGzB,IAFA,IAAIlC,EAAI,EACP2C,EAAM0E,EAAKlG,OACJnB,EAAI2C,EAAK3C,IAChB,GAAKqH,EAAMrH,KAAQkC,EAClB,OAAOlC,EAGT,OAAQ,GAGTsH,EAAW,6HAMXC,EAAa,sBAGbC,EAAa,0BAA4BD,EACxC,0CAGDE,EAAa,MAAQF,EAAa,KAAOC,EAAa,OAASD,EAG9D,gBAAkBA,EAIlB,2DAA6DC,EAAa,OAC1ED,EAAa,OAEdG,EAAU,KAAOF,EAAa,wFAOAC,EAAa,eAO3CE,EAAc,IAAIC,OAAQL,EAAa,IAAK,KAC5CM,EAAQ,IAAID,OAAQ,IAAML,EAAa,8BACtCA,EAAa,KAAM,KAEpBO,EAAS,IAAIF,OAAQ,IAAML,EAAa,KAAOA,EAAa,KAC5DQ,EAAe,IAAIH,OAAQ,IAAML,EAAa,WAAaA,EAAa,IAAMA,EAC7E,KACDS,EAAW,IAAIJ,OAAQL,EAAa,MAEpCU,EAAU,IAAIL,OAAQF,GACtBQ,EAAc,IAAIN,OAAQ,IAAMJ,EAAa,KAE7CW,EAAY,CACXC,GAAM,IAAIR,OAAQ,MAAQJ,EAAa,KACvCa,MAAS,IAAIT,OAAQ,QAAUJ,EAAa,KAC5Cc,IAAO,IAAIV,OAAQ,KAAOJ,EAAa,SACvCe,KAAQ,IAAIX,OAAQ,IAAMH,GAC1Be,OAAU,IAAIZ,OAAQ,IAAMF,GAC5Be,MAAS,IAAIb,OAAQ,yDACpBL,EAAa,+BAAiCA,EAAa,cAC3DA,EAAa,aAAeA,EAAa,SAAU,KACpDmB,KAAQ,IAAId,OAAQ,OAASN,EAAW,KAAM,KAI9CqB,aAAgB,IAAIf,OAAQ,IAAML,EACjC,mDAAqDA,EACrD,mBAAqBA,EAAa,mBAAoB,MAGxDqB,EAAQ,SACRC,EAAU,sCACVC,EAAU,SAEVC,EAAU,yBAGVC,EAAa,mCAEbC,GAAW,OAIXC,GAAY,IAAItB,OAAQ,uBAAyBL,EAAa,uBAAwB,KACtF4B,GAAY,SAAUC,EAAQC,GAC7B,IAAIC,EAAO,KAAOF,EAAOjL,MAAO,GAAM,MAEtC,OAAOkL,IASNC,EAAO,EACNC,OAAOC,aAAcF,EAAO,OAC5BC,OAAOC,aAAcF,GAAQ,GAAK,MAAe,KAAPA,EAAe,SAK5DG,GAAa,sDACbC,GAAa,SAAUC,EAAIC,GAC1B,OAAKA,EAGQ,OAAPD,EACG,SAIDA,EAAGxL,MAAO,GAAI,GAAM,KAC1BwL,EAAGE,WAAYF,EAAGxI,OAAS,GAAIvC,SAAU,IAAO,IAI3C,KAAO+K,GAOfG,GAAgB,WACf7D,KAGD8D,GAAqBC,GACpB,SAAU9H,GACT,OAAyB,IAAlBA,EAAK+H,UAAqD,aAAhC/H,EAAKgI,SAAS5E,eAEhD,CAAE6E,IAAK,aAAcC,KAAM,WAI7B,IACC3L,EAAKD,MACFT,EAAMI,EAAMG,KAAMkI,EAAa6D,YACjC7D,EAAa6D,YAMdtM,EAAKyI,EAAa6D,WAAWlJ,QAAS/B,SACrC,MAAQkL,GACT7L,EAAO,CAAED,MAAOT,EAAIoD,OAGnB,SAAUmC,EAAQiH,GACjBnD,EAAW5I,MAAO8E,EAAQnF,EAAMG,KAAMiM,KAKvC,SAAUjH,EAAQiH,GACjB,IAAI3H,EAAIU,EAAOnC,OACdnB,EAAI,EAGL,MAAUsD,EAAQV,KAAQ2H,EAAKvK,MAC/BsD,EAAOnC,OAASyB,EAAI,IAKvB,SAAS2C,GAAQzE,EAAUC,EAAS0D,EAAS+F,GAC5C,IAAIC,EAAGzK,EAAGkC,EAAMwI,EAAKC,EAAOC,EAAQC,EACnCC,EAAa/J,GAAWA,EAAQgK,cAGhC3L,EAAW2B,EAAUA,EAAQ3B,SAAW,EAKzC,GAHAqF,EAAUA,GAAW,GAGI,iBAAb3D,IAA0BA,GACxB,IAAb1B,GAA+B,IAAbA,GAA+B,KAAbA,EAEpC,OAAOqF,EAIR,IAAM+F,IACLvE,EAAalF,GACbA,EAAUA,GAAWtD,EAEhB0I,GAAiB,CAIrB,GAAkB,KAAb/G,IAAqBuL,EAAQ3B,EAAWgC,KAAMlK,IAGlD,GAAO2J,EAAIE,EAAO,IAGjB,GAAkB,IAAbvL,EAAiB,CACrB,KAAO8C,EAAOnB,EAAQkK,eAAgBR,IAUrC,OAAOhG,EALP,GAAKvC,EAAKgJ,KAAOT,EAEhB,OADAhG,EAAQhG,KAAMyD,GACPuC,OAYT,GAAKqG,IAAgB5I,EAAO4I,EAAWG,eAAgBR,KACtDnE,EAAUvF,EAASmB,IACnBA,EAAKgJ,KAAOT,EAGZ,OADAhG,EAAQhG,KAAMyD,GACPuC,MAKH,CAAA,GAAKkG,EAAO,GAElB,OADAlM,EAAKD,MAAOiG,EAAS1D,EAAQoK,qBAAsBrK,IAC5C2D,EAGD,IAAOgG,EAAIE,EAAO,KAAS1L,EAAQmM,wBACzCrK,EAAQqK,uBAGR,OADA3M,EAAKD,MAAOiG,EAAS1D,EAAQqK,uBAAwBX,IAC9ChG,EAKT,GAAKxF,EAAQoM,MACXtE,EAAwBjG,EAAW,QACjCsF,IAAcA,EAAUkF,KAAMxK,MAIlB,IAAb1B,GAAqD,WAAnC2B,EAAQmJ,SAAS5E,eAA+B,CAYpE,GAVAuF,EAAc/J,EACdgK,EAAa/J,EASK,IAAb3B,IACF4I,EAASsD,KAAMxK,IAAciH,EAAauD,KAAMxK,IAAe,EAGjEgK,EAAa7B,GAASqC,KAAMxK,IAAcyK,GAAaxK,EAAQN,aAC9DM,KAImBA,GAAY9B,EAAQuM,SAGhCd,EAAM3J,EAAQV,aAAc,OAClCqK,EAAMA,EAAI3G,QAAS0F,GAAYC,IAE/B3I,EAAQT,aAAc,KAAQoK,EAAM9G,IAMtC5D,GADA4K,EAASjF,EAAU7E,IACRK,OACX,MAAQnB,IACP4K,EAAQ5K,IAAQ0K,EAAM,IAAMA,EAAM,UAAa,IAC9Ce,GAAYb,EAAQ5K,IAEtB6K,EAAcD,EAAOc,KAAM,KAG5B,IAIC,OAHAjN,EAAKD,MAAOiG,EACXqG,EAAWa,iBAAkBd,IAEvBpG,EACN,MAAQmH,GACT7E,EAAwBjG,GAAU,GACjC,QACI4J,IAAQ9G,GACZ7C,EAAQ8K,gBAAiB,QAQ9B,OAAOhG,EAAQ/E,EAASiD,QAAS8D,EAAO,MAAQ9G,EAAS0D,EAAS+F,GASnE,SAAS5D,KACR,IAAIkF,EAAO,GAYX,OAVA,SAASC,EAAOC,EAAKhH,GAQpB,OALK8G,EAAKrN,KAAMuN,EAAM,KAAQxG,EAAKyG,oBAG3BF,EAAOD,EAAKI,SAEXH,EAAOC,EAAM,KAAQhH,GAShC,SAASmH,GAAcnL,GAEtB,OADAA,EAAI4C,IAAY,EACT5C,EAOR,SAASoL,GAAQpL,GAChB,IAAIqL,EAAK5O,EAAS0C,cAAe,YAEjC,IACC,QAASa,EAAIqL,GACZ,MAAQ/B,GACT,OAAO,EACN,QAGI+B,EAAG5L,YACP4L,EAAG5L,WAAWC,YAAa2L,GAI5BA,EAAK,MASP,SAASC,GAAWC,EAAOC,GAC1B,IAAIzO,EAAMwO,EAAMnH,MAAO,KACtBpF,EAAIjC,EAAIoD,OAET,MAAQnB,IACPwF,EAAKiH,WAAY1O,EAAKiC,IAAQwM,EAUhC,SAASE,GAAczF,EAAGC,GACzB,IAAIyF,EAAMzF,GAAKD,EACd2F,EAAOD,GAAsB,IAAf1F,EAAE7H,UAAiC,IAAf8H,EAAE9H,UACnC6H,EAAE4F,YAAc3F,EAAE2F,YAGpB,GAAKD,EACJ,OAAOA,EAIR,GAAKD,EACJ,MAAUA,EAAMA,EAAIG,YACnB,GAAKH,IAAQzF,EACZ,OAAQ,EAKX,OAAOD,EAAI,GAAK,EAOjB,SAAS8F,GAAmBvN,GAC3B,OAAO,SAAU0C,GAEhB,MAAgB,UADLA,EAAKgI,SAAS5E,eACEpD,EAAK1C,OAASA,GAQ3C,SAASwN,GAAoBxN,GAC5B,OAAO,SAAU0C,GAChB,IAAIgB,EAAOhB,EAAKgI,SAAS5E,cACzB,OAAkB,UAATpC,GAA6B,WAATA,IAAuBhB,EAAK1C,OAASA,GAQpE,SAASyN,GAAsBhD,GAG9B,OAAO,SAAU/H,GAKhB,MAAK,SAAUA,EASTA,EAAKzB,aAAgC,IAAlByB,EAAK+H,SAGvB,UAAW/H,EACV,UAAWA,EAAKzB,WACbyB,EAAKzB,WAAWwJ,WAAaA,EAE7B/H,EAAK+H,WAAaA,EAMpB/H,EAAKgL,aAAejD,GAI1B/H,EAAKgL,cAAgBjD,GACrBF,GAAoB7H,KAAW+H,EAG1B/H,EAAK+H,WAAaA,EAKd,UAAW/H,GACfA,EAAK+H,WAAaA,GAY5B,SAASkD,GAAwBnM,GAChC,OAAOmL,GAAc,SAAUiB,GAE9B,OADAA,GAAYA,EACLjB,GAAc,SAAU3B,EAAM3F,GACpC,IAAIjC,EACHyK,EAAerM,EAAI,GAAIwJ,EAAKrJ,OAAQiM,GACpCpN,EAAIqN,EAAalM,OAGlB,MAAQnB,IACFwK,EAAQ5H,EAAIyK,EAAcrN,MAC9BwK,EAAM5H,KAASiC,EAASjC,GAAM4H,EAAM5H,SAYzC,SAAS2I,GAAaxK,GACrB,OAAOA,GAAmD,oBAAjCA,EAAQoK,sBAAwCpK,EAkrC1E,IAAMf,KA9qCNf,EAAUsG,GAAOtG,QAAU,GAO3ByG,EAAQH,GAAOG,MAAQ,SAAUxD,GAChC,IAAIoL,EAAYpL,GAAQA,EAAKqL,aAC5BrH,EAAUhE,IAAUA,EAAK6I,eAAiB7I,GAAOsL,gBAKlD,OAAQ5E,EAAM0C,KAAMgC,GAAapH,GAAWA,EAAQgE,UAAY,SAQjEjE,EAAcV,GAAOU,YAAc,SAAUnG,GAC5C,IAAI2N,EAAYC,EACf3N,EAAMD,EAAOA,EAAKiL,eAAiBjL,EAAO0G,EAO3C,OAAKzG,GAAOtC,GAA6B,IAAjBsC,EAAIX,UAAmBW,EAAIyN,kBAMnDtH,GADAzI,EAAWsC,GACQyN,gBACnBrH,GAAkBT,EAAOjI,GAQpB+I,GAAgB/I,IAClBiQ,EAAYjQ,EAASkQ,cAAiBD,EAAUE,MAAQF,IAGrDA,EAAUG,iBACdH,EAAUG,iBAAkB,SAAU/D,IAAe,GAG1C4D,EAAUI,aACrBJ,EAAUI,YAAa,WAAYhE,KASrC7K,EAAQuM,MAAQY,GAAQ,SAAUC,GAEjC,OADAnG,EAAQ1F,YAAa6L,GAAK7L,YAAa/C,EAAS0C,cAAe,QACzB,oBAAxBkM,EAAGV,mBACfU,EAAGV,iBAAkB,uBAAwBxK,SAShDlC,EAAQwI,WAAa2E,GAAQ,SAAUC,GAEtC,OADAA,EAAG0B,UAAY,KACP1B,EAAGhM,aAAc,eAO1BpB,EAAQkM,qBAAuBiB,GAAQ,SAAUC,GAEhD,OADAA,EAAG7L,YAAa/C,EAASuQ,cAAe,MAChC3B,EAAGlB,qBAAsB,KAAMhK,SAIxClC,EAAQmM,uBAAyBrC,EAAQuC,KAAM7N,EAAS2N,wBAMxDnM,EAAQgP,QAAU7B,GAAQ,SAAUC,GAEnC,OADAnG,EAAQ1F,YAAa6L,GAAKnB,GAAKtH,GACvBnG,EAASyQ,oBAAsBzQ,EAASyQ,kBAAmBtK,GAAUzC,SAIzElC,EAAQgP,SACZzI,EAAK2I,OAAa,GAAI,SAAUjD,GAC/B,IAAIkD,EAASlD,EAAGnH,QAASmF,GAAWC,IACpC,OAAO,SAAUjH,GAChB,OAAOA,EAAK7B,aAAc,QAAW+N,IAGvC5I,EAAK6I,KAAW,GAAI,SAAUnD,EAAInK,GACjC,GAAuC,oBAA3BA,EAAQkK,gBAAkC9E,EAAiB,CACtE,IAAIjE,EAAOnB,EAAQkK,eAAgBC,GACnC,OAAOhJ,EAAO,CAAEA,GAAS,OAI3BsD,EAAK2I,OAAa,GAAK,SAAUjD,GAChC,IAAIkD,EAASlD,EAAGnH,QAASmF,GAAWC,IACpC,OAAO,SAAUjH,GAChB,IAAIpC,EAAwC,oBAA1BoC,EAAKoM,kBACtBpM,EAAKoM,iBAAkB,MACxB,OAAOxO,GAAQA,EAAKkF,QAAUoJ,IAMhC5I,EAAK6I,KAAW,GAAI,SAAUnD,EAAInK,GACjC,GAAuC,oBAA3BA,EAAQkK,gBAAkC9E,EAAiB,CACtE,IAAIrG,EAAME,EAAG2B,EACZO,EAAOnB,EAAQkK,eAAgBC,GAEhC,GAAKhJ,EAAO,CAIX,IADApC,EAAOoC,EAAKoM,iBAAkB,QACjBxO,EAAKkF,QAAUkG,EAC3B,MAAO,CAAEhJ,GAIVP,EAAQZ,EAAQmN,kBAAmBhD,GACnClL,EAAI,EACJ,MAAUkC,EAAOP,EAAO3B,KAEvB,IADAF,EAAOoC,EAAKoM,iBAAkB,QACjBxO,EAAKkF,QAAUkG,EAC3B,MAAO,CAAEhJ,GAKZ,MAAO,MAMVsD,EAAK6I,KAAY,IAAIpP,EAAQkM,qBAC5B,SAAUoD,EAAKxN,GACd,MAA6C,oBAAjCA,EAAQoK,qBACZpK,EAAQoK,qBAAsBoD,GAG1BtP,EAAQoM,IACZtK,EAAQ4K,iBAAkB4C,QAD3B,GAKR,SAAUA,EAAKxN,GACd,IAAImB,EACHsM,EAAM,GACNxO,EAAI,EAGJyE,EAAU1D,EAAQoK,qBAAsBoD,GAGzC,GAAa,MAARA,EAAc,CAClB,MAAUrM,EAAOuC,EAASzE,KACF,IAAlBkC,EAAK9C,UACToP,EAAI/P,KAAMyD,GAIZ,OAAOsM,EAER,OAAO/J,GAITe,EAAK6I,KAAc,MAAIpP,EAAQmM,wBAA0B,SAAU2C,EAAWhN,GAC7E,GAA+C,oBAAnCA,EAAQqK,wBAA0CjF,EAC7D,OAAOpF,EAAQqK,uBAAwB2C,IAUzC1H,EAAgB,GAOhBD,EAAY,IAELnH,EAAQoM,IAAMtC,EAAQuC,KAAM7N,EAASkO,qBAI3CS,GAAQ,SAAUC,GAEjB,IAAIoC,EAOJvI,EAAQ1F,YAAa6L,GAAKqC,UAAY,UAAY9K,EAAU,qBAC1CA,EAAU,kEAOvByI,EAAGV,iBAAkB,wBAAyBxK,QAClDiF,EAAU3H,KAAM,SAAW8I,EAAa,gBAKnC8E,EAAGV,iBAAkB,cAAexK,QACzCiF,EAAU3H,KAAM,MAAQ8I,EAAa,aAAeD,EAAW,KAI1D+E,EAAGV,iBAAkB,QAAU/H,EAAU,MAAOzC,QACrDiF,EAAU3H,KAAM,OAQjBgQ,EAAQhR,EAAS0C,cAAe,UAC1BG,aAAc,OAAQ,IAC5B+L,EAAG7L,YAAaiO,GACVpC,EAAGV,iBAAkB,aAAcxK,QACxCiF,EAAU3H,KAAM,MAAQ8I,EAAa,QAAUA,EAAa,KAC3DA,EAAa,gBAMT8E,EAAGV,iBAAkB,YAAaxK,QACvCiF,EAAU3H,KAAM,YAMX4N,EAAGV,iBAAkB,KAAO/H,EAAU,MAAOzC,QAClDiF,EAAU3H,KAAM,YAKjB4N,EAAGV,iBAAkB,QACrBvF,EAAU3H,KAAM,iBAGjB2N,GAAQ,SAAUC,GACjBA,EAAGqC,UAAY,oFAKf,IAAID,EAAQhR,EAAS0C,cAAe,SACpCsO,EAAMnO,aAAc,OAAQ,UAC5B+L,EAAG7L,YAAaiO,GAAQnO,aAAc,OAAQ,KAIzC+L,EAAGV,iBAAkB,YAAaxK,QACtCiF,EAAU3H,KAAM,OAAS8I,EAAa,eAKW,IAA7C8E,EAAGV,iBAAkB,YAAaxK,QACtCiF,EAAU3H,KAAM,WAAY,aAK7ByH,EAAQ1F,YAAa6L,GAAKpC,UAAW,EACc,IAA9CoC,EAAGV,iBAAkB,aAAcxK,QACvCiF,EAAU3H,KAAM,WAAY,aAK7B4N,EAAGV,iBAAkB,QACrBvF,EAAU3H,KAAM,YAIXQ,EAAQ0P,gBAAkB5F,EAAQuC,KAAQzG,EAAUqB,EAAQrB,SAClEqB,EAAQ0I,uBACR1I,EAAQ2I,oBACR3I,EAAQ4I,kBACR5I,EAAQ6I,qBAER3C,GAAQ,SAAUC,GAIjBpN,EAAQ+P,kBAAoBnK,EAAQvG,KAAM+N,EAAI,KAI9CxH,EAAQvG,KAAM+N,EAAI,aAClBhG,EAAc5H,KAAM,KAAMiJ,KAI5BtB,EAAYA,EAAUjF,QAAU,IAAIyG,OAAQxB,EAAUsF,KAAM,MAC5DrF,EAAgBA,EAAclF,QAAU,IAAIyG,OAAQvB,EAAcqF,KAAM,MAIxE+B,EAAa1E,EAAQuC,KAAMpF,EAAQ+I,yBAKnC3I,EAAWmH,GAAc1E,EAAQuC,KAAMpF,EAAQI,UAC9C,SAAUW,EAAGC,GACZ,IAAIgI,EAAuB,IAAfjI,EAAE7H,SAAiB6H,EAAEuG,gBAAkBvG,EAClDkI,EAAMjI,GAAKA,EAAEzG,WACd,OAAOwG,IAAMkI,MAAWA,GAAwB,IAAjBA,EAAI/P,YAClC8P,EAAM5I,SACL4I,EAAM5I,SAAU6I,GAChBlI,EAAEgI,yBAA8D,GAAnChI,EAAEgI,wBAAyBE,MAG3D,SAAUlI,EAAGC,GACZ,GAAKA,EACJ,MAAUA,EAAIA,EAAEzG,WACf,GAAKyG,IAAMD,EACV,OAAO,EAIV,OAAO,GAOTD,EAAYyG,EACZ,SAAUxG,EAAGC,GAGZ,GAAKD,IAAMC,EAEV,OADAlB,GAAe,EACR,EAIR,IAAIoJ,GAAWnI,EAAEgI,yBAA2B/H,EAAE+H,wBAC9C,OAAKG,IAgBU,GAPfA,GAAYnI,EAAE8D,eAAiB9D,KAASC,EAAE6D,eAAiB7D,GAC1DD,EAAEgI,wBAAyB/H,GAG3B,KAIGjI,EAAQoQ,cAAgBnI,EAAE+H,wBAAyBhI,KAAQmI,EAOzDnI,GAAKxJ,GAAYwJ,EAAE8D,eAAiBvE,GACxCF,EAAUE,EAAcS,IAChB,EAOJC,GAAKzJ,GAAYyJ,EAAE6D,eAAiBvE,GACxCF,EAAUE,EAAcU,GACjB,EAIDnB,EACJrH,EAASqH,EAAWkB,GAAMvI,EAASqH,EAAWmB,GAChD,EAGe,EAAVkI,GAAe,EAAI,IAE3B,SAAUnI,EAAGC,GAGZ,GAAKD,IAAMC,EAEV,OADAlB,GAAe,EACR,EAGR,IAAI2G,EACH3M,EAAI,EACJsP,EAAMrI,EAAExG,WACR0O,EAAMjI,EAAEzG,WACR8O,EAAK,CAAEtI,GACPuI,EAAK,CAAEtI,GAGR,IAAMoI,IAAQH,EAMb,OAAOlI,GAAKxJ,GAAY,EACvByJ,GAAKzJ,EAAW,EAEhB6R,GAAO,EACPH,EAAM,EACNpJ,EACErH,EAASqH,EAAWkB,GAAMvI,EAASqH,EAAWmB,GAChD,EAGK,GAAKoI,IAAQH,EACnB,OAAOzC,GAAczF,EAAGC,GAIzByF,EAAM1F,EACN,MAAU0F,EAAMA,EAAIlM,WACnB8O,EAAGE,QAAS9C,GAEbA,EAAMzF,EACN,MAAUyF,EAAMA,EAAIlM,WACnB+O,EAAGC,QAAS9C,GAIb,MAAQ4C,EAAIvP,KAAQwP,EAAIxP,GACvBA,IAGD,OAAOA,EAGN0M,GAAc6C,EAAIvP,GAAKwP,EAAIxP,IAO3BuP,EAAIvP,IAAOwG,GAAgB,EAC3BgJ,EAAIxP,IAAOwG,EAAe,EAE1B,IAGK/I,GAGR8H,GAAOV,QAAU,SAAU6K,EAAMC,GAChC,OAAOpK,GAAQmK,EAAM,KAAM,KAAMC,IAGlCpK,GAAOoJ,gBAAkB,SAAUzM,EAAMwN,GAGxC,GAFAzJ,EAAa/D,GAERjD,EAAQ0P,iBAAmBxI,IAC9BY,EAAwB2I,EAAO,QAC7BrJ,IAAkBA,EAAciF,KAAMoE,OACtCtJ,IAAkBA,EAAUkF,KAAMoE,IAErC,IACC,IAAI9N,EAAMiD,EAAQvG,KAAM4D,EAAMwN,GAG9B,GAAK9N,GAAO3C,EAAQ+P,mBAInB9M,EAAKzE,UAAuC,KAA3ByE,EAAKzE,SAAS2B,SAC/B,OAAOwC,EAEP,MAAQ0I,GACTvD,EAAwB2I,GAAM,GAIhC,OAAyD,EAAlDnK,GAAQmK,EAAMjS,EAAU,KAAM,CAAEyE,IAASf,QAGjDoE,GAAOe,SAAW,SAAUvF,EAASmB,GAUpC,OAHOnB,EAAQgK,eAAiBhK,IAAatD,GAC5CwI,EAAalF,GAEPuF,EAAUvF,EAASmB,IAG3BqD,GAAOqK,KAAO,SAAU1N,EAAMgB,IAOtBhB,EAAK6I,eAAiB7I,IAAUzE,GACtCwI,EAAa/D,GAGd,IAAIlB,EAAKwE,EAAKiH,WAAYvJ,EAAKoC,eAG9BrF,EAAMe,GAAMnC,EAAOP,KAAMkH,EAAKiH,WAAYvJ,EAAKoC,eAC9CtE,EAAIkB,EAAMgB,GAAOiD,QACjBxC,EAEF,YAAeA,IAAR1D,EACNA,EACAhB,EAAQwI,aAAetB,EACtBjE,EAAK7B,aAAc6C,IACjBjD,EAAMiC,EAAKoM,iBAAkBpL,KAAYjD,EAAI4P,UAC9C5P,EAAI+E,MACJ,MAGJO,GAAO6D,OAAS,SAAU0G,GACzB,OAASA,EAAM,IAAK/L,QAAS0F,GAAYC,KAG1CnE,GAAOtB,MAAQ,SAAUC,GACxB,MAAM,IAAIvG,MAAO,0CAA4CuG,IAO9DqB,GAAOwK,WAAa,SAAUtL,GAC7B,IAAIvC,EACH8N,EAAa,GACbpN,EAAI,EACJ5C,EAAI,EAOL,GAJAgG,GAAgB/G,EAAQgR,iBACxBlK,GAAa9G,EAAQiR,YAAczL,EAAQtG,MAAO,GAClDsG,EAAQ3B,KAAMkE,GAEThB,EAAe,CACnB,MAAU9D,EAAOuC,EAASzE,KACpBkC,IAASuC,EAASzE,KACtB4C,EAAIoN,EAAWvR,KAAMuB,IAGvB,MAAQ4C,IACP6B,EAAQ1B,OAAQiN,EAAYpN,GAAK,GAQnC,OAFAmD,EAAY,KAELtB,GAORgB,EAAUF,GAAOE,QAAU,SAAUvD,GACpC,IAAIpC,EACH8B,EAAM,GACN5B,EAAI,EACJZ,EAAW8C,EAAK9C,SAEjB,GAAMA,GAQC,GAAkB,IAAbA,GAA+B,IAAbA,GAA+B,KAAbA,EAAkB,CAIjE,GAAiC,iBAArB8C,EAAKiO,YAChB,OAAOjO,EAAKiO,YAIZ,IAAMjO,EAAOA,EAAKkO,WAAYlO,EAAMA,EAAOA,EAAK4K,YAC/ClL,GAAO6D,EAASvD,QAGZ,GAAkB,IAAb9C,GAA+B,IAAbA,EAC7B,OAAO8C,EAAKmO,eAnBZ,MAAUvQ,EAAOoC,EAAMlC,KAGtB4B,GAAO6D,EAAS3F,GAqBlB,OAAO8B,IAGR4D,EAAOD,GAAO+K,UAAY,CAGzBrE,YAAa,GAEbsE,aAAcpE,GAEdxB,MAAOxC,EAEPsE,WAAY,GAEZ4B,KAAM,GAENmC,SAAU,CACTC,IAAK,CAAEtG,IAAK,aAAc/H,OAAO,GACjCsO,IAAK,CAAEvG,IAAK,cACZwG,IAAK,CAAExG,IAAK,kBAAmB/H,OAAO,GACtCwO,IAAK,CAAEzG,IAAK,oBAGb0G,UAAW,CACVtI,KAAQ,SAAUoC,GAWjB,OAVAA,EAAO,GAAMA,EAAO,GAAI5G,QAASmF,GAAWC,IAG5CwB,EAAO,IAAQA,EAAO,IAAOA,EAAO,IACnCA,EAAO,IAAO,IAAK5G,QAASmF,GAAWC,IAEpB,OAAfwB,EAAO,KACXA,EAAO,GAAM,IAAMA,EAAO,GAAM,KAG1BA,EAAMxM,MAAO,EAAG,IAGxBsK,MAAS,SAAUkC,GAiClB,OArBAA,EAAO,GAAMA,EAAO,GAAIrF,cAEU,QAA7BqF,EAAO,GAAIxM,MAAO,EAAG,IAGnBwM,EAAO,IACZpF,GAAOtB,MAAO0G,EAAO,IAKtBA,EAAO,KAASA,EAAO,GACtBA,EAAO,IAAQA,EAAO,IAAO,GAC7B,GAAqB,SAAfA,EAAO,IAAiC,QAAfA,EAAO,KACvCA,EAAO,KAAWA,EAAO,GAAMA,EAAO,IAAwB,QAAfA,EAAO,KAG3CA,EAAO,IAClBpF,GAAOtB,MAAO0G,EAAO,IAGfA,GAGRnC,OAAU,SAAUmC,GACnB,IAAImG,EACHC,GAAYpG,EAAO,IAAOA,EAAO,GAElC,OAAKxC,EAAmB,MAAEmD,KAAMX,EAAO,IAC/B,MAIHA,EAAO,GACXA,EAAO,GAAMA,EAAO,IAAOA,EAAO,IAAO,GAG9BoG,GAAY9I,EAAQqD,KAAMyF,KAGnCD,EAASnL,EAAUoL,GAAU,MAG7BD,EAASC,EAASrS,QAAS,IAAKqS,EAAS5P,OAAS2P,GAAWC,EAAS5P,UAGxEwJ,EAAO,GAAMA,EAAO,GAAIxM,MAAO,EAAG2S,GAClCnG,EAAO,GAAMoG,EAAS5S,MAAO,EAAG2S,IAI1BnG,EAAMxM,MAAO,EAAG,MAIzBgQ,OAAQ,CAEP7F,IAAO,SAAU0I,GAChB,IAAI9G,EAAW8G,EAAiBjN,QAASmF,GAAWC,IAAY7D,cAChE,MAA4B,MAArB0L,EACN,WACC,OAAO,GAER,SAAU9O,GACT,OAAOA,EAAKgI,UAAYhI,EAAKgI,SAAS5E,gBAAkB4E,IAI3D7B,MAAS,SAAU0F,GAClB,IAAIkD,EAAUtK,EAAYoH,EAAY,KAEtC,OAAOkD,IACJA,EAAU,IAAIrJ,OAAQ,MAAQL,EAC/B,IAAMwG,EAAY,IAAMxG,EAAa,SAAaZ,EACjDoH,EAAW,SAAU7L,GACpB,OAAO+O,EAAQ3F,KACY,iBAAnBpJ,EAAK6L,WAA0B7L,EAAK6L,WACd,oBAAtB7L,EAAK7B,cACX6B,EAAK7B,aAAc,UACpB,OAKNkI,KAAQ,SAAUrF,EAAMgO,EAAUC,GACjC,OAAO,SAAUjP,GAChB,IAAIkP,EAAS7L,GAAOqK,KAAM1N,EAAMgB,GAEhC,OAAe,MAAVkO,EACgB,OAAbF,GAEFA,IAINE,GAAU,GAIU,MAAbF,EAAmBE,IAAWD,EACvB,OAAbD,EAAoBE,IAAWD,EAClB,OAAbD,EAAoBC,GAAqC,IAA5BC,EAAO1S,QAASyS,GAChC,OAAbD,EAAoBC,IAAoC,EAA3BC,EAAO1S,QAASyS,GAChC,OAAbD,EAAoBC,GAASC,EAAOjT,OAAQgT,EAAMhQ,UAAagQ,EAClD,OAAbD,GAA2F,GAArE,IAAME,EAAOrN,QAAS4D,EAAa,KAAQ,KAAMjJ,QAASyS,GACnE,OAAbD,IAAoBE,IAAWD,GAASC,EAAOjT,MAAO,EAAGgT,EAAMhQ,OAAS,KAAQgQ,EAAQ,QAO3F1I,MAAS,SAAUjJ,EAAM6R,EAAMC,EAAWlP,EAAOE,GAChD,IAAIiP,EAAgC,QAAvB/R,EAAKrB,MAAO,EAAG,GAC3BqT,EAA+B,SAArBhS,EAAKrB,OAAQ,GACvBsT,EAAkB,YAATJ,EAEV,OAAiB,IAAVjP,GAAwB,IAATE,EAGrB,SAAUJ,GACT,QAASA,EAAKzB,YAGf,SAAUyB,EAAMwP,EAAUC,GACzB,IAAI5F,EAAO6F,EAAaC,EAAY/R,EAAMgS,EAAWC,EACpD5H,EAAMoH,IAAWC,EAAU,cAAgB,kBAC3CQ,EAAS9P,EAAKzB,WACdyC,EAAOuO,GAAUvP,EAAKgI,SAAS5E,cAC/B2M,GAAYN,IAAQF,EACpB7E,GAAO,EAER,GAAKoF,EAAS,CAGb,GAAKT,EAAS,CACb,MAAQpH,EAAM,CACbrK,EAAOoC,EACP,MAAUpC,EAAOA,EAAMqK,GACtB,GAAKsH,EACJ3R,EAAKoK,SAAS5E,gBAAkBpC,EACd,IAAlBpD,EAAKV,SAEL,OAAO,EAKT2S,EAAQ5H,EAAe,SAAT3K,IAAoBuS,GAAS,cAE5C,OAAO,EAMR,GAHAA,EAAQ,CAAEP,EAAUQ,EAAO5B,WAAa4B,EAAOE,WAG1CV,GAAWS,EAAW,CAe1BrF,GADAkF,GADA/F,GAHA6F,GAJAC,GADA/R,EAAOkS,GACYpO,KAAe9D,EAAM8D,GAAY,KAI1B9D,EAAKqS,YAC5BN,EAAY/R,EAAKqS,UAAa,KAEZ3S,IAAU,IACZ,KAAQiH,GAAWsF,EAAO,KACzBA,EAAO,GAC3BjM,EAAOgS,GAAaE,EAAO3H,WAAYyH,GAEvC,MAAUhS,IAASgS,GAAahS,GAAQA,EAAMqK,KAG3CyC,EAAOkF,EAAY,IAAOC,EAAM5K,MAGlC,GAAuB,IAAlBrH,EAAKV,YAAoBwN,GAAQ9M,IAASoC,EAAO,CACrD0P,EAAapS,GAAS,CAAEiH,EAASqL,EAAWlF,GAC5C,YAyBF,GAlBKqF,IAaJrF,EADAkF,GADA/F,GAHA6F,GAJAC,GADA/R,EAAOoC,GACY0B,KAAe9D,EAAM8D,GAAY,KAI1B9D,EAAKqS,YAC5BN,EAAY/R,EAAKqS,UAAa,KAEZ3S,IAAU,IACZ,KAAQiH,GAAWsF,EAAO,KAMhC,IAATa,EAGJ,MAAU9M,IAASgS,GAAahS,GAAQA,EAAMqK,KAC3CyC,EAAOkF,EAAY,IAAOC,EAAM5K,MAElC,IAAOsK,EACN3R,EAAKoK,SAAS5E,gBAAkBpC,EACd,IAAlBpD,EAAKV,aACHwN,IAGGqF,KAMJL,GALAC,EAAa/R,EAAM8D,KAChB9D,EAAM8D,GAAY,KAIK9D,EAAKqS,YAC5BN,EAAY/R,EAAKqS,UAAa,KAEpB3S,GAAS,CAAEiH,EAASmG,IAG7B9M,IAASoC,GACb,MASL,OADA0K,GAAQtK,KACQF,GAAWwK,EAAOxK,GAAU,GAAqB,GAAhBwK,EAAOxK,KAK5DoG,OAAU,SAAU4J,EAAQhF,GAM3B,IAAIiF,EACHrR,EAAKwE,EAAKkC,QAAS0K,IAAY5M,EAAK8M,WAAYF,EAAO9M,gBACtDC,GAAOtB,MAAO,uBAAyBmO,GAKzC,OAAKpR,EAAI4C,GACD5C,EAAIoM,GAIK,EAAZpM,EAAGG,QACPkR,EAAO,CAAED,EAAQA,EAAQ,GAAIhF,GACtB5H,EAAK8M,WAAWxT,eAAgBsT,EAAO9M,eAC7C6G,GAAc,SAAU3B,EAAM3F,GAC7B,IAAI0N,EACHC,EAAUxR,EAAIwJ,EAAM4C,GACpBpN,EAAIwS,EAAQrR,OACb,MAAQnB,IAEPwK,EADA+H,EAAM7T,EAAS8L,EAAMgI,EAASxS,OACb6E,EAAS0N,GAAQC,EAASxS,MAG7C,SAAUkC,GACT,OAAOlB,EAAIkB,EAAM,EAAGmQ,KAIhBrR,IAIT0G,QAAS,CAGR+K,IAAOtG,GAAc,SAAUrL,GAK9B,IAAI2N,EAAQ,GACXhK,EAAU,GACViO,EAAU9M,EAAS9E,EAASiD,QAAS8D,EAAO,OAE7C,OAAO6K,EAAS9O,GACfuI,GAAc,SAAU3B,EAAM3F,EAAS6M,EAAUC,GAChD,IAAIzP,EACHyQ,EAAYD,EAASlI,EAAM,KAAMmH,EAAK,IACtC3R,EAAIwK,EAAKrJ,OAGV,MAAQnB,KACAkC,EAAOyQ,EAAW3S,MACxBwK,EAAMxK,KAAS6E,EAAS7E,GAAMkC,MAIjC,SAAUA,EAAMwP,EAAUC,GAMzB,OALAlD,EAAO,GAAMvM,EACbwQ,EAASjE,EAAO,KAAMkD,EAAKlN,GAG3BgK,EAAO,GAAM,MACLhK,EAAQ0C,SAInByL,IAAOzG,GAAc,SAAUrL,GAC9B,OAAO,SAAUoB,GAChB,OAAyC,EAAlCqD,GAAQzE,EAAUoB,GAAOf,UAIlCmF,SAAY6F,GAAc,SAAU/L,GAEnC,OADAA,EAAOA,EAAK2D,QAASmF,GAAWC,IACzB,SAAUjH,GAChB,OAAkE,GAAzDA,EAAKiO,aAAe1K,EAASvD,IAASxD,QAAS0B,MAW1DyS,KAAQ1G,GAAc,SAAU0G,GAO/B,OAJM3K,EAAYoD,KAAMuH,GAAQ,KAC/BtN,GAAOtB,MAAO,qBAAuB4O,GAEtCA,EAAOA,EAAK9O,QAASmF,GAAWC,IAAY7D,cACrC,SAAUpD,GAChB,IAAI4Q,EACJ,GACC,GAAOA,EAAW3M,EACjBjE,EAAK2Q,KACL3Q,EAAK7B,aAAc,aAAgB6B,EAAK7B,aAAc,QAGtD,OADAyS,EAAWA,EAASxN,iBACAuN,GAA2C,IAAnCC,EAASpU,QAASmU,EAAO,YAE3C3Q,EAAOA,EAAKzB,aAAkC,IAAlByB,EAAK9C,UAC7C,OAAO,KAKTkE,OAAU,SAAUpB,GACnB,IAAI6Q,EAAOnV,EAAOoV,UAAYpV,EAAOoV,SAASD,KAC9C,OAAOA,GAAQA,EAAK5U,MAAO,KAAQ+D,EAAKgJ,IAGzC+H,KAAQ,SAAU/Q,GACjB,OAAOA,IAASgE,GAGjBgN,MAAS,SAAUhR,GAClB,OAAOA,IAASzE,EAAS0V,iBACrB1V,EAAS2V,UAAY3V,EAAS2V,gBAC7BlR,EAAK1C,MAAQ0C,EAAKmR,OAASnR,EAAKoR,WAItCC,QAAWtG,IAAsB,GACjChD,SAAYgD,IAAsB,GAElCuG,QAAW,SAAUtR,GAIpB,IAAIgI,EAAWhI,EAAKgI,SAAS5E,cAC7B,MAAsB,UAAb4E,KAA0BhI,EAAKsR,SACxB,WAAbtJ,KAA2BhI,EAAKuR,UAGpCA,SAAY,SAAUvR,GASrB,OALKA,EAAKzB,YAETyB,EAAKzB,WAAWiT,eAGQ,IAAlBxR,EAAKuR,UAIbE,MAAS,SAAUzR,GAMlB,IAAMA,EAAOA,EAAKkO,WAAYlO,EAAMA,EAAOA,EAAK4K,YAC/C,GAAK5K,EAAK9C,SAAW,EACpB,OAAO,EAGT,OAAO,GAGR4S,OAAU,SAAU9P,GACnB,OAAQsD,EAAKkC,QAAiB,MAAGxF,IAIlC0R,OAAU,SAAU1R,GACnB,OAAO4G,EAAQwC,KAAMpJ,EAAKgI,WAG3BuE,MAAS,SAAUvM,GAClB,OAAO2G,EAAQyC,KAAMpJ,EAAKgI,WAG3B2J,OAAU,SAAU3R,GACnB,IAAIgB,EAAOhB,EAAKgI,SAAS5E,cACzB,MAAgB,UAATpC,GAAkC,WAAdhB,EAAK1C,MAA8B,WAAT0D,GAGtD9C,KAAQ,SAAU8B,GACjB,IAAI0N,EACJ,MAAuC,UAAhC1N,EAAKgI,SAAS5E,eACN,SAAdpD,EAAK1C,OAIuC,OAAxCoQ,EAAO1N,EAAK7B,aAAc,UACN,SAAvBuP,EAAKtK,gBAIRlD,MAAS+K,GAAwB,WAChC,MAAO,CAAE,KAGV7K,KAAQ6K,GAAwB,SAAU2G,EAAe3S,GACxD,MAAO,CAAEA,EAAS,KAGnBkB,GAAM8K,GAAwB,SAAU2G,EAAe3S,EAAQiM,GAC9D,MAAO,CAAEA,EAAW,EAAIA,EAAWjM,EAASiM,KAG7C7K,KAAQ4K,GAAwB,SAAUE,EAAclM,GAEvD,IADA,IAAInB,EAAI,EACAA,EAAImB,EAAQnB,GAAK,EACxBqN,EAAa5O,KAAMuB,GAEpB,OAAOqN,IAGR3K,IAAOyK,GAAwB,SAAUE,EAAclM,GAEtD,IADA,IAAInB,EAAI,EACAA,EAAImB,EAAQnB,GAAK,EACxBqN,EAAa5O,KAAMuB,GAEpB,OAAOqN,IAGR0G,GAAM5G,GAAwB,SAAUE,EAAclM,EAAQiM,GAM7D,IALA,IAAIpN,EAAIoN,EAAW,EAClBA,EAAWjM,EACAA,EAAXiM,EACCjM,EACAiM,EACa,KAALpN,GACTqN,EAAa5O,KAAMuB,GAEpB,OAAOqN,IAGR2G,GAAM7G,GAAwB,SAAUE,EAAclM,EAAQiM,GAE7D,IADA,IAAIpN,EAAIoN,EAAW,EAAIA,EAAWjM,EAASiM,IACjCpN,EAAImB,GACbkM,EAAa5O,KAAMuB,GAEpB,OAAOqN,OAKL3F,QAAe,IAAIlC,EAAKkC,QAAc,GAGhC,CAAEuM,OAAO,EAAMC,UAAU,EAAMC,MAAM,EAAMC,UAAU,EAAMC,OAAO,GAC5E7O,EAAKkC,QAAS1H,GAAM+M,GAAmB/M,GAExC,IAAMA,IAAK,CAAEsU,QAAQ,EAAMC,OAAO,GACjC/O,EAAKkC,QAAS1H,GAAMgN,GAAoBhN,GAIzC,SAASsS,MA0ET,SAAS7G,GAAY+I,GAIpB,IAHA,IAAIxU,EAAI,EACP2C,EAAM6R,EAAOrT,OACbL,EAAW,GACJd,EAAI2C,EAAK3C,IAChBc,GAAY0T,EAAQxU,GAAIgF,MAEzB,OAAOlE,EAGR,SAASkJ,GAAe0I,EAAS+B,EAAYC,GAC5C,IAAIvK,EAAMsK,EAAWtK,IACpBwK,EAAOF,EAAWrK,KAClB4B,EAAM2I,GAAQxK,EACdyK,EAAmBF,GAAgB,eAAR1I,EAC3B6I,EAAWnO,IAEZ,OAAO+N,EAAWrS,MAGjB,SAAUF,EAAMnB,EAAS4Q,GACxB,MAAUzP,EAAOA,EAAMiI,GACtB,GAAuB,IAAlBjI,EAAK9C,UAAkBwV,EAC3B,OAAOlC,EAASxQ,EAAMnB,EAAS4Q,GAGjC,OAAO,GAIR,SAAUzP,EAAMnB,EAAS4Q,GACxB,IAAImD,EAAUlD,EAAaC,EAC1BkD,EAAW,CAAEtO,EAASoO,GAGvB,GAAKlD,GACJ,MAAUzP,EAAOA,EAAMiI,GACtB,IAAuB,IAAlBjI,EAAK9C,UAAkBwV,IACtBlC,EAASxQ,EAAMnB,EAAS4Q,GAC5B,OAAO,OAKV,MAAUzP,EAAOA,EAAMiI,GACtB,GAAuB,IAAlBjI,EAAK9C,UAAkBwV,EAQ3B,GAHAhD,GAJAC,EAAa3P,EAAM0B,KAAe1B,EAAM0B,GAAY,KAI1B1B,EAAKiQ,YAC5BN,EAAY3P,EAAKiQ,UAAa,IAE5BwC,GAAQA,IAASzS,EAAKgI,SAAS5E,cACnCpD,EAAOA,EAAMiI,IAASjI,MAChB,CAAA,IAAO4S,EAAWlD,EAAa5F,KACrC8I,EAAU,KAAQrO,GAAWqO,EAAU,KAAQD,EAG/C,OAASE,EAAU,GAAMD,EAAU,GAOnC,IAHAlD,EAAa5F,GAAQ+I,GAGJ,GAAMrC,EAASxQ,EAAMnB,EAAS4Q,GAC9C,OAAO,EAMZ,OAAO,GAIV,SAASqD,GAAgBC,GACxB,OAAyB,EAAlBA,EAAS9T,OACf,SAAUe,EAAMnB,EAAS4Q,GACxB,IAAI3R,EAAIiV,EAAS9T,OACjB,MAAQnB,IACP,IAAMiV,EAAUjV,GAAKkC,EAAMnB,EAAS4Q,GACnC,OAAO,EAGT,OAAO,GAERsD,EAAU,GAYZ,SAASC,GAAUvC,EAAW1Q,EAAKkM,EAAQpN,EAAS4Q,GAOnD,IANA,IAAIzP,EACHiT,EAAe,GACfnV,EAAI,EACJ2C,EAAMgQ,EAAUxR,OAChBiU,EAAgB,MAAPnT,EAEFjC,EAAI2C,EAAK3C,KACTkC,EAAOyQ,EAAW3S,MAClBmO,IAAUA,EAAQjM,EAAMnB,EAAS4Q,KACtCwD,EAAa1W,KAAMyD,GACdkT,GACJnT,EAAIxD,KAAMuB,KAMd,OAAOmV,EAGR,SAASE,GAAYxE,EAAW/P,EAAU4R,EAAS4C,EAAYC,EAAYC,GAO1E,OANKF,IAAeA,EAAY1R,KAC/B0R,EAAaD,GAAYC,IAErBC,IAAeA,EAAY3R,KAC/B2R,EAAaF,GAAYE,EAAYC,IAE/BrJ,GAAc,SAAU3B,EAAM/F,EAAS1D,EAAS4Q,GACtD,IAAI8D,EAAMzV,EAAGkC,EACZwT,EAAS,GACTC,EAAU,GACVC,EAAcnR,EAAQtD,OAGtBQ,EAAQ6I,GA5CX,SAA2B1J,EAAU+U,EAAUpR,GAG9C,IAFA,IAAIzE,EAAI,EACP2C,EAAMkT,EAAS1U,OACRnB,EAAI2C,EAAK3C,IAChBuF,GAAQzE,EAAU+U,EAAU7V,GAAKyE,GAElC,OAAOA,EAsCWqR,CACfhV,GAAY,IACZC,EAAQ3B,SAAW,CAAE2B,GAAYA,EACjC,IAIDgV,GAAYlF,IAAerG,GAAS1J,EAEnCa,EADAuT,GAAUvT,EAAO+T,EAAQ7E,EAAW9P,EAAS4Q,GAG9CqE,EAAatD,EAGZ6C,IAAgB/K,EAAOqG,EAAY+E,GAAeN,GAGjD,GAGA7Q,EACDsR,EAQF,GALKrD,GACJA,EAASqD,EAAWC,EAAYjV,EAAS4Q,GAIrC2D,EAAa,CACjBG,EAAOP,GAAUc,EAAYL,GAC7BL,EAAYG,EAAM,GAAI1U,EAAS4Q,GAG/B3R,EAAIyV,EAAKtU,OACT,MAAQnB,KACAkC,EAAOuT,EAAMzV,MACnBgW,EAAYL,EAAS3V,MAAW+V,EAAWJ,EAAS3V,IAAQkC,IAK/D,GAAKsI,GACJ,GAAK+K,GAAc1E,EAAY,CAC9B,GAAK0E,EAAa,CAGjBE,EAAO,GACPzV,EAAIgW,EAAW7U,OACf,MAAQnB,KACAkC,EAAO8T,EAAYhW,KAGzByV,EAAKhX,KAAQsX,EAAW/V,GAAMkC,GAGhCqT,EAAY,KAAQS,EAAa,GAAMP,EAAM9D,GAI9C3R,EAAIgW,EAAW7U,OACf,MAAQnB,KACAkC,EAAO8T,EAAYhW,MACsC,GAA7DyV,EAAOF,EAAa7W,EAAS8L,EAAMtI,GAASwT,EAAQ1V,MAEtDwK,EAAMiL,KAAYhR,EAASgR,GAASvT,UAOvC8T,EAAad,GACZc,IAAevR,EACduR,EAAWjT,OAAQ6S,EAAaI,EAAW7U,QAC3C6U,GAEGT,EACJA,EAAY,KAAM9Q,EAASuR,EAAYrE,GAEvClT,EAAKD,MAAOiG,EAASuR,KAMzB,SAASC,GAAmBzB,GAyB3B,IAxBA,IAAI0B,EAAcxD,EAAS9P,EAC1BD,EAAM6R,EAAOrT,OACbgV,EAAkB3Q,EAAKgL,SAAUgE,EAAQ,GAAIhV,MAC7C4W,EAAmBD,GAAmB3Q,EAAKgL,SAAU,KACrDxQ,EAAImW,EAAkB,EAAI,EAG1BE,EAAerM,GAAe,SAAU9H,GACvC,OAAOA,IAASgU,GACdE,GAAkB,GACrBE,EAAkBtM,GAAe,SAAU9H,GAC1C,OAAwC,EAAjCxD,EAASwX,EAAchU,IAC5BkU,GAAkB,GACrBnB,EAAW,CAAE,SAAU/S,EAAMnB,EAAS4Q,GACrC,IAAI/P,GAASuU,IAAqBxE,GAAO5Q,IAAY+E,MAClDoQ,EAAenV,GAAU3B,SAC1BiX,EAAcnU,EAAMnB,EAAS4Q,GAC7B2E,EAAiBpU,EAAMnB,EAAS4Q,IAIlC,OADAuE,EAAe,KACRtU,IAGD5B,EAAI2C,EAAK3C,IAChB,GAAO0S,EAAUlN,EAAKgL,SAAUgE,EAAQxU,GAAIR,MAC3CyV,EAAW,CAAEjL,GAAegL,GAAgBC,GAAYvC,QAClD,CAIN,IAHAA,EAAUlN,EAAK2I,OAAQqG,EAAQxU,GAAIR,MAAOhB,MAAO,KAAMgW,EAAQxU,GAAI6E,UAGrDjB,GAAY,CAIzB,IADAhB,IAAM5C,EACE4C,EAAID,EAAKC,IAChB,GAAK4C,EAAKgL,SAAUgE,EAAQ5R,GAAIpD,MAC/B,MAGF,OAAO6V,GACF,EAAJrV,GAASgV,GAAgBC,GACrB,EAAJjV,GAASyL,GAGT+I,EACErW,MAAO,EAAG6B,EAAI,GACdzB,OAAQ,CAAEyG,MAAgC,MAAzBwP,EAAQxU,EAAI,GAAIR,KAAe,IAAM,MACtDuE,QAAS8D,EAAO,MAClB6K,EACA1S,EAAI4C,GAAKqT,GAAmBzB,EAAOrW,MAAO6B,EAAG4C,IAC7CA,EAAID,GAAOsT,GAAqBzB,EAASA,EAAOrW,MAAOyE,IACvDA,EAAID,GAAO8I,GAAY+I,IAGzBS,EAASxW,KAAMiU,GAIjB,OAAOsC,GAAgBC,GAoTxB,OAtpBA3C,GAAWlR,UAAYoE,EAAK+Q,QAAU/Q,EAAKkC,QAC3ClC,EAAK8M,WAAa,IAAIA,GAEtB3M,EAAWJ,GAAOI,SAAW,SAAU7E,EAAU0V,GAChD,IAAIhE,EAAS7H,EAAO6J,EAAQhV,EAC3BiX,EAAO7L,EAAQ8L,EACfC,EAAS9P,EAAY/F,EAAW,KAEjC,GAAK6V,EACJ,OAAOH,EAAY,EAAIG,EAAOxY,MAAO,GAGtCsY,EAAQ3V,EACR8J,EAAS,GACT8L,EAAalR,EAAKqL,UAElB,MAAQ4F,EAAQ,CA2Bf,IAAMjX,KAxBAgT,KAAa7H,EAAQ7C,EAAOkD,KAAMyL,MAClC9L,IAGJ8L,EAAQA,EAAMtY,MAAOwM,EAAO,GAAIxJ,SAAYsV,GAE7C7L,EAAOnM,KAAQ+V,EAAS,KAGzBhC,GAAU,GAGH7H,EAAQ5C,EAAaiD,KAAMyL,MACjCjE,EAAU7H,EAAMuB,QAChBsI,EAAO/V,KAAM,CACZuG,MAAOwN,EAGPhT,KAAMmL,EAAO,GAAI5G,QAAS8D,EAAO,OAElC4O,EAAQA,EAAMtY,MAAOqU,EAAQrR,SAIhBqE,EAAK2I,SACXxD,EAAQxC,EAAW3I,GAAOwL,KAAMyL,KAAgBC,EAAYlX,MAChEmL,EAAQ+L,EAAYlX,GAAQmL,MAC9B6H,EAAU7H,EAAMuB,QAChBsI,EAAO/V,KAAM,CACZuG,MAAOwN,EACPhT,KAAMA,EACNqF,QAAS8F,IAEV8L,EAAQA,EAAMtY,MAAOqU,EAAQrR,SAI/B,IAAMqR,EACL,MAOF,OAAOgE,EACNC,EAAMtV,OACNsV,EACClR,GAAOtB,MAAOnD,GAGd+F,EAAY/F,EAAU8J,GAASzM,MAAO,IA4ZzCyH,EAAUL,GAAOK,QAAU,SAAU9E,EAAU6J,GAC9C,IAAI3K,EA9H8B4W,EAAiBC,EAC/CC,EACHC,EACAC,EA4HAH,EAAc,GACdD,EAAkB,GAClBD,EAAS7P,EAAehG,EAAW,KAEpC,IAAM6V,EAAS,CAGRhM,IACLA,EAAQhF,EAAU7E,IAEnBd,EAAI2K,EAAMxJ,OACV,MAAQnB,KACP2W,EAASV,GAAmBtL,EAAO3K,KACtB4D,GACZiT,EAAYpY,KAAMkY,GAElBC,EAAgBnY,KAAMkY,IAKxBA,EAAS7P,EACRhG,GArJgC8V,EAsJNA,EArJxBE,EAA6B,GADkBD,EAsJNA,GArJrB1V,OACvB4V,EAAqC,EAAzBH,EAAgBzV,OAC5B6V,EAAe,SAAUxM,EAAMzJ,EAAS4Q,EAAKlN,EAASwS,GACrD,IAAI/U,EAAMU,EAAG8P,EACZwE,EAAe,EACflX,EAAI,IACJ2S,EAAYnI,GAAQ,GACpB2M,EAAa,GACbC,EAAgBtR,EAGhBnE,EAAQ6I,GAAQuM,GAAavR,EAAK6I,KAAY,IAAG,IAAK4I,GAGtDI,EAAkB5Q,GAA4B,MAAjB2Q,EAAwB,EAAIvT,KAAKC,UAAY,GAC1EnB,EAAMhB,EAAMR,OAcb,IAZK8V,IAMJnR,EAAmB/E,GAAWtD,GAAYsD,GAAWkW,GAM9CjX,IAAM2C,GAAgC,OAAvBT,EAAOP,EAAO3B,IAAeA,IAAM,CACzD,GAAK+W,GAAa7U,EAAO,CACxBU,EAAI,EAME7B,GAAWmB,EAAK6I,eAAiBtN,IACtCwI,EAAa/D,GACbyP,GAAOxL,GAER,MAAUuM,EAAUkE,EAAiBhU,KACpC,GAAK8P,EAASxQ,EAAMnB,GAAWtD,EAAUkU,GAAQ,CAChDlN,EAAQhG,KAAMyD,GACd,MAGG+U,IACJxQ,EAAU4Q,GAKPP,KAGG5U,GAAQwQ,GAAWxQ,IACzBgV,IAII1M,GACJmI,EAAUlU,KAAMyD,IAgBnB,GATAgV,GAAgBlX,EASX8W,GAAS9W,IAAMkX,EAAe,CAClCtU,EAAI,EACJ,MAAU8P,EAAUmE,EAAajU,KAChC8P,EAASC,EAAWwE,EAAYpW,EAAS4Q,GAG1C,GAAKnH,EAAO,CAGX,GAAoB,EAAf0M,EACJ,MAAQlX,IACC2S,EAAW3S,IAAOmX,EAAYnX,KACrCmX,EAAYnX,GAAMmH,EAAI7I,KAAMmG,IAM/B0S,EAAajC,GAAUiC,GAIxB1Y,EAAKD,MAAOiG,EAAS0S,GAGhBF,IAAczM,GAA4B,EAApB2M,EAAWhW,QACG,EAAtC+V,EAAeL,EAAY1V,QAE7BoE,GAAOwK,WAAYtL,GAUrB,OALKwS,IACJxQ,EAAU4Q,EACVvR,EAAmBsR,GAGbzE,GAGFmE,EACN3K,GAAc6K,GACdA,KAgCOlW,SAAWA,EAEnB,OAAO6V,GAYR9Q,EAASN,GAAOM,OAAS,SAAU/E,EAAUC,EAAS0D,EAAS+F,GAC9D,IAAIxK,EAAGwU,EAAQ8C,EAAO9X,EAAM6O,EAC3BkJ,EAA+B,mBAAbzW,GAA2BA,EAC7C6J,GAASH,GAAQ7E,EAAY7E,EAAWyW,EAASzW,UAAYA,GAM9D,GAJA2D,EAAUA,GAAW,GAIC,IAAjBkG,EAAMxJ,OAAe,CAIzB,GAAqB,GADrBqT,EAAS7J,EAAO,GAAMA,EAAO,GAAIxM,MAAO,IAC5BgD,QAA+C,QAA/BmW,EAAQ9C,EAAQ,IAAMhV,MAC5B,IAArBuB,EAAQ3B,UAAkB+G,GAAkBX,EAAKgL,SAAUgE,EAAQ,GAAIhV,MAAS,CAIhF,KAFAuB,GAAYyE,EAAK6I,KAAW,GAAGiJ,EAAMzS,QAAS,GAC5Cd,QAASmF,GAAWC,IAAapI,IAAa,IAAM,IAErD,OAAO0D,EAGI8S,IACXxW,EAAUA,EAAQN,YAGnBK,EAAWA,EAAS3C,MAAOqW,EAAOtI,QAAQlH,MAAM7D,QAIjDnB,EAAImI,EAA0B,aAAEmD,KAAMxK,GAAa,EAAI0T,EAAOrT,OAC9D,MAAQnB,IAAM,CAIb,GAHAsX,EAAQ9C,EAAQxU,GAGXwF,EAAKgL,SAAYhR,EAAO8X,EAAM9X,MAClC,MAED,IAAO6O,EAAO7I,EAAK6I,KAAM7O,MAGjBgL,EAAO6D,EACbiJ,EAAMzS,QAAS,GAAId,QAASmF,GAAWC,IACvCF,GAASqC,KAAMkJ,EAAQ,GAAIhV,OAAU+L,GAAaxK,EAAQN,aACzDM,IACI,CAKL,GAFAyT,EAAOzR,OAAQ/C,EAAG,KAClBc,EAAW0J,EAAKrJ,QAAUsK,GAAY+I,IAGrC,OADA/V,EAAKD,MAAOiG,EAAS+F,GACd/F,EAGR,QAeJ,OAPE8S,GAAY3R,EAAS9E,EAAU6J,IAChCH,EACAzJ,GACCoF,EACD1B,GACC1D,GAAWkI,GAASqC,KAAMxK,IAAcyK,GAAaxK,EAAQN,aAAgBM,GAExE0D,GAMRxF,EAAQiR,WAAatM,EAAQwB,MAAO,IAAKtC,KAAMkE,GAAY0E,KAAM,MAAS9H,EAI1E3E,EAAQgR,mBAAqBjK,EAG7BC,IAIAhH,EAAQoQ,aAAejD,GAAQ,SAAUC,GAGxC,OAA4E,EAArEA,EAAG4C,wBAAyBxR,EAAS0C,cAAe,eAMtDiM,GAAQ,SAAUC,GAEvB,OADAA,EAAGqC,UAAY,mBACiC,MAAzCrC,EAAG+D,WAAW/P,aAAc,WAEnCiM,GAAW,yBAA0B,SAAUpK,EAAMgB,EAAMwC,GAC1D,IAAMA,EACL,OAAOxD,EAAK7B,aAAc6C,EAA6B,SAAvBA,EAAKoC,cAA2B,EAAI,KAOjErG,EAAQwI,YAAe2E,GAAQ,SAAUC,GAG9C,OAFAA,EAAGqC,UAAY,WACfrC,EAAG+D,WAAW9P,aAAc,QAAS,IACY,KAA1C+L,EAAG+D,WAAW/P,aAAc,YAEnCiM,GAAW,QAAS,SAAUpK,EAAMsV,EAAO9R,GAC1C,IAAMA,GAAyC,UAAhCxD,EAAKgI,SAAS5E,cAC5B,OAAOpD,EAAKuV,eAOTrL,GAAQ,SAAUC,GACvB,OAAwC,MAAjCA,EAAGhM,aAAc,eAExBiM,GAAWhF,EAAU,SAAUpF,EAAMgB,EAAMwC,GAC1C,IAAIzF,EACJ,IAAMyF,EACL,OAAwB,IAAjBxD,EAAMgB,GAAkBA,EAAKoC,eACjCrF,EAAMiC,EAAKoM,iBAAkBpL,KAAYjD,EAAI4P,UAC9C5P,EAAI+E,MACJ,OAKEO,GA14EP,CA44EK3H,GAILiD,EAAOwN,KAAO9I,EACd1E,EAAO6O,KAAOnK,EAAO+K,UAGrBzP,EAAO6O,KAAM,KAAQ7O,EAAO6O,KAAKhI,QACjC7G,EAAOkP,WAAalP,EAAO6W,OAASnS,EAAOwK,WAC3ClP,EAAOT,KAAOmF,EAAOE,QACrB5E,EAAO8W,SAAWpS,EAAOG,MACzB7E,EAAOyF,SAAWf,EAAOe,SACzBzF,EAAO+W,eAAiBrS,EAAO6D,OAK/B,IAAIe,EAAM,SAAUjI,EAAMiI,EAAK0N,GAC9B,IAAIrF,EAAU,GACbsF,OAAqBnU,IAAVkU,EAEZ,OAAU3V,EAAOA,EAAMiI,KAA6B,IAAlBjI,EAAK9C,SACtC,GAAuB,IAAlB8C,EAAK9C,SAAiB,CAC1B,GAAK0Y,GAAYjX,EAAQqB,GAAO6V,GAAIF,GACnC,MAEDrF,EAAQ/T,KAAMyD,GAGhB,OAAOsQ,GAIJwF,EAAW,SAAUC,EAAG/V,GAG3B,IAFA,IAAIsQ,EAAU,GAENyF,EAAGA,EAAIA,EAAEnL,YACI,IAAfmL,EAAE7Y,UAAkB6Y,IAAM/V,GAC9BsQ,EAAQ/T,KAAMwZ,GAIhB,OAAOzF,GAIJ0F,EAAgBrX,EAAO6O,KAAK/E,MAAMhC,aAItC,SAASuB,EAAUhI,EAAMgB,GAExB,OAAOhB,EAAKgI,UAAYhI,EAAKgI,SAAS5E,gBAAkBpC,EAAKoC,cAG9D,IAAI6S,EAAa,kEAKjB,SAASC,EAAQzI,EAAU0I,EAAW5F,GACrC,OAAKvT,EAAYmZ,GACTxX,EAAO2B,KAAMmN,EAAU,SAAUzN,EAAMlC,GAC7C,QAASqY,EAAU/Z,KAAM4D,EAAMlC,EAAGkC,KAAWuQ,IAK1C4F,EAAUjZ,SACPyB,EAAO2B,KAAMmN,EAAU,SAAUzN,GACvC,OAASA,IAASmW,IAAgB5F,IAKV,iBAAd4F,EACJxX,EAAO2B,KAAMmN,EAAU,SAAUzN,GACvC,OAA4C,EAAnCxD,EAAQJ,KAAM+Z,EAAWnW,KAAkBuQ,IAK/C5R,EAAOsN,OAAQkK,EAAW1I,EAAU8C,GAG5C5R,EAAOsN,OAAS,SAAUuB,EAAM/N,EAAO8Q,GACtC,IAAIvQ,EAAOP,EAAO,GAMlB,OAJK8Q,IACJ/C,EAAO,QAAUA,EAAO,KAGH,IAAjB/N,EAAMR,QAAkC,IAAlBe,EAAK9C,SACxByB,EAAOwN,KAAKM,gBAAiBzM,EAAMwN,GAAS,CAAExN,GAAS,GAGxDrB,EAAOwN,KAAKxJ,QAAS6K,EAAM7O,EAAO2B,KAAMb,EAAO,SAAUO,GAC/D,OAAyB,IAAlBA,EAAK9C,aAIdyB,EAAOG,GAAGgC,OAAQ,CACjBqL,KAAM,SAAUvN,GACf,IAAId,EAAG4B,EACNe,EAAM9E,KAAKsD,OACXmX,EAAOza,KAER,GAAyB,iBAAbiD,EACX,OAAOjD,KAAK6D,UAAWb,EAAQC,GAAWqN,OAAQ,WACjD,IAAMnO,EAAI,EAAGA,EAAI2C,EAAK3C,IACrB,GAAKa,EAAOyF,SAAUgS,EAAMtY,GAAKnC,MAChC,OAAO,KAQX,IAFA+D,EAAM/D,KAAK6D,UAAW,IAEhB1B,EAAI,EAAGA,EAAI2C,EAAK3C,IACrBa,EAAOwN,KAAMvN,EAAUwX,EAAMtY,GAAK4B,GAGnC,OAAa,EAANe,EAAU9B,EAAOkP,WAAYnO,GAAQA,GAE7CuM,OAAQ,SAAUrN,GACjB,OAAOjD,KAAK6D,UAAW0W,EAAQva,KAAMiD,GAAY,IAAI,KAEtD2R,IAAK,SAAU3R,GACd,OAAOjD,KAAK6D,UAAW0W,EAAQva,KAAMiD,GAAY,IAAI,KAEtDiX,GAAI,SAAUjX,GACb,QAASsX,EACRva,KAIoB,iBAAbiD,GAAyBoX,EAAc5M,KAAMxK,GACnDD,EAAQC,GACRA,GAAY,IACb,GACCK,UASJ,IAAIoX,EAMHvP,EAAa,uCAENnI,EAAOG,GAAGC,KAAO,SAAUH,EAAUC,EAASkS,GACpD,IAAItI,EAAOzI,EAGX,IAAMpB,EACL,OAAOjD,KAQR,GAHAoV,EAAOA,GAAQsF,EAGU,iBAAbzX,EAAwB,CAanC,KAPC6J,EALsB,MAAlB7J,EAAU,IACsB,MAApCA,EAAUA,EAASK,OAAS,IACT,GAAnBL,EAASK,OAGD,CAAE,KAAML,EAAU,MAGlBkI,EAAWgC,KAAMlK,MAIV6J,EAAO,IAAQ5J,EA6CxB,OAAMA,GAAWA,EAAQM,QACtBN,GAAWkS,GAAO5E,KAAMvN,GAK1BjD,KAAKyD,YAAaP,GAAUsN,KAAMvN,GAhDzC,GAAK6J,EAAO,GAAM,CAYjB,GAXA5J,EAAUA,aAAmBF,EAASE,EAAS,GAAMA,EAIrDF,EAAOgB,MAAOhE,KAAMgD,EAAO2X,UAC1B7N,EAAO,GACP5J,GAAWA,EAAQ3B,SAAW2B,EAAQgK,eAAiBhK,EAAUtD,GACjE,IAII0a,EAAW7M,KAAMX,EAAO,KAAS9J,EAAO2C,cAAezC,GAC3D,IAAM4J,KAAS5J,EAGT7B,EAAYrB,KAAM8M,IACtB9M,KAAM8M,GAAS5J,EAAS4J,IAIxB9M,KAAK+R,KAAMjF,EAAO5J,EAAS4J,IAK9B,OAAO9M,KAYP,OARAqE,EAAOzE,EAASwN,eAAgBN,EAAO,OAKtC9M,KAAM,GAAMqE,EACZrE,KAAKsD,OAAS,GAERtD,KAcH,OAAKiD,EAAS1B,UACpBvB,KAAM,GAAMiD,EACZjD,KAAKsD,OAAS,EACPtD,MAIIqB,EAAY4B,QACD6C,IAAfsP,EAAKwF,MACXxF,EAAKwF,MAAO3X,GAGZA,EAAUD,GAGLA,EAAO2D,UAAW1D,EAAUjD,QAIhCuD,UAAYP,EAAOG,GAGxBuX,EAAa1X,EAAQpD,GAGrB,IAAIib,EAAe,iCAGlBC,EAAmB,CAClBC,UAAU,EACVC,UAAU,EACVzO,MAAM,EACN0O,MAAM,GAoFR,SAASC,EAASpM,EAAKxC,GACtB,OAAUwC,EAAMA,EAAKxC,KAA4B,IAAjBwC,EAAIvN,UACpC,OAAOuN,EAnFR9L,EAAOG,GAAGgC,OAAQ,CACjB4P,IAAK,SAAUtP,GACd,IAAI0V,EAAUnY,EAAQyC,EAAQzF,MAC7Bob,EAAID,EAAQ7X,OAEb,OAAOtD,KAAKsQ,OAAQ,WAEnB,IADA,IAAInO,EAAI,EACAA,EAAIiZ,EAAGjZ,IACd,GAAKa,EAAOyF,SAAUzI,KAAMmb,EAAShZ,IACpC,OAAO,KAMXkZ,QAAS,SAAU5I,EAAWvP,GAC7B,IAAI4L,EACH3M,EAAI,EACJiZ,EAAIpb,KAAKsD,OACTqR,EAAU,GACVwG,EAA+B,iBAAd1I,GAA0BzP,EAAQyP,GAGpD,IAAM4H,EAAc5M,KAAMgF,GACzB,KAAQtQ,EAAIiZ,EAAGjZ,IACd,IAAM2M,EAAM9O,KAAMmC,GAAK2M,GAAOA,IAAQ5L,EAAS4L,EAAMA,EAAIlM,WAGxD,GAAKkM,EAAIvN,SAAW,KAAQ4Z,GACH,EAAxBA,EAAQG,MAAOxM,GAGE,IAAjBA,EAAIvN,UACHyB,EAAOwN,KAAKM,gBAAiBhC,EAAK2D,IAAgB,CAEnDkC,EAAQ/T,KAAMkO,GACd,MAMJ,OAAO9O,KAAK6D,UAA4B,EAAjB8Q,EAAQrR,OAAaN,EAAOkP,WAAYyC,GAAYA,IAI5E2G,MAAO,SAAUjX,GAGhB,OAAMA,EAKe,iBAATA,EACJxD,EAAQJ,KAAMuC,EAAQqB,GAAQrE,KAAM,IAIrCa,EAAQJ,KAAMT,KAGpBqE,EAAKb,OAASa,EAAM,GAAMA,GAZjBrE,KAAM,IAAOA,KAAM,GAAI4C,WAAe5C,KAAKuE,QAAQgX,UAAUjY,QAAU,GAgBlFkY,IAAK,SAAUvY,EAAUC,GACxB,OAAOlD,KAAK6D,UACXb,EAAOkP,WACNlP,EAAOgB,MAAOhE,KAAK2D,MAAOX,EAAQC,EAAUC,OAK/CuY,QAAS,SAAUxY,GAClB,OAAOjD,KAAKwb,IAAiB,MAAZvY,EAChBjD,KAAKiE,WAAajE,KAAKiE,WAAWqM,OAAQrN,OAU7CD,EAAOkB,KAAM,CACZiQ,OAAQ,SAAU9P,GACjB,IAAI8P,EAAS9P,EAAKzB,WAClB,OAAOuR,GAA8B,KAApBA,EAAO5S,SAAkB4S,EAAS,MAEpDuH,QAAS,SAAUrX,GAClB,OAAOiI,EAAKjI,EAAM,eAEnBsX,aAAc,SAAUtX,EAAMmD,EAAIwS,GACjC,OAAO1N,EAAKjI,EAAM,aAAc2V,IAEjCzN,KAAM,SAAUlI,GACf,OAAO6W,EAAS7W,EAAM,gBAEvB4W,KAAM,SAAU5W,GACf,OAAO6W,EAAS7W,EAAM,oBAEvBuX,QAAS,SAAUvX,GAClB,OAAOiI,EAAKjI,EAAM,gBAEnBkX,QAAS,SAAUlX,GAClB,OAAOiI,EAAKjI,EAAM,oBAEnBwX,UAAW,SAAUxX,EAAMmD,EAAIwS,GAC9B,OAAO1N,EAAKjI,EAAM,cAAe2V,IAElC8B,UAAW,SAAUzX,EAAMmD,EAAIwS,GAC9B,OAAO1N,EAAKjI,EAAM,kBAAmB2V,IAEtCG,SAAU,SAAU9V,GACnB,OAAO8V,GAAY9V,EAAKzB,YAAc,IAAK2P,WAAYlO,IAExD0W,SAAU,SAAU1W,GACnB,OAAO8V,EAAU9V,EAAKkO,aAEvByI,SAAU,SAAU3W,GACnB,OAA6B,MAAxBA,EAAK0X,iBAKT5b,EAAUkE,EAAK0X,iBAER1X,EAAK0X,iBAMR1P,EAAUhI,EAAM,cACpBA,EAAOA,EAAK2X,SAAW3X,GAGjBrB,EAAOgB,MAAO,GAAIK,EAAKmI,eAE7B,SAAUnH,EAAMlC,GAClBH,EAAOG,GAAIkC,GAAS,SAAU2U,EAAO/W,GACpC,IAAI0R,EAAU3R,EAAOoB,IAAKpE,KAAMmD,EAAI6W,GAuBpC,MArB0B,UAArB3U,EAAK/E,OAAQ,KACjB2C,EAAW+W,GAGP/W,GAAgC,iBAAbA,IACvB0R,EAAU3R,EAAOsN,OAAQrN,EAAU0R,IAGjB,EAAd3U,KAAKsD,SAGHwX,EAAkBzV,IACvBrC,EAAOkP,WAAYyC,GAIfkG,EAAapN,KAAMpI,IACvBsP,EAAQsH,WAIHjc,KAAK6D,UAAW8Q,MAGzB,IAAIuH,EAAgB,oBAsOpB,SAASC,EAAUC,GAClB,OAAOA,EAER,SAASC,EAASC,GACjB,MAAMA,EAGP,SAASC,EAAYpV,EAAOqV,EAASC,EAAQC,GAC5C,IAAIC,EAEJ,IAGMxV,GAAS9F,EAAcsb,EAASxV,EAAMyV,SAC1CD,EAAOlc,KAAM0G,GAAQ0B,KAAM2T,GAAUK,KAAMJ,GAGhCtV,GAAS9F,EAAcsb,EAASxV,EAAM2V,MACjDH,EAAOlc,KAAM0G,EAAOqV,EAASC,GAQ7BD,EAAQ7b,WAAOmF,EAAW,CAAEqB,GAAQ7G,MAAOoc,IAM3C,MAAQvV,GAITsV,EAAO9b,WAAOmF,EAAW,CAAEqB,KAvO7BnE,EAAO+Z,UAAY,SAAU3X,GA9B7B,IAAwBA,EACnB4X,EAiCJ5X,EAA6B,iBAAZA,GAlCMA,EAmCPA,EAlCZ4X,EAAS,GACbha,EAAOkB,KAAMkB,EAAQ0H,MAAOoP,IAAmB,GAAI,SAAUe,EAAGC,GAC/DF,EAAQE,IAAS,IAEXF,GA+BNha,EAAOmC,OAAQ,GAAIC,GAEpB,IACC+X,EAGAC,EAGAC,EAGAC,EAGA9T,EAAO,GAGP+T,EAAQ,GAGRC,GAAe,EAGfC,EAAO,WAQN,IALAH,EAASA,GAAUlY,EAAQsY,KAI3BL,EAAQF,GAAS,EACTI,EAAMja,OAAQka,GAAe,EAAI,CACxCJ,EAASG,EAAMlP,QACf,QAAUmP,EAAchU,EAAKlG,QAGmC,IAA1DkG,EAAMgU,GAAc7c,MAAOyc,EAAQ,GAAKA,EAAQ,KACpDhY,EAAQuY,cAGRH,EAAchU,EAAKlG,OACnB8Z,GAAS,GAMNhY,EAAQgY,SACbA,GAAS,GAGVD,GAAS,EAGJG,IAIH9T,EADI4T,EACG,GAIA,KAMV3C,EAAO,CAGNe,IAAK,WA2BJ,OA1BKhS,IAGC4T,IAAWD,IACfK,EAAchU,EAAKlG,OAAS,EAC5Bia,EAAM3c,KAAMwc,IAGb,SAAW5B,EAAKhH,GACfxR,EAAOkB,KAAMsQ,EAAM,SAAUyI,EAAG/V,GAC1B7F,EAAY6F,GACV9B,EAAQyU,QAAWY,EAAK1F,IAAK7N,IAClCsC,EAAK5I,KAAMsG,GAEDA,GAAOA,EAAI5D,QAA4B,WAAlBR,EAAQoE,IAGxCsU,EAAKtU,KATR,CAYK5C,WAEA8Y,IAAWD,GACfM,KAGKzd,MAIR4d,OAAQ,WAYP,OAXA5a,EAAOkB,KAAMI,UAAW,SAAU2Y,EAAG/V,GACpC,IAAIoU,EACJ,OAA0D,GAAhDA,EAAQtY,EAAO6D,QAASK,EAAKsC,EAAM8R,IAC5C9R,EAAKtE,OAAQoW,EAAO,GAGfA,GAASkC,GACbA,MAIIxd,MAKR+U,IAAK,SAAU5R,GACd,OAAOA,GACwB,EAA9BH,EAAO6D,QAAS1D,EAAIqG,GACN,EAAdA,EAAKlG,QAIPwS,MAAO,WAIN,OAHKtM,IACJA,EAAO,IAEDxJ,MAMR6d,QAAS,WAGR,OAFAP,EAASC,EAAQ,GACjB/T,EAAO4T,EAAS,GACTpd,MAERoM,SAAU,WACT,OAAQ5C,GAMTsU,KAAM,WAKL,OAJAR,EAASC,EAAQ,GACXH,GAAWD,IAChB3T,EAAO4T,EAAS,IAEVpd,MAERsd,OAAQ,WACP,QAASA,GAIVS,SAAU,SAAU7a,EAASsR,GAS5B,OARM8I,IAEL9I,EAAO,CAAEtR,GADTsR,EAAOA,GAAQ,IACQlU,MAAQkU,EAAKlU,QAAUkU,GAC9C+I,EAAM3c,KAAM4T,GACN2I,GACLM,KAGKzd,MAIRyd,KAAM,WAEL,OADAhD,EAAKsD,SAAU/d,KAAMsE,WACdtE,MAIRqd,MAAO,WACN,QAASA,IAIZ,OAAO5C,GA4CRzX,EAAOmC,OAAQ,CAEd6Y,SAAU,SAAUC,GACnB,IAAIC,EAAS,CAIX,CAAE,SAAU,WAAYlb,EAAO+Z,UAAW,UACzC/Z,EAAO+Z,UAAW,UAAY,GAC/B,CAAE,UAAW,OAAQ/Z,EAAO+Z,UAAW,eACtC/Z,EAAO+Z,UAAW,eAAiB,EAAG,YACvC,CAAE,SAAU,OAAQ/Z,EAAO+Z,UAAW,eACrC/Z,EAAO+Z,UAAW,eAAiB,EAAG,aAExCoB,EAAQ,UACRvB,EAAU,CACTuB,MAAO,WACN,OAAOA,GAERC,OAAQ,WAEP,OADAC,EAASxV,KAAMvE,WAAYuY,KAAMvY,WAC1BtE,MAERse,QAAS,SAAUnb,GAClB,OAAOyZ,EAAQE,KAAM,KAAM3Z,IAI5Bob,KAAM,WACL,IAAIC,EAAMla,UAEV,OAAOtB,EAAOgb,SAAU,SAAUS,GACjCzb,EAAOkB,KAAMga,EAAQ,SAAU1W,EAAIkX,GAGlC,IAAIvb,EAAK9B,EAAYmd,EAAKE,EAAO,MAAWF,EAAKE,EAAO,IAKxDL,EAAUK,EAAO,IAAO,WACvB,IAAIC,EAAWxb,GAAMA,EAAGxC,MAAOX,KAAMsE,WAChCqa,GAAYtd,EAAYsd,EAAS/B,SACrC+B,EAAS/B,UACPgC,SAAUH,EAASI,QACnBhW,KAAM4V,EAASjC,SACfK,KAAM4B,EAAShC,QAEjBgC,EAAUC,EAAO,GAAM,QACtB1e,KACAmD,EAAK,CAAEwb,GAAara,eAKxBka,EAAM,OACH5B,WAELE,KAAM,SAAUgC,EAAaC,EAAYC,GACxC,IAAIC,EAAW,EACf,SAASzC,EAAS0C,EAAOb,EAAU1P,EAASwQ,GAC3C,OAAO,WACN,IAAIC,EAAOpf,KACVwU,EAAOlQ,UACP+a,EAAa,WACZ,IAAIV,EAAU7B,EAKd,KAAKoC,EAAQD,GAAb,CAQA,IAJAN,EAAWhQ,EAAQhO,MAAOye,EAAM5K,MAId6J,EAASzB,UAC1B,MAAM,IAAI0C,UAAW,4BAOtBxC,EAAO6B,IAKgB,iBAAbA,GACY,mBAAbA,IACRA,EAAS7B,KAGLzb,EAAYyb,GAGXqC,EACJrC,EAAKrc,KACJke,EACAnC,EAASyC,EAAUZ,EAAUlC,EAAUgD,GACvC3C,EAASyC,EAAUZ,EAAUhC,EAAS8C,KAOvCF,IAEAnC,EAAKrc,KACJke,EACAnC,EAASyC,EAAUZ,EAAUlC,EAAUgD,GACvC3C,EAASyC,EAAUZ,EAAUhC,EAAS8C,GACtC3C,EAASyC,EAAUZ,EAAUlC,EAC5BkC,EAASkB,eASP5Q,IAAYwN,IAChBiD,OAAOtZ,EACP0O,EAAO,CAAEmK,KAKRQ,GAAWd,EAASmB,aAAeJ,EAAM5K,MAK7CiL,EAAUN,EACTE,EACA,WACC,IACCA,IACC,MAAQ5S,GAEJzJ,EAAOgb,SAAS0B,eACpB1c,EAAOgb,SAAS0B,cAAejT,EAC9BgT,EAAQE,YAMQV,GAAbC,EAAQ,IAIPvQ,IAAY0N,IAChB+C,OAAOtZ,EACP0O,EAAO,CAAE/H,IAGV4R,EAASuB,WAAYR,EAAM5K,MAS3B0K,EACJO,KAKKzc,EAAOgb,SAAS6B,eACpBJ,EAAQE,WAAa3c,EAAOgb,SAAS6B,gBAEtC9f,EAAO+f,WAAYL,KAKtB,OAAOzc,EAAOgb,SAAU,SAAUS,GAGjCP,EAAQ,GAAK,GAAI1C,IAChBgB,EACC,EACAiC,EACApd,EAAY2d,GACXA,EACA7C,EACDsC,EAASc,aAKXrB,EAAQ,GAAK,GAAI1C,IAChBgB,EACC,EACAiC,EACApd,EAAYyd,GACXA,EACA3C,IAKH+B,EAAQ,GAAK,GAAI1C,IAChBgB,EACC,EACAiC,EACApd,EAAY0d,GACXA,EACA1C,MAGAO,WAKLA,QAAS,SAAUtb,GAClB,OAAc,MAAPA,EAAc0B,EAAOmC,OAAQ7D,EAAKsb,GAAYA,IAGvDyB,EAAW,GAkEZ,OA/DArb,EAAOkB,KAAMga,EAAQ,SAAU/b,EAAGuc,GACjC,IAAIlV,EAAOkV,EAAO,GACjBqB,EAAcrB,EAAO,GAKtB9B,EAAS8B,EAAO,IAAQlV,EAAKgS,IAGxBuE,GACJvW,EAAKgS,IACJ,WAIC2C,EAAQ4B,GAKT7B,EAAQ,EAAI/b,GAAK,GAAI0b,QAIrBK,EAAQ,EAAI/b,GAAK,GAAI0b,QAGrBK,EAAQ,GAAK,GAAIJ,KAGjBI,EAAQ,GAAK,GAAIJ,MAOnBtU,EAAKgS,IAAKkD,EAAO,GAAIjB,MAKrBY,EAAUK,EAAO,IAAQ,WAExB,OADAL,EAAUK,EAAO,GAAM,QAAU1e,OAASqe,OAAWvY,EAAY9F,KAAMsE,WAChEtE,MAMRqe,EAAUK,EAAO,GAAM,QAAWlV,EAAKuU,WAIxCnB,EAAQA,QAASyB,GAGZJ,GACJA,EAAKxd,KAAM4d,EAAUA,GAIfA,GAIR2B,KAAM,SAAUC,GACf,IAGCC,EAAY5b,UAAUhB,OAGtBnB,EAAI+d,EAGJC,EAAkBva,MAAOzD,GACzBie,EAAgB9f,EAAMG,KAAM6D,WAG5B+b,EAAUrd,EAAOgb,WAGjBsC,EAAa,SAAUne,GACtB,OAAO,SAAUgF,GAChBgZ,EAAiBhe,GAAMnC,KACvBogB,EAAeje,GAAyB,EAAnBmC,UAAUhB,OAAahD,EAAMG,KAAM6D,WAAc6C,IAC5D+Y,GACTG,EAAQb,YAAaW,EAAiBC,KAM1C,GAAKF,GAAa,IACjB3D,EAAY0D,EAAaI,EAAQxX,KAAMyX,EAAYne,IAAMqa,QAAS6D,EAAQ5D,QACxEyD,GAGuB,YAApBG,EAAQlC,SACZ9c,EAAY+e,EAAeje,IAAOie,EAAeje,GAAI2a,OAErD,OAAOuD,EAAQvD,OAKjB,MAAQ3a,IACPoa,EAAY6D,EAAeje,GAAKme,EAAYne,GAAKke,EAAQ5D,QAG1D,OAAO4D,EAAQzD,aAOjB,IAAI2D,EAAc,yDAElBvd,EAAOgb,SAAS0B,cAAgB,SAAUtZ,EAAOoa,GAI3CzgB,EAAO0gB,SAAW1gB,EAAO0gB,QAAQC,MAAQta,GAASma,EAAY9S,KAAMrH,EAAMf,OAC9EtF,EAAO0gB,QAAQC,KAAM,8BAAgCta,EAAMua,QAASva,EAAMoa,MAAOA,IAOnFxd,EAAO4d,eAAiB,SAAUxa,GACjCrG,EAAO+f,WAAY,WAClB,MAAM1Z,KAQR,IAAIya,EAAY7d,EAAOgb,WAkDvB,SAAS8C,IACRlhB,EAASmhB,oBAAqB,mBAAoBD,GAClD/gB,EAAOghB,oBAAqB,OAAQD,GACpC9d,EAAO4X,QAnDR5X,EAAOG,GAAGyX,MAAQ,SAAUzX,GAY3B,OAVA0d,EACE/D,KAAM3Z,GAKNmb,SAAO,SAAUlY,GACjBpD,EAAO4d,eAAgBxa,KAGlBpG,MAGRgD,EAAOmC,OAAQ,CAGdgB,SAAS,EAIT6a,UAAW,EAGXpG,MAAO,SAAUqG,KAGF,IAATA,IAAkBje,EAAOge,UAAYhe,EAAOmD,WAKjDnD,EAAOmD,SAAU,KAGZ8a,GAAsC,IAAnBje,EAAOge,WAK/BH,EAAUrB,YAAa5f,EAAU,CAAEoD,OAIrCA,EAAO4X,MAAMkC,KAAO+D,EAAU/D,KAaD,aAAxBld,EAASshB,YACa,YAAxBthB,EAASshB,aAA6BthB,EAAS+P,gBAAgBwR,SAGjEphB,EAAO+f,WAAY9c,EAAO4X,QAK1Bhb,EAASoQ,iBAAkB,mBAAoB8Q,GAG/C/gB,EAAOiQ,iBAAkB,OAAQ8Q,IAQlC,IAAIM,EAAS,SAAUtd,EAAOX,EAAIgL,EAAKhH,EAAOka,EAAWC,EAAUC,GAClE,IAAIpf,EAAI,EACP2C,EAAMhB,EAAMR,OACZke,EAAc,MAAPrT,EAGR,GAAuB,WAAlBrL,EAAQqL,GAEZ,IAAMhM,KADNkf,GAAY,EACDlT,EACViT,EAAQtd,EAAOX,EAAIhB,EAAGgM,EAAKhM,IAAK,EAAMmf,EAAUC,QAI3C,QAAezb,IAAVqB,IACXka,GAAY,EAENhgB,EAAY8F,KACjBoa,GAAM,GAGFC,IAGCD,GACJpe,EAAG1C,KAAMqD,EAAOqD,GAChBhE,EAAK,OAILqe,EAAOre,EACPA,EAAK,SAAUkB,EAAMod,EAAMta,GAC1B,OAAOqa,EAAK/gB,KAAMuC,EAAQqB,GAAQ8C,MAKhChE,GACJ,KAAQhB,EAAI2C,EAAK3C,IAChBgB,EACCW,EAAO3B,GAAKgM,EAAKoT,EAChBpa,EACAA,EAAM1G,KAAMqD,EAAO3B,GAAKA,EAAGgB,EAAIW,EAAO3B,GAAKgM,KAMhD,OAAKkT,EACGvd,EAIH0d,EACGre,EAAG1C,KAAMqD,GAGVgB,EAAM3B,EAAIW,EAAO,GAAKqK,GAAQmT,GAKlCI,EAAY,QACfC,EAAa,YAGd,SAASC,EAAYC,EAAMC,GAC1B,OAAOA,EAAOC,cAMf,SAASC,EAAWC,GACnB,OAAOA,EAAO/b,QAASwb,EAAW,OAAQxb,QAASyb,EAAYC,GAEhE,IAAIM,EAAa,SAAUC,GAQ1B,OAA0B,IAAnBA,EAAM5gB,UAAqC,IAAnB4gB,EAAM5gB,YAAsB4gB,EAAM5gB,UAMlE,SAAS6gB,IACRpiB,KAAK+F,QAAU/C,EAAO+C,QAAUqc,EAAKC,MAGtCD,EAAKC,IAAM,EAEXD,EAAK7e,UAAY,CAEhB2K,MAAO,SAAUiU,GAGhB,IAAIhb,EAAQgb,EAAOniB,KAAK+F,SA4BxB,OAzBMoB,IACLA,EAAQ,GAKH+a,EAAYC,KAIXA,EAAM5gB,SACV4gB,EAAOniB,KAAK+F,SAAYoB,EAMxB/G,OAAOkiB,eAAgBH,EAAOniB,KAAK+F,QAAS,CAC3CoB,MAAOA,EACPob,cAAc,MAMXpb,GAERqb,IAAK,SAAUL,EAAOM,EAAMtb,GAC3B,IAAIub,EACHxU,EAAQlO,KAAKkO,MAAOiU,GAIrB,GAAqB,iBAATM,EACXvU,EAAO8T,EAAWS,IAAWtb,OAM7B,IAAMub,KAAQD,EACbvU,EAAO8T,EAAWU,IAAWD,EAAMC,GAGrC,OAAOxU,GAERvK,IAAK,SAAUwe,EAAOhU,GACrB,YAAerI,IAARqI,EACNnO,KAAKkO,MAAOiU,GAGZA,EAAOniB,KAAK+F,UAAaoc,EAAOniB,KAAK+F,SAAWic,EAAW7T,KAE7DiT,OAAQ,SAAUe,EAAOhU,EAAKhH,GAa7B,YAAarB,IAARqI,GACCA,GAAsB,iBAARA,QAAgCrI,IAAVqB,EAElCnH,KAAK2D,IAAKwe,EAAOhU,IASzBnO,KAAKwiB,IAAKL,EAAOhU,EAAKhH,QAILrB,IAAVqB,EAAsBA,EAAQgH,IAEtCyP,OAAQ,SAAUuE,EAAOhU,GACxB,IAAIhM,EACH+L,EAAQiU,EAAOniB,KAAK+F,SAErB,QAAeD,IAAVoI,EAAL,CAIA,QAAapI,IAARqI,EAAoB,CAkBxBhM,GAXCgM,EAJIvI,MAAMC,QAASsI,GAIbA,EAAI/J,IAAK4d,IAEf7T,EAAM6T,EAAW7T,MAIJD,EACZ,CAAEC,GACAA,EAAIrB,MAAOoP,IAAmB,IAG1B5Y,OAER,MAAQnB,WACA+L,EAAOC,EAAKhM,UAKR2D,IAARqI,GAAqBnL,EAAOyD,cAAeyH,MAM1CiU,EAAM5gB,SACV4gB,EAAOniB,KAAK+F,cAAYD,SAEjBqc,EAAOniB,KAAK+F,YAItB4c,QAAS,SAAUR,GAClB,IAAIjU,EAAQiU,EAAOniB,KAAK+F,SACxB,YAAiBD,IAAVoI,IAAwBlL,EAAOyD,cAAeyH,KAGvD,IAAI0U,EAAW,IAAIR,EAEfS,EAAW,IAAIT,EAcfU,EAAS,gCACZC,EAAa,SA2Bd,SAASC,EAAU3e,EAAM8J,EAAKsU,GAC7B,IAAIpd,EA1Baod,EA8BjB,QAAc3c,IAAT2c,GAAwC,IAAlBpe,EAAK9C,SAI/B,GAHA8D,EAAO,QAAU8I,EAAIjI,QAAS6c,EAAY,OAAQtb,cAG7B,iBAFrBgb,EAAOpe,EAAK7B,aAAc6C,IAEM,CAC/B,IACCod,EAnCW,UADGA,EAoCEA,IA/BL,UAATA,IAIS,SAATA,EACG,KAIHA,KAAUA,EAAO,IACbA,EAGJK,EAAOrV,KAAMgV,GACVQ,KAAKC,MAAOT,GAGbA,GAeH,MAAQhW,IAGVoW,EAASL,IAAKne,EAAM8J,EAAKsU,QAEzBA,OAAO3c,EAGT,OAAO2c,EAGRzf,EAAOmC,OAAQ,CACdwd,QAAS,SAAUte,GAClB,OAAOwe,EAASF,QAASte,IAAUue,EAASD,QAASte,IAGtDoe,KAAM,SAAUpe,EAAMgB,EAAMod,GAC3B,OAAOI,EAASzB,OAAQ/c,EAAMgB,EAAMod,IAGrCU,WAAY,SAAU9e,EAAMgB,GAC3Bwd,EAASjF,OAAQvZ,EAAMgB,IAKxB+d,MAAO,SAAU/e,EAAMgB,EAAMod,GAC5B,OAAOG,EAASxB,OAAQ/c,EAAMgB,EAAMod,IAGrCY,YAAa,SAAUhf,EAAMgB,GAC5Bud,EAAShF,OAAQvZ,EAAMgB,MAIzBrC,EAAOG,GAAGgC,OAAQ,CACjBsd,KAAM,SAAUtU,EAAKhH,GACpB,IAAIhF,EAAGkD,EAAMod,EACZpe,EAAOrE,KAAM,GACb0O,EAAQrK,GAAQA,EAAKuF,WAGtB,QAAa9D,IAARqI,EAAoB,CACxB,GAAKnO,KAAKsD,SACTmf,EAAOI,EAASlf,IAAKU,GAEE,IAAlBA,EAAK9C,WAAmBqhB,EAASjf,IAAKU,EAAM,iBAAmB,CACnElC,EAAIuM,EAAMpL,OACV,MAAQnB,IAIFuM,EAAOvM,IAEsB,KADjCkD,EAAOqJ,EAAOvM,GAAIkD,MACRxE,QAAS,WAClBwE,EAAO2c,EAAW3c,EAAK/E,MAAO,IAC9B0iB,EAAU3e,EAAMgB,EAAMod,EAAMpd,KAI/Bud,EAASJ,IAAKne,EAAM,gBAAgB,GAItC,OAAOoe,EAIR,MAAoB,iBAARtU,EACJnO,KAAKkE,KAAM,WACjB2e,EAASL,IAAKxiB,KAAMmO,KAIfiT,EAAQphB,KAAM,SAAUmH,GAC9B,IAAIsb,EAOJ,GAAKpe,QAAkByB,IAAVqB,EAKZ,YAAcrB,KADd2c,EAAOI,EAASlf,IAAKU,EAAM8J,IAEnBsU,OAMM3c,KADd2c,EAAOO,EAAU3e,EAAM8J,IAEfsU,OAIR,EAIDziB,KAAKkE,KAAM,WAGV2e,EAASL,IAAKxiB,KAAMmO,EAAKhH,MAExB,KAAMA,EAA0B,EAAnB7C,UAAUhB,OAAY,MAAM,IAG7C6f,WAAY,SAAUhV,GACrB,OAAOnO,KAAKkE,KAAM,WACjB2e,EAASjF,OAAQ5d,KAAMmO,QAM1BnL,EAAOmC,OAAQ,CACdoY,MAAO,SAAUlZ,EAAM1C,EAAM8gB,GAC5B,IAAIlF,EAEJ,GAAKlZ,EAYJ,OAXA1C,GAASA,GAAQ,MAAS,QAC1B4b,EAAQqF,EAASjf,IAAKU,EAAM1C,GAGvB8gB,KACElF,GAAS3X,MAAMC,QAAS4c,GAC7BlF,EAAQqF,EAASxB,OAAQ/c,EAAM1C,EAAMqB,EAAO2D,UAAW8b,IAEvDlF,EAAM3c,KAAM6hB,IAGPlF,GAAS,IAIlB+F,QAAS,SAAUjf,EAAM1C,GACxBA,EAAOA,GAAQ,KAEf,IAAI4b,EAAQva,EAAOua,MAAOlZ,EAAM1C,GAC/B4hB,EAAchG,EAAMja,OACpBH,EAAKoa,EAAMlP,QACXmV,EAAQxgB,EAAOygB,YAAapf,EAAM1C,GAMvB,eAAPwB,IACJA,EAAKoa,EAAMlP,QACXkV,KAGIpgB,IAIU,OAATxB,GACJ4b,EAAM3L,QAAS,qBAIT4R,EAAME,KACbvgB,EAAG1C,KAAM4D,EApBF,WACNrB,EAAOsgB,QAASjf,EAAM1C,IAmBF6hB,KAGhBD,GAAeC,GACpBA,EAAM1N,MAAM2H,QAKdgG,YAAa,SAAUpf,EAAM1C,GAC5B,IAAIwM,EAAMxM,EAAO,aACjB,OAAOihB,EAASjf,IAAKU,EAAM8J,IAASyU,EAASxB,OAAQ/c,EAAM8J,EAAK,CAC/D2H,MAAO9S,EAAO+Z,UAAW,eAAgBvB,IAAK,WAC7CoH,EAAShF,OAAQvZ,EAAM,CAAE1C,EAAO,QAASwM,WAM7CnL,EAAOG,GAAGgC,OAAQ,CACjBoY,MAAO,SAAU5b,EAAM8gB,GACtB,IAAIkB,EAAS,EAQb,MANqB,iBAAThiB,IACX8gB,EAAO9gB,EACPA,EAAO,KACPgiB,KAGIrf,UAAUhB,OAASqgB,EAChB3gB,EAAOua,MAAOvd,KAAM,GAAK2B,QAGjBmE,IAAT2c,EACNziB,KACAA,KAAKkE,KAAM,WACV,IAAIqZ,EAAQva,EAAOua,MAAOvd,KAAM2B,EAAM8gB,GAGtCzf,EAAOygB,YAAazjB,KAAM2B,GAEZ,OAATA,GAAgC,eAAf4b,EAAO,IAC5Bva,EAAOsgB,QAAStjB,KAAM2B,MAI1B2hB,QAAS,SAAU3hB,GAClB,OAAO3B,KAAKkE,KAAM,WACjBlB,EAAOsgB,QAAStjB,KAAM2B,MAGxBiiB,WAAY,SAAUjiB,GACrB,OAAO3B,KAAKud,MAAO5b,GAAQ,KAAM,KAKlCib,QAAS,SAAUjb,EAAML,GACxB,IAAIqP,EACHkT,EAAQ,EACRC,EAAQ9gB,EAAOgb,WACflM,EAAW9R,KACXmC,EAAInC,KAAKsD,OACTkZ,EAAU,aACCqH,GACTC,EAAMtE,YAAa1N,EAAU,CAAEA,KAIb,iBAATnQ,IACXL,EAAMK,EACNA,OAAOmE,GAERnE,EAAOA,GAAQ,KAEf,MAAQQ,KACPwO,EAAMiS,EAASjf,IAAKmO,EAAU3P,GAAKR,EAAO,gBAC9BgP,EAAImF,QACf+N,IACAlT,EAAImF,MAAM0F,IAAKgB,IAIjB,OADAA,IACOsH,EAAMlH,QAAStb,MAGxB,IAAIyiB,GAAO,sCAA0CC,OAEjDC,GAAU,IAAIla,OAAQ,iBAAmBga,GAAO,cAAe,KAG/DG,GAAY,CAAE,MAAO,QAAS,SAAU,QAExCvU,GAAkB/P,EAAS+P,gBAI1BwU,GAAa,SAAU9f,GACzB,OAAOrB,EAAOyF,SAAUpE,EAAK6I,cAAe7I,IAE7C+f,GAAW,CAAEA,UAAU,GAOnBzU,GAAgB0U,cACpBF,GAAa,SAAU9f,GACtB,OAAOrB,EAAOyF,SAAUpE,EAAK6I,cAAe7I,IAC3CA,EAAKggB,YAAaD,MAAe/f,EAAK6I,gBAG1C,IAAIoX,GAAqB,SAAUjgB,EAAMmK,GAOvC,MAA8B,UAH9BnK,EAAOmK,GAAMnK,GAGDkgB,MAAMC,SACM,KAAvBngB,EAAKkgB,MAAMC,SAMXL,GAAY9f,IAEsB,SAAlCrB,EAAOyhB,IAAKpgB,EAAM,YAKrB,SAASqgB,GAAWrgB,EAAMqe,EAAMiC,EAAYC,GAC3C,IAAIC,EAAUC,EACbC,EAAgB,GAChBC,EAAeJ,EACd,WACC,OAAOA,EAAM9V,OAEd,WACC,OAAO9L,EAAOyhB,IAAKpgB,EAAMqe,EAAM,KAEjCuC,EAAUD,IACVE,EAAOP,GAAcA,EAAY,KAAS3hB,EAAOmiB,UAAWzC,GAAS,GAAK,MAG1E0C,EAAgB/gB,EAAK9C,WAClByB,EAAOmiB,UAAWzC,IAAmB,OAATwC,IAAkBD,IAChDhB,GAAQ9W,KAAMnK,EAAOyhB,IAAKpgB,EAAMqe,IAElC,GAAK0C,GAAiBA,EAAe,KAAQF,EAAO,CAInDD,GAAoB,EAGpBC,EAAOA,GAAQE,EAAe,GAG9BA,GAAiBH,GAAW,EAE5B,MAAQF,IAIP/hB,EAAOuhB,MAAOlgB,EAAMqe,EAAM0C,EAAgBF,IACnC,EAAIJ,IAAY,GAAMA,EAAQE,IAAiBC,GAAW,MAAW,IAC3EF,EAAgB,GAEjBK,GAAgCN,EAIjCM,GAAgC,EAChCpiB,EAAOuhB,MAAOlgB,EAAMqe,EAAM0C,EAAgBF,GAG1CP,EAAaA,GAAc,GAgB5B,OAbKA,IACJS,GAAiBA,IAAkBH,GAAW,EAG9CJ,EAAWF,EAAY,GACtBS,GAAkBT,EAAY,GAAM,GAAMA,EAAY,IACrDA,EAAY,GACTC,IACJA,EAAMM,KAAOA,EACbN,EAAM1Q,MAAQkR,EACdR,EAAM5f,IAAM6f,IAGPA,EAIR,IAAIQ,GAAoB,GAyBxB,SAASC,GAAUxT,EAAUyT,GAO5B,IANA,IAAIf,EAASngB,EAxBcA,EACvBuT,EACH1V,EACAmK,EACAmY,EAqBAgB,EAAS,GACTlK,EAAQ,EACRhY,EAASwO,EAASxO,OAGXgY,EAAQhY,EAAQgY,KACvBjX,EAAOyN,EAAUwJ,IACNiJ,QAIXC,EAAUngB,EAAKkgB,MAAMC,QAChBe,GAKa,SAAZf,IACJgB,EAAQlK,GAAUsH,EAASjf,IAAKU,EAAM,YAAe,KAC/CmhB,EAAQlK,KACbjX,EAAKkgB,MAAMC,QAAU,KAGK,KAAvBngB,EAAKkgB,MAAMC,SAAkBF,GAAoBjgB,KACrDmhB,EAAQlK,IA7CVkJ,EAFAtiB,EADG0V,OAAAA,EACH1V,GAF0BmC,EAiDaA,GA/C5B6I,cACXb,EAAWhI,EAAKgI,UAChBmY,EAAUa,GAAmBhZ,MAM9BuL,EAAO1V,EAAIujB,KAAK9iB,YAAaT,EAAII,cAAe+J,IAChDmY,EAAUxhB,EAAOyhB,IAAK7M,EAAM,WAE5BA,EAAKhV,WAAWC,YAAa+U,GAEZ,SAAZ4M,IACJA,EAAU,SAEXa,GAAmBhZ,GAAamY,MAkCb,SAAZA,IACJgB,EAAQlK,GAAU,OAGlBsH,EAASJ,IAAKne,EAAM,UAAWmgB,KAMlC,IAAMlJ,EAAQ,EAAGA,EAAQhY,EAAQgY,IACR,MAAnBkK,EAAQlK,KACZxJ,EAAUwJ,GAAQiJ,MAAMC,QAAUgB,EAAQlK,IAI5C,OAAOxJ,EAGR9O,EAAOG,GAAGgC,OAAQ,CACjBogB,KAAM,WACL,OAAOD,GAAUtlB,MAAM,IAExB0lB,KAAM,WACL,OAAOJ,GAAUtlB,OAElB2lB,OAAQ,SAAUxH,GACjB,MAAsB,kBAAVA,EACJA,EAAQne,KAAKulB,OAASvlB,KAAK0lB,OAG5B1lB,KAAKkE,KAAM,WACZogB,GAAoBtkB,MACxBgD,EAAQhD,MAAOulB,OAEfviB,EAAQhD,MAAO0lB,YAKnB,IAUEE,GACAhV,GAXEiV,GAAiB,wBAEjBC,GAAW,iCAEXC,GAAc,qCAMhBH,GADchmB,EAASomB,yBACRrjB,YAAa/C,EAAS0C,cAAe,SACpDsO,GAAQhR,EAAS0C,cAAe,UAM3BG,aAAc,OAAQ,SAC5BmO,GAAMnO,aAAc,UAAW,WAC/BmO,GAAMnO,aAAc,OAAQ,KAE5BmjB,GAAIjjB,YAAaiO,IAIjBxP,EAAQ6kB,WAAaL,GAAIM,WAAW,GAAOA,WAAW,GAAO7R,UAAUsB,QAIvEiQ,GAAI/U,UAAY,yBAChBzP,EAAQ+kB,iBAAmBP,GAAIM,WAAW,GAAO7R,UAAUuF,aAK3DgM,GAAI/U,UAAY,oBAChBzP,EAAQglB,SAAWR,GAAIvR,UAKxB,IAAIgS,GAAU,CAKbC,MAAO,CAAE,EAAG,UAAW,YACvBC,IAAK,CAAE,EAAG,oBAAqB,uBAC/BC,GAAI,CAAE,EAAG,iBAAkB,oBAC3BC,GAAI,CAAE,EAAG,qBAAsB,yBAE/BC,SAAU,CAAE,EAAG,GAAI,KAYpB,SAASC,GAAQzjB,EAASwN,GAIzB,IAAI3M,EAYJ,OATCA,EAD4C,oBAAjCb,EAAQoK,qBACbpK,EAAQoK,qBAAsBoD,GAAO,KAEI,oBAA7BxN,EAAQ4K,iBACpB5K,EAAQ4K,iBAAkB4C,GAAO,KAGjC,QAGM5K,IAAR4K,GAAqBA,GAAOrE,EAAUnJ,EAASwN,GAC5C1N,EAAOgB,MAAO,CAAEd,GAAWa,GAG5BA,EAKR,SAAS6iB,GAAe9iB,EAAO+iB,GAI9B,IAHA,IAAI1kB,EAAI,EACPiZ,EAAItX,EAAMR,OAEHnB,EAAIiZ,EAAGjZ,IACdygB,EAASJ,IACR1e,EAAO3B,GACP,cACC0kB,GAAejE,EAASjf,IAAKkjB,EAAa1kB,GAAK,eA1CnDkkB,GAAQS,MAAQT,GAAQU,MAAQV,GAAQW,SAAWX,GAAQY,QAAUZ,GAAQC,MAC7ED,GAAQa,GAAKb,GAAQI,GAGfrlB,EAAQglB,SACbC,GAAQc,SAAWd,GAAQD,OAAS,CAAE,EAAG,+BAAgC,cA2C1E,IAAIrb,GAAQ,YAEZ,SAASqc,GAAetjB,EAAOZ,EAASmkB,EAASC,EAAWC,GAO3D,IANA,IAAIljB,EAAMsM,EAAKD,EAAK8W,EAAMC,EAAU1iB,EACnC2iB,EAAWxkB,EAAQ8iB,yBACnB2B,EAAQ,GACRxlB,EAAI,EACJiZ,EAAItX,EAAMR,OAEHnB,EAAIiZ,EAAGjZ,IAGd,IAFAkC,EAAOP,EAAO3B,KAEQ,IAATkC,EAGZ,GAAwB,WAAnBvB,EAAQuB,GAIZrB,EAAOgB,MAAO2jB,EAAOtjB,EAAK9C,SAAW,CAAE8C,GAASA,QAG1C,GAAM0G,GAAM0C,KAAMpJ,GAIlB,CACNsM,EAAMA,GAAO+W,EAAS/kB,YAAaO,EAAQZ,cAAe,QAG1DoO,GAAQoV,GAAS3Y,KAAM9I,IAAU,CAAE,GAAI,KAAQ,GAAIoD,cACnD+f,EAAOnB,GAAS3V,IAAS2V,GAAQK,SACjC/V,EAAIE,UAAY2W,EAAM,GAAMxkB,EAAO4kB,cAAevjB,GAASmjB,EAAM,GAGjEziB,EAAIyiB,EAAM,GACV,MAAQziB,IACP4L,EAAMA,EAAI0D,UAKXrR,EAAOgB,MAAO2jB,EAAOhX,EAAInE,aAGzBmE,EAAM+W,EAASnV,YAGXD,YAAc,QAzBlBqV,EAAM/mB,KAAMsC,EAAQ2kB,eAAgBxjB,IA+BvCqjB,EAASpV,YAAc,GAEvBnQ,EAAI,EACJ,MAAUkC,EAAOsjB,EAAOxlB,KAGvB,GAAKmlB,IAAkD,EAArCtkB,EAAO6D,QAASxC,EAAMijB,GAClCC,GACJA,EAAQ3mB,KAAMyD,QAgBhB,GAXAojB,EAAWtD,GAAY9f,GAGvBsM,EAAMgW,GAAQe,EAAS/kB,YAAa0B,GAAQ,UAGvCojB,GACJb,GAAejW,GAIX0W,EAAU,CACdtiB,EAAI,EACJ,MAAUV,EAAOsM,EAAK5L,KAChBghB,GAAYtY,KAAMpJ,EAAK1C,MAAQ,KACnC0lB,EAAQzmB,KAAMyD,GAMlB,OAAOqjB,EAIR,IAAII,GAAiB,sBAErB,SAASC,KACR,OAAO,EAGR,SAASC,KACR,OAAO,EASR,SAASC,GAAY5jB,EAAM1C,GAC1B,OAAS0C,IAMV,WACC,IACC,OAAOzE,EAAS0V,cACf,MAAQ4S,KATQC,KAAqC,UAATxmB,GAY/C,SAASymB,GAAI/jB,EAAMgkB,EAAOplB,EAAUwf,EAAMtf,EAAImlB,GAC7C,IAAIC,EAAQ5mB,EAGZ,GAAsB,iBAAV0mB,EAAqB,CAShC,IAAM1mB,IANmB,iBAAbsB,IAGXwf,EAAOA,GAAQxf,EACfA,OAAW6C,GAEEuiB,EACbD,GAAI/jB,EAAM1C,EAAMsB,EAAUwf,EAAM4F,EAAO1mB,GAAQ2mB,GAEhD,OAAOjkB,EAsBR,GAnBa,MAARoe,GAAsB,MAANtf,GAGpBA,EAAKF,EACLwf,EAAOxf,OAAW6C,GACD,MAAN3C,IACc,iBAAbF,GAGXE,EAAKsf,EACLA,OAAO3c,IAIP3C,EAAKsf,EACLA,EAAOxf,EACPA,OAAW6C,KAGD,IAAP3C,EACJA,EAAK6kB,QACC,IAAM7kB,EACZ,OAAOkB,EAeR,OAZa,IAARikB,IACJC,EAASplB,GACTA,EAAK,SAAUqlB,GAId,OADAxlB,IAASylB,IAAKD,GACPD,EAAO5nB,MAAOX,KAAMsE,aAIzB8C,KAAOmhB,EAAOnhB,OAAUmhB,EAAOnhB,KAAOpE,EAAOoE,SAE1C/C,EAAKH,KAAM,WACjBlB,EAAOwlB,MAAMhN,IAAKxb,KAAMqoB,EAAOllB,EAAIsf,EAAMxf,KA+a3C,SAASylB,GAAgBla,EAAI7M,EAAMsmB,GAG5BA,GAQNrF,EAASJ,IAAKhU,EAAI7M,GAAM,GACxBqB,EAAOwlB,MAAMhN,IAAKhN,EAAI7M,EAAM,CAC3B8N,WAAW,EACXd,QAAS,SAAU6Z,GAClB,IAAIG,EAAUpV,EACbqV,EAAQhG,EAASjf,IAAK3D,KAAM2B,GAE7B,GAAyB,EAAlB6mB,EAAMK,WAAmB7oB,KAAM2B,IAKrC,GAAMinB,EAAMtlB,QAuCEN,EAAOwlB,MAAMrJ,QAASxd,IAAU,IAAKmnB,cAClDN,EAAMO,uBArBN,GAdAH,EAAQtoB,EAAMG,KAAM6D,WACpBse,EAASJ,IAAKxiB,KAAM2B,EAAMinB,GAK1BD,EAAWV,EAAYjoB,KAAM2B,GAC7B3B,KAAM2B,KAEDinB,KADLrV,EAASqP,EAASjf,IAAK3D,KAAM2B,KACJgnB,EACxB/F,EAASJ,IAAKxiB,KAAM2B,GAAM,GAE1B4R,EAAS,GAELqV,IAAUrV,EAWd,OARAiV,EAAMQ,2BACNR,EAAMS,iBAOC1V,GAAUA,EAAOpM,WAefyhB,EAAMtlB,SAGjBsf,EAASJ,IAAKxiB,KAAM2B,EAAM,CACzBwF,MAAOnE,EAAOwlB,MAAMU,QAInBlmB,EAAOmC,OAAQyjB,EAAO,GAAK5lB,EAAOmmB,MAAM5lB,WACxCqlB,EAAMtoB,MAAO,GACbN,QAKFwoB,EAAMQ,qCA/E0BljB,IAA7B8c,EAASjf,IAAK6K,EAAI7M,IACtBqB,EAAOwlB,MAAMhN,IAAKhN,EAAI7M,EAAMomB,IA5a/B/kB,EAAOwlB,MAAQ,CAEdhpB,OAAQ,GAERgc,IAAK,SAAUnX,EAAMgkB,EAAO1Z,EAAS8T,EAAMxf,GAE1C,IAAImmB,EAAaC,EAAa1Y,EAC7B2Y,EAAQC,EAAGC,EACXrK,EAASsK,EAAU9nB,EAAM+nB,EAAYC,EACrCC,EAAWhH,EAASjf,IAAKU,GAG1B,GAAM6d,EAAY7d,GAAlB,CAKKsK,EAAQA,UAEZA,GADAya,EAAcza,GACQA,QACtB1L,EAAWmmB,EAAYnmB,UAKnBA,GACJD,EAAOwN,KAAKM,gBAAiBnB,GAAiB1M,GAIzC0L,EAAQvH,OACbuH,EAAQvH,KAAOpE,EAAOoE,SAIfkiB,EAASM,EAASN,UACzBA,EAASM,EAASN,OAASlpB,OAAOypB,OAAQ,QAEnCR,EAAcO,EAASE,UAC9BT,EAAcO,EAASE,OAAS,SAAUrd,GAIzC,MAAyB,oBAAXzJ,GAA0BA,EAAOwlB,MAAMuB,YAActd,EAAE9K,KACpEqB,EAAOwlB,MAAMwB,SAASrpB,MAAO0D,EAAMC,gBAAcwB,IAMpDyjB,GADAlB,GAAUA,GAAS,IAAKvb,MAAOoP,IAAmB,CAAE,KAC1C5Y,OACV,MAAQimB,IAEP5nB,EAAOgoB,GADPhZ,EAAMmX,GAAe3a,KAAMkb,EAAOkB,KAAS,IACpB,GACvBG,GAAe/Y,EAAK,IAAO,IAAKpJ,MAAO,KAAMtC,OAGvCtD,IAKNwd,EAAUnc,EAAOwlB,MAAMrJ,QAASxd,IAAU,GAG1CA,GAASsB,EAAWkc,EAAQ2J,aAAe3J,EAAQ8K,WAActoB,EAGjEwd,EAAUnc,EAAOwlB,MAAMrJ,QAASxd,IAAU,GAG1C6nB,EAAYxmB,EAAOmC,OAAQ,CAC1BxD,KAAMA,EACNgoB,SAAUA,EACVlH,KAAMA,EACN9T,QAASA,EACTvH,KAAMuH,EAAQvH,KACdnE,SAAUA,EACV6H,aAAc7H,GAAYD,EAAO6O,KAAK/E,MAAMhC,aAAa2C,KAAMxK,GAC/DwM,UAAWia,EAAW7b,KAAM,MAC1Bub,IAGKK,EAAWH,EAAQ3nB,OAC1B8nB,EAAWH,EAAQ3nB,GAAS,IACnBuoB,cAAgB,EAGnB/K,EAAQgL,QACiD,IAA9DhL,EAAQgL,MAAM1pB,KAAM4D,EAAMoe,EAAMiH,EAAYL,IAEvChlB,EAAK2L,kBACT3L,EAAK2L,iBAAkBrO,EAAM0nB,IAK3BlK,EAAQ3D,MACZ2D,EAAQ3D,IAAI/a,KAAM4D,EAAMmlB,GAElBA,EAAU7a,QAAQvH,OACvBoiB,EAAU7a,QAAQvH,KAAOuH,EAAQvH,OAK9BnE,EACJwmB,EAASvkB,OAAQukB,EAASS,gBAAiB,EAAGV,GAE9CC,EAAS7oB,KAAM4oB,GAIhBxmB,EAAOwlB,MAAMhpB,OAAQmC,IAAS,KAMhCic,OAAQ,SAAUvZ,EAAMgkB,EAAO1Z,EAAS1L,EAAUmnB,GAEjD,IAAIrlB,EAAGslB,EAAW1Z,EACjB2Y,EAAQC,EAAGC,EACXrK,EAASsK,EAAU9nB,EAAM+nB,EAAYC,EACrCC,EAAWhH,EAASD,QAASte,IAAUue,EAASjf,IAAKU,GAEtD,GAAMulB,IAAeN,EAASM,EAASN,QAAvC,CAMAC,GADAlB,GAAUA,GAAS,IAAKvb,MAAOoP,IAAmB,CAAE,KAC1C5Y,OACV,MAAQimB,IAMP,GAJA5nB,EAAOgoB,GADPhZ,EAAMmX,GAAe3a,KAAMkb,EAAOkB,KAAS,IACpB,GACvBG,GAAe/Y,EAAK,IAAO,IAAKpJ,MAAO,KAAMtC,OAGvCtD,EAAN,CAOAwd,EAAUnc,EAAOwlB,MAAMrJ,QAASxd,IAAU,GAE1C8nB,EAAWH,EADX3nB,GAASsB,EAAWkc,EAAQ2J,aAAe3J,EAAQ8K,WAActoB,IACpC,GAC7BgP,EAAMA,EAAK,IACV,IAAI5G,OAAQ,UAAY2f,EAAW7b,KAAM,iBAAoB,WAG9Dwc,EAAYtlB,EAAI0kB,EAASnmB,OACzB,MAAQyB,IACPykB,EAAYC,EAAU1kB,IAEfqlB,GAAeT,IAAaH,EAAUG,UACzChb,GAAWA,EAAQvH,OAASoiB,EAAUpiB,MACtCuJ,IAAOA,EAAIlD,KAAM+b,EAAU/Z,YAC3BxM,GAAYA,IAAaumB,EAAUvmB,WACxB,OAAbA,IAAqBumB,EAAUvmB,YAChCwmB,EAASvkB,OAAQH,EAAG,GAEfykB,EAAUvmB,UACdwmB,EAASS,gBAEL/K,EAAQvB,QACZuB,EAAQvB,OAAOnd,KAAM4D,EAAMmlB,IAOzBa,IAAcZ,EAASnmB,SACrB6b,EAAQmL,WACkD,IAA/DnL,EAAQmL,SAAS7pB,KAAM4D,EAAMqlB,EAAYE,EAASE,SAElD9mB,EAAOunB,YAAalmB,EAAM1C,EAAMioB,EAASE,eAGnCR,EAAQ3nB,SA1Cf,IAAMA,KAAQ2nB,EACbtmB,EAAOwlB,MAAM5K,OAAQvZ,EAAM1C,EAAO0mB,EAAOkB,GAAK5a,EAAS1L,GAAU,GA8C/DD,EAAOyD,cAAe6iB,IAC1B1G,EAAShF,OAAQvZ,EAAM,mBAIzB2lB,SAAU,SAAUQ,GAEnB,IAAIroB,EAAG4C,EAAGhB,EAAK4Q,EAAS6U,EAAWiB,EAClCjW,EAAO,IAAI5O,MAAOtB,UAAUhB,QAG5BklB,EAAQxlB,EAAOwlB,MAAMkC,IAAKF,GAE1Bf,GACC7G,EAASjf,IAAK3D,KAAM,WAAcI,OAAOypB,OAAQ,OAC/CrB,EAAM7mB,OAAU,GACnBwd,EAAUnc,EAAOwlB,MAAMrJ,QAASqJ,EAAM7mB,OAAU,GAKjD,IAFA6S,EAAM,GAAMgU,EAENrmB,EAAI,EAAGA,EAAImC,UAAUhB,OAAQnB,IAClCqS,EAAMrS,GAAMmC,UAAWnC,GAMxB,GAHAqmB,EAAMmC,eAAiB3qB,MAGlBmf,EAAQyL,cAA2D,IAA5CzL,EAAQyL,YAAYnqB,KAAMT,KAAMwoB,GAA5D,CAKAiC,EAAeznB,EAAOwlB,MAAMiB,SAAShpB,KAAMT,KAAMwoB,EAAOiB,GAGxDtnB,EAAI,EACJ,OAAUwS,EAAU8V,EAActoB,QAAYqmB,EAAMqC,uBAAyB,CAC5ErC,EAAMsC,cAAgBnW,EAAQtQ,KAE9BU,EAAI,EACJ,OAAUykB,EAAY7U,EAAQ8U,SAAU1kB,QACtCyjB,EAAMuC,gCAIDvC,EAAMwC,aAAsC,IAAxBxB,EAAU/Z,YACnC+Y,EAAMwC,WAAWvd,KAAM+b,EAAU/Z,aAEjC+Y,EAAMgB,UAAYA,EAClBhB,EAAM/F,KAAO+G,EAAU/G,UAKV3c,KAHb/B,IAAUf,EAAOwlB,MAAMrJ,QAASqK,EAAUG,WAAc,IAAKG,QAC5DN,EAAU7a,SAAUhO,MAAOgU,EAAQtQ,KAAMmQ,MAGT,KAAzBgU,EAAMjV,OAASxP,KACrBykB,EAAMS,iBACNT,EAAMO,oBAYX,OAJK5J,EAAQ8L,cACZ9L,EAAQ8L,aAAaxqB,KAAMT,KAAMwoB,GAG3BA,EAAMjV,SAGdkW,SAAU,SAAUjB,EAAOiB,GAC1B,IAAItnB,EAAGqnB,EAAWvX,EAAKiZ,EAAiBC,EACvCV,EAAe,GACfP,EAAgBT,EAASS,cACzBpb,EAAM0Z,EAAM/iB,OAGb,GAAKykB,GAIJpb,EAAIvN,YAOc,UAAfinB,EAAM7mB,MAAoC,GAAhB6mB,EAAMxS,QAEnC,KAAQlH,IAAQ9O,KAAM8O,EAAMA,EAAIlM,YAAc5C,KAI7C,GAAsB,IAAjB8O,EAAIvN,WAAoC,UAAfinB,EAAM7mB,OAAqC,IAAjBmN,EAAI1C,UAAsB,CAGjF,IAFA8e,EAAkB,GAClBC,EAAmB,GACbhpB,EAAI,EAAGA,EAAI+nB,EAAe/nB,SAME2D,IAA5BqlB,EAFLlZ,GAHAuX,EAAYC,EAAUtnB,IAGNc,SAAW,OAG1BkoB,EAAkBlZ,GAAQuX,EAAU1e,cACC,EAApC9H,EAAQiP,EAAKjS,MAAOsb,MAAOxM,GAC3B9L,EAAOwN,KAAMyB,EAAKjS,KAAM,KAAM,CAAE8O,IAAQxL,QAErC6nB,EAAkBlZ,IACtBiZ,EAAgBtqB,KAAM4oB,GAGnB0B,EAAgB5nB,QACpBmnB,EAAa7pB,KAAM,CAAEyD,KAAMyK,EAAK2a,SAAUyB,IAY9C,OALApc,EAAM9O,KACDkqB,EAAgBT,EAASnmB,QAC7BmnB,EAAa7pB,KAAM,CAAEyD,KAAMyK,EAAK2a,SAAUA,EAASnpB,MAAO4pB,KAGpDO,GAGRW,QAAS,SAAU/lB,EAAMgmB,GACxBjrB,OAAOkiB,eAAgBtf,EAAOmmB,MAAM5lB,UAAW8B,EAAM,CACpDimB,YAAY,EACZ/I,cAAc,EAEd5e,IAAKtC,EAAYgqB,GAChB,WACC,GAAKrrB,KAAKurB,cACT,OAAOF,EAAMrrB,KAAKurB,gBAGpB,WACC,GAAKvrB,KAAKurB,cACT,OAAOvrB,KAAKurB,cAAelmB,IAI9Bmd,IAAK,SAAUrb,GACd/G,OAAOkiB,eAAgBtiB,KAAMqF,EAAM,CAClCimB,YAAY,EACZ/I,cAAc,EACdiJ,UAAU,EACVrkB,MAAOA,QAMXujB,IAAK,SAAUa,GACd,OAAOA,EAAevoB,EAAO+C,SAC5BwlB,EACA,IAAIvoB,EAAOmmB,MAAOoC,IAGpBpM,QAAS,CACRsM,KAAM,CAGLC,UAAU,GAEXC,MAAO,CAGNxB,MAAO,SAAU1H,GAIhB,IAAIjU,EAAKxO,MAAQyiB,EAWjB,OARKoD,GAAepY,KAAMe,EAAG7M,OAC5B6M,EAAGmd,OAAStf,EAAUmC,EAAI,UAG1Bka,GAAgBla,EAAI,QAASuZ,KAIvB,GAERmB,QAAS,SAAUzG,GAIlB,IAAIjU,EAAKxO,MAAQyiB,EAUjB,OAPKoD,GAAepY,KAAMe,EAAG7M,OAC5B6M,EAAGmd,OAAStf,EAAUmC,EAAI,UAE1Bka,GAAgBla,EAAI,UAId,GAKRkY,SAAU,SAAU8B,GACnB,IAAI/iB,EAAS+iB,EAAM/iB,OACnB,OAAOogB,GAAepY,KAAMhI,EAAO9D,OAClC8D,EAAOkmB,OAAStf,EAAU5G,EAAQ,UAClCmd,EAASjf,IAAK8B,EAAQ,UACtB4G,EAAU5G,EAAQ,OAIrBmmB,aAAc,CACbX,aAAc,SAAUzC,QAID1iB,IAAjB0iB,EAAMjV,QAAwBiV,EAAM+C,gBACxC/C,EAAM+C,cAAcM,YAAcrD,EAAMjV,YAoG7CvQ,EAAOunB,YAAc,SAAUlmB,EAAM1C,EAAMmoB,GAGrCzlB,EAAK0c,qBACT1c,EAAK0c,oBAAqBpf,EAAMmoB,IAIlC9mB,EAAOmmB,MAAQ,SAAUvnB,EAAKkqB,GAG7B,KAAQ9rB,gBAAgBgD,EAAOmmB,OAC9B,OAAO,IAAInmB,EAAOmmB,MAAOvnB,EAAKkqB,GAI1BlqB,GAAOA,EAAID,MACf3B,KAAKurB,cAAgB3pB,EACrB5B,KAAK2B,KAAOC,EAAID,KAIhB3B,KAAK+rB,mBAAqBnqB,EAAIoqB,uBACHlmB,IAAzBlE,EAAIoqB,mBAGgB,IAApBpqB,EAAIiqB,YACL9D,GACAC,GAKDhoB,KAAKyF,OAAW7D,EAAI6D,QAAkC,IAAxB7D,EAAI6D,OAAOlE,SACxCK,EAAI6D,OAAO7C,WACXhB,EAAI6D,OAELzF,KAAK8qB,cAAgBlpB,EAAIkpB,cACzB9qB,KAAKisB,cAAgBrqB,EAAIqqB,eAIzBjsB,KAAK2B,KAAOC,EAIRkqB,GACJ9oB,EAAOmC,OAAQnF,KAAM8rB,GAItB9rB,KAAKksB,UAAYtqB,GAAOA,EAAIsqB,WAAaxjB,KAAKyjB,MAG9CnsB,KAAMgD,EAAO+C,UAAY,GAK1B/C,EAAOmmB,MAAM5lB,UAAY,CACxBE,YAAaT,EAAOmmB,MACpB4C,mBAAoB/D,GACpB6C,qBAAsB7C,GACtB+C,8BAA+B/C,GAC/BoE,aAAa,EAEbnD,eAAgB,WACf,IAAIxc,EAAIzM,KAAKurB,cAEbvrB,KAAK+rB,mBAAqBhE,GAErBtb,IAAMzM,KAAKosB,aACf3f,EAAEwc,kBAGJF,gBAAiB,WAChB,IAAItc,EAAIzM,KAAKurB,cAEbvrB,KAAK6qB,qBAAuB9C,GAEvBtb,IAAMzM,KAAKosB,aACf3f,EAAEsc,mBAGJC,yBAA0B,WACzB,IAAIvc,EAAIzM,KAAKurB,cAEbvrB,KAAK+qB,8BAAgChD,GAEhCtb,IAAMzM,KAAKosB,aACf3f,EAAEuc,2BAGHhpB,KAAK+oB,oBAKP/lB,EAAOkB,KAAM,CACZmoB,QAAQ,EACRC,SAAS,EACTC,YAAY,EACZC,gBAAgB,EAChBC,SAAS,EACTC,QAAQ,EACRC,YAAY,EACZC,SAAS,EACTC,OAAO,EACPC,OAAO,EACPC,UAAU,EACVC,MAAM,EACNC,QAAQ,EACRjrB,MAAM,EACNkrB,UAAU,EACV/e,KAAK,EACLgf,SAAS,EACTnX,QAAQ,EACRoX,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,WAAW,EACXC,aAAa,EACbC,SAAS,EACTC,SAAS,EACTC,eAAe,EACfC,WAAW,EACXC,SAAS,EACTC,OAAO,GACLhrB,EAAOwlB,MAAM4C,SAEhBpoB,EAAOkB,KAAM,CAAEmR,MAAO,UAAW4Y,KAAM,YAAc,SAAUtsB,EAAMmnB,GACpE9lB,EAAOwlB,MAAMrJ,QAASxd,GAAS,CAG9BwoB,MAAO,WAQN,OAHAzB,GAAgB1oB,KAAM2B,EAAMsmB,KAGrB,GAERiB,QAAS,WAMR,OAHAR,GAAgB1oB,KAAM2B,IAGf,GAKR+kB,SAAU,WACT,OAAO,GAGRoC,aAAcA,KAYhB9lB,EAAOkB,KAAM,CACZgqB,WAAY,YACZC,WAAY,WACZC,aAAc,cACdC,aAAc,cACZ,SAAUC,EAAM5D,GAClB1nB,EAAOwlB,MAAMrJ,QAASmP,GAAS,CAC9BxF,aAAc4B,EACdT,SAAUS,EAEVZ,OAAQ,SAAUtB,GACjB,IAAIzkB,EAEHwqB,EAAU/F,EAAMyD,cAChBzC,EAAYhB,EAAMgB,UASnB,OALM+E,IAAaA,IANTvuB,MAMgCgD,EAAOyF,SANvCzI,KAMyDuuB,MAClE/F,EAAM7mB,KAAO6nB,EAAUG,SACvB5lB,EAAMylB,EAAU7a,QAAQhO,MAAOX,KAAMsE,WACrCkkB,EAAM7mB,KAAO+oB,GAEP3mB,MAKVf,EAAOG,GAAGgC,OAAQ,CAEjBijB,GAAI,SAAUC,EAAOplB,EAAUwf,EAAMtf,GACpC,OAAOilB,GAAIpoB,KAAMqoB,EAAOplB,EAAUwf,EAAMtf,IAEzCmlB,IAAK,SAAUD,EAAOplB,EAAUwf,EAAMtf,GACrC,OAAOilB,GAAIpoB,KAAMqoB,EAAOplB,EAAUwf,EAAMtf,EAAI,IAE7CslB,IAAK,SAAUJ,EAAOplB,EAAUE,GAC/B,IAAIqmB,EAAW7nB,EACf,GAAK0mB,GAASA,EAAMY,gBAAkBZ,EAAMmB,UAW3C,OARAA,EAAYnB,EAAMmB,UAClBxmB,EAAQqlB,EAAMsC,gBAAiBlC,IAC9Be,EAAU/Z,UACT+Z,EAAUG,SAAW,IAAMH,EAAU/Z,UACrC+Z,EAAUG,SACXH,EAAUvmB,SACVumB,EAAU7a,SAEJ3O,KAER,GAAsB,iBAAVqoB,EAAqB,CAGhC,IAAM1mB,KAAQ0mB,EACbroB,KAAKyoB,IAAK9mB,EAAMsB,EAAUolB,EAAO1mB,IAElC,OAAO3B,KAWR,OATkB,IAAbiD,GAA0C,mBAAbA,IAGjCE,EAAKF,EACLA,OAAW6C,IAEA,IAAP3C,IACJA,EAAK6kB,IAEChoB,KAAKkE,KAAM,WACjBlB,EAAOwlB,MAAM5K,OAAQ5d,KAAMqoB,EAAOllB,EAAIF,QAMzC,IAKCurB,GAAe,wBAGfC,GAAW,oCACXC,GAAe,2CAGhB,SAASC,GAAoBtqB,EAAM2X,GAClC,OAAK3P,EAAUhI,EAAM,UACpBgI,EAA+B,KAArB2P,EAAQza,SAAkBya,EAAUA,EAAQzJ,WAAY,OAE3DvP,EAAQqB,GAAO0W,SAAU,SAAW,IAGrC1W,EAIR,SAASuqB,GAAevqB,GAEvB,OADAA,EAAK1C,MAAyC,OAAhC0C,EAAK7B,aAAc,SAAsB,IAAM6B,EAAK1C,KAC3D0C,EAER,SAASwqB,GAAexqB,GAOvB,MAN2C,WAApCA,EAAK1C,MAAQ,IAAKrB,MAAO,EAAG,GAClC+D,EAAK1C,KAAO0C,EAAK1C,KAAKrB,MAAO,GAE7B+D,EAAK2J,gBAAiB,QAGhB3J,EAGR,SAASyqB,GAAgBltB,EAAKmtB,GAC7B,IAAI5sB,EAAGiZ,EAAGzZ,EAAgBqtB,EAAUC,EAAU3F,EAE9C,GAAuB,IAAlByF,EAAKxtB,SAAV,CAKA,GAAKqhB,EAASD,QAAS/gB,KAEtB0nB,EADW1G,EAASjf,IAAK/B,GACP0nB,QAKjB,IAAM3nB,KAFNihB,EAAShF,OAAQmR,EAAM,iBAETzF,EACb,IAAMnnB,EAAI,EAAGiZ,EAAIkO,EAAQ3nB,GAAO2B,OAAQnB,EAAIiZ,EAAGjZ,IAC9Ca,EAAOwlB,MAAMhN,IAAKuT,EAAMptB,EAAM2nB,EAAQ3nB,GAAQQ,IAO7C0gB,EAASF,QAAS/gB,KACtBotB,EAAWnM,EAASzB,OAAQxf,GAC5BqtB,EAAWjsB,EAAOmC,OAAQ,GAAI6pB,GAE9BnM,EAASL,IAAKuM,EAAME,KAkBtB,SAASC,GAAUC,EAAY3a,EAAMrQ,EAAUojB,GAG9C/S,EAAOjU,EAAMiU,GAEb,IAAIkT,EAAUnjB,EAAO8iB,EAAS+H,EAAYntB,EAAMC,EAC/CC,EAAI,EACJiZ,EAAI+T,EAAW7rB,OACf+rB,EAAWjU,EAAI,EACfjU,EAAQqN,EAAM,GACd8a,EAAkBjuB,EAAY8F,GAG/B,GAAKmoB,GACG,EAAJlU,GAA0B,iBAAVjU,IAChB/F,EAAQ6kB,YAAcwI,GAAShhB,KAAMtG,GACxC,OAAOgoB,EAAWjrB,KAAM,SAAUoX,GACjC,IAAIb,EAAO0U,EAAW3qB,GAAI8W,GACrBgU,IACJ9a,EAAM,GAAMrN,EAAM1G,KAAMT,KAAMsb,EAAOb,EAAK8U,SAE3CL,GAAUzU,EAAMjG,EAAMrQ,EAAUojB,KAIlC,GAAKnM,IAEJ7W,GADAmjB,EAAWN,GAAe5S,EAAM2a,EAAY,GAAIjiB,eAAe,EAAOiiB,EAAY5H,IACjEhV,WAEmB,IAA/BmV,EAASlb,WAAWlJ,SACxBokB,EAAWnjB,GAIPA,GAASgjB,GAAU,CAOvB,IALA6H,GADA/H,EAAUrkB,EAAOoB,IAAKuiB,GAAQe,EAAU,UAAYkH,KAC/BtrB,OAKbnB,EAAIiZ,EAAGjZ,IACdF,EAAOylB,EAEFvlB,IAAMktB,IACVptB,EAAOe,EAAOwC,MAAOvD,GAAM,GAAM,GAG5BmtB,GAIJpsB,EAAOgB,MAAOqjB,EAASV,GAAQ1kB,EAAM,YAIvCkC,EAAS1D,KAAM0uB,EAAYhtB,GAAKF,EAAME,GAGvC,GAAKitB,EAOJ,IANAltB,EAAMmlB,EAASA,EAAQ/jB,OAAS,GAAI4J,cAGpClK,EAAOoB,IAAKijB,EAASwH,IAGf1sB,EAAI,EAAGA,EAAIitB,EAAYjtB,IAC5BF,EAAOolB,EAASllB,GACX4jB,GAAYtY,KAAMxL,EAAKN,MAAQ,MAClCihB,EAASxB,OAAQnf,EAAM,eACxBe,EAAOyF,SAAUvG,EAAKD,KAEjBA,EAAKL,KAA8C,YAArCK,EAAKN,MAAQ,IAAK8F,cAG/BzE,EAAOwsB,WAAavtB,EAAKH,UAC7BkB,EAAOwsB,SAAUvtB,EAAKL,IAAK,CAC1BC,MAAOI,EAAKJ,OAASI,EAAKO,aAAc,UACtCN,GAGJH,EAASE,EAAKqQ,YAAYpM,QAASwoB,GAAc,IAAMzsB,EAAMC,IAQnE,OAAOitB,EAGR,SAASvR,GAAQvZ,EAAMpB,EAAUwsB,GAKhC,IAJA,IAAIxtB,EACH0lB,EAAQ1kB,EAAWD,EAAOsN,OAAQrN,EAAUoB,GAASA,EACrDlC,EAAI,EAE4B,OAAvBF,EAAO0lB,EAAOxlB,IAAeA,IAChCstB,GAA8B,IAAlBxtB,EAAKV,UACtByB,EAAO0sB,UAAW/I,GAAQ1kB,IAGtBA,EAAKW,aACJ6sB,GAAYtL,GAAYliB,IAC5B2kB,GAAeD,GAAQ1kB,EAAM,WAE9BA,EAAKW,WAAWC,YAAaZ,IAI/B,OAAOoC,EAGRrB,EAAOmC,OAAQ,CACdyiB,cAAe,SAAU2H,GACxB,OAAOA,GAGR/pB,MAAO,SAAUnB,EAAMsrB,EAAeC,GACrC,IAAIztB,EAAGiZ,EAAGyU,EAAaC,EApINluB,EAAKmtB,EACnB1iB,EAoIF7G,EAAQnB,EAAK6hB,WAAW,GACxB6J,EAAS5L,GAAY9f,GAGtB,KAAMjD,EAAQ+kB,gBAAsC,IAAlB9hB,EAAK9C,UAAoC,KAAlB8C,EAAK9C,UAC3DyB,EAAO8W,SAAUzV,IAMnB,IAHAyrB,EAAenJ,GAAQnhB,GAGjBrD,EAAI,EAAGiZ,GAFbyU,EAAclJ,GAAQtiB,IAEOf,OAAQnB,EAAIiZ,EAAGjZ,IAhJ5BP,EAiJLiuB,EAAa1tB,GAjJH4sB,EAiJQe,EAAc3tB,QAhJzCkK,EAGc,WAHdA,EAAW0iB,EAAK1iB,SAAS5E,gBAGAoe,GAAepY,KAAM7L,EAAID,MACrDotB,EAAKpZ,QAAU/T,EAAI+T,QAGK,UAAbtJ,GAAqC,aAAbA,IACnC0iB,EAAKnV,aAAehY,EAAIgY,cA6IxB,GAAK+V,EACJ,GAAKC,EAIJ,IAHAC,EAAcA,GAAelJ,GAAQtiB,GACrCyrB,EAAeA,GAAgBnJ,GAAQnhB,GAEjCrD,EAAI,EAAGiZ,EAAIyU,EAAYvsB,OAAQnB,EAAIiZ,EAAGjZ,IAC3C2sB,GAAgBe,EAAa1tB,GAAK2tB,EAAc3tB,SAGjD2sB,GAAgBzqB,EAAMmB,GAWxB,OAL2B,GAD3BsqB,EAAenJ,GAAQnhB,EAAO,WACZlC,QACjBsjB,GAAekJ,GAAeC,GAAUpJ,GAAQtiB,EAAM,WAIhDmB,GAGRkqB,UAAW,SAAU5rB,GAKpB,IAJA,IAAI2e,EAAMpe,EAAM1C,EACfwd,EAAUnc,EAAOwlB,MAAMrJ,QACvBhd,EAAI,OAE6B2D,KAAxBzB,EAAOP,EAAO3B,IAAqBA,IAC5C,GAAK+f,EAAY7d,GAAS,CACzB,GAAOoe,EAAOpe,EAAMue,EAAS7c,SAAc,CAC1C,GAAK0c,EAAK6G,OACT,IAAM3nB,KAAQ8gB,EAAK6G,OACbnK,EAASxd,GACbqB,EAAOwlB,MAAM5K,OAAQvZ,EAAM1C,GAI3BqB,EAAOunB,YAAalmB,EAAM1C,EAAM8gB,EAAKqH,QAOxCzlB,EAAMue,EAAS7c,cAAYD,EAEvBzB,EAAMwe,EAAS9c,WAInB1B,EAAMwe,EAAS9c,cAAYD,OAOhC9C,EAAOG,GAAGgC,OAAQ,CACjB6qB,OAAQ,SAAU/sB,GACjB,OAAO2a,GAAQ5d,KAAMiD,GAAU,IAGhC2a,OAAQ,SAAU3a,GACjB,OAAO2a,GAAQ5d,KAAMiD,IAGtBV,KAAM,SAAU4E,GACf,OAAOia,EAAQphB,KAAM,SAAUmH,GAC9B,YAAiBrB,IAAVqB,EACNnE,EAAOT,KAAMvC,MACbA,KAAK8V,QAAQ5R,KAAM,WACK,IAAlBlE,KAAKuB,UAAoC,KAAlBvB,KAAKuB,UAAqC,IAAlBvB,KAAKuB,WACxDvB,KAAKsS,YAAcnL,MAGpB,KAAMA,EAAO7C,UAAUhB,SAG3B2sB,OAAQ,WACP,OAAOf,GAAUlvB,KAAMsE,UAAW,SAAUD,GACpB,IAAlBrE,KAAKuB,UAAoC,KAAlBvB,KAAKuB,UAAqC,IAAlBvB,KAAKuB,UAC3CotB,GAAoB3uB,KAAMqE,GAChC1B,YAAa0B,MAKvB6rB,QAAS,WACR,OAAOhB,GAAUlvB,KAAMsE,UAAW,SAAUD,GAC3C,GAAuB,IAAlBrE,KAAKuB,UAAoC,KAAlBvB,KAAKuB,UAAqC,IAAlBvB,KAAKuB,SAAiB,CACzE,IAAIkE,EAASkpB,GAAoB3uB,KAAMqE,GACvCoB,EAAO0qB,aAAc9rB,EAAMoB,EAAO8M,gBAKrC6d,OAAQ,WACP,OAAOlB,GAAUlvB,KAAMsE,UAAW,SAAUD,GACtCrE,KAAK4C,YACT5C,KAAK4C,WAAWutB,aAAc9rB,EAAMrE,SAKvCqwB,MAAO,WACN,OAAOnB,GAAUlvB,KAAMsE,UAAW,SAAUD,GACtCrE,KAAK4C,YACT5C,KAAK4C,WAAWutB,aAAc9rB,EAAMrE,KAAKiP,gBAK5C6G,MAAO,WAIN,IAHA,IAAIzR,EACHlC,EAAI,EAE2B,OAAtBkC,EAAOrE,KAAMmC,IAAeA,IACd,IAAlBkC,EAAK9C,WAGTyB,EAAO0sB,UAAW/I,GAAQtiB,GAAM,IAGhCA,EAAKiO,YAAc,IAIrB,OAAOtS,MAGRwF,MAAO,SAAUmqB,EAAeC,GAI/B,OAHAD,EAAiC,MAAjBA,GAAgCA,EAChDC,EAAyC,MAArBA,EAA4BD,EAAgBC,EAEzD5vB,KAAKoE,IAAK,WAChB,OAAOpB,EAAOwC,MAAOxF,KAAM2vB,EAAeC,MAI5CL,KAAM,SAAUpoB,GACf,OAAOia,EAAQphB,KAAM,SAAUmH,GAC9B,IAAI9C,EAAOrE,KAAM,IAAO,GACvBmC,EAAI,EACJiZ,EAAIpb,KAAKsD,OAEV,QAAewC,IAAVqB,GAAyC,IAAlB9C,EAAK9C,SAChC,OAAO8C,EAAKwM,UAIb,GAAsB,iBAAV1J,IAAuBqnB,GAAa/gB,KAAMtG,KACpDkf,IAAWP,GAAS3Y,KAAMhG,IAAW,CAAE,GAAI,KAAQ,GAAIM,eAAkB,CAE1EN,EAAQnE,EAAO4kB,cAAezgB,GAE9B,IACC,KAAQhF,EAAIiZ,EAAGjZ,IAIS,KAHvBkC,EAAOrE,KAAMmC,IAAO,IAGVZ,WACTyB,EAAO0sB,UAAW/I,GAAQtiB,GAAM,IAChCA,EAAKwM,UAAY1J,GAInB9C,EAAO,EAGN,MAAQoI,KAGNpI,GACJrE,KAAK8V,QAAQma,OAAQ9oB,IAEpB,KAAMA,EAAO7C,UAAUhB,SAG3BgtB,YAAa,WACZ,IAAI/I,EAAU,GAGd,OAAO2H,GAAUlvB,KAAMsE,UAAW,SAAUD,GAC3C,IAAI8P,EAASnU,KAAK4C,WAEbI,EAAO6D,QAAS7G,KAAMunB,GAAY,IACtCvkB,EAAO0sB,UAAW/I,GAAQ3mB,OACrBmU,GACJA,EAAOoc,aAAclsB,EAAMrE,QAK3BunB,MAILvkB,EAAOkB,KAAM,CACZssB,SAAU,SACVC,UAAW,UACXN,aAAc,SACdO,YAAa,QACbC,WAAY,eACV,SAAUtrB,EAAMurB,GAClB5tB,EAAOG,GAAIkC,GAAS,SAAUpC,GAO7B,IANA,IAAIa,EACHC,EAAM,GACN8sB,EAAS7tB,EAAQC,GACjBwB,EAAOosB,EAAOvtB,OAAS,EACvBnB,EAAI,EAEGA,GAAKsC,EAAMtC,IAClB2B,EAAQ3B,IAAMsC,EAAOzE,KAAOA,KAAKwF,OAAO,GACxCxC,EAAQ6tB,EAAQ1uB,IAAOyuB,GAAY9sB,GAInClD,EAAKD,MAAOoD,EAAKD,EAAMH,OAGxB,OAAO3D,KAAK6D,UAAWE,MAGzB,IAAI+sB,GAAY,IAAI/mB,OAAQ,KAAOga,GAAO,kBAAmB,KAEzDgN,GAAY,SAAU1sB,GAKxB,IAAI2oB,EAAO3oB,EAAK6I,cAAc4C,YAM9B,OAJMkd,GAASA,EAAKgE,SACnBhE,EAAOjtB,GAGDitB,EAAKiE,iBAAkB5sB,IAG5B6sB,GAAO,SAAU7sB,EAAMe,EAASjB,GACnC,IAAIJ,EAAKsB,EACR8rB,EAAM,GAGP,IAAM9rB,KAAQD,EACb+rB,EAAK9rB,GAAShB,EAAKkgB,MAAOlf,GAC1BhB,EAAKkgB,MAAOlf,GAASD,EAASC,GAM/B,IAAMA,KAHNtB,EAAMI,EAAS1D,KAAM4D,GAGPe,EACbf,EAAKkgB,MAAOlf,GAAS8rB,EAAK9rB,GAG3B,OAAOtB,GAIJqtB,GAAY,IAAIrnB,OAAQma,GAAUrW,KAAM,KAAO,KAiJnD,SAASwjB,GAAQhtB,EAAMgB,EAAMisB,GAC5B,IAAIC,EAAOC,EAAUC,EAAU1tB,EAM9BwgB,EAAQlgB,EAAKkgB,MAqCd,OAnCA+M,EAAWA,GAAYP,GAAW1sB,MAQpB,MAFbN,EAAMutB,EAASI,iBAAkBrsB,IAAUisB,EAAUjsB,KAEjC8e,GAAY9f,KAC/BN,EAAMf,EAAOuhB,MAAOlgB,EAAMgB,KAQrBjE,EAAQuwB,kBAAoBb,GAAUrjB,KAAM1J,IAASqtB,GAAU3jB,KAAMpI,KAG1EksB,EAAQhN,EAAMgN,MACdC,EAAWjN,EAAMiN,SACjBC,EAAWlN,EAAMkN,SAGjBlN,EAAMiN,SAAWjN,EAAMkN,SAAWlN,EAAMgN,MAAQxtB,EAChDA,EAAMutB,EAASC,MAGfhN,EAAMgN,MAAQA,EACdhN,EAAMiN,SAAWA,EACjBjN,EAAMkN,SAAWA,SAIJ3rB,IAAR/B,EAINA,EAAM,GACNA,EAIF,SAAS6tB,GAAcC,EAAaC,GAGnC,MAAO,CACNnuB,IAAK,WACJ,IAAKkuB,IASL,OAAS7xB,KAAK2D,IAAMmuB,GAASnxB,MAAOX,KAAMsE,kBALlCtE,KAAK2D,OA3MhB,WAIC,SAASouB,IAGR,GAAMnM,EAAN,CAIAoM,EAAUzN,MAAM0N,QAAU,+EAE1BrM,EAAIrB,MAAM0N,QACT,4HAGDtiB,GAAgBhN,YAAaqvB,GAAYrvB,YAAaijB,GAEtD,IAAIsM,EAAWnyB,EAAOkxB,iBAAkBrL,GACxCuM,EAAoC,OAAjBD,EAASniB,IAG5BqiB,EAAsE,KAA9CC,EAAoBH,EAASI,YAIrD1M,EAAIrB,MAAMgO,MAAQ,MAClBC,EAA6D,KAAzCH,EAAoBH,EAASK,OAIjDE,EAAgE,KAAzCJ,EAAoBH,EAASX,OAMpD3L,EAAIrB,MAAMmO,SAAW,WACrBC,EAAiE,KAA9CN,EAAoBzM,EAAIgN,YAAc,GAEzDjjB,GAAgB9M,YAAamvB,GAI7BpM,EAAM,MAGP,SAASyM,EAAoBQ,GAC5B,OAAO7sB,KAAK8sB,MAAOC,WAAYF,IAGhC,IAAIV,EAAkBM,EAAsBE,EAAkBH,EAC7DQ,EAAyBZ,EACzBJ,EAAYpyB,EAAS0C,cAAe,OACpCsjB,EAAMhmB,EAAS0C,cAAe,OAGzBsjB,EAAIrB,QAMVqB,EAAIrB,MAAM0O,eAAiB,cAC3BrN,EAAIM,WAAW,GAAO3B,MAAM0O,eAAiB,GAC7C7xB,EAAQ8xB,gBAA+C,gBAA7BtN,EAAIrB,MAAM0O,eAEpCjwB,EAAOmC,OAAQ/D,EAAS,CACvB+xB,kBAAmB,WAElB,OADApB,IACOU,GAERd,eAAgB,WAEf,OADAI,IACOS,GAERY,cAAe,WAEd,OADArB,IACOI,GAERkB,mBAAoB,WAEnB,OADAtB,IACOK,GAERkB,cAAe,WAEd,OADAvB,IACOY,GAYRY,qBAAsB,WACrB,IAAIC,EAAOhN,EAAIiN,EAASC,EAmCxB,OAlCgC,MAA3BV,IACJQ,EAAQ5zB,EAAS0C,cAAe,SAChCkkB,EAAK5mB,EAAS0C,cAAe,MAC7BmxB,EAAU7zB,EAAS0C,cAAe,OAElCkxB,EAAMjP,MAAM0N,QAAU,2DACtBzL,EAAGjC,MAAM0N,QAAU,mBAKnBzL,EAAGjC,MAAMoP,OAAS,MAClBF,EAAQlP,MAAMoP,OAAS,MAQvBF,EAAQlP,MAAMC,QAAU,QAExB7U,GACEhN,YAAa6wB,GACb7wB,YAAa6jB,GACb7jB,YAAa8wB,GAEfC,EAAU3zB,EAAOkxB,iBAAkBzK,GACnCwM,EAA4BY,SAAUF,EAAQC,OAAQ,IACrDC,SAAUF,EAAQG,eAAgB,IAClCD,SAAUF,EAAQI,kBAAmB,MAAWtN,EAAGuN,aAEpDpkB,GAAgB9M,YAAa2wB,IAEvBR,MAvIV,GAsNA,IAAIgB,GAAc,CAAE,SAAU,MAAO,MACpCC,GAAar0B,EAAS0C,cAAe,OAAQiiB,MAC7C2P,GAAc,GAkBf,SAASC,GAAe9uB,GACvB,IAAI+uB,EAAQpxB,EAAOqxB,SAAUhvB,IAAU6uB,GAAa7uB,GAEpD,OAAK+uB,IAGA/uB,KAAQ4uB,GACL5uB,EAED6uB,GAAa7uB,GAxBrB,SAAyBA,GAGxB,IAAIivB,EAAUjvB,EAAM,GAAI0c,cAAgB1c,EAAK/E,MAAO,GACnD6B,EAAI6xB,GAAY1wB,OAEjB,MAAQnB,IAEP,IADAkD,EAAO2uB,GAAa7xB,GAAMmyB,KACbL,GACZ,OAAO5uB,EAeoBkvB,CAAgBlvB,IAAUA,GAIxD,IAKCmvB,GAAe,4BACfC,GAAc,MACdC,GAAU,CAAEhC,SAAU,WAAYiC,WAAY,SAAUnQ,QAAS,SACjEoQ,GAAqB,CACpBC,cAAe,IACfC,WAAY,OAGd,SAASC,GAAmBnwB,EAAOuC,EAAO6tB,GAIzC,IAAIhuB,EAAUid,GAAQ9W,KAAMhG,GAC5B,OAAOH,EAGNhB,KAAKivB,IAAK,EAAGjuB,EAAS,IAAQguB,GAAY,KAAUhuB,EAAS,IAAO,MACpEG,EAGF,SAAS+tB,GAAoB7wB,EAAM8wB,EAAWC,EAAKC,EAAaC,EAAQC,GACvE,IAAIpzB,EAAkB,UAAdgzB,EAAwB,EAAI,EACnCK,EAAQ,EACRC,EAAQ,EAGT,GAAKL,KAAUC,EAAc,SAAW,WACvC,OAAO,EAGR,KAAQlzB,EAAI,EAAGA,GAAK,EAGN,WAARizB,IACJK,GAASzyB,EAAOyhB,IAAKpgB,EAAM+wB,EAAMlR,GAAW/hB,IAAK,EAAMmzB,IAIlDD,GAmBQ,YAARD,IACJK,GAASzyB,EAAOyhB,IAAKpgB,EAAM,UAAY6f,GAAW/hB,IAAK,EAAMmzB,IAIjD,WAARF,IACJK,GAASzyB,EAAOyhB,IAAKpgB,EAAM,SAAW6f,GAAW/hB,GAAM,SAAS,EAAMmzB,MAtBvEG,GAASzyB,EAAOyhB,IAAKpgB,EAAM,UAAY6f,GAAW/hB,IAAK,EAAMmzB,GAGhD,YAARF,EACJK,GAASzyB,EAAOyhB,IAAKpgB,EAAM,SAAW6f,GAAW/hB,GAAM,SAAS,EAAMmzB,GAItEE,GAASxyB,EAAOyhB,IAAKpgB,EAAM,SAAW6f,GAAW/hB,GAAM,SAAS,EAAMmzB,IAoCzE,OAhBMD,GAA8B,GAAfE,IAIpBE,GAASzvB,KAAKivB,IAAK,EAAGjvB,KAAK0vB,KAC1BrxB,EAAM,SAAW8wB,EAAW,GAAIpT,cAAgBoT,EAAU70B,MAAO,IACjEi1B,EACAE,EACAD,EACA,MAIM,GAGDC,EAGR,SAASE,GAAkBtxB,EAAM8wB,EAAWK,GAG3C,IAAIF,EAASvE,GAAW1sB,GAKvBgxB,IADmBj0B,EAAQ+xB,qBAAuBqC,IAEE,eAAnDxyB,EAAOyhB,IAAKpgB,EAAM,aAAa,EAAOixB,GACvCM,EAAmBP,EAEnBjzB,EAAMivB,GAAQhtB,EAAM8wB,EAAWG,GAC/BO,EAAa,SAAWV,EAAW,GAAIpT,cAAgBoT,EAAU70B,MAAO,GAIzE,GAAKwwB,GAAUrjB,KAAMrL,GAAQ,CAC5B,IAAMozB,EACL,OAAOpzB,EAERA,EAAM,OAyCP,QAlCQhB,EAAQ+xB,qBAAuBkC,IAMrCj0B,EAAQmyB,wBAA0BlnB,EAAUhI,EAAM,OAI3C,SAARjC,IAIC2wB,WAAY3wB,IAA0D,WAAjDY,EAAOyhB,IAAKpgB,EAAM,WAAW,EAAOixB,KAG1DjxB,EAAKyxB,iBAAiBxyB,SAEtB+xB,EAAiE,eAAnDryB,EAAOyhB,IAAKpgB,EAAM,aAAa,EAAOixB,IAKpDM,EAAmBC,KAAcxxB,KAEhCjC,EAAMiC,EAAMwxB,MAKdzzB,EAAM2wB,WAAY3wB,IAAS,GAI1B8yB,GACC7wB,EACA8wB,EACAK,IAAWH,EAAc,SAAW,WACpCO,EACAN,EAGAlzB,GAEE,KA+SL,SAAS2zB,GAAO1xB,EAAMe,EAASsd,EAAM1d,EAAKgxB,GACzC,OAAO,IAAID,GAAMxyB,UAAUH,KAAMiB,EAAMe,EAASsd,EAAM1d,EAAKgxB,GA7S5DhzB,EAAOmC,OAAQ,CAId8wB,SAAU,CACTC,QAAS,CACRvyB,IAAK,SAAUU,EAAMitB,GACpB,GAAKA,EAAW,CAGf,IAAIvtB,EAAMstB,GAAQhtB,EAAM,WACxB,MAAe,KAARN,EAAa,IAAMA,MAO9BohB,UAAW,CACVgR,yBAA2B,EAC3BC,aAAe,EACfC,aAAe,EACfC,UAAY,EACZC,YAAc,EACdzB,YAAc,EACd0B,UAAY,EACZC,YAAc,EACdC,eAAiB,EACjBC,iBAAmB,EACnBC,SAAW,EACXC,YAAc,EACdC,cAAgB,EAChBC,YAAc,EACdb,SAAW,EACXc,OAAS,EACTC,SAAW,EACXC,QAAU,EACVC,QAAU,EACVC,MAAQ,GAKT/C,SAAU,GAGV9P,MAAO,SAAUlgB,EAAMgB,EAAM8B,EAAOquB,GAGnC,GAAMnxB,GAA0B,IAAlBA,EAAK9C,UAAoC,IAAlB8C,EAAK9C,UAAmB8C,EAAKkgB,MAAlE,CAKA,IAAIxgB,EAAKpC,EAAM6hB,EACd6T,EAAWrV,EAAW3c,GACtBiyB,EAAe7C,GAAYhnB,KAAMpI,GACjCkf,EAAQlgB,EAAKkgB,MAad,GARM+S,IACLjyB,EAAO8uB,GAAekD,IAIvB7T,EAAQxgB,EAAOizB,SAAU5wB,IAAUrC,EAAOizB,SAAUoB,QAGrCvxB,IAAVqB,EA0CJ,OAAKqc,GAAS,QAASA,QACwB1d,KAA5C/B,EAAMyf,EAAM7f,IAAKU,GAAM,EAAOmxB,IAEzBzxB,EAIDwgB,EAAOlf,GA7CA,YAHd1D,SAAcwF,KAGcpD,EAAMkgB,GAAQ9W,KAAMhG,KAAapD,EAAK,KACjEoD,EAAQud,GAAWrgB,EAAMgB,EAAMtB,GAG/BpC,EAAO,UAIM,MAATwF,GAAiBA,GAAUA,IAOlB,WAATxF,GAAsB21B,IAC1BnwB,GAASpD,GAAOA,EAAK,KAASf,EAAOmiB,UAAWkS,GAAa,GAAK,OAI7Dj2B,EAAQ8xB,iBAA6B,KAAV/rB,GAAiD,IAAjC9B,EAAKxE,QAAS,gBAC9D0jB,EAAOlf,GAAS,WAIXme,GAAY,QAASA,QACsB1d,KAA9CqB,EAAQqc,EAAMhB,IAAKne,EAAM8C,EAAOquB,MAE7B8B,EACJ/S,EAAMgT,YAAalyB,EAAM8B,GAEzBod,EAAOlf,GAAS8B,MAkBpBsd,IAAK,SAAUpgB,EAAMgB,EAAMmwB,EAAOF,GACjC,IAAIlzB,EAAKwB,EAAK4f,EACb6T,EAAWrV,EAAW3c,GA6BvB,OA5BgBovB,GAAYhnB,KAAMpI,KAMjCA,EAAO8uB,GAAekD,KAIvB7T,EAAQxgB,EAAOizB,SAAU5wB,IAAUrC,EAAOizB,SAAUoB,KAGtC,QAAS7T,IACtBphB,EAAMohB,EAAM7f,IAAKU,GAAM,EAAMmxB,SAIjB1vB,IAAR1D,IACJA,EAAMivB,GAAQhtB,EAAMgB,EAAMiwB,IAId,WAARlzB,GAAoBiD,KAAQuvB,KAChCxyB,EAAMwyB,GAAoBvvB,IAIZ,KAAVmwB,GAAgBA,GACpB5xB,EAAMmvB,WAAY3wB,IACD,IAAVozB,GAAkBgC,SAAU5zB,GAAQA,GAAO,EAAIxB,GAGhDA,KAITY,EAAOkB,KAAM,CAAE,SAAU,SAAW,SAAUsD,EAAI2tB,GACjDnyB,EAAOizB,SAAUd,GAAc,CAC9BxxB,IAAK,SAAUU,EAAMitB,EAAUkE,GAC9B,GAAKlE,EAIJ,OAAOkD,GAAa/mB,KAAMzK,EAAOyhB,IAAKpgB,EAAM,aAQxCA,EAAKyxB,iBAAiBxyB,QAAWe,EAAKozB,wBAAwBlG,MAIjEoE,GAAkBtxB,EAAM8wB,EAAWK,GAHnCtE,GAAM7sB,EAAMqwB,GAAS,WACpB,OAAOiB,GAAkBtxB,EAAM8wB,EAAWK,MAM9ChT,IAAK,SAAUne,EAAM8C,EAAOquB,GAC3B,IAAIxuB,EACHsuB,EAASvE,GAAW1sB,GAIpBqzB,GAAsBt2B,EAAQkyB,iBACT,aAApBgC,EAAO5C,SAIR2C,GADkBqC,GAAsBlC,IAEY,eAAnDxyB,EAAOyhB,IAAKpgB,EAAM,aAAa,EAAOixB,GACvCN,EAAWQ,EACVN,GACC7wB,EACA8wB,EACAK,EACAH,EACAC,GAED,EAqBF,OAjBKD,GAAeqC,IACnB1C,GAAYhvB,KAAK0vB,KAChBrxB,EAAM,SAAW8wB,EAAW,GAAIpT,cAAgBoT,EAAU70B,MAAO,IACjEyyB,WAAYuC,EAAQH,IACpBD,GAAoB7wB,EAAM8wB,EAAW,UAAU,EAAOG,GACtD,KAKGN,IAAchuB,EAAUid,GAAQ9W,KAAMhG,KACb,QAA3BH,EAAS,IAAO,QAElB3C,EAAKkgB,MAAO4Q,GAAchuB,EAC1BA,EAAQnE,EAAOyhB,IAAKpgB,EAAM8wB,IAGpBJ,GAAmB1wB,EAAM8C,EAAO6tB,OAK1ChyB,EAAOizB,SAAS3D,WAAaV,GAAcxwB,EAAQiyB,mBAClD,SAAUhvB,EAAMitB,GACf,GAAKA,EACJ,OAASyB,WAAY1B,GAAQhtB,EAAM,gBAClCA,EAAKozB,wBAAwBE,KAC5BzG,GAAM7sB,EAAM,CAAEiuB,WAAY,GAAK,WAC9B,OAAOjuB,EAAKozB,wBAAwBE,QAEnC,OAMP30B,EAAOkB,KAAM,CACZ0zB,OAAQ,GACRC,QAAS,GACTC,OAAQ,SACN,SAAUC,EAAQC,GACpBh1B,EAAOizB,SAAU8B,EAASC,GAAW,CACpCC,OAAQ,SAAU9wB,GAOjB,IANA,IAAIhF,EAAI,EACP+1B,EAAW,GAGXC,EAAyB,iBAAVhxB,EAAqBA,EAAMI,MAAO,KAAQ,CAAEJ,GAEpDhF,EAAI,EAAGA,IACd+1B,EAAUH,EAAS7T,GAAW/hB,GAAM61B,GACnCG,EAAOh2B,IAAOg2B,EAAOh2B,EAAI,IAAOg2B,EAAO,GAGzC,OAAOD,IAIO,WAAXH,IACJ/0B,EAAOizB,SAAU8B,EAASC,GAASxV,IAAMuS,MAI3C/xB,EAAOG,GAAGgC,OAAQ,CACjBsf,IAAK,SAAUpf,EAAM8B,GACpB,OAAOia,EAAQphB,KAAM,SAAUqE,EAAMgB,EAAM8B,GAC1C,IAAImuB,EAAQxwB,EACXV,EAAM,GACNjC,EAAI,EAEL,GAAKyD,MAAMC,QAASR,GAAS,CAI5B,IAHAiwB,EAASvE,GAAW1sB,GACpBS,EAAMO,EAAK/B,OAEHnB,EAAI2C,EAAK3C,IAChBiC,EAAKiB,EAAMlD,IAAQa,EAAOyhB,IAAKpgB,EAAMgB,EAAMlD,IAAK,EAAOmzB,GAGxD,OAAOlxB,EAGR,YAAiB0B,IAAVqB,EACNnE,EAAOuhB,MAAOlgB,EAAMgB,EAAM8B,GAC1BnE,EAAOyhB,IAAKpgB,EAAMgB,IACjBA,EAAM8B,EAA0B,EAAnB7C,UAAUhB,aAQ5BN,EAAO+yB,MAAQA,IAETxyB,UAAY,CACjBE,YAAasyB,GACb3yB,KAAM,SAAUiB,EAAMe,EAASsd,EAAM1d,EAAKgxB,EAAQ9Q,GACjDllB,KAAKqE,KAAOA,EACZrE,KAAK0iB,KAAOA,EACZ1iB,KAAKg2B,OAASA,GAAUhzB,EAAOgzB,OAAOtP,SACtC1mB,KAAKoF,QAAUA,EACfpF,KAAKkU,MAAQlU,KAAKmsB,IAAMnsB,KAAK8O,MAC7B9O,KAAKgF,IAAMA,EACXhF,KAAKklB,KAAOA,IAAUliB,EAAOmiB,UAAWzC,GAAS,GAAK,OAEvD5T,IAAK,WACJ,IAAI0U,EAAQuS,GAAMqC,UAAWp4B,KAAK0iB,MAElC,OAAOc,GAASA,EAAM7f,IACrB6f,EAAM7f,IAAK3D,MACX+1B,GAAMqC,UAAU1R,SAAS/iB,IAAK3D,OAEhCq4B,IAAK,SAAUC,GACd,IAAIC,EACH/U,EAAQuS,GAAMqC,UAAWp4B,KAAK0iB,MAoB/B,OAlBK1iB,KAAKoF,QAAQozB,SACjBx4B,KAAKy4B,IAAMF,EAAQv1B,EAAOgzB,OAAQh2B,KAAKg2B,QACtCsC,EAASt4B,KAAKoF,QAAQozB,SAAWF,EAAS,EAAG,EAAGt4B,KAAKoF,QAAQozB,UAG9Dx4B,KAAKy4B,IAAMF,EAAQD,EAEpBt4B,KAAKmsB,KAAQnsB,KAAKgF,IAAMhF,KAAKkU,OAAUqkB,EAAQv4B,KAAKkU,MAE/ClU,KAAKoF,QAAQszB,MACjB14B,KAAKoF,QAAQszB,KAAKj4B,KAAMT,KAAKqE,KAAMrE,KAAKmsB,IAAKnsB,MAGzCwjB,GAASA,EAAMhB,IACnBgB,EAAMhB,IAAKxiB,MAEX+1B,GAAMqC,UAAU1R,SAASlE,IAAKxiB,MAExBA,QAIOoD,KAAKG,UAAYwyB,GAAMxyB,WAEvCwyB,GAAMqC,UAAY,CACjB1R,SAAU,CACT/iB,IAAK,SAAUihB,GACd,IAAIrR,EAIJ,OAA6B,IAAxBqR,EAAMvgB,KAAK9C,UACa,MAA5BqjB,EAAMvgB,KAAMugB,EAAMlC,OAAoD,MAAlCkC,EAAMvgB,KAAKkgB,MAAOK,EAAMlC,MACrDkC,EAAMvgB,KAAMugB,EAAMlC,OAO1BnP,EAASvQ,EAAOyhB,IAAKG,EAAMvgB,KAAMugB,EAAMlC,KAAM,MAGhB,SAAXnP,EAAwBA,EAAJ,GAEvCiP,IAAK,SAAUoC,GAKT5hB,EAAO21B,GAAGD,KAAM9T,EAAMlC,MAC1B1f,EAAO21B,GAAGD,KAAM9T,EAAMlC,MAAQkC,GACK,IAAxBA,EAAMvgB,KAAK9C,WACtByB,EAAOizB,SAAUrR,EAAMlC,OAC6B,MAAnDkC,EAAMvgB,KAAKkgB,MAAO4P,GAAevP,EAAMlC,OAGxCkC,EAAMvgB,KAAMugB,EAAMlC,MAASkC,EAAMuH,IAFjCnpB,EAAOuhB,MAAOK,EAAMvgB,KAAMugB,EAAMlC,KAAMkC,EAAMuH,IAAMvH,EAAMM,UAU5C0T,UAAY7C,GAAMqC,UAAUS,WAAa,CACxDrW,IAAK,SAAUoC,GACTA,EAAMvgB,KAAK9C,UAAYqjB,EAAMvgB,KAAKzB,aACtCgiB,EAAMvgB,KAAMugB,EAAMlC,MAASkC,EAAMuH,OAKpCnpB,EAAOgzB,OAAS,CACf8C,OAAQ,SAAUC,GACjB,OAAOA,GAERC,MAAO,SAAUD,GAChB,MAAO,GAAM/yB,KAAKizB,IAAKF,EAAI/yB,KAAKkzB,IAAO,GAExCxS,SAAU,SAGX1jB,EAAO21B,GAAK5C,GAAMxyB,UAAUH,KAG5BJ,EAAO21B,GAAGD,KAAO,GAKjB,IACCS,GAAOC,GAmrBHxoB,GAEHyoB,GAprBDC,GAAW,yBACXC,GAAO,cAER,SAASC,KACHJ,MACqB,IAApBx5B,EAAS65B,QAAoB15B,EAAO25B,sBACxC35B,EAAO25B,sBAAuBF,IAE9Bz5B,EAAO+f,WAAY0Z,GAAUx2B,EAAO21B,GAAGgB,UAGxC32B,EAAO21B,GAAGiB,QAKZ,SAASC,KAIR,OAHA95B,EAAO+f,WAAY,WAClBqZ,QAAQrzB,IAEAqzB,GAAQzwB,KAAKyjB,MAIvB,SAAS2N,GAAOn4B,EAAMo4B,GACrB,IAAI/L,EACH7rB,EAAI,EACJuM,EAAQ,CAAEilB,OAAQhyB,GAKnB,IADAo4B,EAAeA,EAAe,EAAI,EAC1B53B,EAAI,EAAGA,GAAK,EAAI43B,EAEvBrrB,EAAO,UADPsf,EAAQ9J,GAAW/hB,KACSuM,EAAO,UAAYsf,GAAUrsB,EAO1D,OAJKo4B,IACJrrB,EAAMwnB,QAAUxnB,EAAM6iB,MAAQ5vB,GAGxB+M,EAGR,SAASsrB,GAAa7yB,EAAOub,EAAMuX,GAKlC,IAJA,IAAIrV,EACHuK,GAAe+K,GAAUC,SAAUzX,IAAU,IAAKhiB,OAAQw5B,GAAUC,SAAU,MAC9E7e,EAAQ,EACRhY,EAAS6rB,EAAW7rB,OACbgY,EAAQhY,EAAQgY,IACvB,GAAOsJ,EAAQuK,EAAY7T,GAAQ7a,KAAMw5B,EAAWvX,EAAMvb,GAGzD,OAAOyd,EAsNV,SAASsV,GAAW71B,EAAM+1B,EAAYh1B,GACrC,IAAImO,EACH8mB,EACA/e,EAAQ,EACRhY,EAAS42B,GAAUI,WAAWh3B,OAC9B+a,EAAWrb,EAAOgb,WAAWI,OAAQ,kBAG7Bwb,EAAKv1B,OAEbu1B,EAAO,WACN,GAAKS,EACJ,OAAO,EAYR,IAVA,IAAIE,EAAcpB,IAASU,KAC1B3Z,EAAYla,KAAKivB,IAAK,EAAGgF,EAAUO,UAAYP,EAAUzB,SAAW+B,GAKpEjC,EAAU,GADHpY,EAAY+Z,EAAUzB,UAAY,GAEzCld,EAAQ,EACRhY,EAAS22B,EAAUQ,OAAOn3B,OAEnBgY,EAAQhY,EAAQgY,IACvB2e,EAAUQ,OAAQnf,GAAQ+c,IAAKC,GAMhC,OAHAja,EAASkB,WAAYlb,EAAM,CAAE41B,EAAW3B,EAASpY,IAG5CoY,EAAU,GAAKh1B,EACZ4c,GAIF5c,GACL+a,EAASkB,WAAYlb,EAAM,CAAE41B,EAAW,EAAG,IAI5C5b,EAASmB,YAAanb,EAAM,CAAE41B,KACvB,IAERA,EAAY5b,EAASzB,QAAS,CAC7BvY,KAAMA,EACNynB,MAAO9oB,EAAOmC,OAAQ,GAAIi1B,GAC1BM,KAAM13B,EAAOmC,QAAQ,EAAM,CAC1Bw1B,cAAe,GACf3E,OAAQhzB,EAAOgzB,OAAOtP,UACpBthB,GACHw1B,mBAAoBR,EACpBS,gBAAiBz1B,EACjBo1B,UAAWrB,IAASU,KACpBrB,SAAUpzB,EAAQozB,SAClBiC,OAAQ,GACRT,YAAa,SAAUtX,EAAM1d,GAC5B,IAAI4f,EAAQ5hB,EAAO+yB,MAAO1xB,EAAM41B,EAAUS,KAAMhY,EAAM1d,EACrDi1B,EAAUS,KAAKC,cAAejY,IAAUuX,EAAUS,KAAK1E,QAExD,OADAiE,EAAUQ,OAAO75B,KAAMgkB,GAChBA,GAERlB,KAAM,SAAUoX,GACf,IAAIxf,EAAQ,EAIXhY,EAASw3B,EAAUb,EAAUQ,OAAOn3B,OAAS,EAC9C,GAAK+2B,EACJ,OAAOr6B,KAGR,IADAq6B,GAAU,EACF/e,EAAQhY,EAAQgY,IACvB2e,EAAUQ,OAAQnf,GAAQ+c,IAAK,GAUhC,OANKyC,GACJzc,EAASkB,WAAYlb,EAAM,CAAE41B,EAAW,EAAG,IAC3C5b,EAASmB,YAAanb,EAAM,CAAE41B,EAAWa,KAEzCzc,EAASuB,WAAYvb,EAAM,CAAE41B,EAAWa,IAElC96B,QAGT8rB,EAAQmO,EAAUnO,MAInB,KA/HD,SAAqBA,EAAO6O,GAC3B,IAAIrf,EAAOjW,EAAM2wB,EAAQ7uB,EAAOqc,EAGhC,IAAMlI,KAASwQ,EAed,GAbAkK,EAAS2E,EADTt1B,EAAO2c,EAAW1G,IAElBnU,EAAQ2kB,EAAOxQ,GACV1V,MAAMC,QAASsB,KACnB6uB,EAAS7uB,EAAO,GAChBA,EAAQ2kB,EAAOxQ,GAAUnU,EAAO,IAG5BmU,IAAUjW,IACdymB,EAAOzmB,GAAS8B,SACT2kB,EAAOxQ,KAGfkI,EAAQxgB,EAAOizB,SAAU5wB,KACX,WAAYme,EAMzB,IAAMlI,KALNnU,EAAQqc,EAAMyU,OAAQ9wB,UACf2kB,EAAOzmB,GAIC8B,EACNmU,KAASwQ,IAChBA,EAAOxQ,GAAUnU,EAAOmU,GACxBqf,EAAerf,GAAU0a,QAI3B2E,EAAet1B,GAAS2wB,EA6F1B+E,CAAYjP,EAAOmO,EAAUS,KAAKC,eAE1Brf,EAAQhY,EAAQgY,IAEvB,GADA/H,EAAS2mB,GAAUI,WAAYhf,GAAQ7a,KAAMw5B,EAAW51B,EAAMynB,EAAOmO,EAAUS,MAM9E,OAJKr5B,EAAYkS,EAAOmQ,QACvB1gB,EAAOygB,YAAawW,EAAU51B,KAAM41B,EAAUS,KAAKnd,OAAQmG,KAC1DnQ,EAAOmQ,KAAKsX,KAAMznB,IAEbA,EAyBT,OArBAvQ,EAAOoB,IAAK0nB,EAAOkO,GAAaC,GAE3B54B,EAAY44B,EAAUS,KAAKxmB,QAC/B+lB,EAAUS,KAAKxmB,MAAMzT,KAAM4D,EAAM41B,GAIlCA,EACErb,SAAUqb,EAAUS,KAAK9b,UACzB/V,KAAMoxB,EAAUS,KAAK7xB,KAAMoxB,EAAUS,KAAKO,UAC1Cpe,KAAMod,EAAUS,KAAK7d,MACrBuB,OAAQ6b,EAAUS,KAAKtc,QAEzBpb,EAAO21B,GAAGuC,MACTl4B,EAAOmC,OAAQy0B,EAAM,CACpBv1B,KAAMA,EACN82B,KAAMlB,EACN1c,MAAO0c,EAAUS,KAAKnd,SAIjB0c,EAGRj3B,EAAOk3B,UAAYl3B,EAAOmC,OAAQ+0B,GAAW,CAE5CC,SAAU,CACTiB,IAAK,CAAE,SAAU1Y,EAAMvb,GACtB,IAAIyd,EAAQ5kB,KAAKg6B,YAAatX,EAAMvb,GAEpC,OADAud,GAAWE,EAAMvgB,KAAMqe,EAAMuB,GAAQ9W,KAAMhG,GAASyd,GAC7CA,KAITyW,QAAS,SAAUvP,EAAO3nB,GACpB9C,EAAYyqB,IAChB3nB,EAAW2nB,EACXA,EAAQ,CAAE,MAEVA,EAAQA,EAAMhf,MAAOoP,GAOtB,IAJA,IAAIwG,EACHpH,EAAQ,EACRhY,EAASwoB,EAAMxoB,OAERgY,EAAQhY,EAAQgY,IACvBoH,EAAOoJ,EAAOxQ,GACd4e,GAAUC,SAAUzX,GAASwX,GAAUC,SAAUzX,IAAU,GAC3DwX,GAAUC,SAAUzX,GAAO9Q,QAASzN,IAItCm2B,WAAY,CA3Wb,SAA2Bj2B,EAAMynB,EAAO4O,GACvC,IAAIhY,EAAMvb,EAAOwe,EAAQnC,EAAO8X,EAASC,EAAWC,EAAgBhX,EACnEiX,EAAQ,UAAW3P,GAAS,WAAYA,EACxCqP,EAAOn7B,KACPsuB,EAAO,GACP/J,EAAQlgB,EAAKkgB,MACbkV,EAASp1B,EAAK9C,UAAY+iB,GAAoBjgB,GAC9Cq3B,EAAW9Y,EAASjf,IAAKU,EAAM,UA6BhC,IAAMqe,KA1BAgY,EAAKnd,QAEa,OADvBiG,EAAQxgB,EAAOygB,YAAapf,EAAM,OACvBs3B,WACVnY,EAAMmY,SAAW,EACjBL,EAAU9X,EAAM1N,MAAM2H,KACtB+F,EAAM1N,MAAM2H,KAAO,WACZ+F,EAAMmY,UACXL,MAIH9X,EAAMmY,WAENR,EAAK/c,OAAQ,WAGZ+c,EAAK/c,OAAQ,WACZoF,EAAMmY,WACA34B,EAAOua,MAAOlZ,EAAM,MAAOf,QAChCkgB,EAAM1N,MAAM2H,YAOFqO,EAEb,GADA3kB,EAAQ2kB,EAAOpJ,GACV4W,GAAS7rB,KAAMtG,GAAU,CAG7B,UAFO2kB,EAAOpJ,GACdiD,EAASA,GAAoB,WAAVxe,EACdA,KAAYsyB,EAAS,OAAS,QAAW,CAI7C,GAAe,SAAVtyB,IAAoBu0B,QAAiC51B,IAArB41B,EAAUhZ,GAK9C,SAJA+W,GAAS,EAOXnL,EAAM5L,GAASgZ,GAAYA,EAAUhZ,IAAU1f,EAAOuhB,MAAOlgB,EAAMqe,GAMrE,IADA6Y,GAAav4B,EAAOyD,cAAeqlB,MAChB9oB,EAAOyD,cAAe6nB,GA8DzC,IAAM5L,KAzDD+Y,GAA2B,IAAlBp3B,EAAK9C,WAMlBm5B,EAAKkB,SAAW,CAAErX,EAAMqX,SAAUrX,EAAMsX,UAAWtX,EAAMuX,WAIlC,OADvBN,EAAiBE,GAAYA,EAASlX,WAErCgX,EAAiB5Y,EAASjf,IAAKU,EAAM,YAGrB,UADjBmgB,EAAUxhB,EAAOyhB,IAAKpgB,EAAM,cAEtBm3B,EACJhX,EAAUgX,GAIVlW,GAAU,CAAEjhB,IAAQ,GACpBm3B,EAAiBn3B,EAAKkgB,MAAMC,SAAWgX,EACvChX,EAAUxhB,EAAOyhB,IAAKpgB,EAAM,WAC5BihB,GAAU,CAAEjhB,OAKG,WAAZmgB,GAAoC,iBAAZA,GAAgD,MAAlBgX,IACrB,SAAhCx4B,EAAOyhB,IAAKpgB,EAAM,WAGhBk3B,IACLJ,EAAKtyB,KAAM,WACV0b,EAAMC,QAAUgX,IAEM,MAAlBA,IACJhX,EAAUD,EAAMC,QAChBgX,EAA6B,SAAZhX,EAAqB,GAAKA,IAG7CD,EAAMC,QAAU,iBAKdkW,EAAKkB,WACTrX,EAAMqX,SAAW,SACjBT,EAAK/c,OAAQ,WACZmG,EAAMqX,SAAWlB,EAAKkB,SAAU,GAChCrX,EAAMsX,UAAYnB,EAAKkB,SAAU,GACjCrX,EAAMuX,UAAYpB,EAAKkB,SAAU,MAKnCL,GAAY,EACEjN,EAGPiN,IACAG,EACC,WAAYA,IAChBjC,EAASiC,EAASjC,QAGnBiC,EAAW9Y,EAASxB,OAAQ/c,EAAM,SAAU,CAAEmgB,QAASgX,IAInD7V,IACJ+V,EAASjC,QAAUA,GAIfA,GACJnU,GAAU,CAAEjhB,IAAQ,GAKrB82B,EAAKtyB,KAAM,WASV,IAAM6Z,KAJA+W,GACLnU,GAAU,CAAEjhB,IAEbue,EAAShF,OAAQvZ,EAAM,UACTiqB,EACbtrB,EAAOuhB,MAAOlgB,EAAMqe,EAAM4L,EAAM5L,OAMnC6Y,EAAYvB,GAAaP,EAASiC,EAAUhZ,GAAS,EAAGA,EAAMyY,GACtDzY,KAAQgZ,IACfA,EAAUhZ,GAAS6Y,EAAUrnB,MACxBulB,IACJ8B,EAAUv2B,IAAMu2B,EAAUrnB,MAC1BqnB,EAAUrnB,MAAQ,MAuMrB6nB,UAAW,SAAU53B,EAAU+rB,GACzBA,EACJgK,GAAUI,WAAW1oB,QAASzN,GAE9B+1B,GAAUI,WAAW15B,KAAMuD,MAK9BnB,EAAOg5B,MAAQ,SAAUA,EAAOhG,EAAQ7yB,GACvC,IAAIk2B,EAAM2C,GAA0B,iBAAVA,EAAqBh5B,EAAOmC,OAAQ,GAAI62B,GAAU,CAC3Ef,SAAU93B,IAAOA,GAAM6yB,GACtB30B,EAAY26B,IAAWA,EACxBxD,SAAUwD,EACVhG,OAAQ7yB,GAAM6yB,GAAUA,IAAW30B,EAAY20B,IAAYA,GAoC5D,OAhCKhzB,EAAO21B,GAAGlQ,IACd4Q,EAAIb,SAAW,EAGc,iBAAjBa,EAAIb,WACVa,EAAIb,YAAYx1B,EAAO21B,GAAGsD,OAC9B5C,EAAIb,SAAWx1B,EAAO21B,GAAGsD,OAAQ5C,EAAIb,UAGrCa,EAAIb,SAAWx1B,EAAO21B,GAAGsD,OAAOvV,UAMjB,MAAb2S,EAAI9b,QAA+B,IAAd8b,EAAI9b,QAC7B8b,EAAI9b,MAAQ,MAIb8b,EAAIlI,IAAMkI,EAAI4B,SAEd5B,EAAI4B,SAAW,WACT55B,EAAYg4B,EAAIlI,MACpBkI,EAAIlI,IAAI1wB,KAAMT,MAGVq5B,EAAI9b,OACRva,EAAOsgB,QAAStjB,KAAMq5B,EAAI9b,QAIrB8b,GAGRr2B,EAAOG,GAAGgC,OAAQ,CACjB+2B,OAAQ,SAAUF,EAAOG,EAAInG,EAAQ7xB,GAGpC,OAAOnE,KAAKsQ,OAAQgU,IAAqBG,IAAK,UAAW,GAAIc,OAG3DvgB,MAAMo3B,QAAS,CAAElG,QAASiG,GAAMH,EAAOhG,EAAQ7xB,IAElDi4B,QAAS,SAAU1Z,EAAMsZ,EAAOhG,EAAQ7xB,GACvC,IAAI2R,EAAQ9S,EAAOyD,cAAeic,GACjC2Z,EAASr5B,EAAOg5B,MAAOA,EAAOhG,EAAQ7xB,GACtCm4B,EAAc,WAGb,IAAInB,EAAOjB,GAAWl6B,KAAMgD,EAAOmC,OAAQ,GAAIud,GAAQ2Z,IAGlDvmB,GAAS8M,EAASjf,IAAK3D,KAAM,YACjCm7B,EAAKzX,MAAM,IAMd,OAFA4Y,EAAYC,OAASD,EAEdxmB,IAA0B,IAAjBumB,EAAO9e,MACtBvd,KAAKkE,KAAMo4B,GACXt8B,KAAKud,MAAO8e,EAAO9e,MAAO+e,IAE5B5Y,KAAM,SAAU/hB,EAAMiiB,EAAYkX,GACjC,IAAI0B,EAAY,SAAUhZ,GACzB,IAAIE,EAAOF,EAAME,YACVF,EAAME,KACbA,EAAMoX,IAYP,MATqB,iBAATn5B,IACXm5B,EAAUlX,EACVA,EAAajiB,EACbA,OAAOmE,GAEH8d,GACJ5jB,KAAKud,MAAO5b,GAAQ,KAAM,IAGpB3B,KAAKkE,KAAM,WACjB,IAAIof,GAAU,EACbhI,EAAgB,MAAR3Z,GAAgBA,EAAO,aAC/B86B,EAASz5B,EAAOy5B,OAChBha,EAAOG,EAASjf,IAAK3D,MAEtB,GAAKsb,EACCmH,EAAMnH,IAAWmH,EAAMnH,GAAQoI,MACnC8Y,EAAW/Z,EAAMnH,SAGlB,IAAMA,KAASmH,EACTA,EAAMnH,IAAWmH,EAAMnH,GAAQoI,MAAQ6V,GAAK9rB,KAAM6N,IACtDkhB,EAAW/Z,EAAMnH,IAKpB,IAAMA,EAAQmhB,EAAOn5B,OAAQgY,KACvBmhB,EAAQnhB,GAAQjX,OAASrE,MACnB,MAAR2B,GAAgB86B,EAAQnhB,GAAQiC,QAAU5b,IAE5C86B,EAAQnhB,GAAQ6f,KAAKzX,KAAMoX,GAC3BxX,GAAU,EACVmZ,EAAOv3B,OAAQoW,EAAO,KAOnBgI,GAAYwX,GAChB93B,EAAOsgB,QAAStjB,KAAM2B,MAIzB46B,OAAQ,SAAU56B,GAIjB,OAHc,IAATA,IACJA,EAAOA,GAAQ,MAET3B,KAAKkE,KAAM,WACjB,IAAIoX,EACHmH,EAAOG,EAASjf,IAAK3D,MACrBud,EAAQkF,EAAM9gB,EAAO,SACrB6hB,EAAQf,EAAM9gB,EAAO,cACrB86B,EAASz5B,EAAOy5B,OAChBn5B,EAASia,EAAQA,EAAMja,OAAS,EAajC,IAVAmf,EAAK8Z,QAAS,EAGdv5B,EAAOua,MAAOvd,KAAM2B,EAAM,IAErB6hB,GAASA,EAAME,MACnBF,EAAME,KAAKjjB,KAAMT,MAAM,GAIlBsb,EAAQmhB,EAAOn5B,OAAQgY,KACvBmhB,EAAQnhB,GAAQjX,OAASrE,MAAQy8B,EAAQnhB,GAAQiC,QAAU5b,IAC/D86B,EAAQnhB,GAAQ6f,KAAKzX,MAAM,GAC3B+Y,EAAOv3B,OAAQoW,EAAO,IAKxB,IAAMA,EAAQ,EAAGA,EAAQhY,EAAQgY,IAC3BiC,EAAOjC,IAAWiC,EAAOjC,GAAQihB,QACrChf,EAAOjC,GAAQihB,OAAO97B,KAAMT,aAKvByiB,EAAK8Z,YAKfv5B,EAAOkB,KAAM,CAAE,SAAU,OAAQ,QAAU,SAAUsD,EAAInC,GACxD,IAAIq3B,EAAQ15B,EAAOG,GAAIkC,GACvBrC,EAAOG,GAAIkC,GAAS,SAAU22B,EAAOhG,EAAQ7xB,GAC5C,OAAgB,MAAT63B,GAAkC,kBAAVA,EAC9BU,EAAM/7B,MAAOX,KAAMsE,WACnBtE,KAAKo8B,QAAStC,GAAOz0B,GAAM,GAAQ22B,EAAOhG,EAAQ7xB,MAKrDnB,EAAOkB,KAAM,CACZy4B,UAAW7C,GAAO,QAClB8C,QAAS9C,GAAO,QAChB+C,YAAa/C,GAAO,UACpBgD,OAAQ,CAAE5G,QAAS,QACnB6G,QAAS,CAAE7G,QAAS,QACpB8G,WAAY,CAAE9G,QAAS,WACrB,SAAU7wB,EAAMymB,GAClB9oB,EAAOG,GAAIkC,GAAS,SAAU22B,EAAOhG,EAAQ7xB,GAC5C,OAAOnE,KAAKo8B,QAAStQ,EAAOkQ,EAAOhG,EAAQ7xB,MAI7CnB,EAAOy5B,OAAS,GAChBz5B,EAAO21B,GAAGiB,KAAO,WAChB,IAAIsB,EACH/4B,EAAI,EACJs6B,EAASz5B,EAAOy5B,OAIjB,IAFAtD,GAAQzwB,KAAKyjB,MAELhqB,EAAIs6B,EAAOn5B,OAAQnB,KAC1B+4B,EAAQuB,EAAQt6B,OAGCs6B,EAAQt6B,KAAQ+4B,GAChCuB,EAAOv3B,OAAQ/C,IAAK,GAIhBs6B,EAAOn5B,QACZN,EAAO21B,GAAGjV,OAEXyV,QAAQrzB,GAGT9C,EAAO21B,GAAGuC,MAAQ,SAAUA,GAC3Bl4B,EAAOy5B,OAAO77B,KAAMs6B,GACpBl4B,EAAO21B,GAAGzkB,SAGXlR,EAAO21B,GAAGgB,SAAW,GACrB32B,EAAO21B,GAAGzkB,MAAQ,WACZklB,KAILA,IAAa,EACbI,OAGDx2B,EAAO21B,GAAGjV,KAAO,WAChB0V,GAAa,MAGdp2B,EAAO21B,GAAGsD,OAAS,CAClBgB,KAAM,IACNC,KAAM,IAGNxW,SAAU,KAMX1jB,EAAOG,GAAGg6B,MAAQ,SAAUC,EAAMz7B,GAIjC,OAHAy7B,EAAOp6B,EAAO21B,IAAK31B,EAAO21B,GAAGsD,OAAQmB,IAAiBA,EACtDz7B,EAAOA,GAAQ,KAER3B,KAAKud,MAAO5b,EAAM,SAAU4K,EAAMiX,GACxC,IAAI6Z,EAAUt9B,EAAO+f,WAAYvT,EAAM6wB,GACvC5Z,EAAME,KAAO,WACZ3jB,EAAOu9B,aAAcD,OAOnBzsB,GAAQhR,EAAS0C,cAAe,SAEnC+2B,GADSz5B,EAAS0C,cAAe,UACpBK,YAAa/C,EAAS0C,cAAe,WAEnDsO,GAAMjP,KAAO,WAIbP,EAAQm8B,QAA0B,KAAhB3sB,GAAMzJ,MAIxB/F,EAAQo8B,YAAcnE,GAAIzjB,UAI1BhF,GAAQhR,EAAS0C,cAAe,UAC1B6E,MAAQ,IACdyJ,GAAMjP,KAAO,QACbP,EAAQq8B,WAA6B,MAAhB7sB,GAAMzJ,MAI5B,IAAIu2B,GACH9uB,GAAa5L,EAAO6O,KAAKjD,WAE1B5L,EAAOG,GAAGgC,OAAQ,CACjB4M,KAAM,SAAU1M,EAAM8B,GACrB,OAAOia,EAAQphB,KAAMgD,EAAO+O,KAAM1M,EAAM8B,EAA0B,EAAnB7C,UAAUhB,SAG1Dq6B,WAAY,SAAUt4B,GACrB,OAAOrF,KAAKkE,KAAM,WACjBlB,EAAO26B,WAAY39B,KAAMqF,QAK5BrC,EAAOmC,OAAQ,CACd4M,KAAM,SAAU1N,EAAMgB,EAAM8B,GAC3B,IAAIpD,EAAKyf,EACRoa,EAAQv5B,EAAK9C,SAGd,GAAe,IAAVq8B,GAAyB,IAAVA,GAAyB,IAAVA,EAKnC,MAAkC,oBAAtBv5B,EAAK7B,aACTQ,EAAO0f,KAAMre,EAAMgB,EAAM8B,IAKlB,IAAVy2B,GAAgB56B,EAAO8W,SAAUzV,KACrCmf,EAAQxgB,EAAO66B,UAAWx4B,EAAKoC,iBAC5BzE,EAAO6O,KAAK/E,MAAMjC,KAAK4C,KAAMpI,GAASq4B,QAAW53B,SAGtCA,IAAVqB,EACW,OAAVA,OACJnE,EAAO26B,WAAYt5B,EAAMgB,GAIrBme,GAAS,QAASA,QACuB1d,KAA3C/B,EAAMyf,EAAMhB,IAAKne,EAAM8C,EAAO9B,IACzBtB,GAGRM,EAAK5B,aAAc4C,EAAM8B,EAAQ,IAC1BA,GAGHqc,GAAS,QAASA,GAA+C,QAApCzf,EAAMyf,EAAM7f,IAAKU,EAAMgB,IACjDtB,EAMM,OAHdA,EAAMf,EAAOwN,KAAKuB,KAAM1N,EAAMgB,SAGTS,EAAY/B,IAGlC85B,UAAW,CACVl8B,KAAM,CACL6gB,IAAK,SAAUne,EAAM8C,GACpB,IAAM/F,EAAQq8B,YAAwB,UAAVt2B,GAC3BkF,EAAUhI,EAAM,SAAY,CAC5B,IAAIjC,EAAMiC,EAAK8C,MAKf,OAJA9C,EAAK5B,aAAc,OAAQ0E,GACtB/E,IACJiC,EAAK8C,MAAQ/E,GAEP+E,MAMXw2B,WAAY,SAAUt5B,EAAM8C,GAC3B,IAAI9B,EACHlD,EAAI,EAIJ27B,EAAY32B,GAASA,EAAM2F,MAAOoP,GAEnC,GAAK4hB,GAA+B,IAAlBz5B,EAAK9C,SACtB,MAAU8D,EAAOy4B,EAAW37B,KAC3BkC,EAAK2J,gBAAiB3I,MAO1Bq4B,GAAW,CACVlb,IAAK,SAAUne,EAAM8C,EAAO9B,GAQ3B,OAPe,IAAV8B,EAGJnE,EAAO26B,WAAYt5B,EAAMgB,GAEzBhB,EAAK5B,aAAc4C,EAAMA,GAEnBA,IAITrC,EAAOkB,KAAMlB,EAAO6O,KAAK/E,MAAMjC,KAAKmZ,OAAOlX,MAAO,QAAU,SAAUtF,EAAInC,GACzE,IAAI04B,EAASnvB,GAAYvJ,IAAUrC,EAAOwN,KAAKuB,KAE/CnD,GAAYvJ,GAAS,SAAUhB,EAAMgB,EAAMwC,GAC1C,IAAI9D,EAAK+lB,EACRkU,EAAgB34B,EAAKoC,cAYtB,OAVMI,IAGLiiB,EAASlb,GAAYovB,GACrBpvB,GAAYovB,GAAkBj6B,EAC9BA,EAAqC,MAA/Bg6B,EAAQ15B,EAAMgB,EAAMwC,GACzBm2B,EACA,KACDpvB,GAAYovB,GAAkBlU,GAExB/lB,KAOT,IAAIk6B,GAAa,sCAChBC,GAAa,gBAyIb,SAASC,GAAkBh3B,GAE1B,OADaA,EAAM2F,MAAOoP,IAAmB,IAC/BrO,KAAM,KAItB,SAASuwB,GAAU/5B,GAClB,OAAOA,EAAK7B,cAAgB6B,EAAK7B,aAAc,UAAa,GAG7D,SAAS67B,GAAgBl3B,GACxB,OAAKvB,MAAMC,QAASsB,GACZA,EAEc,iBAAVA,GACJA,EAAM2F,MAAOoP,IAEd,GAxJRlZ,EAAOG,GAAGgC,OAAQ,CACjBud,KAAM,SAAUrd,EAAM8B,GACrB,OAAOia,EAAQphB,KAAMgD,EAAO0f,KAAMrd,EAAM8B,EAA0B,EAAnB7C,UAAUhB,SAG1Dg7B,WAAY,SAAUj5B,GACrB,OAAOrF,KAAKkE,KAAM,kBACVlE,KAAMgD,EAAOu7B,QAASl5B,IAAUA,QAK1CrC,EAAOmC,OAAQ,CACdud,KAAM,SAAUre,EAAMgB,EAAM8B,GAC3B,IAAIpD,EAAKyf,EACRoa,EAAQv5B,EAAK9C,SAGd,GAAe,IAAVq8B,GAAyB,IAAVA,GAAyB,IAAVA,EAWnC,OAPe,IAAVA,GAAgB56B,EAAO8W,SAAUzV,KAGrCgB,EAAOrC,EAAOu7B,QAASl5B,IAAUA,EACjCme,EAAQxgB,EAAOo1B,UAAW/yB,SAGZS,IAAVqB,EACCqc,GAAS,QAASA,QACuB1d,KAA3C/B,EAAMyf,EAAMhB,IAAKne,EAAM8C,EAAO9B,IACzBtB,EAGCM,EAAMgB,GAAS8B,EAGpBqc,GAAS,QAASA,GAA+C,QAApCzf,EAAMyf,EAAM7f,IAAKU,EAAMgB,IACjDtB,EAGDM,EAAMgB,IAGd+yB,UAAW,CACV3iB,SAAU,CACT9R,IAAK,SAAUU,GAOd,IAAIm6B,EAAWx7B,EAAOwN,KAAKuB,KAAM1N,EAAM,YAEvC,OAAKm6B,EACG5K,SAAU4K,EAAU,IAI3BP,GAAWxwB,KAAMpJ,EAAKgI,WACtB6xB,GAAWzwB,KAAMpJ,EAAKgI,WACtBhI,EAAKmR,KAEE,GAGA,KAKX+oB,QAAS,CACRE,MAAO,UACPC,QAAS,eAYLt9B,EAAQo8B,cACbx6B,EAAOo1B,UAAUxiB,SAAW,CAC3BjS,IAAK,SAAUU,GAId,IAAI8P,EAAS9P,EAAKzB,WAIlB,OAHKuR,GAAUA,EAAOvR,YACrBuR,EAAOvR,WAAWiT,cAEZ,MAER2M,IAAK,SAAUne,GAId,IAAI8P,EAAS9P,EAAKzB,WACbuR,IACJA,EAAO0B,cAEF1B,EAAOvR,YACXuR,EAAOvR,WAAWiT,kBAOvB7S,EAAOkB,KAAM,CACZ,WACA,WACA,YACA,cACA,cACA,UACA,UACA,SACA,cACA,mBACE,WACFlB,EAAOu7B,QAASv+B,KAAKyH,eAAkBzH,OA4BxCgD,EAAOG,GAAGgC,OAAQ,CACjBw5B,SAAU,SAAUx3B,GACnB,IAAIy3B,EAASv6B,EAAMyK,EAAK+vB,EAAUC,EAAO/5B,EAAGg6B,EAC3C58B,EAAI,EAEL,GAAKd,EAAY8F,GAChB,OAAOnH,KAAKkE,KAAM,SAAUa,GAC3B/B,EAAQhD,MAAO2+B,SAAUx3B,EAAM1G,KAAMT,KAAM+E,EAAGq5B,GAAUp+B,UAM1D,IAFA4+B,EAAUP,GAAgBl3B,IAEb7D,OACZ,MAAUe,EAAOrE,KAAMmC,KAItB,GAHA08B,EAAWT,GAAU/5B,GACrByK,EAAwB,IAAlBzK,EAAK9C,UAAoB,IAAM48B,GAAkBU,GAAa,IAEzD,CACV95B,EAAI,EACJ,MAAU+5B,EAAQF,EAAS75B,KACrB+J,EAAIjO,QAAS,IAAMi+B,EAAQ,KAAQ,IACvChwB,GAAOgwB,EAAQ,KAMZD,KADLE,EAAaZ,GAAkBrvB,KAE9BzK,EAAK5B,aAAc,QAASs8B,GAMhC,OAAO/+B,MAGRg/B,YAAa,SAAU73B,GACtB,IAAIy3B,EAASv6B,EAAMyK,EAAK+vB,EAAUC,EAAO/5B,EAAGg6B,EAC3C58B,EAAI,EAEL,GAAKd,EAAY8F,GAChB,OAAOnH,KAAKkE,KAAM,SAAUa,GAC3B/B,EAAQhD,MAAOg/B,YAAa73B,EAAM1G,KAAMT,KAAM+E,EAAGq5B,GAAUp+B,UAI7D,IAAMsE,UAAUhB,OACf,OAAOtD,KAAK+R,KAAM,QAAS,IAK5B,IAFA6sB,EAAUP,GAAgBl3B,IAEb7D,OACZ,MAAUe,EAAOrE,KAAMmC,KAMtB,GALA08B,EAAWT,GAAU/5B,GAGrByK,EAAwB,IAAlBzK,EAAK9C,UAAoB,IAAM48B,GAAkBU,GAAa,IAEzD,CACV95B,EAAI,EACJ,MAAU+5B,EAAQF,EAAS75B,KAG1B,OAA4C,EAApC+J,EAAIjO,QAAS,IAAMi+B,EAAQ,KAClChwB,EAAMA,EAAI5I,QAAS,IAAM44B,EAAQ,IAAK,KAMnCD,KADLE,EAAaZ,GAAkBrvB,KAE9BzK,EAAK5B,aAAc,QAASs8B,GAMhC,OAAO/+B,MAGRi/B,YAAa,SAAU93B,EAAO+3B,GAC7B,IAAIv9B,SAAcwF,EACjBg4B,EAAwB,WAATx9B,GAAqBiE,MAAMC,QAASsB,GAEpD,MAAyB,kBAAb+3B,GAA0BC,EAC9BD,EAAWl/B,KAAK2+B,SAAUx3B,GAAUnH,KAAKg/B,YAAa73B,GAGzD9F,EAAY8F,GACTnH,KAAKkE,KAAM,SAAU/B,GAC3Ba,EAAQhD,MAAOi/B,YACd93B,EAAM1G,KAAMT,KAAMmC,EAAGi8B,GAAUp+B,MAAQk/B,GACvCA,KAKIl/B,KAAKkE,KAAM,WACjB,IAAIgM,EAAW/N,EAAGsY,EAAM2kB,EAExB,GAAKD,EAAe,CAGnBh9B,EAAI,EACJsY,EAAOzX,EAAQhD,MACfo/B,EAAaf,GAAgBl3B,GAE7B,MAAU+I,EAAYkvB,EAAYj9B,KAG5BsY,EAAK4kB,SAAUnvB,GACnBuK,EAAKukB,YAAa9uB,GAElBuK,EAAKkkB,SAAUzuB,aAKIpK,IAAVqB,GAAgC,YAATxF,KAClCuO,EAAYkuB,GAAUp+B,QAIrB4iB,EAASJ,IAAKxiB,KAAM,gBAAiBkQ,GAOjClQ,KAAKyC,cACTzC,KAAKyC,aAAc,QAClByN,IAAuB,IAAV/I,EACZ,GACAyb,EAASjf,IAAK3D,KAAM,kBAAqB,QAO/Cq/B,SAAU,SAAUp8B,GACnB,IAAIiN,EAAW7L,EACdlC,EAAI,EAEL+N,EAAY,IAAMjN,EAAW,IAC7B,MAAUoB,EAAOrE,KAAMmC,KACtB,GAAuB,IAAlBkC,EAAK9C,WACoE,GAA3E,IAAM48B,GAAkBC,GAAU/5B,IAAW,KAAMxD,QAASqP,GAC9D,OAAO,EAIT,OAAO,KAOT,IAAIovB,GAAU,MAEdt8B,EAAOG,GAAGgC,OAAQ,CACjB/C,IAAK,SAAU+E,GACd,IAAIqc,EAAOzf,EAAKurB,EACfjrB,EAAOrE,KAAM,GAEd,OAAMsE,UAAUhB,QA0BhBgsB,EAAkBjuB,EAAY8F,GAEvBnH,KAAKkE,KAAM,SAAU/B,GAC3B,IAAIC,EAEmB,IAAlBpC,KAAKuB,WAWE,OANXa,EADIktB,EACEnoB,EAAM1G,KAAMT,KAAMmC,EAAGa,EAAQhD,MAAOoC,OAEpC+E,GAKN/E,EAAM,GAEoB,iBAARA,EAClBA,GAAO,GAEIwD,MAAMC,QAASzD,KAC1BA,EAAMY,EAAOoB,IAAKhC,EAAK,SAAU+E,GAChC,OAAgB,MAATA,EAAgB,GAAKA,EAAQ,OAItCqc,EAAQxgB,EAAOu8B,SAAUv/B,KAAK2B,OAAUqB,EAAOu8B,SAAUv/B,KAAKqM,SAAS5E,iBAGrD,QAAS+b,QAA+C1d,IAApC0d,EAAMhB,IAAKxiB,KAAMoC,EAAK,WAC3DpC,KAAKmH,MAAQ/E,OAzDTiC,GACJmf,EAAQxgB,EAAOu8B,SAAUl7B,EAAK1C,OAC7BqB,EAAOu8B,SAAUl7B,EAAKgI,SAAS5E,iBAG/B,QAAS+b,QACgC1d,KAAvC/B,EAAMyf,EAAM7f,IAAKU,EAAM,UAElBN,EAMY,iBAHpBA,EAAMM,EAAK8C,OAIHpD,EAAImC,QAASo5B,GAAS,IAIhB,MAAPv7B,EAAc,GAAKA,OAG3B,KAyCHf,EAAOmC,OAAQ,CACdo6B,SAAU,CACTnZ,OAAQ,CACPziB,IAAK,SAAUU,GAEd,IAAIjC,EAAMY,EAAOwN,KAAKuB,KAAM1N,EAAM,SAClC,OAAc,MAAPjC,EACNA,EAMA+7B,GAAkBn7B,EAAOT,KAAM8B,MAGlC2D,OAAQ,CACPrE,IAAK,SAAUU,GACd,IAAI8C,EAAOif,EAAQjkB,EAClBiD,EAAUf,EAAKe,QACfkW,EAAQjX,EAAKwR,cACbyS,EAAoB,eAAdjkB,EAAK1C,KACX6jB,EAAS8C,EAAM,KAAO,GACtB2M,EAAM3M,EAAMhN,EAAQ,EAAIlW,EAAQ9B,OAUjC,IAPCnB,EADImZ,EAAQ,EACR2Z,EAGA3M,EAAMhN,EAAQ,EAIXnZ,EAAI8yB,EAAK9yB,IAKhB,KAJAikB,EAAShhB,EAASjD,IAIJyT,UAAYzT,IAAMmZ,KAG7B8K,EAAOha,YACLga,EAAOxjB,WAAWwJ,WACnBC,EAAU+Z,EAAOxjB,WAAY,aAAiB,CAMjD,GAHAuE,EAAQnE,EAAQojB,GAAShkB,MAGpBkmB,EACJ,OAAOnhB,EAIRqe,EAAO5kB,KAAMuG,GAIf,OAAOqe,GAGRhD,IAAK,SAAUne,EAAM8C,GACpB,IAAIq4B,EAAWpZ,EACdhhB,EAAUf,EAAKe,QACfogB,EAASxiB,EAAO2D,UAAWQ,GAC3BhF,EAAIiD,EAAQ9B,OAEb,MAAQnB,MACPikB,EAAShhB,EAASjD,IAINyT,UACuD,EAAlE5S,EAAO6D,QAAS7D,EAAOu8B,SAASnZ,OAAOziB,IAAKyiB,GAAUZ,MAEtDga,GAAY,GAUd,OAHMA,IACLn7B,EAAKwR,eAAiB,GAEhB2P,OAOXxiB,EAAOkB,KAAM,CAAE,QAAS,YAAc,WACrClB,EAAOu8B,SAAUv/B,MAAS,CACzBwiB,IAAK,SAAUne,EAAM8C,GACpB,GAAKvB,MAAMC,QAASsB,GACnB,OAAS9C,EAAKsR,SAA2D,EAAjD3S,EAAO6D,QAAS7D,EAAQqB,GAAOjC,MAAO+E,KAI3D/F,EAAQm8B,UACbv6B,EAAOu8B,SAAUv/B,MAAO2D,IAAM,SAAUU,GACvC,OAAwC,OAAjCA,EAAK7B,aAAc,SAAqB,KAAO6B,EAAK8C,UAW9D/F,EAAQq+B,QAAU,cAAe1/B,EAGjC,IAAI2/B,GAAc,kCACjBC,GAA0B,SAAUlzB,GACnCA,EAAEsc,mBAGJ/lB,EAAOmC,OAAQnC,EAAOwlB,MAAO,CAE5BU,QAAS,SAAUV,EAAO/F,EAAMpe,EAAMu7B,GAErC,IAAIz9B,EAAG2M,EAAK6B,EAAKkvB,EAAYC,EAAQhW,EAAQ3K,EAAS4gB,EACrDC,EAAY,CAAE37B,GAAQzE,GACtB+B,EAAOX,EAAOP,KAAM+nB,EAAO,QAAWA,EAAM7mB,KAAO6mB,EACnDkB,EAAa1oB,EAAOP,KAAM+nB,EAAO,aAAgBA,EAAM/Y,UAAUlI,MAAO,KAAQ,GAKjF,GAHAuH,EAAMixB,EAAcpvB,EAAMtM,EAAOA,GAAQzE,EAGlB,IAAlByE,EAAK9C,UAAoC,IAAlB8C,EAAK9C,WAK5Bm+B,GAAYjyB,KAAM9L,EAAOqB,EAAOwlB,MAAMuB,cAIf,EAAvBpoB,EAAKd,QAAS,OAIlBc,GADA+nB,EAAa/nB,EAAK4F,MAAO,MACP8G,QAClBqb,EAAWzkB,QAEZ66B,EAASn+B,EAAKd,QAAS,KAAQ,GAAK,KAAOc,GAG3C6mB,EAAQA,EAAOxlB,EAAO+C,SACrByiB,EACA,IAAIxlB,EAAOmmB,MAAOxnB,EAAuB,iBAAV6mB,GAAsBA,IAGhDK,UAAY+W,EAAe,EAAI,EACrCpX,EAAM/Y,UAAYia,EAAW7b,KAAM,KACnC2a,EAAMwC,WAAaxC,EAAM/Y,UACxB,IAAI1F,OAAQ,UAAY2f,EAAW7b,KAAM,iBAAoB,WAC7D,KAGD2a,EAAMjV,YAASzN,EACT0iB,EAAM/iB,SACX+iB,EAAM/iB,OAASpB,GAIhBoe,EAAe,MAARA,EACN,CAAE+F,GACFxlB,EAAO2D,UAAW8b,EAAM,CAAE+F,IAG3BrJ,EAAUnc,EAAOwlB,MAAMrJ,QAASxd,IAAU,GACpCi+B,IAAgBzgB,EAAQ+J,UAAmD,IAAxC/J,EAAQ+J,QAAQvoB,MAAO0D,EAAMoe,IAAtE,CAMA,IAAMmd,IAAiBzgB,EAAQuM,WAAajqB,EAAU4C,GAAS,CAM9D,IAJAw7B,EAAa1gB,EAAQ2J,cAAgBnnB,EAC/B+9B,GAAYjyB,KAAMoyB,EAAal+B,KACpCmN,EAAMA,EAAIlM,YAEHkM,EAAKA,EAAMA,EAAIlM,WACtBo9B,EAAUp/B,KAAMkO,GAChB6B,EAAM7B,EAIF6B,KAAUtM,EAAK6I,eAAiBtN,IACpCogC,EAAUp/B,KAAM+P,EAAIb,aAAea,EAAIsvB,cAAgBlgC,GAKzDoC,EAAI,EACJ,OAAU2M,EAAMkxB,EAAW79B,QAAYqmB,EAAMqC,uBAC5CkV,EAAcjxB,EACd0Z,EAAM7mB,KAAW,EAAJQ,EACZ09B,EACA1gB,EAAQ8K,UAAYtoB,GAGrBmoB,GAAWlH,EAASjf,IAAKmL,EAAK,WAAc1O,OAAOypB,OAAQ,OAAUrB,EAAM7mB,OAC1EihB,EAASjf,IAAKmL,EAAK,YAEnBgb,EAAOnpB,MAAOmO,EAAK2T,IAIpBqH,EAASgW,GAAUhxB,EAAKgxB,KACThW,EAAOnpB,OAASuhB,EAAYpT,KAC1C0Z,EAAMjV,OAASuW,EAAOnpB,MAAOmO,EAAK2T,IACZ,IAAjB+F,EAAMjV,QACViV,EAAMS,kBA8CT,OA1CAT,EAAM7mB,KAAOA,EAGPi+B,GAAiBpX,EAAMuD,sBAEpB5M,EAAQuH,WACqC,IAApDvH,EAAQuH,SAAS/lB,MAAOq/B,EAAU12B,MAAOmZ,KACzCP,EAAY7d,IAIPy7B,GAAUz+B,EAAYgD,EAAM1C,MAAaF,EAAU4C,MAGvDsM,EAAMtM,EAAMy7B,MAGXz7B,EAAMy7B,GAAW,MAIlB98B,EAAOwlB,MAAMuB,UAAYpoB,EAEpB6mB,EAAMqC,wBACVkV,EAAY/vB,iBAAkBrO,EAAMg+B,IAGrCt7B,EAAM1C,KAED6mB,EAAMqC,wBACVkV,EAAYhf,oBAAqBpf,EAAMg+B,IAGxC38B,EAAOwlB,MAAMuB,eAAYjkB,EAEpB6K,IACJtM,EAAMy7B,GAAWnvB,IAMd6X,EAAMjV,SAKd2sB,SAAU,SAAUv+B,EAAM0C,EAAMmkB,GAC/B,IAAI/b,EAAIzJ,EAAOmC,OACd,IAAInC,EAAOmmB,MACXX,EACA,CACC7mB,KAAMA,EACNyqB,aAAa,IAIfppB,EAAOwlB,MAAMU,QAASzc,EAAG,KAAMpI,MAKjCrB,EAAOG,GAAGgC,OAAQ,CAEjB+jB,QAAS,SAAUvnB,EAAM8gB,GACxB,OAAOziB,KAAKkE,KAAM,WACjBlB,EAAOwlB,MAAMU,QAASvnB,EAAM8gB,EAAMziB,SAGpCmgC,eAAgB,SAAUx+B,EAAM8gB,GAC/B,IAAIpe,EAAOrE,KAAM,GACjB,GAAKqE,EACJ,OAAOrB,EAAOwlB,MAAMU,QAASvnB,EAAM8gB,EAAMpe,GAAM,MAc5CjD,EAAQq+B,SACbz8B,EAAOkB,KAAM,CAAEmR,MAAO,UAAW4Y,KAAM,YAAc,SAAUK,EAAM5D,GAGpE,IAAI/b,EAAU,SAAU6Z,GACvBxlB,EAAOwlB,MAAM0X,SAAUxV,EAAKlC,EAAM/iB,OAAQzC,EAAOwlB,MAAMkC,IAAKlC,KAG7DxlB,EAAOwlB,MAAMrJ,QAASuL,GAAQ,CAC7BP,MAAO,WAIN,IAAIjoB,EAAMlC,KAAKkN,eAAiBlN,KAAKJ,UAAYI,KAChDogC,EAAWxd,EAASxB,OAAQlf,EAAKwoB,GAE5B0V,GACLl+B,EAAI8N,iBAAkBse,EAAM3f,GAAS,GAEtCiU,EAASxB,OAAQlf,EAAKwoB,GAAO0V,GAAY,GAAM,IAEhD9V,SAAU,WACT,IAAIpoB,EAAMlC,KAAKkN,eAAiBlN,KAAKJ,UAAYI,KAChDogC,EAAWxd,EAASxB,OAAQlf,EAAKwoB,GAAQ,EAEpC0V,EAKLxd,EAASxB,OAAQlf,EAAKwoB,EAAK0V,IAJ3Bl+B,EAAI6e,oBAAqBuN,EAAM3f,GAAS,GACxCiU,EAAShF,OAAQ1b,EAAKwoB,QAS3B,IAAIvV,GAAWpV,EAAOoV,SAElBtT,GAAQ,CAAEuF,KAAMsB,KAAKyjB,OAErBkU,GAAS,KAKbr9B,EAAOs9B,SAAW,SAAU7d,GAC3B,IAAI3O,EAAKysB,EACT,IAAM9d,GAAwB,iBAATA,EACpB,OAAO,KAKR,IACC3O,GAAM,IAAM/T,EAAOygC,WAAcC,gBAAiBhe,EAAM,YACvD,MAAQhW,IAYV,OAVA8zB,EAAkBzsB,GAAOA,EAAIxG,qBAAsB,eAAiB,GAC9DwG,IAAOysB,GACZv9B,EAAOoD,MAAO,iBACbm6B,EACCv9B,EAAOoB,IAAKm8B,EAAgB/zB,WAAY,SAAUgC,GACjD,OAAOA,EAAG8D,cACPzE,KAAM,MACV4U,IAGI3O,GAIR,IACC4sB,GAAW,QACXC,GAAQ,SACRC,GAAkB,wCAClBC,GAAe,qCAEhB,SAASC,GAAa/I,EAAQz2B,EAAKy/B,EAAavlB,GAC/C,IAAInW,EAEJ,GAAKO,MAAMC,QAASvE,GAGnB0B,EAAOkB,KAAM5C,EAAK,SAAUa,EAAGia,GACzB2kB,GAAeL,GAASjzB,KAAMsqB,GAGlCvc,EAAKuc,EAAQ3b,GAKb0kB,GACC/I,EAAS,KAAqB,iBAAN3b,GAAuB,MAALA,EAAYja,EAAI,IAAO,IACjEia,EACA2kB,EACAvlB,UAKG,GAAMulB,GAAiC,WAAlBj+B,EAAQxB,GAUnCka,EAAKuc,EAAQz2B,QAPb,IAAM+D,KAAQ/D,EACbw/B,GAAa/I,EAAS,IAAM1yB,EAAO,IAAK/D,EAAK+D,GAAQ07B,EAAavlB,GAYrExY,EAAOg+B,MAAQ,SAAU53B,EAAG23B,GAC3B,IAAIhJ,EACHkJ,EAAI,GACJzlB,EAAM,SAAUrN,EAAK+yB,GAGpB,IAAI/5B,EAAQ9F,EAAY6/B,GACvBA,IACAA,EAEDD,EAAGA,EAAE39B,QAAW69B,mBAAoBhzB,GAAQ,IAC3CgzB,mBAA6B,MAATh6B,EAAgB,GAAKA,IAG5C,GAAU,MAALiC,EACJ,MAAO,GAIR,GAAKxD,MAAMC,QAASuD,IAASA,EAAE5F,SAAWR,EAAO2C,cAAeyD,GAG/DpG,EAAOkB,KAAMkF,EAAG,WACfoS,EAAKxb,KAAKqF,KAAMrF,KAAKmH,cAOtB,IAAM4wB,KAAU3uB,EACf03B,GAAa/I,EAAQ3uB,EAAG2uB,GAAUgJ,EAAavlB,GAKjD,OAAOylB,EAAEpzB,KAAM,MAGhB7K,EAAOG,GAAGgC,OAAQ,CACjBi8B,UAAW,WACV,OAAOp+B,EAAOg+B,MAAOhhC,KAAKqhC,mBAE3BA,eAAgB,WACf,OAAOrhC,KAAKoE,IAAK,WAGhB,IAAI0N,EAAW9O,EAAO0f,KAAM1iB,KAAM,YAClC,OAAO8R,EAAW9O,EAAO2D,UAAWmL,GAAa9R,OAC9CsQ,OAAQ,WACX,IAAI3O,EAAO3B,KAAK2B,KAGhB,OAAO3B,KAAKqF,OAASrC,EAAQhD,MAAOka,GAAI,cACvC2mB,GAAapzB,KAAMzN,KAAKqM,YAAeu0B,GAAgBnzB,KAAM9L,KAC3D3B,KAAK2V,UAAYkQ,GAAepY,KAAM9L,MACtCyC,IAAK,SAAUoD,EAAInD,GACtB,IAAIjC,EAAMY,EAAQhD,MAAOoC,MAEzB,OAAY,MAAPA,EACG,KAGHwD,MAAMC,QAASzD,GACZY,EAAOoB,IAAKhC,EAAK,SAAUA,GACjC,MAAO,CAAEiD,KAAMhB,EAAKgB,KAAM8B,MAAO/E,EAAI8D,QAASy6B,GAAO,WAIhD,CAAEt7B,KAAMhB,EAAKgB,KAAM8B,MAAO/E,EAAI8D,QAASy6B,GAAO,WAClDh9B,SAKN,IACC29B,GAAM,OACNC,GAAQ,OACRC,GAAa,gBACbC,GAAW,6BAIXC,GAAa,iBACbC,GAAY,QAWZrH,GAAa,GAObsH,GAAa,GAGbC,GAAW,KAAKnhC,OAAQ,KAGxBohC,GAAeliC,EAAS0C,cAAe,KAKxC,SAASy/B,GAA6BC,GAGrC,OAAO,SAAUC,EAAoBhkB,GAED,iBAAvBgkB,IACXhkB,EAAOgkB,EACPA,EAAqB,KAGtB,IAAIC,EACH//B,EAAI,EACJggC,EAAYF,EAAmBx6B,cAAcqF,MAAOoP,IAAmB,GAExE,GAAK7a,EAAY4c,GAGhB,MAAUikB,EAAWC,EAAWhgC,KAGR,MAAlB+/B,EAAU,IACdA,EAAWA,EAAS5hC,MAAO,IAAO,KAChC0hC,EAAWE,GAAaF,EAAWE,IAAc,IAAKtwB,QAASqM,KAI/D+jB,EAAWE,GAAaF,EAAWE,IAAc,IAAKthC,KAAMqd,IAQnE,SAASmkB,GAA+BJ,EAAW58B,EAASy1B,EAAiBwH,GAE5E,IAAIC,EAAY,GACfC,EAAqBP,IAAcJ,GAEpC,SAASY,EAASN,GACjB,IAAItsB,EAcJ,OAbA0sB,EAAWJ,IAAa,EACxBl/B,EAAOkB,KAAM89B,EAAWE,IAAc,GAAI,SAAUjlB,EAAGwlB,GACtD,IAAIC,EAAsBD,EAAoBr9B,EAASy1B,EAAiBwH,GACxE,MAAoC,iBAAxBK,GACVH,GAAqBD,EAAWI,GAKtBH,IACD3sB,EAAW8sB,QADf,GAHNt9B,EAAQ+8B,UAAUvwB,QAAS8wB,GAC3BF,EAASE,IACF,KAKF9sB,EAGR,OAAO4sB,EAASp9B,EAAQ+8B,UAAW,MAAUG,EAAW,MAASE,EAAS,KAM3E,SAASG,GAAYl9B,EAAQ7D,GAC5B,IAAIuM,EAAKzI,EACRk9B,EAAc5/B,EAAO6/B,aAAaD,aAAe,GAElD,IAAMz0B,KAAOvM,OACQkE,IAAflE,EAAKuM,MACPy0B,EAAaz0B,GAAQ1I,EAAWC,IAAUA,EAAO,KAAUyI,GAAQvM,EAAKuM,IAO5E,OAJKzI,GACJ1C,EAAOmC,QAAQ,EAAMM,EAAQC,GAGvBD,EA/ERq8B,GAAatsB,KAAOL,GAASK,KAgP7BxS,EAAOmC,OAAQ,CAGd29B,OAAQ,EAGRC,aAAc,GACdC,KAAM,GAENH,aAAc,CACbI,IAAK9tB,GAASK,KACd7T,KAAM,MACNuhC,QAxRgB,4DAwRQz1B,KAAM0H,GAASguB,UACvC3jC,QAAQ,EACR4jC,aAAa,EACbC,OAAO,EACPC,YAAa,mDAcbC,QAAS,CACRnI,IAAKyG,GACLt/B,KAAM,aACNgtB,KAAM,YACNzb,IAAK,4BACL0vB,KAAM,qCAGPxoB,SAAU,CACTlH,IAAK,UACLyb,KAAM,SACNiU,KAAM,YAGPC,eAAgB,CACf3vB,IAAK,cACLvR,KAAM,eACNihC,KAAM,gBAKPE,WAAY,CAGXC,SAAUj4B,OAGVk4B,aAAa,EAGbC,YAAa5gB,KAAKC,MAGlB4gB,WAAY9gC,EAAOs9B,UAOpBsC,YAAa,CACZK,KAAK,EACL//B,SAAS,IAOX6gC,UAAW,SAAUt+B,EAAQu+B,GAC5B,OAAOA,EAGNrB,GAAYA,GAAYl9B,EAAQzC,EAAO6/B,cAAgBmB,GAGvDrB,GAAY3/B,EAAO6/B,aAAcp9B,IAGnCw+B,cAAelC,GAA6BzH,IAC5C4J,cAAenC,GAA6BH,IAG5CuC,KAAM,SAAUlB,EAAK79B,GAGA,iBAAR69B,IACX79B,EAAU69B,EACVA,OAAMn9B,GAIPV,EAAUA,GAAW,GAErB,IAAIg/B,EAGHC,EAGAC,EACAC,EAGAC,EAGAC,EAGA3jB,EAGA4jB,EAGAviC,EAGAwiC,EAGA1D,EAAIj+B,EAAO+gC,UAAW,GAAI3+B,GAG1Bw/B,EAAkB3D,EAAE/9B,SAAW+9B,EAG/B4D,EAAqB5D,EAAE/9B,UACpB0hC,EAAgBrjC,UAAYqjC,EAAgBphC,QAC9CR,EAAQ4hC,GACR5hC,EAAOwlB,MAGRnK,EAAWrb,EAAOgb,WAClB8mB,EAAmB9hC,EAAO+Z,UAAW,eAGrCgoB,EAAa9D,EAAE8D,YAAc,GAG7BC,EAAiB,GACjBC,EAAsB,GAGtBC,EAAW,WAGX7C,EAAQ,CACPnhB,WAAY,EAGZikB,kBAAmB,SAAUh3B,GAC5B,IAAIrB,EACJ,GAAKgU,EAAY,CAChB,IAAMyjB,EAAkB,CACvBA,EAAkB,GAClB,MAAUz3B,EAAQ20B,GAASt0B,KAAMm3B,GAChCC,EAAiBz3B,EAAO,GAAIrF,cAAgB,MACzC88B,EAAiBz3B,EAAO,GAAIrF,cAAgB,MAAS,IACrD/G,OAAQoM,EAAO,IAGpBA,EAAQy3B,EAAiBp2B,EAAI1G,cAAgB,KAE9C,OAAgB,MAATqF,EAAgB,KAAOA,EAAMe,KAAM,OAI3Cu3B,sBAAuB,WACtB,OAAOtkB,EAAYwjB,EAAwB,MAI5Ce,iBAAkB,SAAUhgC,EAAM8B,GAMjC,OALkB,MAAb2Z,IACJzb,EAAO4/B,EAAqB5/B,EAAKoC,eAChCw9B,EAAqB5/B,EAAKoC,gBAAmBpC,EAC9C2/B,EAAgB3/B,GAAS8B,GAEnBnH,MAIRslC,iBAAkB,SAAU3jC,GAI3B,OAHkB,MAAbmf,IACJmgB,EAAEsE,SAAW5jC,GAEP3B,MAIR+kC,WAAY,SAAU3gC,GACrB,IAAIpC,EACJ,GAAKoC,EACJ,GAAK0c,EAGJuhB,EAAMjkB,OAAQha,EAAKi+B,EAAMmD,cAIzB,IAAMxjC,KAAQoC,EACb2gC,EAAY/iC,GAAS,CAAE+iC,EAAY/iC,GAAQoC,EAAKpC,IAInD,OAAOhC,MAIRylC,MAAO,SAAUC,GAChB,IAAIC,EAAYD,GAAcR,EAK9B,OAJKd,GACJA,EAAUqB,MAAOE,GAElB98B,EAAM,EAAG88B,GACF3lC,OAoBV,GAfAqe,EAASzB,QAASylB,GAKlBpB,EAAEgC,MAAUA,GAAOhC,EAAEgC,KAAO9tB,GAASK,MAAS,IAC5CtP,QAASy7B,GAAWxsB,GAASguB,SAAW,MAG1ClC,EAAEt/B,KAAOyD,EAAQuX,QAAUvX,EAAQzD,MAAQs/B,EAAEtkB,QAAUskB,EAAEt/B,KAGzDs/B,EAAEkB,WAAclB,EAAEiB,UAAY,KAAMz6B,cAAcqF,MAAOoP,IAAmB,CAAE,IAGxD,MAAjB+kB,EAAE2E,YAAsB,CAC5BnB,EAAY7kC,EAAS0C,cAAe,KAKpC,IACCmiC,EAAUjvB,KAAOyrB,EAAEgC,IAInBwB,EAAUjvB,KAAOivB,EAAUjvB,KAC3ByrB,EAAE2E,YAAc9D,GAAaqB,SAAW,KAAOrB,GAAa+D,MAC3DpB,EAAUtB,SAAW,KAAOsB,EAAUoB,KACtC,MAAQp5B,GAITw0B,EAAE2E,aAAc,GAalB,GARK3E,EAAExe,MAAQwe,EAAEmC,aAAiC,iBAAXnC,EAAExe,OACxCwe,EAAExe,KAAOzf,EAAOg+B,MAAOC,EAAExe,KAAMwe,EAAEF,cAIlCqB,GAA+B9H,GAAY2G,EAAG77B,EAASi9B,GAGlDvhB,EACJ,OAAOuhB,EA8ER,IAAMlgC,KAzENuiC,EAAc1hC,EAAOwlB,OAASyY,EAAEzhC,SAGQ,GAApBwD,EAAO8/B,UAC1B9/B,EAAOwlB,MAAMU,QAAS,aAIvB+X,EAAEt/B,KAAOs/B,EAAEt/B,KAAKogB,cAGhBkf,EAAE6E,YAAcpE,GAAWj0B,KAAMwzB,EAAEt/B,MAKnC0iC,EAAWpD,EAAEgC,IAAI/8B,QAASq7B,GAAO,IAG3BN,EAAE6E,WAwBI7E,EAAExe,MAAQwe,EAAEmC,aACoD,KAAzEnC,EAAEqC,aAAe,IAAKziC,QAAS,uCACjCogC,EAAExe,KAAOwe,EAAExe,KAAKvc,QAASo7B,GAAK,OAvB9BqD,EAAW1D,EAAEgC,IAAI3iC,MAAO+jC,EAAS/gC,QAG5B29B,EAAExe,OAAUwe,EAAEmC,aAAiC,iBAAXnC,EAAExe,QAC1C4hB,IAAchE,GAAO5yB,KAAM42B,GAAa,IAAM,KAAQpD,EAAExe,YAGjDwe,EAAExe,OAIO,IAAZwe,EAAE/yB,QACNm2B,EAAWA,EAASn+B,QAASs7B,GAAY,MACzCmD,GAAatE,GAAO5yB,KAAM42B,GAAa,IAAM,KAAQ,KAASxiC,GAAMuF,OACnEu9B,GAIF1D,EAAEgC,IAAMoB,EAAWM,GASf1D,EAAE8E,aACD/iC,EAAO+/B,aAAcsB,IACzBhC,EAAMgD,iBAAkB,oBAAqBriC,EAAO+/B,aAAcsB,IAE9DrhC,EAAOggC,KAAMqB,IACjBhC,EAAMgD,iBAAkB,gBAAiBriC,EAAOggC,KAAMqB,MAKnDpD,EAAExe,MAAQwe,EAAE6E,aAAgC,IAAlB7E,EAAEqC,aAAyBl+B,EAAQk+B,cACjEjB,EAAMgD,iBAAkB,eAAgBpE,EAAEqC,aAI3CjB,EAAMgD,iBACL,SACApE,EAAEkB,UAAW,IAAOlB,EAAEsC,QAAStC,EAAEkB,UAAW,IAC3ClB,EAAEsC,QAAStC,EAAEkB,UAAW,KACA,MAArBlB,EAAEkB,UAAW,GAAc,KAAON,GAAW,WAAa,IAC7DZ,EAAEsC,QAAS,MAIFtC,EAAE+E,QACZ3D,EAAMgD,iBAAkBljC,EAAG8+B,EAAE+E,QAAS7jC,IAIvC,GAAK8+B,EAAEgF,cAC+C,IAAnDhF,EAAEgF,WAAWxlC,KAAMmkC,EAAiBvC,EAAOpB,IAAiBngB,GAG9D,OAAOuhB,EAAMoD,QAed,GAXAP,EAAW,QAGXJ,EAAiBtpB,IAAKylB,EAAEhG,UACxBoH,EAAMx5B,KAAMo4B,EAAEiF,SACd7D,EAAMxlB,KAAMokB,EAAE76B,OAGdg+B,EAAYhC,GAA+BR,GAAYX,EAAG77B,EAASi9B,GAK5D,CASN,GARAA,EAAMnhB,WAAa,EAGdwjB,GACJG,EAAmB3b,QAAS,WAAY,CAAEmZ,EAAOpB,IAI7CngB,EACJ,OAAOuhB,EAIHpB,EAAEoC,OAAqB,EAAZpC,EAAE5D,UACjBmH,EAAezkC,EAAO+f,WAAY,WACjCuiB,EAAMoD,MAAO,YACXxE,EAAE5D,UAGN,IACCvc,GAAY,EACZsjB,EAAU+B,KAAMnB,EAAgBn8B,GAC/B,MAAQ4D,GAGT,GAAKqU,EACJ,MAAMrU,EAIP5D,GAAO,EAAG4D,SAhCX5D,GAAO,EAAG,gBAqCX,SAASA,EAAM28B,EAAQY,EAAkBC,EAAWL,GACnD,IAAIM,EAAWJ,EAAS9/B,EAAOmgC,EAAUC,EACxCd,EAAaU,EAGTtlB,IAILA,GAAY,EAGP0jB,GACJzkC,EAAOu9B,aAAckH,GAKtBJ,OAAYt+B,EAGZw+B,EAAwB0B,GAAW,GAGnC3D,EAAMnhB,WAAsB,EAATskB,EAAa,EAAI,EAGpCc,EAAsB,KAAVd,GAAiBA,EAAS,KAAkB,MAAXA,EAGxCa,IACJE,EA7lBJ,SAA8BtF,EAAGoB,EAAOgE,GAEvC,IAAII,EAAI9kC,EAAM+kC,EAAeC,EAC5B3rB,EAAWimB,EAAEjmB,SACbmnB,EAAYlB,EAAEkB,UAGf,MAA2B,MAAnBA,EAAW,GAClBA,EAAU9zB,aACEvI,IAAP2gC,IACJA,EAAKxF,EAAEsE,UAAYlD,EAAM8C,kBAAmB,iBAK9C,GAAKsB,EACJ,IAAM9kC,KAAQqZ,EACb,GAAKA,EAAUrZ,IAAUqZ,EAAUrZ,GAAO8L,KAAMg5B,GAAO,CACtDtE,EAAUvwB,QAASjQ,GACnB,MAMH,GAAKwgC,EAAW,KAAOkE,EACtBK,EAAgBvE,EAAW,OACrB,CAGN,IAAMxgC,KAAQ0kC,EAAY,CACzB,IAAMlE,EAAW,IAAOlB,EAAEyC,WAAY/hC,EAAO,IAAMwgC,EAAW,IAAQ,CACrEuE,EAAgB/kC,EAChB,MAEKglC,IACLA,EAAgBhlC,GAKlB+kC,EAAgBA,GAAiBC,EAMlC,GAAKD,EAIJ,OAHKA,IAAkBvE,EAAW,IACjCA,EAAUvwB,QAAS80B,GAEbL,EAAWK,GA0iBLE,CAAqB3F,EAAGoB,EAAOgE,KAIrCC,IACsC,EAA3CtjC,EAAO6D,QAAS,SAAUo6B,EAAEkB,YAC5Bn/B,EAAO6D,QAAS,OAAQo6B,EAAEkB,WAAc,IACxClB,EAAEyC,WAAY,eAAkB,cAIjC6C,EA9iBH,SAAsBtF,EAAGsF,EAAUlE,EAAOiE,GACzC,IAAIO,EAAOC,EAASC,EAAMp2B,EAAKsK,EAC9ByoB,EAAa,GAGbvB,EAAYlB,EAAEkB,UAAU7hC,QAGzB,GAAK6hC,EAAW,GACf,IAAM4E,KAAQ9F,EAAEyC,WACfA,EAAYqD,EAAKt/B,eAAkBw5B,EAAEyC,WAAYqD,GAInDD,EAAU3E,EAAU9zB,QAGpB,MAAQy4B,EAcP,GAZK7F,EAAEwC,eAAgBqD,KACtBzE,EAAOpB,EAAEwC,eAAgBqD,IAAcP,IAIlCtrB,GAAQqrB,GAAarF,EAAE+F,aAC5BT,EAAWtF,EAAE+F,WAAYT,EAAUtF,EAAEiB,WAGtCjnB,EAAO6rB,EACPA,EAAU3E,EAAU9zB,QAKnB,GAAiB,MAAZy4B,EAEJA,EAAU7rB,OAGJ,GAAc,MAATA,GAAgBA,IAAS6rB,EAAU,CAM9C,KAHAC,EAAOrD,EAAYzoB,EAAO,IAAM6rB,IAAapD,EAAY,KAAOoD,IAI/D,IAAMD,KAASnD,EAId,IADA/yB,EAAMk2B,EAAMt/B,MAAO,MACT,KAAQu/B,IAGjBC,EAAOrD,EAAYzoB,EAAO,IAAMtK,EAAK,KACpC+yB,EAAY,KAAO/yB,EAAK,KACb,EAGG,IAATo2B,EACJA,EAAOrD,EAAYmD,IAGgB,IAAxBnD,EAAYmD,KACvBC,EAAUn2B,EAAK,GACfwxB,EAAUvwB,QAASjB,EAAK,KAEzB,MAOJ,IAAc,IAATo2B,EAGJ,GAAKA,GAAQ9F,EAAEgG,UACdV,EAAWQ,EAAMR,QAEjB,IACCA,EAAWQ,EAAMR,GAChB,MAAQ95B,GACT,MAAO,CACN0R,MAAO,cACP/X,MAAO2gC,EAAOt6B,EAAI,sBAAwBwO,EAAO,OAAS6rB,IASjE,MAAO,CAAE3oB,MAAO,UAAWsE,KAAM8jB,GAidpBW,CAAajG,EAAGsF,EAAUlE,EAAOiE,GAGvCA,GAGCrF,EAAE8E,cACNS,EAAWnE,EAAM8C,kBAAmB,oBAEnCniC,EAAO+/B,aAAcsB,GAAamC,IAEnCA,EAAWnE,EAAM8C,kBAAmB,WAEnCniC,EAAOggC,KAAMqB,GAAamC,IAKZ,MAAXhB,GAA6B,SAAXvE,EAAEt/B,KACxB+jC,EAAa,YAGS,MAAXF,EACXE,EAAa,eAIbA,EAAaa,EAASpoB,MACtB+nB,EAAUK,EAAS9jB,KAEnB6jB,IADAlgC,EAAQmgC,EAASngC,UAMlBA,EAAQs/B,GACHF,GAAWE,IACfA,EAAa,QACRF,EAAS,IACbA,EAAS,KAMZnD,EAAMmD,OAASA,EACfnD,EAAMqD,YAAeU,GAAoBV,GAAe,GAGnDY,EACJjoB,EAASmB,YAAaolB,EAAiB,CAAEsB,EAASR,EAAYrD,IAE9DhkB,EAASuB,WAAYglB,EAAiB,CAAEvC,EAAOqD,EAAYt/B,IAI5Di8B,EAAM0C,WAAYA,GAClBA,OAAaj/B,EAER4+B,GACJG,EAAmB3b,QAASod,EAAY,cAAgB,YACvD,CAAEjE,EAAOpB,EAAGqF,EAAYJ,EAAU9/B,IAIpC0+B,EAAiB/mB,SAAU6mB,EAAiB,CAAEvC,EAAOqD,IAEhDhB,IACJG,EAAmB3b,QAAS,eAAgB,CAAEmZ,EAAOpB,MAG3Cj+B,EAAO8/B,QAChB9/B,EAAOwlB,MAAMU,QAAS,cAKzB,OAAOmZ,GAGR8E,QAAS,SAAUlE,EAAKxgB,EAAMte,GAC7B,OAAOnB,EAAOW,IAAKs/B,EAAKxgB,EAAMte,EAAU,SAGzCijC,UAAW,SAAUnE,EAAK9+B,GACzB,OAAOnB,EAAOW,IAAKs/B,OAAKn9B,EAAW3B,EAAU,aAI/CnB,EAAOkB,KAAM,CAAE,MAAO,QAAU,SAAUsD,EAAImV,GAC7C3Z,EAAQ2Z,GAAW,SAAUsmB,EAAKxgB,EAAMte,EAAUxC,GAUjD,OAPKN,EAAYohB,KAChB9gB,EAAOA,GAAQwC,EACfA,EAAWse,EACXA,OAAO3c,GAID9C,EAAOmhC,KAAMnhC,EAAOmC,OAAQ,CAClC89B,IAAKA,EACLthC,KAAMgb,EACNulB,SAAUvgC,EACV8gB,KAAMA,EACNyjB,QAAS/hC,GACPnB,EAAO2C,cAAes9B,IAASA,OAIpCjgC,EAAOihC,cAAe,SAAUhD,GAC/B,IAAI9+B,EACJ,IAAMA,KAAK8+B,EAAE+E,QACa,iBAApB7jC,EAAEsF,gBACNw5B,EAAEqC,YAAcrC,EAAE+E,QAAS7jC,IAAO,MAMrCa,EAAOwsB,SAAW,SAAUyT,EAAK79B,EAASlD,GACzC,OAAOc,EAAOmhC,KAAM,CACnBlB,IAAKA,EAGLthC,KAAM,MACNugC,SAAU,SACVh0B,OAAO,EACPm1B,OAAO,EACP7jC,QAAQ,EAKRkkC,WAAY,CACX2D,cAAe,cAEhBL,WAAY,SAAUT,GACrBvjC,EAAO0D,WAAY6/B,EAAUnhC,EAASlD,OAMzCc,EAAOG,GAAGgC,OAAQ,CACjBmiC,QAAS,SAAU/X,GAClB,IAAI/H,EAyBJ,OAvBKxnB,KAAM,KACLqB,EAAYkuB,KAChBA,EAAOA,EAAK9uB,KAAMT,KAAM,KAIzBwnB,EAAOxkB,EAAQusB,EAAMvvB,KAAM,GAAIkN,eAAgB1I,GAAI,GAAIgB,OAAO,GAEzDxF,KAAM,GAAI4C,YACd4kB,EAAK2I,aAAcnwB,KAAM,IAG1BwnB,EAAKpjB,IAAK,WACT,IAAIC,EAAOrE,KAEX,MAAQqE,EAAKkjC,kBACZljC,EAAOA,EAAKkjC,kBAGb,OAAOljC,IACJ4rB,OAAQjwB,OAGNA,MAGRwnC,UAAW,SAAUjY,GACpB,OAAKluB,EAAYkuB,GACTvvB,KAAKkE,KAAM,SAAU/B,GAC3Ba,EAAQhD,MAAOwnC,UAAWjY,EAAK9uB,KAAMT,KAAMmC,MAItCnC,KAAKkE,KAAM,WACjB,IAAIuW,EAAOzX,EAAQhD,MAClBgb,EAAWP,EAAKO,WAEZA,EAAS1X,OACb0X,EAASssB,QAAS/X,GAGlB9U,EAAKwV,OAAQV,MAKhB/H,KAAM,SAAU+H,GACf,IAAIkY,EAAiBpmC,EAAYkuB,GAEjC,OAAOvvB,KAAKkE,KAAM,SAAU/B,GAC3Ba,EAAQhD,MAAOsnC,QAASG,EAAiBlY,EAAK9uB,KAAMT,KAAMmC,GAAMotB,MAIlEmY,OAAQ,SAAUzkC,GAIjB,OAHAjD,KAAKmU,OAAQlR,GAAW2R,IAAK,QAAS1Q,KAAM,WAC3ClB,EAAQhD,MAAOswB,YAAatwB,KAAKwM,cAE3BxM,QAKTgD,EAAO6O,KAAKhI,QAAQ4vB,OAAS,SAAUp1B,GACtC,OAAQrB,EAAO6O,KAAKhI,QAAQ89B,QAAStjC,IAEtCrB,EAAO6O,KAAKhI,QAAQ89B,QAAU,SAAUtjC,GACvC,SAAWA,EAAKuuB,aAAevuB,EAAK0vB,cAAgB1vB,EAAKyxB,iBAAiBxyB,SAM3EN,EAAO6/B,aAAa+E,IAAM,WACzB,IACC,OAAO,IAAI7nC,EAAO8nC,eACjB,MAAQp7B,MAGX,IAAIq7B,GAAmB,CAGrBC,EAAG,IAIHC,KAAM,KAEPC,GAAejlC,EAAO6/B,aAAa+E,MAEpCxmC,EAAQ8mC,OAASD,IAAkB,oBAAqBA,GACxD7mC,EAAQ+iC,KAAO8D,KAAiBA,GAEhCjlC,EAAOkhC,cAAe,SAAU9+B,GAC/B,IAAIjB,EAAUgkC,EAGd,GAAK/mC,EAAQ8mC,MAAQD,KAAiB7iC,EAAQwgC,YAC7C,MAAO,CACNO,KAAM,SAAUH,EAAS/K,GACxB,IAAI94B,EACHylC,EAAMxiC,EAAQwiC,MAWf,GATAA,EAAIQ,KACHhjC,EAAQzD,KACRyD,EAAQ69B,IACR79B,EAAQi+B,MACRj+B,EAAQijC,SACRjjC,EAAQmR,UAIJnR,EAAQkjC,UACZ,IAAMnmC,KAAKiD,EAAQkjC,UAClBV,EAAKzlC,GAAMiD,EAAQkjC,UAAWnmC,GAmBhC,IAAMA,KAdDiD,EAAQmgC,UAAYqC,EAAItC,kBAC5BsC,EAAItC,iBAAkBlgC,EAAQmgC,UAQzBngC,EAAQwgC,aAAgBI,EAAS,sBACtCA,EAAS,oBAAuB,kBAItBA,EACV4B,EAAIvC,iBAAkBljC,EAAG6jC,EAAS7jC,IAInCgC,EAAW,SAAUxC,GACpB,OAAO,WACDwC,IACJA,EAAWgkC,EAAgBP,EAAIW,OAC9BX,EAAIY,QAAUZ,EAAIa,QAAUb,EAAIc,UAC/Bd,EAAIe,mBAAqB,KAEb,UAAThnC,EACJimC,EAAInC,QACgB,UAAT9jC,EAKgB,iBAAfimC,EAAIpC,OACfvK,EAAU,EAAG,SAEbA,EAGC2M,EAAIpC,OACJoC,EAAIlC,YAINzK,EACC6M,GAAkBF,EAAIpC,SAAYoC,EAAIpC,OACtCoC,EAAIlC,WAK+B,UAAjCkC,EAAIgB,cAAgB,SACM,iBAArBhB,EAAIiB,aACV,CAAEC,OAAQlB,EAAIrB,UACd,CAAEhkC,KAAMqlC,EAAIiB,cACbjB,EAAIxC,4BAQTwC,EAAIW,OAASpkC,IACbgkC,EAAgBP,EAAIY,QAAUZ,EAAIc,UAAYvkC,EAAU,cAKnC2B,IAAhB8hC,EAAIa,QACRb,EAAIa,QAAUN,EAEdP,EAAIe,mBAAqB,WAGA,IAAnBf,EAAI1mB,YAMRnhB,EAAO+f,WAAY,WACb3b,GACJgkC,OAQLhkC,EAAWA,EAAU,SAErB,IAGCyjC,EAAIzB,KAAM/gC,EAAQ0gC,YAAc1gC,EAAQqd,MAAQ,MAC/C,MAAQhW,GAGT,GAAKtI,EACJ,MAAMsI,IAKTg5B,MAAO,WACDthC,GACJA,QAWLnB,EAAOihC,cAAe,SAAUhD,GAC1BA,EAAE2E,cACN3E,EAAEjmB,SAAS3Y,QAAS,KAKtBW,EAAO+gC,UAAW,CACjBR,QAAS,CACRlhC,OAAQ,6FAGT2Y,SAAU,CACT3Y,OAAQ,2BAETqhC,WAAY,CACX2D,cAAe,SAAU9kC,GAExB,OADAS,EAAO0D,WAAYnE,GACZA,MAMVS,EAAOihC,cAAe,SAAU,SAAUhD,QACxBn7B,IAAZm7B,EAAE/yB,QACN+yB,EAAE/yB,OAAQ,GAEN+yB,EAAE2E,cACN3E,EAAEt/B,KAAO,SAKXqB,EAAOkhC,cAAe,SAAU,SAAUjD,GAIxC,IAAI5+B,EAAQ8B,EADb,GAAK88B,EAAE2E,aAAe3E,EAAE8H,YAEvB,MAAO,CACN5C,KAAM,SAAUlpB,EAAGge,GAClB54B,EAASW,EAAQ,YACf+O,KAAMkvB,EAAE8H,aAAe,IACvBrmB,KAAM,CAAEsmB,QAAS/H,EAAEgI,cAAernC,IAAKq/B,EAAEgC,MACzC7a,GAAI,aAAcjkB,EAAW,SAAU+kC,GACvC7mC,EAAOub,SACPzZ,EAAW,KACN+kC,GACJjO,EAAuB,UAAbiO,EAAIvnC,KAAmB,IAAM,IAAKunC,EAAIvnC,QAKnD/B,EAAS8C,KAAKC,YAAaN,EAAQ,KAEpCojC,MAAO,WACDthC,GACJA,QAUL,IAqGKshB,GArGD0jB,GAAe,GAClBC,GAAS,oBAGVpmC,EAAO+gC,UAAW,CACjBsF,MAAO,WACPC,cAAe,WACd,IAAInlC,EAAWglC,GAAa7/B,OAAWtG,EAAO+C,QAAU,IAAQlE,GAAMuF,OAEtE,OADApH,KAAMmE,IAAa,EACZA,KAKTnB,EAAOihC,cAAe,aAAc,SAAUhD,EAAGsI,EAAkBlH,GAElE,IAAImH,EAAcC,EAAaC,EAC9BC,GAAuB,IAAZ1I,EAAEoI,QAAqBD,GAAO37B,KAAMwzB,EAAEgC,KAChD,MACkB,iBAAXhC,EAAExe,MAE6C,KADnDwe,EAAEqC,aAAe,IACjBziC,QAAS,sCACXuoC,GAAO37B,KAAMwzB,EAAExe,OAAU,QAI5B,GAAKknB,GAAiC,UAArB1I,EAAEkB,UAAW,GA8D7B,OA3DAqH,EAAevI,EAAEqI,cAAgBjoC,EAAY4/B,EAAEqI,eAC9CrI,EAAEqI,gBACFrI,EAAEqI,cAGEK,EACJ1I,EAAG0I,GAAa1I,EAAG0I,GAAWzjC,QAASkjC,GAAQ,KAAOI,IAC/B,IAAZvI,EAAEoI,QACbpI,EAAEgC,MAAS5C,GAAO5yB,KAAMwzB,EAAEgC,KAAQ,IAAM,KAAQhC,EAAEoI,MAAQ,IAAMG,GAIjEvI,EAAEyC,WAAY,eAAkB,WAI/B,OAHMgG,GACL1mC,EAAOoD,MAAOojC,EAAe,mBAEvBE,EAAmB,IAI3BzI,EAAEkB,UAAW,GAAM,OAGnBsH,EAAc1pC,EAAQypC,GACtBzpC,EAAQypC,GAAiB,WACxBE,EAAoBplC,WAIrB+9B,EAAMjkB,OAAQ,gBAGQtY,IAAhB2jC,EACJzmC,EAAQjD,GAASu+B,WAAYkL,GAI7BzpC,EAAQypC,GAAiBC,EAIrBxI,EAAGuI,KAGPvI,EAAEqI,cAAgBC,EAAiBD,cAGnCH,GAAavoC,KAAM4oC,IAIfE,GAAqBroC,EAAYooC,IACrCA,EAAaC,EAAmB,IAGjCA,EAAoBD,OAAc3jC,IAI5B,WAYT1E,EAAQwoC,qBACHnkB,GAAO7lB,EAASiqC,eAAeD,mBAAoB,IAAKnkB,MACvD5U,UAAY,6BACiB,IAA3B4U,GAAKjZ,WAAWlJ,QAQxBN,EAAO2X,UAAY,SAAU8H,EAAMvf,EAAS4mC,GAC3C,MAAqB,iBAATrnB,EACJ,IAEgB,kBAAZvf,IACX4mC,EAAc5mC,EACdA,GAAU,GAKLA,IAIA9B,EAAQwoC,qBAMZ/yB,GALA3T,EAAUtD,EAASiqC,eAAeD,mBAAoB,KAKvCtnC,cAAe,SACzBkT,KAAO5V,EAASuV,SAASK,KAC9BtS,EAAQR,KAAKC,YAAakU,IAE1B3T,EAAUtD,GAKZynB,GAAWyiB,GAAe,IAD1BC,EAASzvB,EAAWnN,KAAMsV,IAKlB,CAAEvf,EAAQZ,cAAeynC,EAAQ,MAGzCA,EAAS3iB,GAAe,CAAE3E,GAAQvf,EAASmkB,GAEtCA,GAAWA,EAAQ/jB,QACvBN,EAAQqkB,GAAUzJ,SAGZ5a,EAAOgB,MAAO,GAAI+lC,EAAOv9B,cAlChC,IAAIqK,EAAMkzB,EAAQ1iB,GAyCnBrkB,EAAOG,GAAGsoB,KAAO,SAAUwX,EAAK+G,EAAQ7lC,GACvC,IAAIlB,EAAUtB,EAAM4kC,EACnB9rB,EAAOza,KACPyoB,EAAMwa,EAAIpiC,QAAS,KAsDpB,OApDY,EAAP4nB,IACJxlB,EAAWk7B,GAAkB8E,EAAI3iC,MAAOmoB,IACxCwa,EAAMA,EAAI3iC,MAAO,EAAGmoB,IAIhBpnB,EAAY2oC,IAGhB7lC,EAAW6lC,EACXA,OAASlkC,GAGEkkC,GAA4B,iBAAXA,IAC5BroC,EAAO,QAIW,EAAd8Y,EAAKnX,QACTN,EAAOmhC,KAAM,CACZlB,IAAKA,EAKLthC,KAAMA,GAAQ,MACdugC,SAAU,OACVzf,KAAMunB,IACHnhC,KAAM,SAAUggC,GAGnBtC,EAAWjiC,UAEXmW,EAAK8U,KAAMtsB,EAIVD,EAAQ,SAAUitB,OAAQjtB,EAAO2X,UAAWkuB,IAAiBr4B,KAAMvN,GAGnE4lC,KAKEzqB,OAAQja,GAAY,SAAUk+B,EAAOmD,GACxC/qB,EAAKvW,KAAM,WACVC,EAASxD,MAAOX,KAAMumC,GAAY,CAAElE,EAAMwG,aAAcrD,EAAQnD,QAK5DriC,MAMRgD,EAAO6O,KAAKhI,QAAQogC,SAAW,SAAU5lC,GACxC,OAAOrB,EAAO2B,KAAM3B,EAAOy5B,OAAQ,SAAUt5B,GAC5C,OAAOkB,IAASlB,EAAGkB,OAChBf,QAMLN,EAAOknC,OAAS,CACfC,UAAW,SAAU9lC,EAAMe,EAASjD,GACnC,IAAIioC,EAAaC,EAASC,EAAWC,EAAQC,EAAWC,EACvD/X,EAAW1vB,EAAOyhB,IAAKpgB,EAAM,YAC7BqmC,EAAU1nC,EAAQqB,GAClBynB,EAAQ,GAGS,WAAb4G,IACJruB,EAAKkgB,MAAMmO,SAAW,YAGvB8X,EAAYE,EAAQR,SACpBI,EAAYtnC,EAAOyhB,IAAKpgB,EAAM,OAC9BomC,EAAaznC,EAAOyhB,IAAKpgB,EAAM,SACI,aAAbquB,GAAwC,UAAbA,KACA,GAA9C4X,EAAYG,GAAa5pC,QAAS,SAMpC0pC,GADAH,EAAcM,EAAQhY,YACD3iB,IACrBs6B,EAAUD,EAAYzS,OAGtB4S,EAASxX,WAAYuX,IAAe,EACpCD,EAAUtX,WAAY0X,IAAgB,GAGlCppC,EAAY+D,KAGhBA,EAAUA,EAAQ3E,KAAM4D,EAAMlC,EAAGa,EAAOmC,OAAQ,GAAIqlC,KAGjC,MAAfplC,EAAQ2K,MACZ+b,EAAM/b,IAAQ3K,EAAQ2K,IAAMy6B,EAAUz6B,IAAQw6B,GAE1B,MAAhBnlC,EAAQuyB,OACZ7L,EAAM6L,KAASvyB,EAAQuyB,KAAO6S,EAAU7S,KAAS0S,GAG7C,UAAWjlC,EACfA,EAAQulC,MAAMlqC,KAAM4D,EAAMynB,GAG1B4e,EAAQjmB,IAAKqH,KAKhB9oB,EAAOG,GAAGgC,OAAQ,CAGjB+kC,OAAQ,SAAU9kC,GAGjB,GAAKd,UAAUhB,OACd,YAAmBwC,IAAZV,EACNpF,KACAA,KAAKkE,KAAM,SAAU/B,GACpBa,EAAOknC,OAAOC,UAAWnqC,KAAMoF,EAASjD,KAI3C,IAAIyoC,EAAMC,EACTxmC,EAAOrE,KAAM,GAEd,OAAMqE,EAQAA,EAAKyxB,iBAAiBxyB,QAK5BsnC,EAAOvmC,EAAKozB,wBACZoT,EAAMxmC,EAAK6I,cAAc4C,YAClB,CACNC,IAAK66B,EAAK76B,IAAM86B,EAAIC,YACpBnT,KAAMiT,EAAKjT,KAAOkT,EAAIE,cARf,CAAEh7B,IAAK,EAAG4nB,KAAM,QATxB,GAuBDjF,SAAU,WACT,GAAM1yB,KAAM,GAAZ,CAIA,IAAIgrC,EAAcd,EAAQhoC,EACzBmC,EAAOrE,KAAM,GACbirC,EAAe,CAAEl7B,IAAK,EAAG4nB,KAAM,GAGhC,GAAwC,UAAnC30B,EAAOyhB,IAAKpgB,EAAM,YAGtB6lC,EAAS7lC,EAAKozB,4BAER,CACNyS,EAASlqC,KAAKkqC,SAIdhoC,EAAMmC,EAAK6I,cACX89B,EAAe3mC,EAAK2mC,cAAgB9oC,EAAIyN,gBACxC,MAAQq7B,IACLA,IAAiB9oC,EAAIujB,MAAQulB,IAAiB9oC,EAAIyN,kBACT,WAA3C3M,EAAOyhB,IAAKumB,EAAc,YAE1BA,EAAeA,EAAapoC,WAExBooC,GAAgBA,IAAiB3mC,GAAkC,IAA1B2mC,EAAazpC,YAG1D0pC,EAAejoC,EAAQgoC,GAAed,UACzBn6B,KAAO/M,EAAOyhB,IAAKumB,EAAc,kBAAkB,GAChEC,EAAatT,MAAQ30B,EAAOyhB,IAAKumB,EAAc,mBAAmB,IAKpE,MAAO,CACNj7B,IAAKm6B,EAAOn6B,IAAMk7B,EAAal7B,IAAM/M,EAAOyhB,IAAKpgB,EAAM,aAAa,GACpEszB,KAAMuS,EAAOvS,KAAOsT,EAAatT,KAAO30B,EAAOyhB,IAAKpgB,EAAM,cAAc,MAc1E2mC,aAAc,WACb,OAAOhrC,KAAKoE,IAAK,WAChB,IAAI4mC,EAAehrC,KAAKgrC,aAExB,MAAQA,GAA2D,WAA3ChoC,EAAOyhB,IAAKumB,EAAc,YACjDA,EAAeA,EAAaA,aAG7B,OAAOA,GAAgBr7B,QAM1B3M,EAAOkB,KAAM,CAAE20B,WAAY,cAAeD,UAAW,eAAiB,SAAUjc,EAAQ+F,GACvF,IAAI3S,EAAM,gBAAkB2S,EAE5B1f,EAAOG,GAAIwZ,GAAW,SAAUva,GAC/B,OAAOgf,EAAQphB,KAAM,SAAUqE,EAAMsY,EAAQva,GAG5C,IAAIyoC,EAOJ,GANKppC,EAAU4C,GACdwmC,EAAMxmC,EACuB,IAAlBA,EAAK9C,WAChBspC,EAAMxmC,EAAKyL,kBAGChK,IAAR1D,EACJ,OAAOyoC,EAAMA,EAAKnoB,GAASre,EAAMsY,GAG7BkuB,EACJA,EAAIK,SACFn7B,EAAY86B,EAAIE,YAAV3oC,EACP2N,EAAM3N,EAAMyoC,EAAIC,aAIjBzmC,EAAMsY,GAAWva,GAEhBua,EAAQva,EAAKkC,UAAUhB,WAU5BN,EAAOkB,KAAM,CAAE,MAAO,QAAU,SAAUsD,EAAIkb,GAC7C1f,EAAOizB,SAAUvT,GAASkP,GAAcxwB,EAAQgyB,cAC/C,SAAU/uB,EAAMitB,GACf,GAAKA,EAIJ,OAHAA,EAAWD,GAAQhtB,EAAMqe,GAGlBoO,GAAUrjB,KAAM6jB,GACtBtuB,EAAQqB,GAAOquB,WAAYhQ,GAAS,KACpC4O,MAQLtuB,EAAOkB,KAAM,CAAEinC,OAAQ,SAAUC,MAAO,SAAW,SAAU/lC,EAAM1D,GAClEqB,EAAOkB,KAAM,CACZ2zB,QAAS,QAAUxyB,EACnB2W,QAASra,EACT0pC,GAAI,QAAUhmC,GACZ,SAAUimC,EAAcC,GAG1BvoC,EAAOG,GAAIooC,GAAa,SAAU3T,EAAQzwB,GACzC,IAAIka,EAAY/c,UAAUhB,SAAYgoC,GAAkC,kBAAX1T,GAC5DpC,EAAQ8V,KAA6B,IAAX1T,IAA6B,IAAVzwB,EAAiB,SAAW,UAE1E,OAAOia,EAAQphB,KAAM,SAAUqE,EAAM1C,EAAMwF,GAC1C,IAAIjF,EAEJ,OAAKT,EAAU4C,GAGyB,IAAhCknC,EAAS1qC,QAAS,SACxBwD,EAAM,QAAUgB,GAChBhB,EAAKzE,SAAS+P,gBAAiB,SAAWtK,GAIrB,IAAlBhB,EAAK9C,UACTW,EAAMmC,EAAKsL,gBAIJ3J,KAAKivB,IACX5wB,EAAKohB,KAAM,SAAWpgB,GAAQnD,EAAK,SAAWmD,GAC9ChB,EAAKohB,KAAM,SAAWpgB,GAAQnD,EAAK,SAAWmD,GAC9CnD,EAAK,SAAWmD,UAIDS,IAAVqB,EAGNnE,EAAOyhB,IAAKpgB,EAAM1C,EAAM6zB,GAGxBxyB,EAAOuhB,MAAOlgB,EAAM1C,EAAMwF,EAAOquB,IAChC7zB,EAAM0f,EAAYuW,OAAS9xB,EAAWub,QAM5Cre,EAAOkB,KAAM,CACZ,YACA,WACA,eACA,YACA,cACA,YACE,SAAUsD,EAAI7F,GAChBqB,EAAOG,GAAIxB,GAAS,SAAUwB,GAC7B,OAAOnD,KAAKooB,GAAIzmB,EAAMwB,MAOxBH,EAAOG,GAAGgC,OAAQ,CAEjB61B,KAAM,SAAU3S,EAAO5F,EAAMtf,GAC5B,OAAOnD,KAAKooB,GAAIC,EAAO,KAAM5F,EAAMtf,IAEpCqoC,OAAQ,SAAUnjB,EAAOllB,GACxB,OAAOnD,KAAKyoB,IAAKJ,EAAO,KAAMllB,IAG/BsoC,SAAU,SAAUxoC,EAAUolB,EAAO5F,EAAMtf,GAC1C,OAAOnD,KAAKooB,GAAIC,EAAOplB,EAAUwf,EAAMtf,IAExCuoC,WAAY,SAAUzoC,EAAUolB,EAAOllB,GAGtC,OAA4B,IAArBmB,UAAUhB,OAChBtD,KAAKyoB,IAAKxlB,EAAU,MACpBjD,KAAKyoB,IAAKJ,EAAOplB,GAAY,KAAME,IAGrCwoC,MAAO,SAAUC,EAAQC,GACxB,OAAO7rC,KAAKkuB,WAAY0d,GAASzd,WAAY0d,GAASD,MAIxD5oC,EAAOkB,KACN,wLAE4DqD,MAAO,KACnE,SAAUC,EAAInC,GAGbrC,EAAOG,GAAIkC,GAAS,SAAUod,EAAMtf,GACnC,OAA0B,EAAnBmB,UAAUhB,OAChBtD,KAAKooB,GAAI/iB,EAAM,KAAMod,EAAMtf,GAC3BnD,KAAKkpB,QAAS7jB,MAUlB,IAAI2E,GAAQ,qCAMZhH,EAAO8oC,MAAQ,SAAU3oC,EAAID,GAC5B,IAAIyN,EAAK6D,EAAMs3B,EAUf,GARwB,iBAAZ5oC,IACXyN,EAAMxN,EAAID,GACVA,EAAUC,EACVA,EAAKwN,GAKAtP,EAAY8B,GAalB,OARAqR,EAAOlU,EAAMG,KAAM6D,UAAW,IAC9BwnC,EAAQ,WACP,OAAO3oC,EAAGxC,MAAOuC,GAAWlD,KAAMwU,EAAK9T,OAAQJ,EAAMG,KAAM6D,eAItD8C,KAAOjE,EAAGiE,KAAOjE,EAAGiE,MAAQpE,EAAOoE,OAElC0kC,GAGR9oC,EAAO+oC,UAAY,SAAUC,GACvBA,EACJhpC,EAAOge,YAEPhe,EAAO4X,OAAO,IAGhB5X,EAAO6C,QAAUD,MAAMC,QACvB7C,EAAOipC,UAAYhpB,KAAKC,MACxBlgB,EAAOqJ,SAAWA,EAClBrJ,EAAO3B,WAAaA,EACpB2B,EAAOvB,SAAWA,EAClBuB,EAAOgf,UAAYA,EACnBhf,EAAOrB,KAAOmB,EAEdE,EAAOmpB,IAAMzjB,KAAKyjB,IAElBnpB,EAAOkpC,UAAY,SAAU5qC,GAK5B,IAAIK,EAAOqB,EAAOrB,KAAML,GACxB,OAAkB,WAATK,GAA8B,WAATA,KAK5BwqC,MAAO7qC,EAAMyxB,WAAYzxB,KAG5B0B,EAAOopC,KAAO,SAAU7pC,GACvB,OAAe,MAARA,EACN,IACEA,EAAO,IAAK2D,QAAS8D,GAAO,KAkBT,mBAAXqiC,QAAyBA,OAAOC,KAC3CD,OAAQ,SAAU,GAAI,WACrB,OAAOrpC,IAOT,IAGCupC,GAAUxsC,EAAOiD,OAGjBwpC,GAAKzsC,EAAO0sC,EAwBb,OAtBAzpC,EAAO0pC,WAAa,SAAUhnC,GAS7B,OARK3F,EAAO0sC,IAAMzpC,IACjBjD,EAAO0sC,EAAID,IAGP9mC,GAAQ3F,EAAOiD,SAAWA,IAC9BjD,EAAOiD,OAASupC,IAGVvpC,GAMiB,oBAAb/C,IACXF,EAAOiD,OAASjD,EAAO0sC,EAAIzpC,GAMrBA","file":"jquery-3.6.0.min.js"} \ No newline at end of file diff --git a/src/base/component/container.rs b/src/base/component/container.rs index dfb1a010..d4315ddc 100644 --- a/src/base/component/container.rs +++ b/src/base/component/container.rs @@ -34,7 +34,7 @@ impl PageComponent for Container { fn default_render(&self, assets: &mut PageAssets) -> Markup { let classes = match self.container { - ContainerType::Wrapper => "wrapper", + ContainerType::Wrapper => "container", ContainerType::Row => "row", ContainerType::Column => "col", }; diff --git a/src/base/module/user/mod.rs b/src/base/module/user/mod.rs index 61d50ca1..eea6528c 100644 --- a/src/base/module/user/mod.rs +++ b/src/base/module/user/mod.rs @@ -42,6 +42,9 @@ async fn login() -> server::Result { .with_title( "Identificación del usuario" ) - .add_to("content", form_login()) + .add_to("content", Container::prepare() + .with_id("welcome") + .add(form_login()) + ) .render() } diff --git a/src/base/theme/aliner/assets/css/styles.css b/src/base/theme/aliner/assets/css/styles.css new file mode 100644 index 00000000..ffeee7db --- /dev/null +++ b/src/base/theme/aliner/assets/css/styles.css @@ -0,0 +1,343 @@ +html { + background-color: white; +} +* * { + outline: 5px solid rgba(255,0,0,.1); +} +* * * { + outline: 3px dashed rgba(255,0,0,.4); +} +* * * * { + outline: 2px dotted rgba(255,0,0,.6); +} +* * * * * { + outline: 1px dotted rgba(255,0,0,.9); +} +* * * * * * { + outline-color: gray; +} + +*::before, *::after { + background: #faa; + border-radius: 3px; + font: normal normal 400 10px/1.2 monospace; + padding: 1px 3px; +} +*::before { + content: "("; +} +*::after { + content: ")"; +} + +a::before { content: ""; } +a::after { content: ""; } +abbr::before { content: ""; } +abbr::after { content: ""; } +acronym::before { content: ""; } +acronym::after { content: ""; } +address::before { content: "
"; } +address::after { content: "
"; } +applet::before { content: ""; } +applet::after { content: ""; } +area::before { content: ""; } +area::after { content: ""; } +article::before { content: "
"; } +article::after { content: "
"; } +aside::before { content: ""; } +audio::before { content: ""; } + +b::before { content: ""; } +b::after { content: ""; } +base::before { content: ""; } +base::after { content: ""; } +basefont::before { content: ""; } +basefont::after { content: ""; } +bdi::before { content: ""; } +bdi::after { content: ""; } +bdo::before { content: ""; } +bdo::after { content: ""; } +bgsound::before { content: ""; } +bgsound::after { content: ""; } +big::before { content: ""; } +big::after { content: ""; } +blink::before { content: ""; } +blink::after { content: ""; } +blockquote::before { content: "
"; } +blockquote::after { content: "
"; } +body::before { content: ""; } +body::after { content: ""; } +br::before { content: "
"; } +br::after { content: "
"; } +button::before { content: ""; } + +caption::before { content: ""; } +caption::after { content: ""; } +canvas::before { content: ""; } +canvas::after { content: ""; } +center::before { content: "
"; } +center::after { content: "
"; } +cite::before { content: ""; } +cite::after { content: ""; } +code::before { content: ""; } +code::after { content: ""; } +col::before { content: ""; } +col::after { content: ""; } +colgroup::before { content: ""; } +colgroup::after { content: ""; } +command::before { content: ""; } +command::after { content: ""; } +content::before { content: ""; } +content::after { content: ""; } + +data::before { content: ""; } +data::after { content: ""; } +datalist::before { content: ""; } +datalist::after { content: ""; } +dd::before { content: "
"; } +dd::after { content: "
"; } +del::before { content: ""; } +del::after { content: ""; } +details::before { content: "
"; } +details::after { content: "
"; } +dfn::before { content: ""; } +dfn::after { content: ""; } +dialog::before { content: ""; } +dialog::after { content: ""; } +dir::before { content: ""; } +dir::after { content: ""; } +div::before { content: "
"; } +div::after { content: "
"; } +dl::before { content: "
"; } +dl::after { content: "
"; } +dt::before { content: "
"; } +dt::after { content: "
"; } + +element::before { content: ""; } +element::after { content: ""; } +em::before { content: ""; } +em::after { content: ""; } +embed::before { content: ""; } +embed::after { content: ""; } + +fieldset::before { content: "
"; } +fieldset::after { content: "
"; } +figcaption::before { content: "
"; } +figcaption::after { content: "
"; } +figure::before { content: "
"; } +figure::after { content: "
"; } +font::before { content: ""; } +font::after { content: ""; } +footer::before { content: "
"; } +footer::after { content: "
"; } +form::before { content: "
"; } +form::after { content: "
"; } +frame::before { content: ""; } +frame::after { content: ""; } +frameset::before { content: ""; } +frameset::after { content: ""; } + +h1::before { content: "

"; } +h1::after { content: "

"; } +h2::before { content: "

"; } +h2::after { content: "

"; } +h3::before { content: "

"; } +h3::after { content: "

"; } +h4::before { content: "

"; } +h4::after { content: "

"; } +h5::before { content: "
"; } +h5::after { content: "
"; } +h6::before { content: "
"; } +h6::after { content: "
"; } +head::before { content: ""; } +head::after { content: ""; } +header::before { content: "
"; } +header::after { content: "
"; } +hgroup::before { content: "
"; } +hgroup::after { content: "
"; } +hr::before { content: "
"; } +hr::after { content: ""; } +html::before { content: ""; } +html::after { content: ""; } + +i::before { content: ""; } +i::after { content: ""; } +iframe::before { content: ""; } +image::before { content: ""; } +image::after { content: ""; } +img::before { content: ""; } +img::after { content: ""; } +input::before { content: ""; } +input::after { content: ""; } +ins::before { content: ""; } +ins::after { content: ""; } +isindex::before { content: ""; } +isindex::after { content: ""; } + +kbd::before { content: ""; } +kbd::after { content: ""; } +keygen::before { content: ""; } +keygen::after { content: ""; } + +label::before { content: ""; } +legend::before { content: ""; } +legend::after { content: ""; } +li::before { content: "
  • "; } +li::after { content: "
  • "; } +link::before { content: ""; } +link::after { content: ""; } +listing::before { content: ""; } +listing::after { content: ""; } + +main::before { content: "
    "; } +main::after { content: "
    "; } +map::before { content: ""; } +map::after { content: ""; } +mark::before { content: ""; } +mark::after { content: ""; } +marquee::before { content: ""; } +marquee::after { content: ""; } +menu::before { content: ""; } +menu::after { content: ""; } +menuitem::before { content: ""; } +menuitem::after { content: ""; } +meta::before { content: ""; } +meta::after { content: ""; } +meter::before { content: ""; } +meter::after { content: ""; } +multicol::before { content: ""; } +multicol::after { content: ""; } + +nav::before { content: ""; } +nextid::before { content: ""; } +nextid::after { content: ""; } +nobr::before { content: ""; } +nobr::after { content: ""; } +noembed::before { content: ""; } +noembed::after { content: ""; } +noframes::before { content: ""; } +noframes::after { content: ""; } +noscript::before { content: ""; } + +object::before { content: ""; } +object::after { content: ""; } +ol::before { content: "
      "; } +ol::after { content: "
    "; } +optgroup::before { content: ""; } +optgroup::after { content: ""; } +option::before { content: ""; } +output::before { content: ""; } +output::after { content: ""; } + +p::before { content: "

    "; } +p::after { content: "

    "; } +param::before { content: ""; } +param::after { content: ""; } +picture::before { content: ""; } +picture::after { content: ""; } +plaintext::before { content: ""; } +plaintext::after { content: "</plaintext>"; } +pre::before { content: "<pre>"; } +pre::after { content: "</pre>"; } +progress::before { content: "<progress>"; } +progress::after { content: "</progress>"; } + +q::before { content: "<q>"; } +q::after { content: "</q>"; } + +rb::before { content: "<rb>"; } +rb::after { content: "</rb>"; } +rp::before { content: "<rp>"; } +rp::after { content: "</rp>"; } +rt::before { content: "<rt>"; } +rt::after { content: "</rt>"; } +rtc::before { content: "<rtc>"; } +rtc::after { content: "</rtc>"; } +ruby::before { content: "<ruby>"; } +ruby::after { content: "</ruby>"; } + +s::before { content: "<s>"; } +s::after { content: "</s>"; } +samp::before { content: "<samp>"; } +samp::after { content: "</samp>"; } +script::before { content: "<script>"; } +script::after { content: "</script>"; } +section::before { content: "<section>"; } +section::after { content: "</section>"; } +select::before { content: "<select>"; } +select::after { content: "</select>"; } +shadow::before { content: "<shadow>"; } +shadow::after { content: "</shadow>"; } +slot::before { content: "<slot>"; } +slot::after { content: "</slot>"; } +small::before { content: "<small>"; } +small::after { content: "</small>"; } +source::before { content: "<source>"; } +source::after { content: "</source>"; } +spacer::before { content: "<spacer>"; } +spacer::after { content: "</spacer>"; } +span::before { content: "<span>"; } +span::after { content: "</span>"; } +strike::before { content: "<strike>"; } +strike::after { content: "</strike>"; } +strong::before { content: "<strong>"; } +strong::after { content: "</strong>"; } +style::before { content: "<style>"; } +style::after { content: "<\/style>"; } +sub::before { content: "<sub>"; } +sub::after { content: "</sub>"; } +summary::before { content: "<summary>"; } +summary::after { content: "</summary>"; } +sup::before { content: "<sup>"; } +sup::after { content: "</sup>"; } + +table::before { content: "<table>"; } +table::after { content: "</table>"; } +tbody::before { content: "<tbody>"; } +tbody::after { content: "</tbody>"; } +td::before { content: "<td>"; } +td::after { content: "</td>"; } +template::before { content: "<template>"; } +template::after { content: "</template>"; } +textarea::before { content: "<textarea>"; } +textarea::after { content: "</textarea>"; } +tfoot::before { content: "<tfoot>"; } +tfoot::after { content: "</tfoot>"; } +th::before { content: "<th>"; } +th::after { content: "</th>"; } +thead::before { content: "<thead>"; } +thead::after { content: "</thead>"; } +time::before { content: "<time>"; } +time::after { content: "</time>"; } +title::before { content: "<title>"; } +title::after { content: "</title>"; } +tr::before { content: "<tr>"; } +tr::after { content: "</tr>"; } +track::before { content: "<track>"; } +track::after { content: "</track>"; } +tt::before { content: "<tt>"; } +tt::after { content: "</tt>"; } + +u::before { content: "<u>"; } +u::after { content: "</u>"; } +ul::before { content: "<ul>"; } +ul::after { content: "</ul>"; } + +var::before { content: "<var>"; } +var::after { content: "</var>"; } +video::before { content: "<video>"; } +video::after { content: "</video>"; } + +wbr::before { content: "<wbr>"; } +wbr::after { content: "</wbr>"; } + +xmp::before { content: "<xmp>"; } +xmp::after { content: "</xmp>"; } diff --git a/src/base/theme/aliner/mod.rs b/src/base/theme/aliner/mod.rs new file mode 100644 index 00000000..8ad4e291 --- /dev/null +++ b/src/base/theme/aliner/mod.rs @@ -0,0 +1,28 @@ +use crate::prelude::*; + +include!(concat!(env!("OUT_DIR"), "/aliner.rs")); + +pub struct AlinerTheme; + +impl Theme for AlinerTheme { + fn name(&self) -> &str { + "Aliner" + } + + fn configure_theme(&self, cfg: &mut server::web::ServiceConfig) { + cfg.service(actix_web_static_files::ResourceFiles::new( + "/aliner", + generate() + )); + } + + fn before_render_page(&self, page: &mut Page) { + page.assets() + .add_stylesheet( + StyleSheet::source( + "/aliner/css/styles.css" + ) + .with_weight(-99) + ); + } +} diff --git a/src/base/theme/bootsier/assets/css/bootstrap.min.css b/src/base/theme/bootsier/assets/css/bootstrap.min.css new file mode 100644 index 00000000..1472dec0 --- /dev/null +++ b/src/base/theme/bootsier/assets/css/bootstrap.min.css @@ -0,0 +1,7 @@ +@charset "UTF-8";/*! + * Bootstrap v5.1.3 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors + * Copyright 2011-2021 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-color-rgb:33,37,41;--bs-body-bg-rgb:255,255,255;--bs-font-sans-serif: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";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:#6c757d}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{width:100%;padding-right:var(--bs-gutter-x,.75rem);padding-left:var(--bs-gutter-x,.75rem);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.6666666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.6666666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.6666666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.6666666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.6666666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.6666666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-bg:transparent;--bs-table-accent-bg:transparent;--bs-table-striped-color:#212529;--bs-table-striped-bg:rgba(0, 0, 0, 0.05);--bs-table-active-color:#212529;--bs-table-active-bg:rgba(0, 0, 0, 0.1);--bs-table-hover-color:#212529;--bs-table-hover-bg:rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#212529;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:first-child){border-top:2px solid currentColor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-accent-bg:var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg:var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover>*{--bs-table-accent-bg:var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg:#cfe2ff;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:#000;border-color:#bacbe6}.table-secondary{--bs-table-bg:#e2e3e5;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:#000;border-color:#cbccce}.table-success{--bs-table-bg:#d1e7dd;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:#000;border-color:#bcd0c7}.table-info{--bs-table-bg:#cff4fc;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:#000;border-color:#badce3}.table-warning{--bs-table-bg:#fff3cd;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:#000;border-color:#e6dbb9}.table-danger{--bs-table-bg:#f8d7da;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:#000;border-color:#dfc2c4}.table-light{--bs-table-bg:#f8f9fa;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg:#212529;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:#fff;border-color:#373b3e}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + 2px)}textarea.form-control-sm{min-height:calc(1.5em + .5rem + 2px)}textarea.form-control-lg{min-height:calc(1.5em + 1rem + 2px)}.form-control-color{width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em;border-radius:.25rem}.form-control-color::-webkit-color-swatch{height:1.5em;border-radius:.25rem}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:.2rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:.3rem}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px;border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(25,135,84,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#198754;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:#198754}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:#198754}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:#198754}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group .form-control.is-valid,.input-group .form-select.is-valid,.was-validated .input-group .form-control:valid,.was-validated .input-group .form-select:valid{z-index:1}.input-group .form-control.is-valid:focus,.input-group .form-select.is-valid:focus,.was-validated .input-group .form-control:valid:focus,.was-validated .input-group .form-select:valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:#dc3545}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:#dc3545}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:#dc3545}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group .form-control.is-invalid,.input-group .form-select.is-invalid,.was-validated .input-group .form-control:invalid,.was-validated .input-group .form-select:invalid{z-index:2}.input-group .form-control.is-invalid:focus,.input-group .form-select.is-invalid:focus,.was-validated .input-group .form-control:invalid:focus,.was-validated .input-group .form-select:invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#212529;text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-primary{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-primary:hover{color:#fff;background-color:#0b5ed7;border-color:#0a58ca}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#0b5ed7;border-color:#0a58ca;box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-check:active+.btn-primary,.btn-check:checked+.btn-primary,.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0a58ca;border-color:#0a53be}.btn-check:active+.btn-primary:focus,.btn-check:checked+.btn-primary:focus,.btn-primary.active:focus,.btn-primary:active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5c636a;border-color:#565e64}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#5c636a;border-color:#565e64;box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-check:active+.btn-secondary,.btn-check:checked+.btn-secondary,.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#565e64;border-color:#51585e}.btn-check:active+.btn-secondary:focus,.btn-check:checked+.btn-secondary:focus,.btn-secondary.active:focus,.btn-secondary:active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-success{color:#fff;background-color:#198754;border-color:#198754}.btn-success:hover{color:#fff;background-color:#157347;border-color:#146c43}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#157347;border-color:#146c43;box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-check:active+.btn-success,.btn-check:checked+.btn-success,.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#146c43;border-color:#13653f}.btn-check:active+.btn-success:focus,.btn-check:checked+.btn-success:focus,.btn-success.active:focus,.btn-success:active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#198754;border-color:#198754}.btn-info{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-info:hover{color:#000;background-color:#31d2f2;border-color:#25cff2}.btn-check:focus+.btn-info,.btn-info:focus{color:#000;background-color:#31d2f2;border-color:#25cff2;box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-check:active+.btn-info,.btn-check:checked+.btn-info,.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{color:#000;background-color:#3dd5f3;border-color:#25cff2}.btn-check:active+.btn-info:focus,.btn-check:checked+.btn-info:focus,.btn-info.active:focus,.btn-info:active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-info.disabled,.btn-info:disabled{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-warning{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#000;background-color:#ffca2c;border-color:#ffc720}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#000;background-color:#ffca2c;border-color:#ffc720;box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-check:active+.btn-warning,.btn-check:checked+.btn-warning,.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{color:#000;background-color:#ffcd39;border-color:#ffc720}.btn-check:active+.btn-warning:focus,.btn-check:checked+.btn-warning:focus,.btn-warning.active:focus,.btn-warning:active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#bb2d3b;border-color:#b02a37}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#bb2d3b;border-color:#b02a37;box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-check:active+.btn-danger,.btn-check:checked+.btn-danger,.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#b02a37;border-color:#a52834}.btn-check:active+.btn-danger:focus,.btn-check:checked+.btn-danger:focus,.btn-danger.active:focus,.btn-danger:active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:active+.btn-light,.btn-check:checked+.btn-light,.btn-light.active,.btn-light:active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:active+.btn-light:focus,.btn-check:checked+.btn-light:focus,.btn-light.active:focus,.btn-light:active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light.disabled,.btn-light:disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#212529;border-color:#212529}.btn-dark:hover{color:#fff;background-color:#1c1f23;border-color:#1a1e21}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#1c1f23;border-color:#1a1e21;box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-check:active+.btn-dark,.btn-check:checked+.btn-dark,.btn-dark.active,.btn-dark:active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1a1e21;border-color:#191c1f}.btn-check:active+.btn-dark:focus,.btn-check:checked+.btn-dark:focus,.btn-dark.active:focus,.btn-dark:active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#212529;border-color:#212529}.btn-outline-primary{color:#0d6efd;border-color:#0d6efd}.btn-outline-primary:hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-check:active+.btn-outline-primary,.btn-check:checked+.btn-outline-primary,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show,.btn-outline-primary:active{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:active+.btn-outline-primary:focus,.btn-check:checked+.btn-outline-primary:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus,.btn-outline-primary:active:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#0d6efd;background-color:transparent}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-check:active+.btn-outline-secondary,.btn-check:checked+.btn-outline-secondary,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show,.btn-outline-secondary:active{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:active+.btn-outline-secondary:focus,.btn-check:checked+.btn-outline-secondary:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus,.btn-outline-secondary:active:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-success{color:#198754;border-color:#198754}.btn-outline-success:hover{color:#fff;background-color:#198754;border-color:#198754}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-check:active+.btn-outline-success,.btn-check:checked+.btn-outline-success,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show,.btn-outline-success:active{color:#fff;background-color:#198754;border-color:#198754}.btn-check:active+.btn-outline-success:focus,.btn-check:checked+.btn-outline-success:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus,.btn-outline-success:active:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#198754;background-color:transparent}.btn-outline-info{color:#0dcaf0;border-color:#0dcaf0}.btn-outline-info:hover{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-check:active+.btn-outline-info,.btn-check:checked+.btn-outline-info,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show,.btn-outline-info:active{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:active+.btn-outline-info:focus,.btn-check:checked+.btn-outline-info:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus,.btn-outline-info:active:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#0dcaf0;background-color:transparent}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-check:active+.btn-outline-warning,.btn-check:checked+.btn-outline-warning,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show,.btn-outline-warning:active{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:active+.btn-outline-warning:focus,.btn-check:checked+.btn-outline-warning:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus,.btn-outline-warning:active:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-check:active+.btn-outline-danger,.btn-check:checked+.btn-outline-danger,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show,.btn-outline-danger:active{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:active+.btn-outline-danger:focus,.btn-check:checked+.btn-outline-danger:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus,.btn-outline-danger:active:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:active+.btn-outline-light,.btn-check:checked+.btn-outline-light,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show,.btn-outline-light:active{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:active+.btn-outline-light:focus,.btn-check:checked+.btn-outline-light:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus,.btn-outline-light:active:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-dark{color:#212529;border-color:#212529}.btn-outline-dark:hover{color:#fff;background-color:#212529;border-color:#212529}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-check:active+.btn-outline-dark,.btn-check:checked+.btn-outline-dark,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show,.btn-outline-dark:active{color:#fff;background-color:#212529;border-color:#212529}.btn-check:active+.btn-outline-dark:focus,.btn-check:checked+.btn-outline-dark:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus,.btn-outline-dark:active:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#212529;background-color:transparent}.btn-link{font-weight:400;color:#0d6efd;text-decoration:underline}.btn-link:hover{color:#0a58ca}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropend,.dropstart,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#0d6efd}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#343a40;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:focus,.dropdown-menu-dark .dropdown-item:hover{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#0d6efd}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#0d6efd;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:#0a58ca}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:0 0;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{background:0 0;border:0;border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#0d6efd}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem;transition:box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas-header{display:none}.navbar-expand-sm .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-sm .offcanvas-bottom,.navbar-expand-sm .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas-header{display:none}.navbar-expand-md .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-md .offcanvas-bottom,.navbar-expand-md .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas-header{display:none}.navbar-expand-lg .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-lg .offcanvas-bottom,.navbar-expand-lg .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas-header{display:none}.navbar-expand-xl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xl .offcanvas-bottom,.navbar-expand-xl .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xxl .offcanvas-bottom,.navbar-expand-xxl .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas-header{display:none}.navbar-expand .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand .offcanvas-bottom,.navbar-expand .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.55)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.55);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.55)}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.55)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.55);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.55)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.5rem 1rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.5rem;margin-bottom:-.5rem;margin-left:-.5rem;border-bottom:0}.card-header-pills{margin-right:-.5rem;margin-left:-.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-group>.card{margin-bottom:.75rem}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#212529;text-align:left;background-color:#fff;border:0;border-radius:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#0c63e4;background-color:#e7f1ff;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:first-of-type{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.accordion-item:first-of-type .accordion-button{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button{border-radius:0}.breadcrumb{display:flex;flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#0d6efd;text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#0a58ca;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#0a58ca;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe}.alert-primary .alert-link{color:#06357a}.alert-secondary{color:#41464b;background-color:#e2e3e5;border-color:#d3d6d8}.alert-secondary .alert-link{color:#34383c}.alert-success{color:#0f5132;background-color:#d1e7dd;border-color:#badbcc}.alert-success .alert-link{color:#0c4128}.alert-info{color:#055160;background-color:#cff4fc;border-color:#b6effb}.alert-info .alert-link{color:#04414d}.alert-warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5}.alert-warning .alert-link{color:#523e02}.alert-danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7}.alert-danger .alert-link{color:#6a1a21}.alert-light{color:#636464;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#4f5050}.alert-dark{color:#141619;background-color:#d3d3d4;border-color:#bcbebf}.alert-dark .alert-link{color:#101214}@-webkit-keyframes progress-bar-stripes{0%{background-position-x:1rem}}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#0d6efd;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:1s linear infinite progress-bar-stripes;animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#084298;background-color:#cfe2ff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#084298;background-color:#bacbe6}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#084298;border-color:#084298}.list-group-item-secondary{color:#41464b;background-color:#e2e3e5}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#41464b;background-color:#cbccce}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#41464b;border-color:#41464b}.list-group-item-success{color:#0f5132;background-color:#d1e7dd}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#0f5132;background-color:#bcd0c7}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#0f5132;border-color:#0f5132}.list-group-item-info{color:#055160;background-color:#cff4fc}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#055160;background-color:#badce3}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#055160;border-color:#055160}.list-group-item-warning{color:#664d03;background-color:#fff3cd}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#664d03;background-color:#e6dbb9}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#664d03;border-color:#664d03}.list-group-item-danger{color:#842029;background-color:#f8d7da}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#842029;background-color:#dfc2c4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#842029;border-color:#842029}.list-group-item-light{color:#636464;background-color:#fefefe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#636464;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#636464;border-color:#636464}.list-group-item-dark{color:#141619;background-color:#d3d3d4}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#141619;background-color:#bebebf}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#141619;border-color:#141619}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;border-radius:.25rem;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25);opacity:1}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15);border-radius:.25rem}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-header .btn-close{margin-right:-.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1055;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - 1rem)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1050;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .btn-close{padding:.5rem .5rem;margin:-.5rem -.5rem -.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;flex-shrink:0;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}.modal-fullscreen .modal-footer{border-radius:0}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}.modal-fullscreen-sm-down .modal-footer{border-radius:0}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}.modal-fullscreen-md-down .modal-footer{border-radius:0}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}.modal-fullscreen-lg-down .modal-footer{border-radius:0}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}.modal-fullscreen-xl-down .modal-footer{border-radius:0}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}.modal-fullscreen-xxl-down .modal-footer{border-radius:0}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[data-popper-placement^=right],.bs-tooltip-end{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[data-popper-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[data-popper-placement^=left],.bs-tooltip-start{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2);border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@-webkit-keyframes spinner-border{to{transform:rotate(360deg)}}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:.75s linear infinite spinner-border;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:.75s linear infinite spinner-grow;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{-webkit-animation-duration:1.5s;animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1045;display:flex;flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-.5rem;margin-right:-.5rem;margin-bottom:-.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentColor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{-webkit-animation:placeholder-glow 2s ease-in-out infinite;animation:placeholder-glow 2s ease-in-out infinite}@-webkit-keyframes placeholder-glow{50%{opacity:.2}}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;-webkit-animation:placeholder-wave 2s linear infinite;animation:placeholder-wave 2s linear infinite}@-webkit-keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.link-primary{color:#0d6efd}.link-primary:focus,.link-primary:hover{color:#0a58ca}.link-secondary{color:#6c757d}.link-secondary:focus,.link-secondary:hover{color:#565e64}.link-success{color:#198754}.link-success:focus,.link-success:hover{color:#146c43}.link-info{color:#0dcaf0}.link-info:focus,.link-info:hover{color:#3dd5f3}.link-warning{color:#ffc107}.link-warning:focus,.link-warning:hover{color:#ffcd39}.link-danger{color:#dc3545}.link-danger:focus,.link-danger:hover{color:#b02a37}.link-light{color:#f8f9fa}.link-light:focus,.link-light:hover{color:#f9fafb}.link-dark{color:#212529}.link-dark:focus,.link-dark:hover{color:#1a1e21}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:1px;min-height:1em;background-color:currentColor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:1px solid #dee2e6!important}.border-0{border:0!important}.border-top{border-top:1px solid #dee2e6!important}.border-top-0{border-top:0!important}.border-end{border-right:1px solid #dee2e6!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:1px solid #dee2e6!important}.border-start-0{border-left:0!important}.border-primary{border-color:#0d6efd!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#198754!important}.border-info{border-color:#0dcaf0!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#212529!important}.border-white{border-color:#fff!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-light{font-weight:300!important}.fw-lighter{font-weight:lighter!important}.fw-normal{font-weight:400!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:#6c757d!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:.25rem!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:.2rem!important}.rounded-2{border-radius:.25rem!important}.rounded-3{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-end{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-start{border-bottom-left-radius:.25rem!important;border-top-left-radius:.25rem!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/src/base/theme/bootsier/assets/css/bootstrap.min.css.map b/src/base/theme/bootsier/assets/css/bootstrap.min.css.map new file mode 100644 index 00000000..c84afa43 --- /dev/null +++ b/src/base/theme/bootsier/assets/css/bootstrap.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../scss/bootstrap.scss","../../scss/_root.scss","../../scss/_reboot.scss","dist/css/bootstrap.css","../../scss/vendor/_rfs.scss","../../scss/mixins/_border-radius.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/_containers.scss","../../scss/mixins/_container.scss","../../scss/mixins/_breakpoints.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/_tables.scss","../../scss/mixins/_table-variants.scss","../../scss/forms/_labels.scss","../../scss/forms/_form-text.scss","../../scss/forms/_form-control.scss","../../scss/mixins/_transition.scss","../../scss/mixins/_gradients.scss","../../scss/forms/_form-select.scss","../../scss/forms/_form-check.scss","../../scss/forms/_form-range.scss","../../scss/forms/_floating-labels.scss","../../scss/forms/_input-group.scss","../../scss/mixins/_forms.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_caret.scss","../../scss/_button-group.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_accordion.scss","../../scss/_breadcrumb.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_close.scss","../../scss/_toasts.scss","../../scss/_modal.scss","../../scss/mixins/_backdrop.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/mixins/_clearfix.scss","../../scss/_spinners.scss","../../scss/_offcanvas.scss","../../scss/_placeholders.scss","../../scss/helpers/_colored-links.scss","../../scss/helpers/_ratio.scss","../../scss/helpers/_position.scss","../../scss/helpers/_stacks.scss","../../scss/helpers/_visually-hidden.scss","../../scss/mixins/_visually-hidden.scss","../../scss/helpers/_stretched-link.scss","../../scss/helpers/_text-truncation.scss","../../scss/mixins/_text-truncate.scss","../../scss/helpers/_vr.scss","../../scss/mixins/_utilities.scss","../../scss/utilities/_api.scss"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Bootstrap v5.1.3 (https://getbootstrap.com/)\n * Copyright 2011-2021 The Bootstrap Authors\n * Copyright 2011-2021 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n\n// scss-docs-start import-stack\n// Configuration\n@import \"functions\";\n@import \"variables\";\n@import \"mixins\";\n@import \"utilities\";\n\n// Layout & components\n@import \"root\";\n@import \"reboot\";\n@import \"type\";\n@import \"images\";\n@import \"containers\";\n@import \"grid\";\n@import \"tables\";\n@import \"forms\";\n@import \"buttons\";\n@import \"transitions\";\n@import \"dropdown\";\n@import \"button-group\";\n@import \"nav\";\n@import \"navbar\";\n@import \"card\";\n@import \"accordion\";\n@import \"breadcrumb\";\n@import \"pagination\";\n@import \"badge\";\n@import \"alert\";\n@import \"progress\";\n@import \"list-group\";\n@import \"close\";\n@import \"toasts\";\n@import \"modal\";\n@import \"tooltip\";\n@import \"popover\";\n@import \"carousel\";\n@import \"spinners\";\n@import \"offcanvas\";\n@import \"placeholders\";\n\n// Helpers\n@import \"helpers\";\n\n// Utilities\n@import \"utilities/api\";\n// scss-docs-end import-stack\n",":root {\n // Note: Custom variable values only support SassScript inside `#{}`.\n\n // Colors\n //\n // Generate palettes for full colors, grays, and theme colors.\n\n @each $color, $value in $colors {\n --#{$variable-prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $grays {\n --#{$variable-prefix}gray-#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors {\n --#{$variable-prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors-rgb {\n --#{$variable-prefix}#{$color}-rgb: #{$value};\n }\n\n --#{$variable-prefix}white-rgb: #{to-rgb($white)};\n --#{$variable-prefix}black-rgb: #{to-rgb($black)};\n --#{$variable-prefix}body-color-rgb: #{to-rgb($body-color)};\n --#{$variable-prefix}body-bg-rgb: #{to-rgb($body-bg)};\n\n // Fonts\n\n // Note: Use `inspect` for lists so that quoted items keep the quotes.\n // See https://github.com/sass/sass/issues/2383#issuecomment-336349172\n --#{$variable-prefix}font-sans-serif: #{inspect($font-family-sans-serif)};\n --#{$variable-prefix}font-monospace: #{inspect($font-family-monospace)};\n --#{$variable-prefix}gradient: #{$gradient};\n\n // Root and body\n // stylelint-disable custom-property-empty-line-before\n // scss-docs-start root-body-variables\n @if $font-size-root != null {\n --#{$variable-prefix}root-font-size: #{$font-size-root};\n }\n --#{$variable-prefix}body-font-family: #{$font-family-base};\n --#{$variable-prefix}body-font-size: #{$font-size-base};\n --#{$variable-prefix}body-font-weight: #{$font-weight-base};\n --#{$variable-prefix}body-line-height: #{$line-height-base};\n --#{$variable-prefix}body-color: #{$body-color};\n @if $body-text-align != null {\n --#{$variable-prefix}body-text-align: #{$body-text-align};\n }\n --#{$variable-prefix}body-bg: #{$body-bg};\n // scss-docs-end root-body-variables\n // stylelint-enable custom-property-empty-line-before\n}\n","// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix\n\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n\n// Document\n//\n// Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n\n// Root\n//\n// Ability to the value of the root font sizes, affecting the value of `rem`.\n// null by default, thus nothing is generated.\n\n:root {\n @if $font-size-root != null {\n font-size: var(--#{$variable-prefix}root-font-size);\n }\n\n @if $enable-smooth-scroll {\n @media (prefers-reduced-motion: no-preference) {\n scroll-behavior: smooth;\n }\n }\n}\n\n\n// Body\n//\n// 1. Remove the margin in all browsers.\n// 2. As a best practice, apply a default `background-color`.\n// 3. Prevent adjustments of font size after orientation changes in iOS.\n// 4. Change the default tap highlight to be completely transparent in iOS.\n\n// scss-docs-start reboot-body-rules\nbody {\n margin: 0; // 1\n font-family: var(--#{$variable-prefix}body-font-family);\n @include font-size(var(--#{$variable-prefix}body-font-size));\n font-weight: var(--#{$variable-prefix}body-font-weight);\n line-height: var(--#{$variable-prefix}body-line-height);\n color: var(--#{$variable-prefix}body-color);\n text-align: var(--#{$variable-prefix}body-text-align);\n background-color: var(--#{$variable-prefix}body-bg); // 2\n -webkit-text-size-adjust: 100%; // 3\n -webkit-tap-highlight-color: rgba($black, 0); // 4\n}\n// scss-docs-end reboot-body-rules\n\n\n// Content grouping\n//\n// 1. Reset Firefox's gray color\n// 2. Set correct height and prevent the `size` attribute to make the `hr` look like an input field\n\nhr {\n margin: $hr-margin-y 0;\n color: $hr-color; // 1\n background-color: currentColor;\n border: 0;\n opacity: $hr-opacity;\n}\n\nhr:not([size]) {\n height: $hr-height; // 2\n}\n\n\n// Typography\n//\n// 1. Remove top margins from headings\n// By default, `<h1>`-`<h6>` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\n\n%heading {\n margin-top: 0; // 1\n margin-bottom: $headings-margin-bottom;\n font-family: $headings-font-family;\n font-style: $headings-font-style;\n font-weight: $headings-font-weight;\n line-height: $headings-line-height;\n color: $headings-color;\n}\n\nh1 {\n @extend %heading;\n @include font-size($h1-font-size);\n}\n\nh2 {\n @extend %heading;\n @include font-size($h2-font-size);\n}\n\nh3 {\n @extend %heading;\n @include font-size($h3-font-size);\n}\n\nh4 {\n @extend %heading;\n @include font-size($h4-font-size);\n}\n\nh5 {\n @extend %heading;\n @include font-size($h5-font-size);\n}\n\nh6 {\n @extend %heading;\n @include font-size($h6-font-size);\n}\n\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `<p>`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\n\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n\n// Abbreviations\n//\n// 1. Duplicate behavior to the data-bs-* attribute for our tooltip plugin\n// 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari.\n// 3. Add explicit cursor to indicate changed behavior.\n// 4. Prevent the text-decoration to be skipped.\n\nabbr[title],\nabbr[data-bs-original-title] { // 1\n text-decoration: underline dotted; // 2\n cursor: help; // 3\n text-decoration-skip-ink: none; // 4\n}\n\n\n// Address\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\n\n// Lists\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\n// 1. Undo browser default\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // 1\n}\n\n\n// Blockquote\n\nblockquote {\n margin: 0 0 1rem;\n}\n\n\n// Strong\n//\n// Add the correct font weight in Chrome, Edge, and Safari\n\nb,\nstrong {\n font-weight: $font-weight-bolder;\n}\n\n\n// Small\n//\n// Add the correct font size in all browsers\n\nsmall {\n @include font-size($small-font-size);\n}\n\n\n// Mark\n\nmark {\n padding: $mark-padding;\n background-color: $mark-bg;\n}\n\n\n// Sub and Sup\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n\nsub,\nsup {\n position: relative;\n @include font-size($sub-sup-font-size);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n// Links\n\na {\n color: $link-color;\n text-decoration: $link-decoration;\n\n &:hover {\n color: $link-hover-color;\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n &,\n &:hover {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n// Code\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-code;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n direction: ltr #{\"/* rtl:ignore */\"};\n unicode-bidi: bidi-override;\n}\n\n// 1. Remove browser default top margin\n// 2. Reset browser default of `1em` to use `rem`s\n// 3. Don't allow content to break outside\n\npre {\n display: block;\n margin-top: 0; // 1\n margin-bottom: 1rem; // 2\n overflow: auto; // 3\n @include font-size($code-font-size);\n color: $pre-color;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n @include font-size(inherit);\n color: inherit;\n word-break: normal;\n }\n}\n\ncode {\n @include font-size($code-font-size);\n color: $code-color;\n word-wrap: break-word;\n\n // Streamline the style when inside anchors to avoid broken underline and more\n a > & {\n color: inherit;\n }\n}\n\nkbd {\n padding: $kbd-padding-y $kbd-padding-x;\n @include font-size($kbd-font-size);\n color: $kbd-color;\n background-color: $kbd-bg;\n @include border-radius($border-radius-sm);\n\n kbd {\n padding: 0;\n @include font-size(1em);\n font-weight: $nested-kbd-font-weight;\n }\n}\n\n\n// Figures\n//\n// Apply a consistent margin strategy (matches our type styles).\n\nfigure {\n margin: 0 0 1rem;\n}\n\n\n// Images and content\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\n\n// Tables\n//\n// Prevent double borders\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: $table-cell-padding-y;\n padding-bottom: $table-cell-padding-y;\n color: $table-caption-color;\n text-align: left;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `<td>` alignment by inheriting `text-align`.\n// 3. Fix alignment for Safari\n\nth {\n font-weight: $table-th-font-weight; // 1\n text-align: inherit; // 2\n text-align: -webkit-match-parent; // 3\n}\n\nthead,\ntbody,\ntfoot,\ntr,\ntd,\nth {\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n}\n\n\n// Forms\n//\n// 1. Allow labels to use `margin` for spacing.\n\nlabel {\n display: inline-block; // 1\n}\n\n// Remove the default `border-radius` that macOS Chrome adds.\n// See https://github.com/twbs/bootstrap/issues/24093\n\nbutton {\n // stylelint-disable-next-line property-disallowed-list\n border-radius: 0;\n}\n\n// Explicitly remove focus outline in Chromium when it shouldn't be\n// visible (e.g. as result of mouse click or touch tap). It already\n// should be doing this automatically, but seems to currently be\n// confused and applies its very visible two-tone outline anyway.\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\n// 1. Remove the margin in Firefox and Safari\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0; // 1\n font-family: inherit;\n @include font-size(inherit);\n line-height: inherit;\n}\n\n// Remove the inheritance of text transform in Firefox\nbutton,\nselect {\n text-transform: none;\n}\n// Set the cursor for non-`<button>` buttons\n//\n// Details at https://github.com/twbs/bootstrap/pull/30562\n[role=\"button\"] {\n cursor: pointer;\n}\n\nselect {\n // Remove the inheritance of word-wrap in Safari.\n // See https://github.com/twbs/bootstrap/issues/24990\n word-wrap: normal;\n\n // Undo the opacity change from Chrome\n &:disabled {\n opacity: 1;\n }\n}\n\n// Remove the dropdown arrow in Chrome from inputs built with datalists.\n// See https://stackoverflow.com/a/54997118\n\n[list]::-webkit-calendar-picker-indicator {\n display: none;\n}\n\n// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`\n// controls in Android 4.\n// 2. Correct the inability to style clickable types in iOS and Safari.\n// 3. Opinionated: add \"hand\" cursor to non-disabled button elements.\n\nbutton,\n[type=\"button\"], // 1\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button; // 2\n\n @if $enable-button-pointers {\n &:not(:disabled) {\n cursor: pointer; // 3\n }\n }\n}\n\n// Remove inner border and padding from Firefox, but don't restore the outline like Normalize.\n\n::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\n// 1. Textareas should really only resize vertically so they don't break their (horizontal) containers.\n\ntextarea {\n resize: vertical; // 1\n}\n\n// 1. Browsers set a default `min-width: min-content;` on fieldsets,\n// unlike e.g. `<div>`s, which have `min-width: 0;` by default.\n// So we reset that to ensure fieldsets behave more like a standard block element.\n// See https://github.com/twbs/bootstrap/issues/12359\n// and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements\n// 2. Reset the default outline behavior of fieldsets so they don't affect page layout.\n\nfieldset {\n min-width: 0; // 1\n padding: 0; // 2\n margin: 0; // 2\n border: 0; // 2\n}\n\n// 1. By using `float: left`, the legend will behave like a block element.\n// This way the border of a fieldset wraps around the legend if present.\n// 2. Fix wrapping bug.\n// See https://github.com/twbs/bootstrap/issues/29712\n\nlegend {\n float: left; // 1\n width: 100%;\n padding: 0;\n margin-bottom: $legend-margin-bottom;\n @include font-size($legend-font-size);\n font-weight: $legend-font-weight;\n line-height: inherit;\n\n + * {\n clear: left; // 2\n }\n}\n\n// Fix height of inputs with a type of datetime-local, date, month, week, or time\n// See https://github.com/twbs/bootstrap/issues/18842\n\n::-webkit-datetime-edit-fields-wrapper,\n::-webkit-datetime-edit-text,\n::-webkit-datetime-edit-minute,\n::-webkit-datetime-edit-hour-field,\n::-webkit-datetime-edit-day-field,\n::-webkit-datetime-edit-month-field,\n::-webkit-datetime-edit-year-field {\n padding: 0;\n}\n\n::-webkit-inner-spin-button {\n height: auto;\n}\n\n// 1. Correct the outline style in Safari.\n// 2. This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\n[type=\"search\"] {\n outline-offset: -2px; // 1\n -webkit-appearance: textfield; // 2\n}\n\n// 1. A few input types should stay LTR\n// See https://rtlstyling.com/posts/rtl-styling#form-inputs\n// 2. RTL only output\n// See https://rtlcss.com/learn/usage-guide/control-directives/#raw\n\n/* rtl:raw:\n[type=\"tel\"],\n[type=\"url\"],\n[type=\"email\"],\n[type=\"number\"] {\n direction: ltr;\n}\n*/\n\n// Remove the inner padding in Chrome and Safari on macOS.\n\n::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n// Remove padding around color pickers in webkit browsers\n\n::-webkit-color-swatch-wrapper {\n padding: 0;\n}\n\n\n// Inherit font family and line height for file input buttons\n\n::file-selector-button {\n font: inherit;\n}\n\n// 1. Change font properties to `inherit`\n// 2. Correct the inability to style clickable types in iOS and Safari.\n\n::-webkit-file-upload-button {\n font: inherit; // 1\n -webkit-appearance: button; // 2\n}\n\n// Correct element displays\n\noutput {\n display: inline-block;\n}\n\n// Remove border from iframe\n\niframe {\n border: 0;\n}\n\n// Summary\n//\n// 1. Add the correct display in all browsers\n\nsummary {\n display: list-item; // 1\n cursor: pointer;\n}\n\n\n// Progress\n//\n// Add the correct vertical alignment in Chrome, Firefox, and Opera.\n\nprogress {\n vertical-align: baseline;\n}\n\n\n// Hidden attribute\n//\n// Always hide an element with the `hidden` HTML attribute.\n\n[hidden] {\n display: none !important;\n}\n","@charset \"UTF-8\";\n/*!\n * Bootstrap v5.1.3 (https://getbootstrap.com/)\n * Copyright 2011-2021 The Bootstrap Authors\n * Copyright 2011-2021 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n:root {\n --bs-blue: #0d6efd;\n --bs-indigo: #6610f2;\n --bs-purple: #6f42c1;\n --bs-pink: #d63384;\n --bs-red: #dc3545;\n --bs-orange: #fd7e14;\n --bs-yellow: #ffc107;\n --bs-green: #198754;\n --bs-teal: #20c997;\n --bs-cyan: #0dcaf0;\n --bs-white: #fff;\n --bs-gray: #6c757d;\n --bs-gray-dark: #343a40;\n --bs-gray-100: #f8f9fa;\n --bs-gray-200: #e9ecef;\n --bs-gray-300: #dee2e6;\n --bs-gray-400: #ced4da;\n --bs-gray-500: #adb5bd;\n --bs-gray-600: #6c757d;\n --bs-gray-700: #495057;\n --bs-gray-800: #343a40;\n --bs-gray-900: #212529;\n --bs-primary: #0d6efd;\n --bs-secondary: #6c757d;\n --bs-success: #198754;\n --bs-info: #0dcaf0;\n --bs-warning: #ffc107;\n --bs-danger: #dc3545;\n --bs-light: #f8f9fa;\n --bs-dark: #212529;\n --bs-primary-rgb: 13, 110, 253;\n --bs-secondary-rgb: 108, 117, 125;\n --bs-success-rgb: 25, 135, 84;\n --bs-info-rgb: 13, 202, 240;\n --bs-warning-rgb: 255, 193, 7;\n --bs-danger-rgb: 220, 53, 69;\n --bs-light-rgb: 248, 249, 250;\n --bs-dark-rgb: 33, 37, 41;\n --bs-white-rgb: 255, 255, 255;\n --bs-black-rgb: 0, 0, 0;\n --bs-body-color-rgb: 33, 37, 41;\n --bs-body-bg-rgb: 255, 255, 255;\n --bs-font-sans-serif: 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\";\n --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));\n --bs-body-font-family: var(--bs-font-sans-serif);\n --bs-body-font-size: 1rem;\n --bs-body-font-weight: 400;\n --bs-body-line-height: 1.5;\n --bs-body-color: #212529;\n --bs-body-bg: #fff;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n :root {\n scroll-behavior: smooth;\n }\n}\n\nbody {\n margin: 0;\n font-family: var(--bs-body-font-family);\n font-size: var(--bs-body-font-size);\n font-weight: var(--bs-body-font-weight);\n line-height: var(--bs-body-line-height);\n color: var(--bs-body-color);\n text-align: var(--bs-body-text-align);\n background-color: var(--bs-body-bg);\n -webkit-text-size-adjust: 100%;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\nhr {\n margin: 1rem 0;\n color: inherit;\n background-color: currentColor;\n border: 0;\n opacity: 0.25;\n}\n\nhr:not([size]) {\n height: 1px;\n}\n\nh6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 {\n margin-top: 0;\n margin-bottom: 0.5rem;\n font-weight: 500;\n line-height: 1.2;\n}\n\nh1, .h1 {\n font-size: calc(1.375rem + 1.5vw);\n}\n@media (min-width: 1200px) {\n h1, .h1 {\n font-size: 2.5rem;\n }\n}\n\nh2, .h2 {\n font-size: calc(1.325rem + 0.9vw);\n}\n@media (min-width: 1200px) {\n h2, .h2 {\n font-size: 2rem;\n }\n}\n\nh3, .h3 {\n font-size: calc(1.3rem + 0.6vw);\n}\n@media (min-width: 1200px) {\n h3, .h3 {\n font-size: 1.75rem;\n }\n}\n\nh4, .h4 {\n font-size: calc(1.275rem + 0.3vw);\n}\n@media (min-width: 1200px) {\n h4, .h4 {\n font-size: 1.5rem;\n }\n}\n\nh5, .h5 {\n font-size: 1.25rem;\n}\n\nh6, .h6 {\n font-size: 1rem;\n}\n\np {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nabbr[title],\nabbr[data-bs-original-title] {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n cursor: help;\n -webkit-text-decoration-skip-ink: none;\n text-decoration-skip-ink: none;\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: 700;\n}\n\ndd {\n margin-bottom: 0.5rem;\n margin-left: 0;\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\nb,\nstrong {\n font-weight: bolder;\n}\n\nsmall, .small {\n font-size: 0.875em;\n}\n\nmark, .mark {\n padding: 0.2em;\n background-color: #fcf8e3;\n}\n\nsub,\nsup {\n position: relative;\n font-size: 0.75em;\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\na {\n color: #0d6efd;\n text-decoration: underline;\n}\na:hover {\n color: #0a58ca;\n}\n\na:not([href]):not([class]), a:not([href]):not([class]):hover {\n color: inherit;\n text-decoration: none;\n}\n\npre,\ncode,\nkbd,\nsamp {\n font-family: var(--bs-font-monospace);\n font-size: 1em;\n direction: ltr /* rtl:ignore */;\n unicode-bidi: bidi-override;\n}\n\npre {\n display: block;\n margin-top: 0;\n margin-bottom: 1rem;\n overflow: auto;\n font-size: 0.875em;\n}\npre code {\n font-size: inherit;\n color: inherit;\n word-break: normal;\n}\n\ncode {\n font-size: 0.875em;\n color: #d63384;\n word-wrap: break-word;\n}\na > code {\n color: inherit;\n}\n\nkbd {\n padding: 0.2rem 0.4rem;\n font-size: 0.875em;\n color: #fff;\n background-color: #212529;\n border-radius: 0.2rem;\n}\nkbd kbd {\n padding: 0;\n font-size: 1em;\n font-weight: 700;\n}\n\nfigure {\n margin: 0 0 1rem;\n}\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n color: #6c757d;\n text-align: left;\n}\n\nth {\n text-align: inherit;\n text-align: -webkit-match-parent;\n}\n\nthead,\ntbody,\ntfoot,\ntr,\ntd,\nth {\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n}\n\nlabel {\n display: inline-block;\n}\n\nbutton {\n border-radius: 0;\n}\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\nbutton,\nselect {\n text-transform: none;\n}\n\n[role=button] {\n cursor: pointer;\n}\n\nselect {\n word-wrap: normal;\n}\nselect:disabled {\n opacity: 1;\n}\n\n[list]::-webkit-calendar-picker-indicator {\n display: none;\n}\n\nbutton,\n[type=button],\n[type=reset],\n[type=submit] {\n -webkit-appearance: button;\n}\nbutton:not(:disabled),\n[type=button]:not(:disabled),\n[type=reset]:not(:disabled),\n[type=submit]:not(:disabled) {\n cursor: pointer;\n}\n\n::-moz-focus-inner {\n padding: 0;\n border-style: none;\n}\n\ntextarea {\n resize: vertical;\n}\n\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n float: left;\n width: 100%;\n padding: 0;\n margin-bottom: 0.5rem;\n font-size: calc(1.275rem + 0.3vw);\n line-height: inherit;\n}\n@media (min-width: 1200px) {\n legend {\n font-size: 1.5rem;\n }\n}\nlegend + * {\n clear: left;\n}\n\n::-webkit-datetime-edit-fields-wrapper,\n::-webkit-datetime-edit-text,\n::-webkit-datetime-edit-minute,\n::-webkit-datetime-edit-hour-field,\n::-webkit-datetime-edit-day-field,\n::-webkit-datetime-edit-month-field,\n::-webkit-datetime-edit-year-field {\n padding: 0;\n}\n\n::-webkit-inner-spin-button {\n height: auto;\n}\n\n[type=search] {\n outline-offset: -2px;\n -webkit-appearance: textfield;\n}\n\n/* rtl:raw:\n[type=\"tel\"],\n[type=\"url\"],\n[type=\"email\"],\n[type=\"number\"] {\n direction: ltr;\n}\n*/\n::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n::-webkit-color-swatch-wrapper {\n padding: 0;\n}\n\n::-webkit-file-upload-button {\n font: inherit;\n}\n\n::file-selector-button {\n font: inherit;\n}\n\n::-webkit-file-upload-button {\n font: inherit;\n -webkit-appearance: button;\n}\n\noutput {\n display: inline-block;\n}\n\niframe {\n border: 0;\n}\n\nsummary {\n display: list-item;\n cursor: pointer;\n}\n\nprogress {\n vertical-align: baseline;\n}\n\n[hidden] {\n display: none !important;\n}\n\n.lead {\n font-size: 1.25rem;\n font-weight: 300;\n}\n\n.display-1 {\n font-size: calc(1.625rem + 4.5vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-1 {\n font-size: 5rem;\n }\n}\n\n.display-2 {\n font-size: calc(1.575rem + 3.9vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-2 {\n font-size: 4.5rem;\n }\n}\n\n.display-3 {\n font-size: calc(1.525rem + 3.3vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-3 {\n font-size: 4rem;\n }\n}\n\n.display-4 {\n font-size: calc(1.475rem + 2.7vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-4 {\n font-size: 3.5rem;\n }\n}\n\n.display-5 {\n font-size: calc(1.425rem + 2.1vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-5 {\n font-size: 3rem;\n }\n}\n\n.display-6 {\n font-size: calc(1.375rem + 1.5vw);\n font-weight: 300;\n line-height: 1.2;\n}\n@media (min-width: 1200px) {\n .display-6 {\n font-size: 2.5rem;\n }\n}\n\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline {\n padding-left: 0;\n list-style: none;\n}\n\n.list-inline-item {\n display: inline-block;\n}\n.list-inline-item:not(:last-child) {\n margin-right: 0.5rem;\n}\n\n.initialism {\n font-size: 0.875em;\n text-transform: uppercase;\n}\n\n.blockquote {\n margin-bottom: 1rem;\n font-size: 1.25rem;\n}\n.blockquote > :last-child {\n margin-bottom: 0;\n}\n\n.blockquote-footer {\n margin-top: -1rem;\n margin-bottom: 1rem;\n font-size: 0.875em;\n color: #6c757d;\n}\n.blockquote-footer::before {\n content: \"— \";\n}\n\n.img-fluid {\n max-width: 100%;\n height: auto;\n}\n\n.img-thumbnail {\n padding: 0.25rem;\n background-color: #fff;\n border: 1px solid #dee2e6;\n border-radius: 0.25rem;\n max-width: 100%;\n height: auto;\n}\n\n.figure {\n display: inline-block;\n}\n\n.figure-img {\n margin-bottom: 0.5rem;\n line-height: 1;\n}\n\n.figure-caption {\n font-size: 0.875em;\n color: #6c757d;\n}\n\n.container,\n.container-fluid,\n.container-xxl,\n.container-xl,\n.container-lg,\n.container-md,\n.container-sm {\n width: 100%;\n padding-right: var(--bs-gutter-x, 0.75rem);\n padding-left: var(--bs-gutter-x, 0.75rem);\n margin-right: auto;\n margin-left: auto;\n}\n\n@media (min-width: 576px) {\n .container-sm, .container {\n max-width: 540px;\n }\n}\n@media (min-width: 768px) {\n .container-md, .container-sm, .container {\n max-width: 720px;\n }\n}\n@media (min-width: 992px) {\n .container-lg, .container-md, .container-sm, .container {\n max-width: 960px;\n }\n}\n@media (min-width: 1200px) {\n .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1140px;\n }\n}\n@media (min-width: 1400px) {\n .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container {\n max-width: 1320px;\n }\n}\n.row {\n --bs-gutter-x: 1.5rem;\n --bs-gutter-y: 0;\n display: flex;\n flex-wrap: wrap;\n margin-top: calc(-1 * var(--bs-gutter-y));\n margin-right: calc(-0.5 * var(--bs-gutter-x));\n margin-left: calc(-0.5 * var(--bs-gutter-x));\n}\n.row > * {\n flex-shrink: 0;\n width: 100%;\n max-width: 100%;\n padding-right: calc(var(--bs-gutter-x) * 0.5);\n padding-left: calc(var(--bs-gutter-x) * 0.5);\n margin-top: var(--bs-gutter-y);\n}\n\n.col {\n flex: 1 0 0%;\n}\n\n.row-cols-auto > * {\n flex: 0 0 auto;\n width: auto;\n}\n\n.row-cols-1 > * {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.row-cols-2 > * {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.row-cols-3 > * {\n flex: 0 0 auto;\n width: 33.3333333333%;\n}\n\n.row-cols-4 > * {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.row-cols-5 > * {\n flex: 0 0 auto;\n width: 20%;\n}\n\n.row-cols-6 > * {\n flex: 0 0 auto;\n width: 16.6666666667%;\n}\n\n.col-auto {\n flex: 0 0 auto;\n width: auto;\n}\n\n.col-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n}\n\n.col-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n}\n\n.col-3 {\n flex: 0 0 auto;\n width: 25%;\n}\n\n.col-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n}\n\n.col-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n}\n\n.col-6 {\n flex: 0 0 auto;\n width: 50%;\n}\n\n.col-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n}\n\n.col-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n}\n\n.col-9 {\n flex: 0 0 auto;\n width: 75%;\n}\n\n.col-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n}\n\n.col-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n}\n\n.col-12 {\n flex: 0 0 auto;\n width: 100%;\n}\n\n.offset-1 {\n margin-left: 8.33333333%;\n}\n\n.offset-2 {\n margin-left: 16.66666667%;\n}\n\n.offset-3 {\n margin-left: 25%;\n}\n\n.offset-4 {\n margin-left: 33.33333333%;\n}\n\n.offset-5 {\n margin-left: 41.66666667%;\n}\n\n.offset-6 {\n margin-left: 50%;\n}\n\n.offset-7 {\n margin-left: 58.33333333%;\n}\n\n.offset-8 {\n margin-left: 66.66666667%;\n}\n\n.offset-9 {\n margin-left: 75%;\n}\n\n.offset-10 {\n margin-left: 83.33333333%;\n}\n\n.offset-11 {\n margin-left: 91.66666667%;\n}\n\n.g-0,\n.gx-0 {\n --bs-gutter-x: 0;\n}\n\n.g-0,\n.gy-0 {\n --bs-gutter-y: 0;\n}\n\n.g-1,\n.gx-1 {\n --bs-gutter-x: 0.25rem;\n}\n\n.g-1,\n.gy-1 {\n --bs-gutter-y: 0.25rem;\n}\n\n.g-2,\n.gx-2 {\n --bs-gutter-x: 0.5rem;\n}\n\n.g-2,\n.gy-2 {\n --bs-gutter-y: 0.5rem;\n}\n\n.g-3,\n.gx-3 {\n --bs-gutter-x: 1rem;\n}\n\n.g-3,\n.gy-3 {\n --bs-gutter-y: 1rem;\n}\n\n.g-4,\n.gx-4 {\n --bs-gutter-x: 1.5rem;\n}\n\n.g-4,\n.gy-4 {\n --bs-gutter-y: 1.5rem;\n}\n\n.g-5,\n.gx-5 {\n --bs-gutter-x: 3rem;\n}\n\n.g-5,\n.gy-5 {\n --bs-gutter-y: 3rem;\n}\n\n@media (min-width: 576px) {\n .col-sm {\n flex: 1 0 0%;\n }\n\n .row-cols-sm-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n\n .row-cols-sm-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n\n .row-cols-sm-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n\n .row-cols-sm-3 > * {\n flex: 0 0 auto;\n width: 33.3333333333%;\n }\n\n .row-cols-sm-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n\n .row-cols-sm-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n\n .row-cols-sm-6 > * {\n flex: 0 0 auto;\n width: 16.6666666667%;\n }\n\n .col-sm-auto {\n flex: 0 0 auto;\n width: auto;\n }\n\n .col-sm-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n\n .col-sm-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n\n .col-sm-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n\n .col-sm-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n\n .col-sm-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n\n .col-sm-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n\n .col-sm-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n\n .col-sm-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n\n .col-sm-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n\n .col-sm-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n\n .col-sm-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n\n .col-sm-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n\n .offset-sm-0 {\n margin-left: 0;\n }\n\n .offset-sm-1 {\n margin-left: 8.33333333%;\n }\n\n .offset-sm-2 {\n margin-left: 16.66666667%;\n }\n\n .offset-sm-3 {\n margin-left: 25%;\n }\n\n .offset-sm-4 {\n margin-left: 33.33333333%;\n }\n\n .offset-sm-5 {\n margin-left: 41.66666667%;\n }\n\n .offset-sm-6 {\n margin-left: 50%;\n }\n\n .offset-sm-7 {\n margin-left: 58.33333333%;\n }\n\n .offset-sm-8 {\n margin-left: 66.66666667%;\n }\n\n .offset-sm-9 {\n margin-left: 75%;\n }\n\n .offset-sm-10 {\n margin-left: 83.33333333%;\n }\n\n .offset-sm-11 {\n margin-left: 91.66666667%;\n }\n\n .g-sm-0,\n.gx-sm-0 {\n --bs-gutter-x: 0;\n }\n\n .g-sm-0,\n.gy-sm-0 {\n --bs-gutter-y: 0;\n }\n\n .g-sm-1,\n.gx-sm-1 {\n --bs-gutter-x: 0.25rem;\n }\n\n .g-sm-1,\n.gy-sm-1 {\n --bs-gutter-y: 0.25rem;\n }\n\n .g-sm-2,\n.gx-sm-2 {\n --bs-gutter-x: 0.5rem;\n }\n\n .g-sm-2,\n.gy-sm-2 {\n --bs-gutter-y: 0.5rem;\n }\n\n .g-sm-3,\n.gx-sm-3 {\n --bs-gutter-x: 1rem;\n }\n\n .g-sm-3,\n.gy-sm-3 {\n --bs-gutter-y: 1rem;\n }\n\n .g-sm-4,\n.gx-sm-4 {\n --bs-gutter-x: 1.5rem;\n }\n\n .g-sm-4,\n.gy-sm-4 {\n --bs-gutter-y: 1.5rem;\n }\n\n .g-sm-5,\n.gx-sm-5 {\n --bs-gutter-x: 3rem;\n }\n\n .g-sm-5,\n.gy-sm-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 768px) {\n .col-md {\n flex: 1 0 0%;\n }\n\n .row-cols-md-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n\n .row-cols-md-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n\n .row-cols-md-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n\n .row-cols-md-3 > * {\n flex: 0 0 auto;\n width: 33.3333333333%;\n }\n\n .row-cols-md-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n\n .row-cols-md-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n\n .row-cols-md-6 > * {\n flex: 0 0 auto;\n width: 16.6666666667%;\n }\n\n .col-md-auto {\n flex: 0 0 auto;\n width: auto;\n }\n\n .col-md-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n\n .col-md-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n\n .col-md-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n\n .col-md-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n\n .col-md-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n\n .col-md-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n\n .col-md-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n\n .col-md-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n\n .col-md-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n\n .col-md-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n\n .col-md-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n\n .col-md-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n\n .offset-md-0 {\n margin-left: 0;\n }\n\n .offset-md-1 {\n margin-left: 8.33333333%;\n }\n\n .offset-md-2 {\n margin-left: 16.66666667%;\n }\n\n .offset-md-3 {\n margin-left: 25%;\n }\n\n .offset-md-4 {\n margin-left: 33.33333333%;\n }\n\n .offset-md-5 {\n margin-left: 41.66666667%;\n }\n\n .offset-md-6 {\n margin-left: 50%;\n }\n\n .offset-md-7 {\n margin-left: 58.33333333%;\n }\n\n .offset-md-8 {\n margin-left: 66.66666667%;\n }\n\n .offset-md-9 {\n margin-left: 75%;\n }\n\n .offset-md-10 {\n margin-left: 83.33333333%;\n }\n\n .offset-md-11 {\n margin-left: 91.66666667%;\n }\n\n .g-md-0,\n.gx-md-0 {\n --bs-gutter-x: 0;\n }\n\n .g-md-0,\n.gy-md-0 {\n --bs-gutter-y: 0;\n }\n\n .g-md-1,\n.gx-md-1 {\n --bs-gutter-x: 0.25rem;\n }\n\n .g-md-1,\n.gy-md-1 {\n --bs-gutter-y: 0.25rem;\n }\n\n .g-md-2,\n.gx-md-2 {\n --bs-gutter-x: 0.5rem;\n }\n\n .g-md-2,\n.gy-md-2 {\n --bs-gutter-y: 0.5rem;\n }\n\n .g-md-3,\n.gx-md-3 {\n --bs-gutter-x: 1rem;\n }\n\n .g-md-3,\n.gy-md-3 {\n --bs-gutter-y: 1rem;\n }\n\n .g-md-4,\n.gx-md-4 {\n --bs-gutter-x: 1.5rem;\n }\n\n .g-md-4,\n.gy-md-4 {\n --bs-gutter-y: 1.5rem;\n }\n\n .g-md-5,\n.gx-md-5 {\n --bs-gutter-x: 3rem;\n }\n\n .g-md-5,\n.gy-md-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 992px) {\n .col-lg {\n flex: 1 0 0%;\n }\n\n .row-cols-lg-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n\n .row-cols-lg-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n\n .row-cols-lg-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n\n .row-cols-lg-3 > * {\n flex: 0 0 auto;\n width: 33.3333333333%;\n }\n\n .row-cols-lg-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n\n .row-cols-lg-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n\n .row-cols-lg-6 > * {\n flex: 0 0 auto;\n width: 16.6666666667%;\n }\n\n .col-lg-auto {\n flex: 0 0 auto;\n width: auto;\n }\n\n .col-lg-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n\n .col-lg-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n\n .col-lg-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n\n .col-lg-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n\n .col-lg-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n\n .col-lg-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n\n .col-lg-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n\n .col-lg-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n\n .col-lg-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n\n .col-lg-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n\n .col-lg-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n\n .col-lg-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n\n .offset-lg-0 {\n margin-left: 0;\n }\n\n .offset-lg-1 {\n margin-left: 8.33333333%;\n }\n\n .offset-lg-2 {\n margin-left: 16.66666667%;\n }\n\n .offset-lg-3 {\n margin-left: 25%;\n }\n\n .offset-lg-4 {\n margin-left: 33.33333333%;\n }\n\n .offset-lg-5 {\n margin-left: 41.66666667%;\n }\n\n .offset-lg-6 {\n margin-left: 50%;\n }\n\n .offset-lg-7 {\n margin-left: 58.33333333%;\n }\n\n .offset-lg-8 {\n margin-left: 66.66666667%;\n }\n\n .offset-lg-9 {\n margin-left: 75%;\n }\n\n .offset-lg-10 {\n margin-left: 83.33333333%;\n }\n\n .offset-lg-11 {\n margin-left: 91.66666667%;\n }\n\n .g-lg-0,\n.gx-lg-0 {\n --bs-gutter-x: 0;\n }\n\n .g-lg-0,\n.gy-lg-0 {\n --bs-gutter-y: 0;\n }\n\n .g-lg-1,\n.gx-lg-1 {\n --bs-gutter-x: 0.25rem;\n }\n\n .g-lg-1,\n.gy-lg-1 {\n --bs-gutter-y: 0.25rem;\n }\n\n .g-lg-2,\n.gx-lg-2 {\n --bs-gutter-x: 0.5rem;\n }\n\n .g-lg-2,\n.gy-lg-2 {\n --bs-gutter-y: 0.5rem;\n }\n\n .g-lg-3,\n.gx-lg-3 {\n --bs-gutter-x: 1rem;\n }\n\n .g-lg-3,\n.gy-lg-3 {\n --bs-gutter-y: 1rem;\n }\n\n .g-lg-4,\n.gx-lg-4 {\n --bs-gutter-x: 1.5rem;\n }\n\n .g-lg-4,\n.gy-lg-4 {\n --bs-gutter-y: 1.5rem;\n }\n\n .g-lg-5,\n.gx-lg-5 {\n --bs-gutter-x: 3rem;\n }\n\n .g-lg-5,\n.gy-lg-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1200px) {\n .col-xl {\n flex: 1 0 0%;\n }\n\n .row-cols-xl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n\n .row-cols-xl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n\n .row-cols-xl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n\n .row-cols-xl-3 > * {\n flex: 0 0 auto;\n width: 33.3333333333%;\n }\n\n .row-cols-xl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n\n .row-cols-xl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n\n .row-cols-xl-6 > * {\n flex: 0 0 auto;\n width: 16.6666666667%;\n }\n\n .col-xl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n\n .col-xl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n\n .col-xl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n\n .col-xl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n\n .col-xl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n\n .col-xl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n\n .col-xl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n\n .col-xl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n\n .col-xl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n\n .col-xl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n\n .col-xl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n\n .col-xl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n\n .col-xl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n\n .offset-xl-0 {\n margin-left: 0;\n }\n\n .offset-xl-1 {\n margin-left: 8.33333333%;\n }\n\n .offset-xl-2 {\n margin-left: 16.66666667%;\n }\n\n .offset-xl-3 {\n margin-left: 25%;\n }\n\n .offset-xl-4 {\n margin-left: 33.33333333%;\n }\n\n .offset-xl-5 {\n margin-left: 41.66666667%;\n }\n\n .offset-xl-6 {\n margin-left: 50%;\n }\n\n .offset-xl-7 {\n margin-left: 58.33333333%;\n }\n\n .offset-xl-8 {\n margin-left: 66.66666667%;\n }\n\n .offset-xl-9 {\n margin-left: 75%;\n }\n\n .offset-xl-10 {\n margin-left: 83.33333333%;\n }\n\n .offset-xl-11 {\n margin-left: 91.66666667%;\n }\n\n .g-xl-0,\n.gx-xl-0 {\n --bs-gutter-x: 0;\n }\n\n .g-xl-0,\n.gy-xl-0 {\n --bs-gutter-y: 0;\n }\n\n .g-xl-1,\n.gx-xl-1 {\n --bs-gutter-x: 0.25rem;\n }\n\n .g-xl-1,\n.gy-xl-1 {\n --bs-gutter-y: 0.25rem;\n }\n\n .g-xl-2,\n.gx-xl-2 {\n --bs-gutter-x: 0.5rem;\n }\n\n .g-xl-2,\n.gy-xl-2 {\n --bs-gutter-y: 0.5rem;\n }\n\n .g-xl-3,\n.gx-xl-3 {\n --bs-gutter-x: 1rem;\n }\n\n .g-xl-3,\n.gy-xl-3 {\n --bs-gutter-y: 1rem;\n }\n\n .g-xl-4,\n.gx-xl-4 {\n --bs-gutter-x: 1.5rem;\n }\n\n .g-xl-4,\n.gy-xl-4 {\n --bs-gutter-y: 1.5rem;\n }\n\n .g-xl-5,\n.gx-xl-5 {\n --bs-gutter-x: 3rem;\n }\n\n .g-xl-5,\n.gy-xl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n@media (min-width: 1400px) {\n .col-xxl {\n flex: 1 0 0%;\n }\n\n .row-cols-xxl-auto > * {\n flex: 0 0 auto;\n width: auto;\n }\n\n .row-cols-xxl-1 > * {\n flex: 0 0 auto;\n width: 100%;\n }\n\n .row-cols-xxl-2 > * {\n flex: 0 0 auto;\n width: 50%;\n }\n\n .row-cols-xxl-3 > * {\n flex: 0 0 auto;\n width: 33.3333333333%;\n }\n\n .row-cols-xxl-4 > * {\n flex: 0 0 auto;\n width: 25%;\n }\n\n .row-cols-xxl-5 > * {\n flex: 0 0 auto;\n width: 20%;\n }\n\n .row-cols-xxl-6 > * {\n flex: 0 0 auto;\n width: 16.6666666667%;\n }\n\n .col-xxl-auto {\n flex: 0 0 auto;\n width: auto;\n }\n\n .col-xxl-1 {\n flex: 0 0 auto;\n width: 8.33333333%;\n }\n\n .col-xxl-2 {\n flex: 0 0 auto;\n width: 16.66666667%;\n }\n\n .col-xxl-3 {\n flex: 0 0 auto;\n width: 25%;\n }\n\n .col-xxl-4 {\n flex: 0 0 auto;\n width: 33.33333333%;\n }\n\n .col-xxl-5 {\n flex: 0 0 auto;\n width: 41.66666667%;\n }\n\n .col-xxl-6 {\n flex: 0 0 auto;\n width: 50%;\n }\n\n .col-xxl-7 {\n flex: 0 0 auto;\n width: 58.33333333%;\n }\n\n .col-xxl-8 {\n flex: 0 0 auto;\n width: 66.66666667%;\n }\n\n .col-xxl-9 {\n flex: 0 0 auto;\n width: 75%;\n }\n\n .col-xxl-10 {\n flex: 0 0 auto;\n width: 83.33333333%;\n }\n\n .col-xxl-11 {\n flex: 0 0 auto;\n width: 91.66666667%;\n }\n\n .col-xxl-12 {\n flex: 0 0 auto;\n width: 100%;\n }\n\n .offset-xxl-0 {\n margin-left: 0;\n }\n\n .offset-xxl-1 {\n margin-left: 8.33333333%;\n }\n\n .offset-xxl-2 {\n margin-left: 16.66666667%;\n }\n\n .offset-xxl-3 {\n margin-left: 25%;\n }\n\n .offset-xxl-4 {\n margin-left: 33.33333333%;\n }\n\n .offset-xxl-5 {\n margin-left: 41.66666667%;\n }\n\n .offset-xxl-6 {\n margin-left: 50%;\n }\n\n .offset-xxl-7 {\n margin-left: 58.33333333%;\n }\n\n .offset-xxl-8 {\n margin-left: 66.66666667%;\n }\n\n .offset-xxl-9 {\n margin-left: 75%;\n }\n\n .offset-xxl-10 {\n margin-left: 83.33333333%;\n }\n\n .offset-xxl-11 {\n margin-left: 91.66666667%;\n }\n\n .g-xxl-0,\n.gx-xxl-0 {\n --bs-gutter-x: 0;\n }\n\n .g-xxl-0,\n.gy-xxl-0 {\n --bs-gutter-y: 0;\n }\n\n .g-xxl-1,\n.gx-xxl-1 {\n --bs-gutter-x: 0.25rem;\n }\n\n .g-xxl-1,\n.gy-xxl-1 {\n --bs-gutter-y: 0.25rem;\n }\n\n .g-xxl-2,\n.gx-xxl-2 {\n --bs-gutter-x: 0.5rem;\n }\n\n .g-xxl-2,\n.gy-xxl-2 {\n --bs-gutter-y: 0.5rem;\n }\n\n .g-xxl-3,\n.gx-xxl-3 {\n --bs-gutter-x: 1rem;\n }\n\n .g-xxl-3,\n.gy-xxl-3 {\n --bs-gutter-y: 1rem;\n }\n\n .g-xxl-4,\n.gx-xxl-4 {\n --bs-gutter-x: 1.5rem;\n }\n\n .g-xxl-4,\n.gy-xxl-4 {\n --bs-gutter-y: 1.5rem;\n }\n\n .g-xxl-5,\n.gx-xxl-5 {\n --bs-gutter-x: 3rem;\n }\n\n .g-xxl-5,\n.gy-xxl-5 {\n --bs-gutter-y: 3rem;\n }\n}\n.table {\n --bs-table-bg: transparent;\n --bs-table-accent-bg: transparent;\n --bs-table-striped-color: #212529;\n --bs-table-striped-bg: rgba(0, 0, 0, 0.05);\n --bs-table-active-color: #212529;\n --bs-table-active-bg: rgba(0, 0, 0, 0.1);\n --bs-table-hover-color: #212529;\n --bs-table-hover-bg: rgba(0, 0, 0, 0.075);\n width: 100%;\n margin-bottom: 1rem;\n color: #212529;\n vertical-align: top;\n border-color: #dee2e6;\n}\n.table > :not(caption) > * > * {\n padding: 0.5rem 0.5rem;\n background-color: var(--bs-table-bg);\n border-bottom-width: 1px;\n box-shadow: inset 0 0 0 9999px var(--bs-table-accent-bg);\n}\n.table > tbody {\n vertical-align: inherit;\n}\n.table > thead {\n vertical-align: bottom;\n}\n.table > :not(:first-child) {\n border-top: 2px solid currentColor;\n}\n\n.caption-top {\n caption-side: top;\n}\n\n.table-sm > :not(caption) > * > * {\n padding: 0.25rem 0.25rem;\n}\n\n.table-bordered > :not(caption) > * {\n border-width: 1px 0;\n}\n.table-bordered > :not(caption) > * > * {\n border-width: 0 1px;\n}\n\n.table-borderless > :not(caption) > * > * {\n border-bottom-width: 0;\n}\n.table-borderless > :not(:first-child) {\n border-top-width: 0;\n}\n\n.table-striped > tbody > tr:nth-of-type(odd) > * {\n --bs-table-accent-bg: var(--bs-table-striped-bg);\n color: var(--bs-table-striped-color);\n}\n\n.table-active {\n --bs-table-accent-bg: var(--bs-table-active-bg);\n color: var(--bs-table-active-color);\n}\n\n.table-hover > tbody > tr:hover > * {\n --bs-table-accent-bg: var(--bs-table-hover-bg);\n color: var(--bs-table-hover-color);\n}\n\n.table-primary {\n --bs-table-bg: #cfe2ff;\n --bs-table-striped-bg: #c5d7f2;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #bacbe6;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #bfd1ec;\n --bs-table-hover-color: #000;\n color: #000;\n border-color: #bacbe6;\n}\n\n.table-secondary {\n --bs-table-bg: #e2e3e5;\n --bs-table-striped-bg: #d7d8da;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #cbccce;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #d1d2d4;\n --bs-table-hover-color: #000;\n color: #000;\n border-color: #cbccce;\n}\n\n.table-success {\n --bs-table-bg: #d1e7dd;\n --bs-table-striped-bg: #c7dbd2;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #bcd0c7;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #c1d6cc;\n --bs-table-hover-color: #000;\n color: #000;\n border-color: #bcd0c7;\n}\n\n.table-info {\n --bs-table-bg: #cff4fc;\n --bs-table-striped-bg: #c5e8ef;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #badce3;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #bfe2e9;\n --bs-table-hover-color: #000;\n color: #000;\n border-color: #badce3;\n}\n\n.table-warning {\n --bs-table-bg: #fff3cd;\n --bs-table-striped-bg: #f2e7c3;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #e6dbb9;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #ece1be;\n --bs-table-hover-color: #000;\n color: #000;\n border-color: #e6dbb9;\n}\n\n.table-danger {\n --bs-table-bg: #f8d7da;\n --bs-table-striped-bg: #eccccf;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #dfc2c4;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #e5c7ca;\n --bs-table-hover-color: #000;\n color: #000;\n border-color: #dfc2c4;\n}\n\n.table-light {\n --bs-table-bg: #f8f9fa;\n --bs-table-striped-bg: #ecedee;\n --bs-table-striped-color: #000;\n --bs-table-active-bg: #dfe0e1;\n --bs-table-active-color: #000;\n --bs-table-hover-bg: #e5e6e7;\n --bs-table-hover-color: #000;\n color: #000;\n border-color: #dfe0e1;\n}\n\n.table-dark {\n --bs-table-bg: #212529;\n --bs-table-striped-bg: #2c3034;\n --bs-table-striped-color: #fff;\n --bs-table-active-bg: #373b3e;\n --bs-table-active-color: #fff;\n --bs-table-hover-bg: #323539;\n --bs-table-hover-color: #fff;\n color: #fff;\n border-color: #373b3e;\n}\n\n.table-responsive {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n@media (max-width: 575.98px) {\n .table-responsive-sm {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n@media (max-width: 767.98px) {\n .table-responsive-md {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n@media (max-width: 991.98px) {\n .table-responsive-lg {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n@media (max-width: 1199.98px) {\n .table-responsive-xl {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n@media (max-width: 1399.98px) {\n .table-responsive-xxl {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n}\n.form-label {\n margin-bottom: 0.5rem;\n}\n\n.col-form-label {\n padding-top: calc(0.375rem + 1px);\n padding-bottom: calc(0.375rem + 1px);\n margin-bottom: 0;\n font-size: inherit;\n line-height: 1.5;\n}\n\n.col-form-label-lg {\n padding-top: calc(0.5rem + 1px);\n padding-bottom: calc(0.5rem + 1px);\n font-size: 1.25rem;\n}\n\n.col-form-label-sm {\n padding-top: calc(0.25rem + 1px);\n padding-bottom: calc(0.25rem + 1px);\n font-size: 0.875rem;\n}\n\n.form-text {\n margin-top: 0.25rem;\n font-size: 0.875em;\n color: #6c757d;\n}\n\n.form-control {\n display: block;\n width: 100%;\n padding: 0.375rem 0.75rem;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: #212529;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #ced4da;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n border-radius: 0.25rem;\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-control {\n transition: none;\n }\n}\n.form-control[type=file] {\n overflow: hidden;\n}\n.form-control[type=file]:not(:disabled):not([readonly]) {\n cursor: pointer;\n}\n.form-control:focus {\n color: #212529;\n background-color: #fff;\n border-color: #86b7fe;\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-control::-webkit-date-and-time-value {\n height: 1.5em;\n}\n.form-control::-moz-placeholder {\n color: #6c757d;\n opacity: 1;\n}\n.form-control::placeholder {\n color: #6c757d;\n opacity: 1;\n}\n.form-control:disabled, .form-control[readonly] {\n background-color: #e9ecef;\n opacity: 1;\n}\n.form-control::-webkit-file-upload-button {\n padding: 0.375rem 0.75rem;\n margin: -0.375rem -0.75rem;\n -webkit-margin-end: 0.75rem;\n margin-inline-end: 0.75rem;\n color: #212529;\n background-color: #e9ecef;\n pointer-events: none;\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n border-inline-end-width: 1px;\n border-radius: 0;\n -webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n.form-control::file-selector-button {\n padding: 0.375rem 0.75rem;\n margin: -0.375rem -0.75rem;\n -webkit-margin-end: 0.75rem;\n margin-inline-end: 0.75rem;\n color: #212529;\n background-color: #e9ecef;\n pointer-events: none;\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n border-inline-end-width: 1px;\n border-radius: 0;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-control::-webkit-file-upload-button {\n -webkit-transition: none;\n transition: none;\n }\n .form-control::file-selector-button {\n transition: none;\n }\n}\n.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button {\n background-color: #dde0e3;\n}\n.form-control:hover:not(:disabled):not([readonly])::file-selector-button {\n background-color: #dde0e3;\n}\n.form-control::-webkit-file-upload-button {\n padding: 0.375rem 0.75rem;\n margin: -0.375rem -0.75rem;\n -webkit-margin-end: 0.75rem;\n margin-inline-end: 0.75rem;\n color: #212529;\n background-color: #e9ecef;\n pointer-events: none;\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n border-inline-end-width: 1px;\n border-radius: 0;\n -webkit-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-control::-webkit-file-upload-button {\n -webkit-transition: none;\n transition: none;\n }\n}\n.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button {\n background-color: #dde0e3;\n}\n\n.form-control-plaintext {\n display: block;\n width: 100%;\n padding: 0.375rem 0;\n margin-bottom: 0;\n line-height: 1.5;\n color: #212529;\n background-color: transparent;\n border: solid transparent;\n border-width: 1px 0;\n}\n.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg {\n padding-right: 0;\n padding-left: 0;\n}\n\n.form-control-sm {\n min-height: calc(1.5em + 0.5rem + 2px);\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n border-radius: 0.2rem;\n}\n.form-control-sm::-webkit-file-upload-button {\n padding: 0.25rem 0.5rem;\n margin: -0.25rem -0.5rem;\n -webkit-margin-end: 0.5rem;\n margin-inline-end: 0.5rem;\n}\n.form-control-sm::file-selector-button {\n padding: 0.25rem 0.5rem;\n margin: -0.25rem -0.5rem;\n -webkit-margin-end: 0.5rem;\n margin-inline-end: 0.5rem;\n}\n.form-control-sm::-webkit-file-upload-button {\n padding: 0.25rem 0.5rem;\n margin: -0.25rem -0.5rem;\n -webkit-margin-end: 0.5rem;\n margin-inline-end: 0.5rem;\n}\n\n.form-control-lg {\n min-height: calc(1.5em + 1rem + 2px);\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n border-radius: 0.3rem;\n}\n.form-control-lg::-webkit-file-upload-button {\n padding: 0.5rem 1rem;\n margin: -0.5rem -1rem;\n -webkit-margin-end: 1rem;\n margin-inline-end: 1rem;\n}\n.form-control-lg::file-selector-button {\n padding: 0.5rem 1rem;\n margin: -0.5rem -1rem;\n -webkit-margin-end: 1rem;\n margin-inline-end: 1rem;\n}\n.form-control-lg::-webkit-file-upload-button {\n padding: 0.5rem 1rem;\n margin: -0.5rem -1rem;\n -webkit-margin-end: 1rem;\n margin-inline-end: 1rem;\n}\n\ntextarea.form-control {\n min-height: calc(1.5em + 0.75rem + 2px);\n}\ntextarea.form-control-sm {\n min-height: calc(1.5em + 0.5rem + 2px);\n}\ntextarea.form-control-lg {\n min-height: calc(1.5em + 1rem + 2px);\n}\n\n.form-control-color {\n width: 3rem;\n height: auto;\n padding: 0.375rem;\n}\n.form-control-color:not(:disabled):not([readonly]) {\n cursor: pointer;\n}\n.form-control-color::-moz-color-swatch {\n height: 1.5em;\n border-radius: 0.25rem;\n}\n.form-control-color::-webkit-color-swatch {\n height: 1.5em;\n border-radius: 0.25rem;\n}\n\n.form-select {\n display: block;\n width: 100%;\n padding: 0.375rem 2.25rem 0.375rem 0.75rem;\n -moz-padding-start: calc(0.75rem - 3px);\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: #212529;\n background-color: #fff;\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e\");\n background-repeat: no-repeat;\n background-position: right 0.75rem center;\n background-size: 16px 12px;\n border: 1px solid #ced4da;\n border-radius: 0.25rem;\n transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-select {\n transition: none;\n }\n}\n.form-select:focus {\n border-color: #86b7fe;\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-select[multiple], .form-select[size]:not([size=\"1\"]) {\n padding-right: 0.75rem;\n background-image: none;\n}\n.form-select:disabled {\n background-color: #e9ecef;\n}\n.form-select:-moz-focusring {\n color: transparent;\n text-shadow: 0 0 0 #212529;\n}\n\n.form-select-sm {\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n padding-left: 0.5rem;\n font-size: 0.875rem;\n border-radius: 0.2rem;\n}\n\n.form-select-lg {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n padding-left: 1rem;\n font-size: 1.25rem;\n border-radius: 0.3rem;\n}\n\n.form-check {\n display: block;\n min-height: 1.5rem;\n padding-left: 1.5em;\n margin-bottom: 0.125rem;\n}\n.form-check .form-check-input {\n float: left;\n margin-left: -1.5em;\n}\n\n.form-check-input {\n width: 1em;\n height: 1em;\n margin-top: 0.25em;\n vertical-align: top;\n background-color: #fff;\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n border: 1px solid rgba(0, 0, 0, 0.25);\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n -webkit-print-color-adjust: exact;\n color-adjust: exact;\n}\n.form-check-input[type=checkbox] {\n border-radius: 0.25em;\n}\n.form-check-input[type=radio] {\n border-radius: 50%;\n}\n.form-check-input:active {\n filter: brightness(90%);\n}\n.form-check-input:focus {\n border-color: #86b7fe;\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-check-input:checked {\n background-color: #0d6efd;\n border-color: #0d6efd;\n}\n.form-check-input:checked[type=checkbox] {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e\");\n}\n.form-check-input:checked[type=radio] {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e\");\n}\n.form-check-input[type=checkbox]:indeterminate {\n background-color: #0d6efd;\n border-color: #0d6efd;\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e\");\n}\n.form-check-input:disabled {\n pointer-events: none;\n filter: none;\n opacity: 0.5;\n}\n.form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label {\n opacity: 0.5;\n}\n\n.form-switch {\n padding-left: 2.5em;\n}\n.form-switch .form-check-input {\n width: 2em;\n margin-left: -2.5em;\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e\");\n background-position: left center;\n border-radius: 2em;\n transition: background-position 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-switch .form-check-input {\n transition: none;\n }\n}\n.form-switch .form-check-input:focus {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e\");\n}\n.form-switch .form-check-input:checked {\n background-position: right center;\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e\");\n}\n\n.form-check-inline {\n display: inline-block;\n margin-right: 1rem;\n}\n\n.btn-check {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.btn-check[disabled] + .btn, .btn-check:disabled + .btn {\n pointer-events: none;\n filter: none;\n opacity: 0.65;\n}\n\n.form-range {\n width: 100%;\n height: 1.5rem;\n padding: 0;\n background-color: transparent;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n.form-range:focus {\n outline: 0;\n}\n.form-range:focus::-webkit-slider-thumb {\n box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-range:focus::-moz-range-thumb {\n box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.form-range::-moz-focus-outer {\n border: 0;\n}\n.form-range::-webkit-slider-thumb {\n width: 1rem;\n height: 1rem;\n margin-top: -0.25rem;\n background-color: #0d6efd;\n border: 0;\n border-radius: 1rem;\n -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n -webkit-appearance: none;\n appearance: none;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-range::-webkit-slider-thumb {\n -webkit-transition: none;\n transition: none;\n }\n}\n.form-range::-webkit-slider-thumb:active {\n background-color: #b6d4fe;\n}\n.form-range::-webkit-slider-runnable-track {\n width: 100%;\n height: 0.5rem;\n color: transparent;\n cursor: pointer;\n background-color: #dee2e6;\n border-color: transparent;\n border-radius: 1rem;\n}\n.form-range::-moz-range-thumb {\n width: 1rem;\n height: 1rem;\n background-color: #0d6efd;\n border: 0;\n border-radius: 1rem;\n -moz-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n -moz-appearance: none;\n appearance: none;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-range::-moz-range-thumb {\n -moz-transition: none;\n transition: none;\n }\n}\n.form-range::-moz-range-thumb:active {\n background-color: #b6d4fe;\n}\n.form-range::-moz-range-track {\n width: 100%;\n height: 0.5rem;\n color: transparent;\n cursor: pointer;\n background-color: #dee2e6;\n border-color: transparent;\n border-radius: 1rem;\n}\n.form-range:disabled {\n pointer-events: none;\n}\n.form-range:disabled::-webkit-slider-thumb {\n background-color: #adb5bd;\n}\n.form-range:disabled::-moz-range-thumb {\n background-color: #adb5bd;\n}\n\n.form-floating {\n position: relative;\n}\n.form-floating > .form-control,\n.form-floating > .form-select {\n height: calc(3.5rem + 2px);\n line-height: 1.25;\n}\n.form-floating > label {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n padding: 1rem 0.75rem;\n pointer-events: none;\n border: 1px solid transparent;\n transform-origin: 0 0;\n transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .form-floating > label {\n transition: none;\n }\n}\n.form-floating > .form-control {\n padding: 1rem 0.75rem;\n}\n.form-floating > .form-control::-moz-placeholder {\n color: transparent;\n}\n.form-floating > .form-control::placeholder {\n color: transparent;\n}\n.form-floating > .form-control:not(:-moz-placeholder-shown) {\n padding-top: 1.625rem;\n padding-bottom: 0.625rem;\n}\n.form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown) {\n padding-top: 1.625rem;\n padding-bottom: 0.625rem;\n}\n.form-floating > .form-control:-webkit-autofill {\n padding-top: 1.625rem;\n padding-bottom: 0.625rem;\n}\n.form-floating > .form-select {\n padding-top: 1.625rem;\n padding-bottom: 0.625rem;\n}\n.form-floating > .form-control:not(:-moz-placeholder-shown) ~ label {\n opacity: 0.65;\n transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);\n}\n.form-floating > .form-control:focus ~ label,\n.form-floating > .form-control:not(:placeholder-shown) ~ label,\n.form-floating > .form-select ~ label {\n opacity: 0.65;\n transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);\n}\n.form-floating > .form-control:-webkit-autofill ~ label {\n opacity: 0.65;\n transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);\n}\n\n.input-group {\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-items: stretch;\n width: 100%;\n}\n.input-group > .form-control,\n.input-group > .form-select {\n position: relative;\n flex: 1 1 auto;\n width: 1%;\n min-width: 0;\n}\n.input-group > .form-control:focus,\n.input-group > .form-select:focus {\n z-index: 3;\n}\n.input-group .btn {\n position: relative;\n z-index: 2;\n}\n.input-group .btn:focus {\n z-index: 3;\n}\n\n.input-group-text {\n display: flex;\n align-items: center;\n padding: 0.375rem 0.75rem;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5;\n color: #212529;\n text-align: center;\n white-space: nowrap;\n background-color: #e9ecef;\n border: 1px solid #ced4da;\n border-radius: 0.25rem;\n}\n\n.input-group-lg > .form-control,\n.input-group-lg > .form-select,\n.input-group-lg > .input-group-text,\n.input-group-lg > .btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n border-radius: 0.3rem;\n}\n\n.input-group-sm > .form-control,\n.input-group-sm > .form-select,\n.input-group-sm > .input-group-text,\n.input-group-sm > .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n border-radius: 0.2rem;\n}\n\n.input-group-lg > .form-select,\n.input-group-sm > .form-select {\n padding-right: 3rem;\n}\n\n.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu),\n.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu),\n.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {\n margin-left: -1px;\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.valid-feedback {\n display: none;\n width: 100%;\n margin-top: 0.25rem;\n font-size: 0.875em;\n color: #198754;\n}\n\n.valid-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n max-width: 100%;\n padding: 0.25rem 0.5rem;\n margin-top: 0.1rem;\n font-size: 0.875rem;\n color: #fff;\n background-color: rgba(25, 135, 84, 0.9);\n border-radius: 0.25rem;\n}\n\n.was-validated :valid ~ .valid-feedback,\n.was-validated :valid ~ .valid-tooltip,\n.is-valid ~ .valid-feedback,\n.is-valid ~ .valid-tooltip {\n display: block;\n}\n\n.was-validated .form-control:valid, .form-control.is-valid {\n border-color: #198754;\n padding-right: calc(1.5em + 0.75rem);\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\");\n background-repeat: no-repeat;\n background-position: right calc(0.375em + 0.1875rem) center;\n background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n.was-validated .form-control:valid:focus, .form-control.is-valid:focus {\n border-color: #198754;\n box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25);\n}\n\n.was-validated textarea.form-control:valid, textarea.form-control.is-valid {\n padding-right: calc(1.5em + 0.75rem);\n background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);\n}\n\n.was-validated .form-select:valid, .form-select.is-valid {\n border-color: #198754;\n}\n.was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple])[size=\"1\"], .form-select.is-valid:not([multiple]):not([size]), .form-select.is-valid:not([multiple])[size=\"1\"] {\n padding-right: 4.125rem;\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e\"), url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e\");\n background-position: right 0.75rem center, center right 2.25rem;\n background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n.was-validated .form-select:valid:focus, .form-select.is-valid:focus {\n border-color: #198754;\n box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25);\n}\n\n.was-validated .form-check-input:valid, .form-check-input.is-valid {\n border-color: #198754;\n}\n.was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked {\n background-color: #198754;\n}\n.was-validated .form-check-input:valid:focus, .form-check-input.is-valid:focus {\n box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25);\n}\n.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label {\n color: #198754;\n}\n\n.form-check-inline .form-check-input ~ .valid-feedback {\n margin-left: 0.5em;\n}\n\n.was-validated .input-group .form-control:valid, .input-group .form-control.is-valid,\n.was-validated .input-group .form-select:valid,\n.input-group .form-select.is-valid {\n z-index: 1;\n}\n.was-validated .input-group .form-control:valid:focus, .input-group .form-control.is-valid:focus,\n.was-validated .input-group .form-select:valid:focus,\n.input-group .form-select.is-valid:focus {\n z-index: 3;\n}\n\n.invalid-feedback {\n display: none;\n width: 100%;\n margin-top: 0.25rem;\n font-size: 0.875em;\n color: #dc3545;\n}\n\n.invalid-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n max-width: 100%;\n padding: 0.25rem 0.5rem;\n margin-top: 0.1rem;\n font-size: 0.875rem;\n color: #fff;\n background-color: rgba(220, 53, 69, 0.9);\n border-radius: 0.25rem;\n}\n\n.was-validated :invalid ~ .invalid-feedback,\n.was-validated :invalid ~ .invalid-tooltip,\n.is-invalid ~ .invalid-feedback,\n.is-invalid ~ .invalid-tooltip {\n display: block;\n}\n\n.was-validated .form-control:invalid, .form-control.is-invalid {\n border-color: #dc3545;\n padding-right: calc(1.5em + 0.75rem);\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e\");\n background-repeat: no-repeat;\n background-position: right calc(0.375em + 0.1875rem) center;\n background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus {\n border-color: #dc3545;\n box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);\n}\n\n.was-validated textarea.form-control:invalid, textarea.form-control.is-invalid {\n padding-right: calc(1.5em + 0.75rem);\n background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem);\n}\n\n.was-validated .form-select:invalid, .form-select.is-invalid {\n border-color: #dc3545;\n}\n.was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple])[size=\"1\"], .form-select.is-invalid:not([multiple]):not([size]), .form-select.is-invalid:not([multiple])[size=\"1\"] {\n padding-right: 4.125rem;\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e\"), url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e\");\n background-position: right 0.75rem center, center right 2.25rem;\n background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);\n}\n.was-validated .form-select:invalid:focus, .form-select.is-invalid:focus {\n border-color: #dc3545;\n box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);\n}\n\n.was-validated .form-check-input:invalid, .form-check-input.is-invalid {\n border-color: #dc3545;\n}\n.was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked {\n background-color: #dc3545;\n}\n.was-validated .form-check-input:invalid:focus, .form-check-input.is-invalid:focus {\n box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);\n}\n.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label {\n color: #dc3545;\n}\n\n.form-check-inline .form-check-input ~ .invalid-feedback {\n margin-left: 0.5em;\n}\n\n.was-validated .input-group .form-control:invalid, .input-group .form-control.is-invalid,\n.was-validated .input-group .form-select:invalid,\n.input-group .form-select.is-invalid {\n z-index: 2;\n}\n.was-validated .input-group .form-control:invalid:focus, .input-group .form-control.is-invalid:focus,\n.was-validated .input-group .form-select:invalid:focus,\n.input-group .form-select.is-invalid:focus {\n z-index: 3;\n}\n\n.btn {\n display: inline-block;\n font-weight: 400;\n line-height: 1.5;\n color: #212529;\n text-align: center;\n text-decoration: none;\n vertical-align: middle;\n cursor: pointer;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n background-color: transparent;\n border: 1px solid transparent;\n padding: 0.375rem 0.75rem;\n font-size: 1rem;\n border-radius: 0.25rem;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .btn {\n transition: none;\n }\n}\n.btn:hover {\n color: #212529;\n}\n.btn-check:focus + .btn, .btn:focus {\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n.btn:disabled, .btn.disabled, fieldset:disabled .btn {\n pointer-events: none;\n opacity: 0.65;\n}\n\n.btn-primary {\n color: #fff;\n background-color: #0d6efd;\n border-color: #0d6efd;\n}\n.btn-primary:hover {\n color: #fff;\n background-color: #0b5ed7;\n border-color: #0a58ca;\n}\n.btn-check:focus + .btn-primary, .btn-primary:focus {\n color: #fff;\n background-color: #0b5ed7;\n border-color: #0a58ca;\n box-shadow: 0 0 0 0.25rem rgba(49, 132, 253, 0.5);\n}\n.btn-check:checked + .btn-primary, .btn-check:active + .btn-primary, .btn-primary:active, .btn-primary.active, .show > .btn-primary.dropdown-toggle {\n color: #fff;\n background-color: #0a58ca;\n border-color: #0a53be;\n}\n.btn-check:checked + .btn-primary:focus, .btn-check:active + .btn-primary:focus, .btn-primary:active:focus, .btn-primary.active:focus, .show > .btn-primary.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.25rem rgba(49, 132, 253, 0.5);\n}\n.btn-primary:disabled, .btn-primary.disabled {\n color: #fff;\n background-color: #0d6efd;\n border-color: #0d6efd;\n}\n\n.btn-secondary {\n color: #fff;\n background-color: #6c757d;\n border-color: #6c757d;\n}\n.btn-secondary:hover {\n color: #fff;\n background-color: #5c636a;\n border-color: #565e64;\n}\n.btn-check:focus + .btn-secondary, .btn-secondary:focus {\n color: #fff;\n background-color: #5c636a;\n border-color: #565e64;\n box-shadow: 0 0 0 0.25rem rgba(130, 138, 145, 0.5);\n}\n.btn-check:checked + .btn-secondary, .btn-check:active + .btn-secondary, .btn-secondary:active, .btn-secondary.active, .show > .btn-secondary.dropdown-toggle {\n color: #fff;\n background-color: #565e64;\n border-color: #51585e;\n}\n.btn-check:checked + .btn-secondary:focus, .btn-check:active + .btn-secondary:focus, .btn-secondary:active:focus, .btn-secondary.active:focus, .show > .btn-secondary.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.25rem rgba(130, 138, 145, 0.5);\n}\n.btn-secondary:disabled, .btn-secondary.disabled {\n color: #fff;\n background-color: #6c757d;\n border-color: #6c757d;\n}\n\n.btn-success {\n color: #fff;\n background-color: #198754;\n border-color: #198754;\n}\n.btn-success:hover {\n color: #fff;\n background-color: #157347;\n border-color: #146c43;\n}\n.btn-check:focus + .btn-success, .btn-success:focus {\n color: #fff;\n background-color: #157347;\n border-color: #146c43;\n box-shadow: 0 0 0 0.25rem rgba(60, 153, 110, 0.5);\n}\n.btn-check:checked + .btn-success, .btn-check:active + .btn-success, .btn-success:active, .btn-success.active, .show > .btn-success.dropdown-toggle {\n color: #fff;\n background-color: #146c43;\n border-color: #13653f;\n}\n.btn-check:checked + .btn-success:focus, .btn-check:active + .btn-success:focus, .btn-success:active:focus, .btn-success.active:focus, .show > .btn-success.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.25rem rgba(60, 153, 110, 0.5);\n}\n.btn-success:disabled, .btn-success.disabled {\n color: #fff;\n background-color: #198754;\n border-color: #198754;\n}\n\n.btn-info {\n color: #000;\n background-color: #0dcaf0;\n border-color: #0dcaf0;\n}\n.btn-info:hover {\n color: #000;\n background-color: #31d2f2;\n border-color: #25cff2;\n}\n.btn-check:focus + .btn-info, .btn-info:focus {\n color: #000;\n background-color: #31d2f2;\n border-color: #25cff2;\n box-shadow: 0 0 0 0.25rem rgba(11, 172, 204, 0.5);\n}\n.btn-check:checked + .btn-info, .btn-check:active + .btn-info, .btn-info:active, .btn-info.active, .show > .btn-info.dropdown-toggle {\n color: #000;\n background-color: #3dd5f3;\n border-color: #25cff2;\n}\n.btn-check:checked + .btn-info:focus, .btn-check:active + .btn-info:focus, .btn-info:active:focus, .btn-info.active:focus, .show > .btn-info.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.25rem rgba(11, 172, 204, 0.5);\n}\n.btn-info:disabled, .btn-info.disabled {\n color: #000;\n background-color: #0dcaf0;\n border-color: #0dcaf0;\n}\n\n.btn-warning {\n color: #000;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n.btn-warning:hover {\n color: #000;\n background-color: #ffca2c;\n border-color: #ffc720;\n}\n.btn-check:focus + .btn-warning, .btn-warning:focus {\n color: #000;\n background-color: #ffca2c;\n border-color: #ffc720;\n box-shadow: 0 0 0 0.25rem rgba(217, 164, 6, 0.5);\n}\n.btn-check:checked + .btn-warning, .btn-check:active + .btn-warning, .btn-warning:active, .btn-warning.active, .show > .btn-warning.dropdown-toggle {\n color: #000;\n background-color: #ffcd39;\n border-color: #ffc720;\n}\n.btn-check:checked + .btn-warning:focus, .btn-check:active + .btn-warning:focus, .btn-warning:active:focus, .btn-warning.active:focus, .show > .btn-warning.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.25rem rgba(217, 164, 6, 0.5);\n}\n.btn-warning:disabled, .btn-warning.disabled {\n color: #000;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n\n.btn-danger {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n.btn-danger:hover {\n color: #fff;\n background-color: #bb2d3b;\n border-color: #b02a37;\n}\n.btn-check:focus + .btn-danger, .btn-danger:focus {\n color: #fff;\n background-color: #bb2d3b;\n border-color: #b02a37;\n box-shadow: 0 0 0 0.25rem rgba(225, 83, 97, 0.5);\n}\n.btn-check:checked + .btn-danger, .btn-check:active + .btn-danger, .btn-danger:active, .btn-danger.active, .show > .btn-danger.dropdown-toggle {\n color: #fff;\n background-color: #b02a37;\n border-color: #a52834;\n}\n.btn-check:checked + .btn-danger:focus, .btn-check:active + .btn-danger:focus, .btn-danger:active:focus, .btn-danger.active:focus, .show > .btn-danger.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.25rem rgba(225, 83, 97, 0.5);\n}\n.btn-danger:disabled, .btn-danger.disabled {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n\n.btn-light {\n color: #000;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n.btn-light:hover {\n color: #000;\n background-color: #f9fafb;\n border-color: #f9fafb;\n}\n.btn-check:focus + .btn-light, .btn-light:focus {\n color: #000;\n background-color: #f9fafb;\n border-color: #f9fafb;\n box-shadow: 0 0 0 0.25rem rgba(211, 212, 213, 0.5);\n}\n.btn-check:checked + .btn-light, .btn-check:active + .btn-light, .btn-light:active, .btn-light.active, .show > .btn-light.dropdown-toggle {\n color: #000;\n background-color: #f9fafb;\n border-color: #f9fafb;\n}\n.btn-check:checked + .btn-light:focus, .btn-check:active + .btn-light:focus, .btn-light:active:focus, .btn-light.active:focus, .show > .btn-light.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.25rem rgba(211, 212, 213, 0.5);\n}\n.btn-light:disabled, .btn-light.disabled {\n color: #000;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n\n.btn-dark {\n color: #fff;\n background-color: #212529;\n border-color: #212529;\n}\n.btn-dark:hover {\n color: #fff;\n background-color: #1c1f23;\n border-color: #1a1e21;\n}\n.btn-check:focus + .btn-dark, .btn-dark:focus {\n color: #fff;\n background-color: #1c1f23;\n border-color: #1a1e21;\n box-shadow: 0 0 0 0.25rem rgba(66, 70, 73, 0.5);\n}\n.btn-check:checked + .btn-dark, .btn-check:active + .btn-dark, .btn-dark:active, .btn-dark.active, .show > .btn-dark.dropdown-toggle {\n color: #fff;\n background-color: #1a1e21;\n border-color: #191c1f;\n}\n.btn-check:checked + .btn-dark:focus, .btn-check:active + .btn-dark:focus, .btn-dark:active:focus, .btn-dark.active:focus, .show > .btn-dark.dropdown-toggle:focus {\n box-shadow: 0 0 0 0.25rem rgba(66, 70, 73, 0.5);\n}\n.btn-dark:disabled, .btn-dark.disabled {\n color: #fff;\n background-color: #212529;\n border-color: #212529;\n}\n\n.btn-outline-primary {\n color: #0d6efd;\n border-color: #0d6efd;\n}\n.btn-outline-primary:hover {\n color: #fff;\n background-color: #0d6efd;\n border-color: #0d6efd;\n}\n.btn-check:focus + .btn-outline-primary, .btn-outline-primary:focus {\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.5);\n}\n.btn-check:checked + .btn-outline-primary, .btn-check:active + .btn-outline-primary, .btn-outline-primary:active, .btn-outline-primary.active, .btn-outline-primary.dropdown-toggle.show {\n color: #fff;\n background-color: #0d6efd;\n border-color: #0d6efd;\n}\n.btn-check:checked + .btn-outline-primary:focus, .btn-check:active + .btn-outline-primary:focus, .btn-outline-primary:active:focus, .btn-outline-primary.active:focus, .btn-outline-primary.dropdown-toggle.show:focus {\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.5);\n}\n.btn-outline-primary:disabled, .btn-outline-primary.disabled {\n color: #0d6efd;\n background-color: transparent;\n}\n\n.btn-outline-secondary {\n color: #6c757d;\n border-color: #6c757d;\n}\n.btn-outline-secondary:hover {\n color: #fff;\n background-color: #6c757d;\n border-color: #6c757d;\n}\n.btn-check:focus + .btn-outline-secondary, .btn-outline-secondary:focus {\n box-shadow: 0 0 0 0.25rem rgba(108, 117, 125, 0.5);\n}\n.btn-check:checked + .btn-outline-secondary, .btn-check:active + .btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show {\n color: #fff;\n background-color: #6c757d;\n border-color: #6c757d;\n}\n.btn-check:checked + .btn-outline-secondary:focus, .btn-check:active + .btn-outline-secondary:focus, .btn-outline-secondary:active:focus, .btn-outline-secondary.active:focus, .btn-outline-secondary.dropdown-toggle.show:focus {\n box-shadow: 0 0 0 0.25rem rgba(108, 117, 125, 0.5);\n}\n.btn-outline-secondary:disabled, .btn-outline-secondary.disabled {\n color: #6c757d;\n background-color: transparent;\n}\n\n.btn-outline-success {\n color: #198754;\n border-color: #198754;\n}\n.btn-outline-success:hover {\n color: #fff;\n background-color: #198754;\n border-color: #198754;\n}\n.btn-check:focus + .btn-outline-success, .btn-outline-success:focus {\n box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.5);\n}\n.btn-check:checked + .btn-outline-success, .btn-check:active + .btn-outline-success, .btn-outline-success:active, .btn-outline-success.active, .btn-outline-success.dropdown-toggle.show {\n color: #fff;\n background-color: #198754;\n border-color: #198754;\n}\n.btn-check:checked + .btn-outline-success:focus, .btn-check:active + .btn-outline-success:focus, .btn-outline-success:active:focus, .btn-outline-success.active:focus, .btn-outline-success.dropdown-toggle.show:focus {\n box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.5);\n}\n.btn-outline-success:disabled, .btn-outline-success.disabled {\n color: #198754;\n background-color: transparent;\n}\n\n.btn-outline-info {\n color: #0dcaf0;\n border-color: #0dcaf0;\n}\n.btn-outline-info:hover {\n color: #000;\n background-color: #0dcaf0;\n border-color: #0dcaf0;\n}\n.btn-check:focus + .btn-outline-info, .btn-outline-info:focus {\n box-shadow: 0 0 0 0.25rem rgba(13, 202, 240, 0.5);\n}\n.btn-check:checked + .btn-outline-info, .btn-check:active + .btn-outline-info, .btn-outline-info:active, .btn-outline-info.active, .btn-outline-info.dropdown-toggle.show {\n color: #000;\n background-color: #0dcaf0;\n border-color: #0dcaf0;\n}\n.btn-check:checked + .btn-outline-info:focus, .btn-check:active + .btn-outline-info:focus, .btn-outline-info:active:focus, .btn-outline-info.active:focus, .btn-outline-info.dropdown-toggle.show:focus {\n box-shadow: 0 0 0 0.25rem rgba(13, 202, 240, 0.5);\n}\n.btn-outline-info:disabled, .btn-outline-info.disabled {\n color: #0dcaf0;\n background-color: transparent;\n}\n\n.btn-outline-warning {\n color: #ffc107;\n border-color: #ffc107;\n}\n.btn-outline-warning:hover {\n color: #000;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n.btn-check:focus + .btn-outline-warning, .btn-outline-warning:focus {\n box-shadow: 0 0 0 0.25rem rgba(255, 193, 7, 0.5);\n}\n.btn-check:checked + .btn-outline-warning, .btn-check:active + .btn-outline-warning, .btn-outline-warning:active, .btn-outline-warning.active, .btn-outline-warning.dropdown-toggle.show {\n color: #000;\n background-color: #ffc107;\n border-color: #ffc107;\n}\n.btn-check:checked + .btn-outline-warning:focus, .btn-check:active + .btn-outline-warning:focus, .btn-outline-warning:active:focus, .btn-outline-warning.active:focus, .btn-outline-warning.dropdown-toggle.show:focus {\n box-shadow: 0 0 0 0.25rem rgba(255, 193, 7, 0.5);\n}\n.btn-outline-warning:disabled, .btn-outline-warning.disabled {\n color: #ffc107;\n background-color: transparent;\n}\n\n.btn-outline-danger {\n color: #dc3545;\n border-color: #dc3545;\n}\n.btn-outline-danger:hover {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n.btn-check:focus + .btn-outline-danger, .btn-outline-danger:focus {\n box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.5);\n}\n.btn-check:checked + .btn-outline-danger, .btn-check:active + .btn-outline-danger, .btn-outline-danger:active, .btn-outline-danger.active, .btn-outline-danger.dropdown-toggle.show {\n color: #fff;\n background-color: #dc3545;\n border-color: #dc3545;\n}\n.btn-check:checked + .btn-outline-danger:focus, .btn-check:active + .btn-outline-danger:focus, .btn-outline-danger:active:focus, .btn-outline-danger.active:focus, .btn-outline-danger.dropdown-toggle.show:focus {\n box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.5);\n}\n.btn-outline-danger:disabled, .btn-outline-danger.disabled {\n color: #dc3545;\n background-color: transparent;\n}\n\n.btn-outline-light {\n color: #f8f9fa;\n border-color: #f8f9fa;\n}\n.btn-outline-light:hover {\n color: #000;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n.btn-check:focus + .btn-outline-light, .btn-outline-light:focus {\n box-shadow: 0 0 0 0.25rem rgba(248, 249, 250, 0.5);\n}\n.btn-check:checked + .btn-outline-light, .btn-check:active + .btn-outline-light, .btn-outline-light:active, .btn-outline-light.active, .btn-outline-light.dropdown-toggle.show {\n color: #000;\n background-color: #f8f9fa;\n border-color: #f8f9fa;\n}\n.btn-check:checked + .btn-outline-light:focus, .btn-check:active + .btn-outline-light:focus, .btn-outline-light:active:focus, .btn-outline-light.active:focus, .btn-outline-light.dropdown-toggle.show:focus {\n box-shadow: 0 0 0 0.25rem rgba(248, 249, 250, 0.5);\n}\n.btn-outline-light:disabled, .btn-outline-light.disabled {\n color: #f8f9fa;\n background-color: transparent;\n}\n\n.btn-outline-dark {\n color: #212529;\n border-color: #212529;\n}\n.btn-outline-dark:hover {\n color: #fff;\n background-color: #212529;\n border-color: #212529;\n}\n.btn-check:focus + .btn-outline-dark, .btn-outline-dark:focus {\n box-shadow: 0 0 0 0.25rem rgba(33, 37, 41, 0.5);\n}\n.btn-check:checked + .btn-outline-dark, .btn-check:active + .btn-outline-dark, .btn-outline-dark:active, .btn-outline-dark.active, .btn-outline-dark.dropdown-toggle.show {\n color: #fff;\n background-color: #212529;\n border-color: #212529;\n}\n.btn-check:checked + .btn-outline-dark:focus, .btn-check:active + .btn-outline-dark:focus, .btn-outline-dark:active:focus, .btn-outline-dark.active:focus, .btn-outline-dark.dropdown-toggle.show:focus {\n box-shadow: 0 0 0 0.25rem rgba(33, 37, 41, 0.5);\n}\n.btn-outline-dark:disabled, .btn-outline-dark.disabled {\n color: #212529;\n background-color: transparent;\n}\n\n.btn-link {\n font-weight: 400;\n color: #0d6efd;\n text-decoration: underline;\n}\n.btn-link:hover {\n color: #0a58ca;\n}\n.btn-link:disabled, .btn-link.disabled {\n color: #6c757d;\n}\n\n.btn-lg, .btn-group-lg > .btn {\n padding: 0.5rem 1rem;\n font-size: 1.25rem;\n border-radius: 0.3rem;\n}\n\n.btn-sm, .btn-group-sm > .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n border-radius: 0.2rem;\n}\n\n.fade {\n transition: opacity 0.15s linear;\n}\n@media (prefers-reduced-motion: reduce) {\n .fade {\n transition: none;\n }\n}\n.fade:not(.show) {\n opacity: 0;\n}\n\n.collapse:not(.show) {\n display: none;\n}\n\n.collapsing {\n height: 0;\n overflow: hidden;\n transition: height 0.35s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .collapsing {\n transition: none;\n }\n}\n.collapsing.collapse-horizontal {\n width: 0;\n height: auto;\n transition: width 0.35s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .collapsing.collapse-horizontal {\n transition: none;\n }\n}\n\n.dropup,\n.dropend,\n.dropdown,\n.dropstart {\n position: relative;\n}\n\n.dropdown-toggle {\n white-space: nowrap;\n}\n.dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid;\n border-right: 0.3em solid transparent;\n border-bottom: 0;\n border-left: 0.3em solid transparent;\n}\n.dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropdown-menu {\n position: absolute;\n z-index: 1000;\n display: none;\n min-width: 10rem;\n padding: 0.5rem 0;\n margin: 0;\n font-size: 1rem;\n color: #212529;\n text-align: left;\n list-style: none;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n}\n.dropdown-menu[data-bs-popper] {\n top: 100%;\n left: 0;\n margin-top: 0.125rem;\n}\n\n.dropdown-menu-start {\n --bs-position: start;\n}\n.dropdown-menu-start[data-bs-popper] {\n right: auto;\n left: 0;\n}\n\n.dropdown-menu-end {\n --bs-position: end;\n}\n.dropdown-menu-end[data-bs-popper] {\n right: 0;\n left: auto;\n}\n\n@media (min-width: 576px) {\n .dropdown-menu-sm-start {\n --bs-position: start;\n }\n .dropdown-menu-sm-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n\n .dropdown-menu-sm-end {\n --bs-position: end;\n }\n .dropdown-menu-sm-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n@media (min-width: 768px) {\n .dropdown-menu-md-start {\n --bs-position: start;\n }\n .dropdown-menu-md-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n\n .dropdown-menu-md-end {\n --bs-position: end;\n }\n .dropdown-menu-md-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n@media (min-width: 992px) {\n .dropdown-menu-lg-start {\n --bs-position: start;\n }\n .dropdown-menu-lg-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n\n .dropdown-menu-lg-end {\n --bs-position: end;\n }\n .dropdown-menu-lg-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n@media (min-width: 1200px) {\n .dropdown-menu-xl-start {\n --bs-position: start;\n }\n .dropdown-menu-xl-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n\n .dropdown-menu-xl-end {\n --bs-position: end;\n }\n .dropdown-menu-xl-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n@media (min-width: 1400px) {\n .dropdown-menu-xxl-start {\n --bs-position: start;\n }\n .dropdown-menu-xxl-start[data-bs-popper] {\n right: auto;\n left: 0;\n }\n\n .dropdown-menu-xxl-end {\n --bs-position: end;\n }\n .dropdown-menu-xxl-end[data-bs-popper] {\n right: 0;\n left: auto;\n }\n}\n.dropup .dropdown-menu[data-bs-popper] {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: 0.125rem;\n}\n.dropup .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0;\n border-right: 0.3em solid transparent;\n border-bottom: 0.3em solid;\n border-left: 0.3em solid transparent;\n}\n.dropup .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n\n.dropend .dropdown-menu[data-bs-popper] {\n top: 0;\n right: auto;\n left: 100%;\n margin-top: 0;\n margin-left: 0.125rem;\n}\n.dropend .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid transparent;\n border-right: 0;\n border-bottom: 0.3em solid transparent;\n border-left: 0.3em solid;\n}\n.dropend .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n.dropend .dropdown-toggle::after {\n vertical-align: 0;\n}\n\n.dropstart .dropdown-menu[data-bs-popper] {\n top: 0;\n right: 100%;\n left: auto;\n margin-top: 0;\n margin-right: 0.125rem;\n}\n.dropstart .dropdown-toggle::after {\n display: inline-block;\n margin-left: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n}\n.dropstart .dropdown-toggle::after {\n display: none;\n}\n.dropstart .dropdown-toggle::before {\n display: inline-block;\n margin-right: 0.255em;\n vertical-align: 0.255em;\n content: \"\";\n border-top: 0.3em solid transparent;\n border-right: 0.3em solid;\n border-bottom: 0.3em solid transparent;\n}\n.dropstart .dropdown-toggle:empty::after {\n margin-left: 0;\n}\n.dropstart .dropdown-toggle::before {\n vertical-align: 0;\n}\n\n.dropdown-divider {\n height: 0;\n margin: 0.5rem 0;\n overflow: hidden;\n border-top: 1px solid rgba(0, 0, 0, 0.15);\n}\n\n.dropdown-item {\n display: block;\n width: 100%;\n padding: 0.25rem 1rem;\n clear: both;\n font-weight: 400;\n color: #212529;\n text-align: inherit;\n text-decoration: none;\n white-space: nowrap;\n background-color: transparent;\n border: 0;\n}\n.dropdown-item:hover, .dropdown-item:focus {\n color: #1e2125;\n background-color: #e9ecef;\n}\n.dropdown-item.active, .dropdown-item:active {\n color: #fff;\n text-decoration: none;\n background-color: #0d6efd;\n}\n.dropdown-item.disabled, .dropdown-item:disabled {\n color: #adb5bd;\n pointer-events: none;\n background-color: transparent;\n}\n\n.dropdown-menu.show {\n display: block;\n}\n\n.dropdown-header {\n display: block;\n padding: 0.5rem 1rem;\n margin-bottom: 0;\n font-size: 0.875rem;\n color: #6c757d;\n white-space: nowrap;\n}\n\n.dropdown-item-text {\n display: block;\n padding: 0.25rem 1rem;\n color: #212529;\n}\n\n.dropdown-menu-dark {\n color: #dee2e6;\n background-color: #343a40;\n border-color: rgba(0, 0, 0, 0.15);\n}\n.dropdown-menu-dark .dropdown-item {\n color: #dee2e6;\n}\n.dropdown-menu-dark .dropdown-item:hover, .dropdown-menu-dark .dropdown-item:focus {\n color: #fff;\n background-color: rgba(255, 255, 255, 0.15);\n}\n.dropdown-menu-dark .dropdown-item.active, .dropdown-menu-dark .dropdown-item:active {\n color: #fff;\n background-color: #0d6efd;\n}\n.dropdown-menu-dark .dropdown-item.disabled, .dropdown-menu-dark .dropdown-item:disabled {\n color: #adb5bd;\n}\n.dropdown-menu-dark .dropdown-divider {\n border-color: rgba(0, 0, 0, 0.15);\n}\n.dropdown-menu-dark .dropdown-item-text {\n color: #dee2e6;\n}\n.dropdown-menu-dark .dropdown-header {\n color: #adb5bd;\n}\n\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-flex;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n flex: 1 1 auto;\n}\n.btn-group > .btn-check:checked + .btn,\n.btn-group > .btn-check:focus + .btn,\n.btn-group > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn-check:checked + .btn,\n.btn-group-vertical > .btn-check:focus + .btn,\n.btn-group-vertical > .btn:hover,\n.btn-group-vertical > .btn:focus,\n.btn-group-vertical > .btn:active,\n.btn-group-vertical > .btn.active {\n z-index: 1;\n}\n\n.btn-toolbar {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-start;\n}\n.btn-toolbar .input-group {\n width: auto;\n}\n\n.btn-group > .btn:not(:first-child),\n.btn-group > .btn-group:not(:first-child) {\n margin-left: -1px;\n}\n.btn-group > .btn:not(:last-child):not(.dropdown-toggle),\n.btn-group > .btn-group:not(:last-child) > .btn {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.btn-group > .btn:nth-child(n+3),\n.btn-group > :not(.btn-check) + .btn,\n.btn-group > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n.dropdown-toggle-split {\n padding-right: 0.5625rem;\n padding-left: 0.5625rem;\n}\n.dropdown-toggle-split::after, .dropup .dropdown-toggle-split::after, .dropend .dropdown-toggle-split::after {\n margin-left: 0;\n}\n.dropstart .dropdown-toggle-split::before {\n margin-right: 0;\n}\n\n.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split {\n padding-right: 0.375rem;\n padding-left: 0.375rem;\n}\n\n.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split {\n padding-right: 0.75rem;\n padding-left: 0.75rem;\n}\n\n.btn-group-vertical {\n flex-direction: column;\n align-items: flex-start;\n justify-content: center;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group {\n width: 100%;\n}\n.btn-group-vertical > .btn:not(:first-child),\n.btn-group-vertical > .btn-group:not(:first-child) {\n margin-top: -1px;\n}\n.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle),\n.btn-group-vertical > .btn-group:not(:last-child) > .btn {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn ~ .btn,\n.btn-group-vertical > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.nav {\n display: flex;\n flex-wrap: wrap;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n\n.nav-link {\n display: block;\n padding: 0.5rem 1rem;\n color: #0d6efd;\n text-decoration: none;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .nav-link {\n transition: none;\n }\n}\n.nav-link:hover, .nav-link:focus {\n color: #0a58ca;\n}\n.nav-link.disabled {\n color: #6c757d;\n pointer-events: none;\n cursor: default;\n}\n\n.nav-tabs {\n border-bottom: 1px solid #dee2e6;\n}\n.nav-tabs .nav-link {\n margin-bottom: -1px;\n background: none;\n border: 1px solid transparent;\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {\n border-color: #e9ecef #e9ecef #dee2e6;\n isolation: isolate;\n}\n.nav-tabs .nav-link.disabled {\n color: #6c757d;\n background-color: transparent;\n border-color: transparent;\n}\n.nav-tabs .nav-link.active,\n.nav-tabs .nav-item.show .nav-link {\n color: #495057;\n background-color: #fff;\n border-color: #dee2e6 #dee2e6 #fff;\n}\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n\n.nav-pills .nav-link {\n background: none;\n border: 0;\n border-radius: 0.25rem;\n}\n.nav-pills .nav-link.active,\n.nav-pills .show > .nav-link {\n color: #fff;\n background-color: #0d6efd;\n}\n\n.nav-fill > .nav-link,\n.nav-fill .nav-item {\n flex: 1 1 auto;\n text-align: center;\n}\n\n.nav-justified > .nav-link,\n.nav-justified .nav-item {\n flex-basis: 0;\n flex-grow: 1;\n text-align: center;\n}\n\n.nav-fill .nav-item .nav-link,\n.nav-justified .nav-item .nav-link {\n width: 100%;\n}\n\n.tab-content > .tab-pane {\n display: none;\n}\n.tab-content > .active {\n display: block;\n}\n\n.navbar {\n position: relative;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n.navbar > .container,\n.navbar > .container-fluid,\n.navbar > .container-sm,\n.navbar > .container-md,\n.navbar > .container-lg,\n.navbar > .container-xl,\n.navbar > .container-xxl {\n display: flex;\n flex-wrap: inherit;\n align-items: center;\n justify-content: space-between;\n}\n.navbar-brand {\n padding-top: 0.3125rem;\n padding-bottom: 0.3125rem;\n margin-right: 1rem;\n font-size: 1.25rem;\n text-decoration: none;\n white-space: nowrap;\n}\n.navbar-nav {\n display: flex;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n.navbar-nav .nav-link {\n padding-right: 0;\n padding-left: 0;\n}\n.navbar-nav .dropdown-menu {\n position: static;\n}\n\n.navbar-text {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n\n.navbar-collapse {\n flex-basis: 100%;\n flex-grow: 1;\n align-items: center;\n}\n\n.navbar-toggler {\n padding: 0.25rem 0.75rem;\n font-size: 1.25rem;\n line-height: 1;\n background-color: transparent;\n border: 1px solid transparent;\n border-radius: 0.25rem;\n transition: box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .navbar-toggler {\n transition: none;\n }\n}\n.navbar-toggler:hover {\n text-decoration: none;\n}\n.navbar-toggler:focus {\n text-decoration: none;\n outline: 0;\n box-shadow: 0 0 0 0.25rem;\n}\n\n.navbar-toggler-icon {\n display: inline-block;\n width: 1.5em;\n height: 1.5em;\n vertical-align: middle;\n background-repeat: no-repeat;\n background-position: center;\n background-size: 100%;\n}\n\n.navbar-nav-scroll {\n max-height: var(--bs-scroll-height, 75vh);\n overflow-y: auto;\n}\n\n@media (min-width: 576px) {\n .navbar-expand-sm {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-sm .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-sm .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-sm .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n }\n .navbar-expand-sm .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-sm .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-sm .navbar-toggler {\n display: none;\n }\n .navbar-expand-sm .offcanvas-header {\n display: none;\n }\n .navbar-expand-sm .offcanvas {\n position: inherit;\n bottom: 0;\n z-index: 1000;\n flex-grow: 1;\n visibility: visible !important;\n background-color: transparent;\n border-right: 0;\n border-left: 0;\n transition: none;\n transform: none;\n }\n .navbar-expand-sm .offcanvas-top,\n.navbar-expand-sm .offcanvas-bottom {\n height: auto;\n border-top: 0;\n border-bottom: 0;\n }\n .navbar-expand-sm .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n@media (min-width: 768px) {\n .navbar-expand-md {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-md .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-md .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-md .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n }\n .navbar-expand-md .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-md .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-md .navbar-toggler {\n display: none;\n }\n .navbar-expand-md .offcanvas-header {\n display: none;\n }\n .navbar-expand-md .offcanvas {\n position: inherit;\n bottom: 0;\n z-index: 1000;\n flex-grow: 1;\n visibility: visible !important;\n background-color: transparent;\n border-right: 0;\n border-left: 0;\n transition: none;\n transform: none;\n }\n .navbar-expand-md .offcanvas-top,\n.navbar-expand-md .offcanvas-bottom {\n height: auto;\n border-top: 0;\n border-bottom: 0;\n }\n .navbar-expand-md .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n@media (min-width: 992px) {\n .navbar-expand-lg {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-lg .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-lg .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-lg .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n }\n .navbar-expand-lg .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-lg .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-lg .navbar-toggler {\n display: none;\n }\n .navbar-expand-lg .offcanvas-header {\n display: none;\n }\n .navbar-expand-lg .offcanvas {\n position: inherit;\n bottom: 0;\n z-index: 1000;\n flex-grow: 1;\n visibility: visible !important;\n background-color: transparent;\n border-right: 0;\n border-left: 0;\n transition: none;\n transform: none;\n }\n .navbar-expand-lg .offcanvas-top,\n.navbar-expand-lg .offcanvas-bottom {\n height: auto;\n border-top: 0;\n border-bottom: 0;\n }\n .navbar-expand-lg .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n@media (min-width: 1200px) {\n .navbar-expand-xl {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-xl .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-xl .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-xl .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n }\n .navbar-expand-xl .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-xl .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-xl .navbar-toggler {\n display: none;\n }\n .navbar-expand-xl .offcanvas-header {\n display: none;\n }\n .navbar-expand-xl .offcanvas {\n position: inherit;\n bottom: 0;\n z-index: 1000;\n flex-grow: 1;\n visibility: visible !important;\n background-color: transparent;\n border-right: 0;\n border-left: 0;\n transition: none;\n transform: none;\n }\n .navbar-expand-xl .offcanvas-top,\n.navbar-expand-xl .offcanvas-bottom {\n height: auto;\n border-top: 0;\n border-bottom: 0;\n }\n .navbar-expand-xl .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n@media (min-width: 1400px) {\n .navbar-expand-xxl {\n flex-wrap: nowrap;\n justify-content: flex-start;\n }\n .navbar-expand-xxl .navbar-nav {\n flex-direction: row;\n }\n .navbar-expand-xxl .navbar-nav .dropdown-menu {\n position: absolute;\n }\n .navbar-expand-xxl .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n }\n .navbar-expand-xxl .navbar-nav-scroll {\n overflow: visible;\n }\n .navbar-expand-xxl .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n }\n .navbar-expand-xxl .navbar-toggler {\n display: none;\n }\n .navbar-expand-xxl .offcanvas-header {\n display: none;\n }\n .navbar-expand-xxl .offcanvas {\n position: inherit;\n bottom: 0;\n z-index: 1000;\n flex-grow: 1;\n visibility: visible !important;\n background-color: transparent;\n border-right: 0;\n border-left: 0;\n transition: none;\n transform: none;\n }\n .navbar-expand-xxl .offcanvas-top,\n.navbar-expand-xxl .offcanvas-bottom {\n height: auto;\n border-top: 0;\n border-bottom: 0;\n }\n .navbar-expand-xxl .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n}\n.navbar-expand {\n flex-wrap: nowrap;\n justify-content: flex-start;\n}\n.navbar-expand .navbar-nav {\n flex-direction: row;\n}\n.navbar-expand .navbar-nav .dropdown-menu {\n position: absolute;\n}\n.navbar-expand .navbar-nav .nav-link {\n padding-right: 0.5rem;\n padding-left: 0.5rem;\n}\n.navbar-expand .navbar-nav-scroll {\n overflow: visible;\n}\n.navbar-expand .navbar-collapse {\n display: flex !important;\n flex-basis: auto;\n}\n.navbar-expand .navbar-toggler {\n display: none;\n}\n.navbar-expand .offcanvas-header {\n display: none;\n}\n.navbar-expand .offcanvas {\n position: inherit;\n bottom: 0;\n z-index: 1000;\n flex-grow: 1;\n visibility: visible !important;\n background-color: transparent;\n border-right: 0;\n border-left: 0;\n transition: none;\n transform: none;\n}\n.navbar-expand .offcanvas-top,\n.navbar-expand .offcanvas-bottom {\n height: auto;\n border-top: 0;\n border-bottom: 0;\n}\n.navbar-expand .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n}\n\n.navbar-light .navbar-brand {\n color: rgba(0, 0, 0, 0.9);\n}\n.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus {\n color: rgba(0, 0, 0, 0.9);\n}\n.navbar-light .navbar-nav .nav-link {\n color: rgba(0, 0, 0, 0.55);\n}\n.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus {\n color: rgba(0, 0, 0, 0.7);\n}\n.navbar-light .navbar-nav .nav-link.disabled {\n color: rgba(0, 0, 0, 0.3);\n}\n.navbar-light .navbar-nav .show > .nav-link,\n.navbar-light .navbar-nav .nav-link.active {\n color: rgba(0, 0, 0, 0.9);\n}\n.navbar-light .navbar-toggler {\n color: rgba(0, 0, 0, 0.55);\n border-color: rgba(0, 0, 0, 0.1);\n}\n.navbar-light .navbar-toggler-icon {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n}\n.navbar-light .navbar-text {\n color: rgba(0, 0, 0, 0.55);\n}\n.navbar-light .navbar-text a,\n.navbar-light .navbar-text a:hover,\n.navbar-light .navbar-text a:focus {\n color: rgba(0, 0, 0, 0.9);\n}\n\n.navbar-dark .navbar-brand {\n color: #fff;\n}\n.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus {\n color: #fff;\n}\n.navbar-dark .navbar-nav .nav-link {\n color: rgba(255, 255, 255, 0.55);\n}\n.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus {\n color: rgba(255, 255, 255, 0.75);\n}\n.navbar-dark .navbar-nav .nav-link.disabled {\n color: rgba(255, 255, 255, 0.25);\n}\n.navbar-dark .navbar-nav .show > .nav-link,\n.navbar-dark .navbar-nav .nav-link.active {\n color: #fff;\n}\n.navbar-dark .navbar-toggler {\n color: rgba(255, 255, 255, 0.55);\n border-color: rgba(255, 255, 255, 0.1);\n}\n.navbar-dark .navbar-toggler-icon {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e\");\n}\n.navbar-dark .navbar-text {\n color: rgba(255, 255, 255, 0.55);\n}\n.navbar-dark .navbar-text a,\n.navbar-dark .navbar-text a:hover,\n.navbar-dark .navbar-text a:focus {\n color: #fff;\n}\n\n.card {\n position: relative;\n display: flex;\n flex-direction: column;\n min-width: 0;\n word-wrap: break-word;\n background-color: #fff;\n background-clip: border-box;\n border: 1px solid rgba(0, 0, 0, 0.125);\n border-radius: 0.25rem;\n}\n.card > hr {\n margin-right: 0;\n margin-left: 0;\n}\n.card > .list-group {\n border-top: inherit;\n border-bottom: inherit;\n}\n.card > .list-group:first-child {\n border-top-width: 0;\n border-top-left-radius: calc(0.25rem - 1px);\n border-top-right-radius: calc(0.25rem - 1px);\n}\n.card > .list-group:last-child {\n border-bottom-width: 0;\n border-bottom-right-radius: calc(0.25rem - 1px);\n border-bottom-left-radius: calc(0.25rem - 1px);\n}\n.card > .card-header + .list-group,\n.card > .list-group + .card-footer {\n border-top: 0;\n}\n\n.card-body {\n flex: 1 1 auto;\n padding: 1rem 1rem;\n}\n\n.card-title {\n margin-bottom: 0.5rem;\n}\n\n.card-subtitle {\n margin-top: -0.25rem;\n margin-bottom: 0;\n}\n\n.card-text:last-child {\n margin-bottom: 0;\n}\n\n.card-link + .card-link {\n margin-left: 1rem;\n}\n\n.card-header {\n padding: 0.5rem 1rem;\n margin-bottom: 0;\n background-color: rgba(0, 0, 0, 0.03);\n border-bottom: 1px solid rgba(0, 0, 0, 0.125);\n}\n.card-header:first-child {\n border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0;\n}\n\n.card-footer {\n padding: 0.5rem 1rem;\n background-color: rgba(0, 0, 0, 0.03);\n border-top: 1px solid rgba(0, 0, 0, 0.125);\n}\n.card-footer:last-child {\n border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px);\n}\n\n.card-header-tabs {\n margin-right: -0.5rem;\n margin-bottom: -0.5rem;\n margin-left: -0.5rem;\n border-bottom: 0;\n}\n\n.card-header-pills {\n margin-right: -0.5rem;\n margin-left: -0.5rem;\n}\n\n.card-img-overlay {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n padding: 1rem;\n border-radius: calc(0.25rem - 1px);\n}\n\n.card-img,\n.card-img-top,\n.card-img-bottom {\n width: 100%;\n}\n\n.card-img,\n.card-img-top {\n border-top-left-radius: calc(0.25rem - 1px);\n border-top-right-radius: calc(0.25rem - 1px);\n}\n\n.card-img,\n.card-img-bottom {\n border-bottom-right-radius: calc(0.25rem - 1px);\n border-bottom-left-radius: calc(0.25rem - 1px);\n}\n\n.card-group > .card {\n margin-bottom: 0.75rem;\n}\n@media (min-width: 576px) {\n .card-group {\n display: flex;\n flex-flow: row wrap;\n }\n .card-group > .card {\n flex: 1 0 0%;\n margin-bottom: 0;\n }\n .card-group > .card + .card {\n margin-left: 0;\n border-left: 0;\n }\n .card-group > .card:not(:last-child) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n .card-group > .card:not(:last-child) .card-img-top,\n.card-group > .card:not(:last-child) .card-header {\n border-top-right-radius: 0;\n }\n .card-group > .card:not(:last-child) .card-img-bottom,\n.card-group > .card:not(:last-child) .card-footer {\n border-bottom-right-radius: 0;\n }\n .card-group > .card:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n .card-group > .card:not(:first-child) .card-img-top,\n.card-group > .card:not(:first-child) .card-header {\n border-top-left-radius: 0;\n }\n .card-group > .card:not(:first-child) .card-img-bottom,\n.card-group > .card:not(:first-child) .card-footer {\n border-bottom-left-radius: 0;\n }\n}\n\n.accordion-button {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n padding: 1rem 1.25rem;\n font-size: 1rem;\n color: #212529;\n text-align: left;\n background-color: #fff;\n border: 0;\n border-radius: 0;\n overflow-anchor: none;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .accordion-button {\n transition: none;\n }\n}\n.accordion-button:not(.collapsed) {\n color: #0c63e4;\n background-color: #e7f1ff;\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.125);\n}\n.accordion-button:not(.collapsed)::after {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\");\n transform: rotate(-180deg);\n}\n.accordion-button::after {\n flex-shrink: 0;\n width: 1.25rem;\n height: 1.25rem;\n margin-left: auto;\n content: \"\";\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\");\n background-repeat: no-repeat;\n background-size: 1.25rem;\n transition: transform 0.2s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .accordion-button::after {\n transition: none;\n }\n}\n.accordion-button:hover {\n z-index: 2;\n}\n.accordion-button:focus {\n z-index: 3;\n border-color: #86b7fe;\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n\n.accordion-header {\n margin-bottom: 0;\n}\n\n.accordion-item {\n background-color: #fff;\n border: 1px solid rgba(0, 0, 0, 0.125);\n}\n.accordion-item:first-of-type {\n border-top-left-radius: 0.25rem;\n border-top-right-radius: 0.25rem;\n}\n.accordion-item:first-of-type .accordion-button {\n border-top-left-radius: calc(0.25rem - 1px);\n border-top-right-radius: calc(0.25rem - 1px);\n}\n.accordion-item:not(:first-of-type) {\n border-top: 0;\n}\n.accordion-item:last-of-type {\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n.accordion-item:last-of-type .accordion-button.collapsed {\n border-bottom-right-radius: calc(0.25rem - 1px);\n border-bottom-left-radius: calc(0.25rem - 1px);\n}\n.accordion-item:last-of-type .accordion-collapse {\n border-bottom-right-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n\n.accordion-body {\n padding: 1rem 1.25rem;\n}\n\n.accordion-flush .accordion-collapse {\n border-width: 0;\n}\n.accordion-flush .accordion-item {\n border-right: 0;\n border-left: 0;\n border-radius: 0;\n}\n.accordion-flush .accordion-item:first-child {\n border-top: 0;\n}\n.accordion-flush .accordion-item:last-child {\n border-bottom: 0;\n}\n.accordion-flush .accordion-item .accordion-button {\n border-radius: 0;\n}\n\n.breadcrumb {\n display: flex;\n flex-wrap: wrap;\n padding: 0 0;\n margin-bottom: 1rem;\n list-style: none;\n}\n\n.breadcrumb-item + .breadcrumb-item {\n padding-left: 0.5rem;\n}\n.breadcrumb-item + .breadcrumb-item::before {\n float: left;\n padding-right: 0.5rem;\n color: #6c757d;\n content: var(--bs-breadcrumb-divider, \"/\") /* rtl: var(--bs-breadcrumb-divider, \"/\") */;\n}\n.breadcrumb-item.active {\n color: #6c757d;\n}\n\n.pagination {\n display: flex;\n padding-left: 0;\n list-style: none;\n}\n\n.page-link {\n position: relative;\n display: block;\n color: #0d6efd;\n text-decoration: none;\n background-color: #fff;\n border: 1px solid #dee2e6;\n transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .page-link {\n transition: none;\n }\n}\n.page-link:hover {\n z-index: 2;\n color: #0a58ca;\n background-color: #e9ecef;\n border-color: #dee2e6;\n}\n.page-link:focus {\n z-index: 3;\n color: #0a58ca;\n background-color: #e9ecef;\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n}\n\n.page-item:not(:first-child) .page-link {\n margin-left: -1px;\n}\n.page-item.active .page-link {\n z-index: 3;\n color: #fff;\n background-color: #0d6efd;\n border-color: #0d6efd;\n}\n.page-item.disabled .page-link {\n color: #6c757d;\n pointer-events: none;\n background-color: #fff;\n border-color: #dee2e6;\n}\n\n.page-link {\n padding: 0.375rem 0.75rem;\n}\n\n.page-item:first-child .page-link {\n border-top-left-radius: 0.25rem;\n border-bottom-left-radius: 0.25rem;\n}\n.page-item:last-child .page-link {\n border-top-right-radius: 0.25rem;\n border-bottom-right-radius: 0.25rem;\n}\n\n.pagination-lg .page-link {\n padding: 0.75rem 1.5rem;\n font-size: 1.25rem;\n}\n.pagination-lg .page-item:first-child .page-link {\n border-top-left-radius: 0.3rem;\n border-bottom-left-radius: 0.3rem;\n}\n.pagination-lg .page-item:last-child .page-link {\n border-top-right-radius: 0.3rem;\n border-bottom-right-radius: 0.3rem;\n}\n\n.pagination-sm .page-link {\n padding: 0.25rem 0.5rem;\n font-size: 0.875rem;\n}\n.pagination-sm .page-item:first-child .page-link {\n border-top-left-radius: 0.2rem;\n border-bottom-left-radius: 0.2rem;\n}\n.pagination-sm .page-item:last-child .page-link {\n border-top-right-radius: 0.2rem;\n border-bottom-right-radius: 0.2rem;\n}\n\n.badge {\n display: inline-block;\n padding: 0.35em 0.65em;\n font-size: 0.75em;\n font-weight: 700;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: 0.25rem;\n}\n.badge:empty {\n display: none;\n}\n\n.btn .badge {\n position: relative;\n top: -1px;\n}\n\n.alert {\n position: relative;\n padding: 1rem 1rem;\n margin-bottom: 1rem;\n border: 1px solid transparent;\n border-radius: 0.25rem;\n}\n\n.alert-heading {\n color: inherit;\n}\n\n.alert-link {\n font-weight: 700;\n}\n\n.alert-dismissible {\n padding-right: 3rem;\n}\n.alert-dismissible .btn-close {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n padding: 1.25rem 1rem;\n}\n\n.alert-primary {\n color: #084298;\n background-color: #cfe2ff;\n border-color: #b6d4fe;\n}\n.alert-primary .alert-link {\n color: #06357a;\n}\n\n.alert-secondary {\n color: #41464b;\n background-color: #e2e3e5;\n border-color: #d3d6d8;\n}\n.alert-secondary .alert-link {\n color: #34383c;\n}\n\n.alert-success {\n color: #0f5132;\n background-color: #d1e7dd;\n border-color: #badbcc;\n}\n.alert-success .alert-link {\n color: #0c4128;\n}\n\n.alert-info {\n color: #055160;\n background-color: #cff4fc;\n border-color: #b6effb;\n}\n.alert-info .alert-link {\n color: #04414d;\n}\n\n.alert-warning {\n color: #664d03;\n background-color: #fff3cd;\n border-color: #ffecb5;\n}\n.alert-warning .alert-link {\n color: #523e02;\n}\n\n.alert-danger {\n color: #842029;\n background-color: #f8d7da;\n border-color: #f5c2c7;\n}\n.alert-danger .alert-link {\n color: #6a1a21;\n}\n\n.alert-light {\n color: #636464;\n background-color: #fefefe;\n border-color: #fdfdfe;\n}\n.alert-light .alert-link {\n color: #4f5050;\n}\n\n.alert-dark {\n color: #141619;\n background-color: #d3d3d4;\n border-color: #bcbebf;\n}\n.alert-dark .alert-link {\n color: #101214;\n}\n\n@-webkit-keyframes progress-bar-stripes {\n 0% {\n background-position-x: 1rem;\n }\n}\n\n@keyframes progress-bar-stripes {\n 0% {\n background-position-x: 1rem;\n }\n}\n.progress {\n display: flex;\n height: 1rem;\n overflow: hidden;\n font-size: 0.75rem;\n background-color: #e9ecef;\n border-radius: 0.25rem;\n}\n\n.progress-bar {\n display: flex;\n flex-direction: column;\n justify-content: center;\n overflow: hidden;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n background-color: #0d6efd;\n transition: width 0.6s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .progress-bar {\n transition: none;\n }\n}\n\n.progress-bar-striped {\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 1rem 1rem;\n}\n\n.progress-bar-animated {\n -webkit-animation: 1s linear infinite progress-bar-stripes;\n animation: 1s linear infinite progress-bar-stripes;\n}\n@media (prefers-reduced-motion: reduce) {\n .progress-bar-animated {\n -webkit-animation: none;\n animation: none;\n }\n}\n\n.list-group {\n display: flex;\n flex-direction: column;\n padding-left: 0;\n margin-bottom: 0;\n border-radius: 0.25rem;\n}\n\n.list-group-numbered {\n list-style-type: none;\n counter-reset: section;\n}\n.list-group-numbered > li::before {\n content: counters(section, \".\") \". \";\n counter-increment: section;\n}\n\n.list-group-item-action {\n width: 100%;\n color: #495057;\n text-align: inherit;\n}\n.list-group-item-action:hover, .list-group-item-action:focus {\n z-index: 1;\n color: #495057;\n text-decoration: none;\n background-color: #f8f9fa;\n}\n.list-group-item-action:active {\n color: #212529;\n background-color: #e9ecef;\n}\n\n.list-group-item {\n position: relative;\n display: block;\n padding: 0.5rem 1rem;\n color: #212529;\n text-decoration: none;\n background-color: #fff;\n border: 1px solid rgba(0, 0, 0, 0.125);\n}\n.list-group-item:first-child {\n border-top-left-radius: inherit;\n border-top-right-radius: inherit;\n}\n.list-group-item:last-child {\n border-bottom-right-radius: inherit;\n border-bottom-left-radius: inherit;\n}\n.list-group-item.disabled, .list-group-item:disabled {\n color: #6c757d;\n pointer-events: none;\n background-color: #fff;\n}\n.list-group-item.active {\n z-index: 2;\n color: #fff;\n background-color: #0d6efd;\n border-color: #0d6efd;\n}\n.list-group-item + .list-group-item {\n border-top-width: 0;\n}\n.list-group-item + .list-group-item.active {\n margin-top: -1px;\n border-top-width: 1px;\n}\n\n.list-group-horizontal {\n flex-direction: row;\n}\n.list-group-horizontal > .list-group-item:first-child {\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n}\n.list-group-horizontal > .list-group-item:last-child {\n border-top-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n}\n.list-group-horizontal > .list-group-item.active {\n margin-top: 0;\n}\n.list-group-horizontal > .list-group-item + .list-group-item {\n border-top-width: 1px;\n border-left-width: 0;\n}\n.list-group-horizontal > .list-group-item + .list-group-item.active {\n margin-left: -1px;\n border-left-width: 1px;\n}\n\n@media (min-width: 576px) {\n .list-group-horizontal-sm {\n flex-direction: row;\n }\n .list-group-horizontal-sm > .list-group-item:first-child {\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n }\n .list-group-horizontal-sm > .list-group-item:last-child {\n border-top-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-sm > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-sm > .list-group-item + .list-group-item {\n border-top-width: 1px;\n border-left-width: 0;\n }\n .list-group-horizontal-sm > .list-group-item + .list-group-item.active {\n margin-left: -1px;\n border-left-width: 1px;\n }\n}\n@media (min-width: 768px) {\n .list-group-horizontal-md {\n flex-direction: row;\n }\n .list-group-horizontal-md > .list-group-item:first-child {\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n }\n .list-group-horizontal-md > .list-group-item:last-child {\n border-top-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-md > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-md > .list-group-item + .list-group-item {\n border-top-width: 1px;\n border-left-width: 0;\n }\n .list-group-horizontal-md > .list-group-item + .list-group-item.active {\n margin-left: -1px;\n border-left-width: 1px;\n }\n}\n@media (min-width: 992px) {\n .list-group-horizontal-lg {\n flex-direction: row;\n }\n .list-group-horizontal-lg > .list-group-item:first-child {\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n }\n .list-group-horizontal-lg > .list-group-item:last-child {\n border-top-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-lg > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-lg > .list-group-item + .list-group-item {\n border-top-width: 1px;\n border-left-width: 0;\n }\n .list-group-horizontal-lg > .list-group-item + .list-group-item.active {\n margin-left: -1px;\n border-left-width: 1px;\n }\n}\n@media (min-width: 1200px) {\n .list-group-horizontal-xl {\n flex-direction: row;\n }\n .list-group-horizontal-xl > .list-group-item:first-child {\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n }\n .list-group-horizontal-xl > .list-group-item:last-child {\n border-top-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-xl > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-xl > .list-group-item + .list-group-item {\n border-top-width: 1px;\n border-left-width: 0;\n }\n .list-group-horizontal-xl > .list-group-item + .list-group-item.active {\n margin-left: -1px;\n border-left-width: 1px;\n }\n}\n@media (min-width: 1400px) {\n .list-group-horizontal-xxl {\n flex-direction: row;\n }\n .list-group-horizontal-xxl > .list-group-item:first-child {\n border-bottom-left-radius: 0.25rem;\n border-top-right-radius: 0;\n }\n .list-group-horizontal-xxl > .list-group-item:last-child {\n border-top-right-radius: 0.25rem;\n border-bottom-left-radius: 0;\n }\n .list-group-horizontal-xxl > .list-group-item.active {\n margin-top: 0;\n }\n .list-group-horizontal-xxl > .list-group-item + .list-group-item {\n border-top-width: 1px;\n border-left-width: 0;\n }\n .list-group-horizontal-xxl > .list-group-item + .list-group-item.active {\n margin-left: -1px;\n border-left-width: 1px;\n }\n}\n.list-group-flush {\n border-radius: 0;\n}\n.list-group-flush > .list-group-item {\n border-width: 0 0 1px;\n}\n.list-group-flush > .list-group-item:last-child {\n border-bottom-width: 0;\n}\n\n.list-group-item-primary {\n color: #084298;\n background-color: #cfe2ff;\n}\n.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus {\n color: #084298;\n background-color: #bacbe6;\n}\n.list-group-item-primary.list-group-item-action.active {\n color: #fff;\n background-color: #084298;\n border-color: #084298;\n}\n\n.list-group-item-secondary {\n color: #41464b;\n background-color: #e2e3e5;\n}\n.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus {\n color: #41464b;\n background-color: #cbccce;\n}\n.list-group-item-secondary.list-group-item-action.active {\n color: #fff;\n background-color: #41464b;\n border-color: #41464b;\n}\n\n.list-group-item-success {\n color: #0f5132;\n background-color: #d1e7dd;\n}\n.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus {\n color: #0f5132;\n background-color: #bcd0c7;\n}\n.list-group-item-success.list-group-item-action.active {\n color: #fff;\n background-color: #0f5132;\n border-color: #0f5132;\n}\n\n.list-group-item-info {\n color: #055160;\n background-color: #cff4fc;\n}\n.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus {\n color: #055160;\n background-color: #badce3;\n}\n.list-group-item-info.list-group-item-action.active {\n color: #fff;\n background-color: #055160;\n border-color: #055160;\n}\n\n.list-group-item-warning {\n color: #664d03;\n background-color: #fff3cd;\n}\n.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus {\n color: #664d03;\n background-color: #e6dbb9;\n}\n.list-group-item-warning.list-group-item-action.active {\n color: #fff;\n background-color: #664d03;\n border-color: #664d03;\n}\n\n.list-group-item-danger {\n color: #842029;\n background-color: #f8d7da;\n}\n.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus {\n color: #842029;\n background-color: #dfc2c4;\n}\n.list-group-item-danger.list-group-item-action.active {\n color: #fff;\n background-color: #842029;\n border-color: #842029;\n}\n\n.list-group-item-light {\n color: #636464;\n background-color: #fefefe;\n}\n.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus {\n color: #636464;\n background-color: #e5e5e5;\n}\n.list-group-item-light.list-group-item-action.active {\n color: #fff;\n background-color: #636464;\n border-color: #636464;\n}\n\n.list-group-item-dark {\n color: #141619;\n background-color: #d3d3d4;\n}\n.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus {\n color: #141619;\n background-color: #bebebf;\n}\n.list-group-item-dark.list-group-item-action.active {\n color: #fff;\n background-color: #141619;\n border-color: #141619;\n}\n\n.btn-close {\n box-sizing: content-box;\n width: 1em;\n height: 1em;\n padding: 0.25em 0.25em;\n color: #000;\n background: transparent url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e\") center/1em auto no-repeat;\n border: 0;\n border-radius: 0.25rem;\n opacity: 0.5;\n}\n.btn-close:hover {\n color: #000;\n text-decoration: none;\n opacity: 0.75;\n}\n.btn-close:focus {\n outline: 0;\n box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);\n opacity: 1;\n}\n.btn-close:disabled, .btn-close.disabled {\n pointer-events: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n opacity: 0.25;\n}\n\n.btn-close-white {\n filter: invert(1) grayscale(100%) brightness(200%);\n}\n\n.toast {\n width: 350px;\n max-width: 100%;\n font-size: 0.875rem;\n pointer-events: auto;\n background-color: rgba(255, 255, 255, 0.85);\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.1);\n box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);\n border-radius: 0.25rem;\n}\n.toast.showing {\n opacity: 0;\n}\n.toast:not(.show) {\n display: none;\n}\n\n.toast-container {\n width: -webkit-max-content;\n width: -moz-max-content;\n width: max-content;\n max-width: 100%;\n pointer-events: none;\n}\n.toast-container > :not(:last-child) {\n margin-bottom: 0.75rem;\n}\n\n.toast-header {\n display: flex;\n align-items: center;\n padding: 0.5rem 0.75rem;\n color: #6c757d;\n background-color: rgba(255, 255, 255, 0.85);\n background-clip: padding-box;\n border-bottom: 1px solid rgba(0, 0, 0, 0.05);\n border-top-left-radius: calc(0.25rem - 1px);\n border-top-right-radius: calc(0.25rem - 1px);\n}\n.toast-header .btn-close {\n margin-right: -0.375rem;\n margin-left: 0.75rem;\n}\n\n.toast-body {\n padding: 0.75rem;\n word-wrap: break-word;\n}\n\n.modal {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 1055;\n display: none;\n width: 100%;\n height: 100%;\n overflow-x: hidden;\n overflow-y: auto;\n outline: 0;\n}\n\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 0.5rem;\n pointer-events: none;\n}\n.modal.fade .modal-dialog {\n transition: transform 0.3s ease-out;\n transform: translate(0, -50px);\n}\n@media (prefers-reduced-motion: reduce) {\n .modal.fade .modal-dialog {\n transition: none;\n }\n}\n.modal.show .modal-dialog {\n transform: none;\n}\n.modal.modal-static .modal-dialog {\n transform: scale(1.02);\n}\n\n.modal-dialog-scrollable {\n height: calc(100% - 1rem);\n}\n.modal-dialog-scrollable .modal-content {\n max-height: 100%;\n overflow: hidden;\n}\n.modal-dialog-scrollable .modal-body {\n overflow-y: auto;\n}\n\n.modal-dialog-centered {\n display: flex;\n align-items: center;\n min-height: calc(100% - 1rem);\n}\n\n.modal-content {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n pointer-events: auto;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 0.3rem;\n outline: 0;\n}\n\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 1050;\n width: 100vw;\n height: 100vh;\n background-color: #000;\n}\n.modal-backdrop.fade {\n opacity: 0;\n}\n.modal-backdrop.show {\n opacity: 0.5;\n}\n\n.modal-header {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: space-between;\n padding: 1rem 1rem;\n border-bottom: 1px solid #dee2e6;\n border-top-left-radius: calc(0.3rem - 1px);\n border-top-right-radius: calc(0.3rem - 1px);\n}\n.modal-header .btn-close {\n padding: 0.5rem 0.5rem;\n margin: -0.5rem -0.5rem -0.5rem auto;\n}\n\n.modal-title {\n margin-bottom: 0;\n line-height: 1.5;\n}\n\n.modal-body {\n position: relative;\n flex: 1 1 auto;\n padding: 1rem;\n}\n\n.modal-footer {\n display: flex;\n flex-wrap: wrap;\n flex-shrink: 0;\n align-items: center;\n justify-content: flex-end;\n padding: 0.75rem;\n border-top: 1px solid #dee2e6;\n border-bottom-right-radius: calc(0.3rem - 1px);\n border-bottom-left-radius: calc(0.3rem - 1px);\n}\n.modal-footer > * {\n margin: 0.25rem;\n}\n\n@media (min-width: 576px) {\n .modal-dialog {\n max-width: 500px;\n margin: 1.75rem auto;\n }\n\n .modal-dialog-scrollable {\n height: calc(100% - 3.5rem);\n }\n\n .modal-dialog-centered {\n min-height: calc(100% - 3.5rem);\n }\n\n .modal-sm {\n max-width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg,\n.modal-xl {\n max-width: 800px;\n }\n}\n@media (min-width: 1200px) {\n .modal-xl {\n max-width: 1140px;\n }\n}\n.modal-fullscreen {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n}\n.modal-fullscreen .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n}\n.modal-fullscreen .modal-header {\n border-radius: 0;\n}\n.modal-fullscreen .modal-body {\n overflow-y: auto;\n}\n.modal-fullscreen .modal-footer {\n border-radius: 0;\n}\n\n@media (max-width: 575.98px) {\n .modal-fullscreen-sm-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-sm-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-sm-down .modal-header {\n border-radius: 0;\n }\n .modal-fullscreen-sm-down .modal-body {\n overflow-y: auto;\n }\n .modal-fullscreen-sm-down .modal-footer {\n border-radius: 0;\n }\n}\n@media (max-width: 767.98px) {\n .modal-fullscreen-md-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-md-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-md-down .modal-header {\n border-radius: 0;\n }\n .modal-fullscreen-md-down .modal-body {\n overflow-y: auto;\n }\n .modal-fullscreen-md-down .modal-footer {\n border-radius: 0;\n }\n}\n@media (max-width: 991.98px) {\n .modal-fullscreen-lg-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-lg-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-lg-down .modal-header {\n border-radius: 0;\n }\n .modal-fullscreen-lg-down .modal-body {\n overflow-y: auto;\n }\n .modal-fullscreen-lg-down .modal-footer {\n border-radius: 0;\n }\n}\n@media (max-width: 1199.98px) {\n .modal-fullscreen-xl-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-xl-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-xl-down .modal-header {\n border-radius: 0;\n }\n .modal-fullscreen-xl-down .modal-body {\n overflow-y: auto;\n }\n .modal-fullscreen-xl-down .modal-footer {\n border-radius: 0;\n }\n}\n@media (max-width: 1399.98px) {\n .modal-fullscreen-xxl-down {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n }\n .modal-fullscreen-xxl-down .modal-content {\n height: 100%;\n border: 0;\n border-radius: 0;\n }\n .modal-fullscreen-xxl-down .modal-header {\n border-radius: 0;\n }\n .modal-fullscreen-xxl-down .modal-body {\n overflow-y: auto;\n }\n .modal-fullscreen-xxl-down .modal-footer {\n border-radius: 0;\n }\n}\n.tooltip {\n position: absolute;\n z-index: 1080;\n display: block;\n margin: 0;\n font-family: var(--bs-font-sans-serif);\n font-style: normal;\n font-weight: 400;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n white-space: normal;\n line-break: auto;\n font-size: 0.875rem;\n word-wrap: break-word;\n opacity: 0;\n}\n.tooltip.show {\n opacity: 0.9;\n}\n.tooltip .tooltip-arrow {\n position: absolute;\n display: block;\n width: 0.8rem;\n height: 0.4rem;\n}\n.tooltip .tooltip-arrow::before {\n position: absolute;\n content: \"\";\n border-color: transparent;\n border-style: solid;\n}\n\n.bs-tooltip-top, .bs-tooltip-auto[data-popper-placement^=top] {\n padding: 0.4rem 0;\n}\n.bs-tooltip-top .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow {\n bottom: 0;\n}\n.bs-tooltip-top .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before {\n top: -1px;\n border-width: 0.4rem 0.4rem 0;\n border-top-color: #000;\n}\n\n.bs-tooltip-end, .bs-tooltip-auto[data-popper-placement^=right] {\n padding: 0 0.4rem;\n}\n.bs-tooltip-end .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow {\n left: 0;\n width: 0.4rem;\n height: 0.8rem;\n}\n.bs-tooltip-end .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before {\n right: -1px;\n border-width: 0.4rem 0.4rem 0.4rem 0;\n border-right-color: #000;\n}\n\n.bs-tooltip-bottom, .bs-tooltip-auto[data-popper-placement^=bottom] {\n padding: 0.4rem 0;\n}\n.bs-tooltip-bottom .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow {\n top: 0;\n}\n.bs-tooltip-bottom .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before {\n bottom: -1px;\n border-width: 0 0.4rem 0.4rem;\n border-bottom-color: #000;\n}\n\n.bs-tooltip-start, .bs-tooltip-auto[data-popper-placement^=left] {\n padding: 0 0.4rem;\n}\n.bs-tooltip-start .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow {\n right: 0;\n width: 0.4rem;\n height: 0.8rem;\n}\n.bs-tooltip-start .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before {\n left: -1px;\n border-width: 0.4rem 0 0.4rem 0.4rem;\n border-left-color: #000;\n}\n\n.tooltip-inner {\n max-width: 200px;\n padding: 0.25rem 0.5rem;\n color: #fff;\n text-align: center;\n background-color: #000;\n border-radius: 0.25rem;\n}\n\n.popover {\n position: absolute;\n top: 0;\n left: 0 /* rtl:ignore */;\n z-index: 1070;\n display: block;\n max-width: 276px;\n font-family: var(--bs-font-sans-serif);\n font-style: normal;\n font-weight: 400;\n line-height: 1.5;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n white-space: normal;\n line-break: auto;\n font-size: 0.875rem;\n word-wrap: break-word;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 0.3rem;\n}\n.popover .popover-arrow {\n position: absolute;\n display: block;\n width: 1rem;\n height: 0.5rem;\n}\n.popover .popover-arrow::before, .popover .popover-arrow::after {\n position: absolute;\n display: block;\n content: \"\";\n border-color: transparent;\n border-style: solid;\n}\n\n.bs-popover-top > .popover-arrow, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow {\n bottom: calc(-0.5rem - 1px);\n}\n.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before {\n bottom: 0;\n border-width: 0.5rem 0.5rem 0;\n border-top-color: rgba(0, 0, 0, 0.25);\n}\n.bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after {\n bottom: 1px;\n border-width: 0.5rem 0.5rem 0;\n border-top-color: #fff;\n}\n\n.bs-popover-end > .popover-arrow, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow {\n left: calc(-0.5rem - 1px);\n width: 0.5rem;\n height: 1rem;\n}\n.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before {\n left: 0;\n border-width: 0.5rem 0.5rem 0.5rem 0;\n border-right-color: rgba(0, 0, 0, 0.25);\n}\n.bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after {\n left: 1px;\n border-width: 0.5rem 0.5rem 0.5rem 0;\n border-right-color: #fff;\n}\n\n.bs-popover-bottom > .popover-arrow, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow {\n top: calc(-0.5rem - 1px);\n}\n.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before {\n top: 0;\n border-width: 0 0.5rem 0.5rem 0.5rem;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n}\n.bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after {\n top: 1px;\n border-width: 0 0.5rem 0.5rem 0.5rem;\n border-bottom-color: #fff;\n}\n.bs-popover-bottom .popover-header::before, .bs-popover-auto[data-popper-placement^=bottom] .popover-header::before {\n position: absolute;\n top: 0;\n left: 50%;\n display: block;\n width: 1rem;\n margin-left: -0.5rem;\n content: \"\";\n border-bottom: 1px solid #f0f0f0;\n}\n\n.bs-popover-start > .popover-arrow, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow {\n right: calc(-0.5rem - 1px);\n width: 0.5rem;\n height: 1rem;\n}\n.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before {\n right: 0;\n border-width: 0.5rem 0 0.5rem 0.5rem;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n.bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after {\n right: 1px;\n border-width: 0.5rem 0 0.5rem 0.5rem;\n border-left-color: #fff;\n}\n\n.popover-header {\n padding: 0.5rem 1rem;\n margin-bottom: 0;\n font-size: 1rem;\n background-color: #f0f0f0;\n border-bottom: 1px solid rgba(0, 0, 0, 0.2);\n border-top-left-radius: calc(0.3rem - 1px);\n border-top-right-radius: calc(0.3rem - 1px);\n}\n.popover-header:empty {\n display: none;\n}\n\n.popover-body {\n padding: 1rem 1rem;\n color: #212529;\n}\n\n.carousel {\n position: relative;\n}\n\n.carousel.pointer-event {\n touch-action: pan-y;\n}\n\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n}\n.carousel-inner::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.carousel-item {\n position: relative;\n display: none;\n float: left;\n width: 100%;\n margin-right: -100%;\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n transition: transform 0.6s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .carousel-item {\n transition: none;\n }\n}\n\n.carousel-item.active,\n.carousel-item-next,\n.carousel-item-prev {\n display: block;\n}\n\n/* rtl:begin:ignore */\n.carousel-item-next:not(.carousel-item-start),\n.active.carousel-item-end {\n transform: translateX(100%);\n}\n\n.carousel-item-prev:not(.carousel-item-end),\n.active.carousel-item-start {\n transform: translateX(-100%);\n}\n\n/* rtl:end:ignore */\n.carousel-fade .carousel-item {\n opacity: 0;\n transition-property: opacity;\n transform: none;\n}\n.carousel-fade .carousel-item.active,\n.carousel-fade .carousel-item-next.carousel-item-start,\n.carousel-fade .carousel-item-prev.carousel-item-end {\n z-index: 1;\n opacity: 1;\n}\n.carousel-fade .active.carousel-item-start,\n.carousel-fade .active.carousel-item-end {\n z-index: 0;\n opacity: 0;\n transition: opacity 0s 0.6s;\n}\n@media (prefers-reduced-motion: reduce) {\n .carousel-fade .active.carousel-item-start,\n.carousel-fade .active.carousel-item-end {\n transition: none;\n }\n}\n\n.carousel-control-prev,\n.carousel-control-next {\n position: absolute;\n top: 0;\n bottom: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 15%;\n padding: 0;\n color: #fff;\n text-align: center;\n background: none;\n border: 0;\n opacity: 0.5;\n transition: opacity 0.15s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .carousel-control-prev,\n.carousel-control-next {\n transition: none;\n }\n}\n.carousel-control-prev:hover, .carousel-control-prev:focus,\n.carousel-control-next:hover,\n.carousel-control-next:focus {\n color: #fff;\n text-decoration: none;\n outline: 0;\n opacity: 0.9;\n}\n\n.carousel-control-prev {\n left: 0;\n}\n\n.carousel-control-next {\n right: 0;\n}\n\n.carousel-control-prev-icon,\n.carousel-control-next-icon {\n display: inline-block;\n width: 2rem;\n height: 2rem;\n background-repeat: no-repeat;\n background-position: 50%;\n background-size: 100% 100%;\n}\n\n/* rtl:options: {\n \"autoRename\": true,\n \"stringMap\":[ {\n \"name\" : \"prev-next\",\n \"search\" : \"prev\",\n \"replace\" : \"next\"\n } ]\n} */\n.carousel-control-prev-icon {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e\");\n}\n\n.carousel-control-next-icon {\n background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\");\n}\n\n.carousel-indicators {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 2;\n display: flex;\n justify-content: center;\n padding: 0;\n margin-right: 15%;\n margin-bottom: 1rem;\n margin-left: 15%;\n list-style: none;\n}\n.carousel-indicators [data-bs-target] {\n box-sizing: content-box;\n flex: 0 1 auto;\n width: 30px;\n height: 3px;\n padding: 0;\n margin-right: 3px;\n margin-left: 3px;\n text-indent: -999px;\n cursor: pointer;\n background-color: #fff;\n background-clip: padding-box;\n border: 0;\n border-top: 10px solid transparent;\n border-bottom: 10px solid transparent;\n opacity: 0.5;\n transition: opacity 0.6s ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .carousel-indicators [data-bs-target] {\n transition: none;\n }\n}\n.carousel-indicators .active {\n opacity: 1;\n}\n\n.carousel-caption {\n position: absolute;\n right: 15%;\n bottom: 1.25rem;\n left: 15%;\n padding-top: 1.25rem;\n padding-bottom: 1.25rem;\n color: #fff;\n text-align: center;\n}\n\n.carousel-dark .carousel-control-prev-icon,\n.carousel-dark .carousel-control-next-icon {\n filter: invert(1) grayscale(100);\n}\n.carousel-dark .carousel-indicators [data-bs-target] {\n background-color: #000;\n}\n.carousel-dark .carousel-caption {\n color: #000;\n}\n\n@-webkit-keyframes spinner-border {\n to {\n transform: rotate(360deg) /* rtl:ignore */;\n }\n}\n\n@keyframes spinner-border {\n to {\n transform: rotate(360deg) /* rtl:ignore */;\n }\n}\n.spinner-border {\n display: inline-block;\n width: 2rem;\n height: 2rem;\n vertical-align: -0.125em;\n border: 0.25em solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n -webkit-animation: 0.75s linear infinite spinner-border;\n animation: 0.75s linear infinite spinner-border;\n}\n\n.spinner-border-sm {\n width: 1rem;\n height: 1rem;\n border-width: 0.2em;\n}\n\n@-webkit-keyframes spinner-grow {\n 0% {\n transform: scale(0);\n }\n 50% {\n opacity: 1;\n transform: none;\n }\n}\n\n@keyframes spinner-grow {\n 0% {\n transform: scale(0);\n }\n 50% {\n opacity: 1;\n transform: none;\n }\n}\n.spinner-grow {\n display: inline-block;\n width: 2rem;\n height: 2rem;\n vertical-align: -0.125em;\n background-color: currentColor;\n border-radius: 50%;\n opacity: 0;\n -webkit-animation: 0.75s linear infinite spinner-grow;\n animation: 0.75s linear infinite spinner-grow;\n}\n\n.spinner-grow-sm {\n width: 1rem;\n height: 1rem;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .spinner-border,\n.spinner-grow {\n -webkit-animation-duration: 1.5s;\n animation-duration: 1.5s;\n }\n}\n.offcanvas {\n position: fixed;\n bottom: 0;\n z-index: 1045;\n display: flex;\n flex-direction: column;\n max-width: 100%;\n visibility: hidden;\n background-color: #fff;\n background-clip: padding-box;\n outline: 0;\n transition: transform 0.3s ease-in-out;\n}\n@media (prefers-reduced-motion: reduce) {\n .offcanvas {\n transition: none;\n }\n}\n\n.offcanvas-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 1040;\n width: 100vw;\n height: 100vh;\n background-color: #000;\n}\n.offcanvas-backdrop.fade {\n opacity: 0;\n}\n.offcanvas-backdrop.show {\n opacity: 0.5;\n}\n\n.offcanvas-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 1rem 1rem;\n}\n.offcanvas-header .btn-close {\n padding: 0.5rem 0.5rem;\n margin-top: -0.5rem;\n margin-right: -0.5rem;\n margin-bottom: -0.5rem;\n}\n\n.offcanvas-title {\n margin-bottom: 0;\n line-height: 1.5;\n}\n\n.offcanvas-body {\n flex-grow: 1;\n padding: 1rem 1rem;\n overflow-y: auto;\n}\n\n.offcanvas-start {\n top: 0;\n left: 0;\n width: 400px;\n border-right: 1px solid rgba(0, 0, 0, 0.2);\n transform: translateX(-100%);\n}\n\n.offcanvas-end {\n top: 0;\n right: 0;\n width: 400px;\n border-left: 1px solid rgba(0, 0, 0, 0.2);\n transform: translateX(100%);\n}\n\n.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: 30vh;\n max-height: 100%;\n border-bottom: 1px solid rgba(0, 0, 0, 0.2);\n transform: translateY(-100%);\n}\n\n.offcanvas-bottom {\n right: 0;\n left: 0;\n height: 30vh;\n max-height: 100%;\n border-top: 1px solid rgba(0, 0, 0, 0.2);\n transform: translateY(100%);\n}\n\n.offcanvas.show {\n transform: none;\n}\n\n.placeholder {\n display: inline-block;\n min-height: 1em;\n vertical-align: middle;\n cursor: wait;\n background-color: currentColor;\n opacity: 0.5;\n}\n.placeholder.btn::before {\n display: inline-block;\n content: \"\";\n}\n\n.placeholder-xs {\n min-height: 0.6em;\n}\n\n.placeholder-sm {\n min-height: 0.8em;\n}\n\n.placeholder-lg {\n min-height: 1.2em;\n}\n\n.placeholder-glow .placeholder {\n -webkit-animation: placeholder-glow 2s ease-in-out infinite;\n animation: placeholder-glow 2s ease-in-out infinite;\n}\n\n@-webkit-keyframes placeholder-glow {\n 50% {\n opacity: 0.2;\n }\n}\n\n@keyframes placeholder-glow {\n 50% {\n opacity: 0.2;\n }\n}\n.placeholder-wave {\n -webkit-mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);\n mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);\n -webkit-mask-size: 200% 100%;\n mask-size: 200% 100%;\n -webkit-animation: placeholder-wave 2s linear infinite;\n animation: placeholder-wave 2s linear infinite;\n}\n\n@-webkit-keyframes placeholder-wave {\n 100% {\n -webkit-mask-position: -200% 0%;\n mask-position: -200% 0%;\n }\n}\n\n@keyframes placeholder-wave {\n 100% {\n -webkit-mask-position: -200% 0%;\n mask-position: -200% 0%;\n }\n}\n.clearfix::after {\n display: block;\n clear: both;\n content: \"\";\n}\n\n.link-primary {\n color: #0d6efd;\n}\n.link-primary:hover, .link-primary:focus {\n color: #0a58ca;\n}\n\n.link-secondary {\n color: #6c757d;\n}\n.link-secondary:hover, .link-secondary:focus {\n color: #565e64;\n}\n\n.link-success {\n color: #198754;\n}\n.link-success:hover, .link-success:focus {\n color: #146c43;\n}\n\n.link-info {\n color: #0dcaf0;\n}\n.link-info:hover, .link-info:focus {\n color: #3dd5f3;\n}\n\n.link-warning {\n color: #ffc107;\n}\n.link-warning:hover, .link-warning:focus {\n color: #ffcd39;\n}\n\n.link-danger {\n color: #dc3545;\n}\n.link-danger:hover, .link-danger:focus {\n color: #b02a37;\n}\n\n.link-light {\n color: #f8f9fa;\n}\n.link-light:hover, .link-light:focus {\n color: #f9fafb;\n}\n\n.link-dark {\n color: #212529;\n}\n.link-dark:hover, .link-dark:focus {\n color: #1a1e21;\n}\n\n.ratio {\n position: relative;\n width: 100%;\n}\n.ratio::before {\n display: block;\n padding-top: var(--bs-aspect-ratio);\n content: \"\";\n}\n.ratio > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n}\n\n.ratio-1x1 {\n --bs-aspect-ratio: 100%;\n}\n\n.ratio-4x3 {\n --bs-aspect-ratio: 75%;\n}\n\n.ratio-16x9 {\n --bs-aspect-ratio: 56.25%;\n}\n\n.ratio-21x9 {\n --bs-aspect-ratio: 42.8571428571%;\n}\n\n.fixed-top {\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n\n.fixed-bottom {\n position: fixed;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1030;\n}\n\n.sticky-top {\n position: -webkit-sticky;\n position: sticky;\n top: 0;\n z-index: 1020;\n}\n\n@media (min-width: 576px) {\n .sticky-sm-top {\n position: -webkit-sticky;\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n}\n@media (min-width: 768px) {\n .sticky-md-top {\n position: -webkit-sticky;\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n}\n@media (min-width: 992px) {\n .sticky-lg-top {\n position: -webkit-sticky;\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n}\n@media (min-width: 1200px) {\n .sticky-xl-top {\n position: -webkit-sticky;\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n}\n@media (min-width: 1400px) {\n .sticky-xxl-top {\n position: -webkit-sticky;\n position: sticky;\n top: 0;\n z-index: 1020;\n }\n}\n.hstack {\n display: flex;\n flex-direction: row;\n align-items: center;\n align-self: stretch;\n}\n\n.vstack {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n align-self: stretch;\n}\n\n.visually-hidden,\n.visually-hidden-focusable:not(:focus):not(:focus-within) {\n position: absolute !important;\n width: 1px !important;\n height: 1px !important;\n padding: 0 !important;\n margin: -1px !important;\n overflow: hidden !important;\n clip: rect(0, 0, 0, 0) !important;\n white-space: nowrap !important;\n border: 0 !important;\n}\n\n.stretched-link::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1;\n content: \"\";\n}\n\n.text-truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.vr {\n display: inline-block;\n align-self: stretch;\n width: 1px;\n min-height: 1em;\n background-color: currentColor;\n opacity: 0.25;\n}\n\n.align-baseline {\n vertical-align: baseline !important;\n}\n\n.align-top {\n vertical-align: top !important;\n}\n\n.align-middle {\n vertical-align: middle !important;\n}\n\n.align-bottom {\n vertical-align: bottom !important;\n}\n\n.align-text-bottom {\n vertical-align: text-bottom !important;\n}\n\n.align-text-top {\n vertical-align: text-top !important;\n}\n\n.float-start {\n float: left !important;\n}\n\n.float-end {\n float: right !important;\n}\n\n.float-none {\n float: none !important;\n}\n\n.opacity-0 {\n opacity: 0 !important;\n}\n\n.opacity-25 {\n opacity: 0.25 !important;\n}\n\n.opacity-50 {\n opacity: 0.5 !important;\n}\n\n.opacity-75 {\n opacity: 0.75 !important;\n}\n\n.opacity-100 {\n opacity: 1 !important;\n}\n\n.overflow-auto {\n overflow: auto !important;\n}\n\n.overflow-hidden {\n overflow: hidden !important;\n}\n\n.overflow-visible {\n overflow: visible !important;\n}\n\n.overflow-scroll {\n overflow: scroll !important;\n}\n\n.d-inline {\n display: inline !important;\n}\n\n.d-inline-block {\n display: inline-block !important;\n}\n\n.d-block {\n display: block !important;\n}\n\n.d-grid {\n display: grid !important;\n}\n\n.d-table {\n display: table !important;\n}\n\n.d-table-row {\n display: table-row !important;\n}\n\n.d-table-cell {\n display: table-cell !important;\n}\n\n.d-flex {\n display: flex !important;\n}\n\n.d-inline-flex {\n display: inline-flex !important;\n}\n\n.d-none {\n display: none !important;\n}\n\n.shadow {\n box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;\n}\n\n.shadow-sm {\n box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important;\n}\n\n.shadow-lg {\n box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important;\n}\n\n.shadow-none {\n box-shadow: none !important;\n}\n\n.position-static {\n position: static !important;\n}\n\n.position-relative {\n position: relative !important;\n}\n\n.position-absolute {\n position: absolute !important;\n}\n\n.position-fixed {\n position: fixed !important;\n}\n\n.position-sticky {\n position: -webkit-sticky !important;\n position: sticky !important;\n}\n\n.top-0 {\n top: 0 !important;\n}\n\n.top-50 {\n top: 50% !important;\n}\n\n.top-100 {\n top: 100% !important;\n}\n\n.bottom-0 {\n bottom: 0 !important;\n}\n\n.bottom-50 {\n bottom: 50% !important;\n}\n\n.bottom-100 {\n bottom: 100% !important;\n}\n\n.start-0 {\n left: 0 !important;\n}\n\n.start-50 {\n left: 50% !important;\n}\n\n.start-100 {\n left: 100% !important;\n}\n\n.end-0 {\n right: 0 !important;\n}\n\n.end-50 {\n right: 50% !important;\n}\n\n.end-100 {\n right: 100% !important;\n}\n\n.translate-middle {\n transform: translate(-50%, -50%) !important;\n}\n\n.translate-middle-x {\n transform: translateX(-50%) !important;\n}\n\n.translate-middle-y {\n transform: translateY(-50%) !important;\n}\n\n.border {\n border: 1px solid #dee2e6 !important;\n}\n\n.border-0 {\n border: 0 !important;\n}\n\n.border-top {\n border-top: 1px solid #dee2e6 !important;\n}\n\n.border-top-0 {\n border-top: 0 !important;\n}\n\n.border-end {\n border-right: 1px solid #dee2e6 !important;\n}\n\n.border-end-0 {\n border-right: 0 !important;\n}\n\n.border-bottom {\n border-bottom: 1px solid #dee2e6 !important;\n}\n\n.border-bottom-0 {\n border-bottom: 0 !important;\n}\n\n.border-start {\n border-left: 1px solid #dee2e6 !important;\n}\n\n.border-start-0 {\n border-left: 0 !important;\n}\n\n.border-primary {\n border-color: #0d6efd !important;\n}\n\n.border-secondary {\n border-color: #6c757d !important;\n}\n\n.border-success {\n border-color: #198754 !important;\n}\n\n.border-info {\n border-color: #0dcaf0 !important;\n}\n\n.border-warning {\n border-color: #ffc107 !important;\n}\n\n.border-danger {\n border-color: #dc3545 !important;\n}\n\n.border-light {\n border-color: #f8f9fa !important;\n}\n\n.border-dark {\n border-color: #212529 !important;\n}\n\n.border-white {\n border-color: #fff !important;\n}\n\n.border-1 {\n border-width: 1px !important;\n}\n\n.border-2 {\n border-width: 2px !important;\n}\n\n.border-3 {\n border-width: 3px !important;\n}\n\n.border-4 {\n border-width: 4px !important;\n}\n\n.border-5 {\n border-width: 5px !important;\n}\n\n.w-25 {\n width: 25% !important;\n}\n\n.w-50 {\n width: 50% !important;\n}\n\n.w-75 {\n width: 75% !important;\n}\n\n.w-100 {\n width: 100% !important;\n}\n\n.w-auto {\n width: auto !important;\n}\n\n.mw-100 {\n max-width: 100% !important;\n}\n\n.vw-100 {\n width: 100vw !important;\n}\n\n.min-vw-100 {\n min-width: 100vw !important;\n}\n\n.h-25 {\n height: 25% !important;\n}\n\n.h-50 {\n height: 50% !important;\n}\n\n.h-75 {\n height: 75% !important;\n}\n\n.h-100 {\n height: 100% !important;\n}\n\n.h-auto {\n height: auto !important;\n}\n\n.mh-100 {\n max-height: 100% !important;\n}\n\n.vh-100 {\n height: 100vh !important;\n}\n\n.min-vh-100 {\n min-height: 100vh !important;\n}\n\n.flex-fill {\n flex: 1 1 auto !important;\n}\n\n.flex-row {\n flex-direction: row !important;\n}\n\n.flex-column {\n flex-direction: column !important;\n}\n\n.flex-row-reverse {\n flex-direction: row-reverse !important;\n}\n\n.flex-column-reverse {\n flex-direction: column-reverse !important;\n}\n\n.flex-grow-0 {\n flex-grow: 0 !important;\n}\n\n.flex-grow-1 {\n flex-grow: 1 !important;\n}\n\n.flex-shrink-0 {\n flex-shrink: 0 !important;\n}\n\n.flex-shrink-1 {\n flex-shrink: 1 !important;\n}\n\n.flex-wrap {\n flex-wrap: wrap !important;\n}\n\n.flex-nowrap {\n flex-wrap: nowrap !important;\n}\n\n.flex-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n}\n\n.gap-0 {\n gap: 0 !important;\n}\n\n.gap-1 {\n gap: 0.25rem !important;\n}\n\n.gap-2 {\n gap: 0.5rem !important;\n}\n\n.gap-3 {\n gap: 1rem !important;\n}\n\n.gap-4 {\n gap: 1.5rem !important;\n}\n\n.gap-5 {\n gap: 3rem !important;\n}\n\n.justify-content-start {\n justify-content: flex-start !important;\n}\n\n.justify-content-end {\n justify-content: flex-end !important;\n}\n\n.justify-content-center {\n justify-content: center !important;\n}\n\n.justify-content-between {\n justify-content: space-between !important;\n}\n\n.justify-content-around {\n justify-content: space-around !important;\n}\n\n.justify-content-evenly {\n justify-content: space-evenly !important;\n}\n\n.align-items-start {\n align-items: flex-start !important;\n}\n\n.align-items-end {\n align-items: flex-end !important;\n}\n\n.align-items-center {\n align-items: center !important;\n}\n\n.align-items-baseline {\n align-items: baseline !important;\n}\n\n.align-items-stretch {\n align-items: stretch !important;\n}\n\n.align-content-start {\n align-content: flex-start !important;\n}\n\n.align-content-end {\n align-content: flex-end !important;\n}\n\n.align-content-center {\n align-content: center !important;\n}\n\n.align-content-between {\n align-content: space-between !important;\n}\n\n.align-content-around {\n align-content: space-around !important;\n}\n\n.align-content-stretch {\n align-content: stretch !important;\n}\n\n.align-self-auto {\n align-self: auto !important;\n}\n\n.align-self-start {\n align-self: flex-start !important;\n}\n\n.align-self-end {\n align-self: flex-end !important;\n}\n\n.align-self-center {\n align-self: center !important;\n}\n\n.align-self-baseline {\n align-self: baseline !important;\n}\n\n.align-self-stretch {\n align-self: stretch !important;\n}\n\n.order-first {\n order: -1 !important;\n}\n\n.order-0 {\n order: 0 !important;\n}\n\n.order-1 {\n order: 1 !important;\n}\n\n.order-2 {\n order: 2 !important;\n}\n\n.order-3 {\n order: 3 !important;\n}\n\n.order-4 {\n order: 4 !important;\n}\n\n.order-5 {\n order: 5 !important;\n}\n\n.order-last {\n order: 6 !important;\n}\n\n.m-0 {\n margin: 0 !important;\n}\n\n.m-1 {\n margin: 0.25rem !important;\n}\n\n.m-2 {\n margin: 0.5rem !important;\n}\n\n.m-3 {\n margin: 1rem !important;\n}\n\n.m-4 {\n margin: 1.5rem !important;\n}\n\n.m-5 {\n margin: 3rem !important;\n}\n\n.m-auto {\n margin: auto !important;\n}\n\n.mx-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n}\n\n.mx-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n}\n\n.mx-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n}\n\n.mx-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n}\n\n.mx-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n}\n\n.mx-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n}\n\n.mx-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n}\n\n.my-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n.my-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n}\n\n.my-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n}\n\n.my-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n}\n\n.my-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n}\n\n.my-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n}\n\n.my-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n}\n\n.mt-0 {\n margin-top: 0 !important;\n}\n\n.mt-1 {\n margin-top: 0.25rem !important;\n}\n\n.mt-2 {\n margin-top: 0.5rem !important;\n}\n\n.mt-3 {\n margin-top: 1rem !important;\n}\n\n.mt-4 {\n margin-top: 1.5rem !important;\n}\n\n.mt-5 {\n margin-top: 3rem !important;\n}\n\n.mt-auto {\n margin-top: auto !important;\n}\n\n.me-0 {\n margin-right: 0 !important;\n}\n\n.me-1 {\n margin-right: 0.25rem !important;\n}\n\n.me-2 {\n margin-right: 0.5rem !important;\n}\n\n.me-3 {\n margin-right: 1rem !important;\n}\n\n.me-4 {\n margin-right: 1.5rem !important;\n}\n\n.me-5 {\n margin-right: 3rem !important;\n}\n\n.me-auto {\n margin-right: auto !important;\n}\n\n.mb-0 {\n margin-bottom: 0 !important;\n}\n\n.mb-1 {\n margin-bottom: 0.25rem !important;\n}\n\n.mb-2 {\n margin-bottom: 0.5rem !important;\n}\n\n.mb-3 {\n margin-bottom: 1rem !important;\n}\n\n.mb-4 {\n margin-bottom: 1.5rem !important;\n}\n\n.mb-5 {\n margin-bottom: 3rem !important;\n}\n\n.mb-auto {\n margin-bottom: auto !important;\n}\n\n.ms-0 {\n margin-left: 0 !important;\n}\n\n.ms-1 {\n margin-left: 0.25rem !important;\n}\n\n.ms-2 {\n margin-left: 0.5rem !important;\n}\n\n.ms-3 {\n margin-left: 1rem !important;\n}\n\n.ms-4 {\n margin-left: 1.5rem !important;\n}\n\n.ms-5 {\n margin-left: 3rem !important;\n}\n\n.ms-auto {\n margin-left: auto !important;\n}\n\n.p-0 {\n padding: 0 !important;\n}\n\n.p-1 {\n padding: 0.25rem !important;\n}\n\n.p-2 {\n padding: 0.5rem !important;\n}\n\n.p-3 {\n padding: 1rem !important;\n}\n\n.p-4 {\n padding: 1.5rem !important;\n}\n\n.p-5 {\n padding: 3rem !important;\n}\n\n.px-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n}\n\n.px-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n}\n\n.px-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n}\n\n.px-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n}\n\n.px-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n}\n\n.px-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n}\n\n.py-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n}\n\n.py-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n}\n\n.py-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n}\n\n.py-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n}\n\n.py-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n}\n\n.py-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n}\n\n.pt-0 {\n padding-top: 0 !important;\n}\n\n.pt-1 {\n padding-top: 0.25rem !important;\n}\n\n.pt-2 {\n padding-top: 0.5rem !important;\n}\n\n.pt-3 {\n padding-top: 1rem !important;\n}\n\n.pt-4 {\n padding-top: 1.5rem !important;\n}\n\n.pt-5 {\n padding-top: 3rem !important;\n}\n\n.pe-0 {\n padding-right: 0 !important;\n}\n\n.pe-1 {\n padding-right: 0.25rem !important;\n}\n\n.pe-2 {\n padding-right: 0.5rem !important;\n}\n\n.pe-3 {\n padding-right: 1rem !important;\n}\n\n.pe-4 {\n padding-right: 1.5rem !important;\n}\n\n.pe-5 {\n padding-right: 3rem !important;\n}\n\n.pb-0 {\n padding-bottom: 0 !important;\n}\n\n.pb-1 {\n padding-bottom: 0.25rem !important;\n}\n\n.pb-2 {\n padding-bottom: 0.5rem !important;\n}\n\n.pb-3 {\n padding-bottom: 1rem !important;\n}\n\n.pb-4 {\n padding-bottom: 1.5rem !important;\n}\n\n.pb-5 {\n padding-bottom: 3rem !important;\n}\n\n.ps-0 {\n padding-left: 0 !important;\n}\n\n.ps-1 {\n padding-left: 0.25rem !important;\n}\n\n.ps-2 {\n padding-left: 0.5rem !important;\n}\n\n.ps-3 {\n padding-left: 1rem !important;\n}\n\n.ps-4 {\n padding-left: 1.5rem !important;\n}\n\n.ps-5 {\n padding-left: 3rem !important;\n}\n\n.font-monospace {\n font-family: var(--bs-font-monospace) !important;\n}\n\n.fs-1 {\n font-size: calc(1.375rem + 1.5vw) !important;\n}\n\n.fs-2 {\n font-size: calc(1.325rem + 0.9vw) !important;\n}\n\n.fs-3 {\n font-size: calc(1.3rem + 0.6vw) !important;\n}\n\n.fs-4 {\n font-size: calc(1.275rem + 0.3vw) !important;\n}\n\n.fs-5 {\n font-size: 1.25rem !important;\n}\n\n.fs-6 {\n font-size: 1rem !important;\n}\n\n.fst-italic {\n font-style: italic !important;\n}\n\n.fst-normal {\n font-style: normal !important;\n}\n\n.fw-light {\n font-weight: 300 !important;\n}\n\n.fw-lighter {\n font-weight: lighter !important;\n}\n\n.fw-normal {\n font-weight: 400 !important;\n}\n\n.fw-bold {\n font-weight: 700 !important;\n}\n\n.fw-bolder {\n font-weight: bolder !important;\n}\n\n.lh-1 {\n line-height: 1 !important;\n}\n\n.lh-sm {\n line-height: 1.25 !important;\n}\n\n.lh-base {\n line-height: 1.5 !important;\n}\n\n.lh-lg {\n line-height: 2 !important;\n}\n\n.text-start {\n text-align: left !important;\n}\n\n.text-end {\n text-align: right !important;\n}\n\n.text-center {\n text-align: center !important;\n}\n\n.text-decoration-none {\n text-decoration: none !important;\n}\n\n.text-decoration-underline {\n text-decoration: underline !important;\n}\n\n.text-decoration-line-through {\n text-decoration: line-through !important;\n}\n\n.text-lowercase {\n text-transform: lowercase !important;\n}\n\n.text-uppercase {\n text-transform: uppercase !important;\n}\n\n.text-capitalize {\n text-transform: capitalize !important;\n}\n\n.text-wrap {\n white-space: normal !important;\n}\n\n.text-nowrap {\n white-space: nowrap !important;\n}\n\n/* rtl:begin:remove */\n.text-break {\n word-wrap: break-word !important;\n word-break: break-word !important;\n}\n\n/* rtl:end:remove */\n.text-primary {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-secondary {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-success {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-info {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-warning {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-danger {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-light {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-dark {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-black {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-white {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-body {\n --bs-text-opacity: 1;\n color: rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important;\n}\n\n.text-muted {\n --bs-text-opacity: 1;\n color: #6c757d !important;\n}\n\n.text-black-50 {\n --bs-text-opacity: 1;\n color: rgba(0, 0, 0, 0.5) !important;\n}\n\n.text-white-50 {\n --bs-text-opacity: 1;\n color: rgba(255, 255, 255, 0.5) !important;\n}\n\n.text-reset {\n --bs-text-opacity: 1;\n color: inherit !important;\n}\n\n.text-opacity-25 {\n --bs-text-opacity: 0.25;\n}\n\n.text-opacity-50 {\n --bs-text-opacity: 0.5;\n}\n\n.text-opacity-75 {\n --bs-text-opacity: 0.75;\n}\n\n.text-opacity-100 {\n --bs-text-opacity: 1;\n}\n\n.bg-primary {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-secondary {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-success {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-info {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-warning {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-danger {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-light {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-dark {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-black {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-white {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-body {\n --bs-bg-opacity: 1;\n background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;\n}\n\n.bg-transparent {\n --bs-bg-opacity: 1;\n background-color: transparent !important;\n}\n\n.bg-opacity-10 {\n --bs-bg-opacity: 0.1;\n}\n\n.bg-opacity-25 {\n --bs-bg-opacity: 0.25;\n}\n\n.bg-opacity-50 {\n --bs-bg-opacity: 0.5;\n}\n\n.bg-opacity-75 {\n --bs-bg-opacity: 0.75;\n}\n\n.bg-opacity-100 {\n --bs-bg-opacity: 1;\n}\n\n.bg-gradient {\n background-image: var(--bs-gradient) !important;\n}\n\n.user-select-all {\n -webkit-user-select: all !important;\n -moz-user-select: all !important;\n user-select: all !important;\n}\n\n.user-select-auto {\n -webkit-user-select: auto !important;\n -moz-user-select: auto !important;\n user-select: auto !important;\n}\n\n.user-select-none {\n -webkit-user-select: none !important;\n -moz-user-select: none !important;\n user-select: none !important;\n}\n\n.pe-none {\n pointer-events: none !important;\n}\n\n.pe-auto {\n pointer-events: auto !important;\n}\n\n.rounded {\n border-radius: 0.25rem !important;\n}\n\n.rounded-0 {\n border-radius: 0 !important;\n}\n\n.rounded-1 {\n border-radius: 0.2rem !important;\n}\n\n.rounded-2 {\n border-radius: 0.25rem !important;\n}\n\n.rounded-3 {\n border-radius: 0.3rem !important;\n}\n\n.rounded-circle {\n border-radius: 50% !important;\n}\n\n.rounded-pill {\n border-radius: 50rem !important;\n}\n\n.rounded-top {\n border-top-left-radius: 0.25rem !important;\n border-top-right-radius: 0.25rem !important;\n}\n\n.rounded-end {\n border-top-right-radius: 0.25rem !important;\n border-bottom-right-radius: 0.25rem !important;\n}\n\n.rounded-bottom {\n border-bottom-right-radius: 0.25rem !important;\n border-bottom-left-radius: 0.25rem !important;\n}\n\n.rounded-start {\n border-bottom-left-radius: 0.25rem !important;\n border-top-left-radius: 0.25rem !important;\n}\n\n.visible {\n visibility: visible !important;\n}\n\n.invisible {\n visibility: hidden !important;\n}\n\n@media (min-width: 576px) {\n .float-sm-start {\n float: left !important;\n }\n\n .float-sm-end {\n float: right !important;\n }\n\n .float-sm-none {\n float: none !important;\n }\n\n .d-sm-inline {\n display: inline !important;\n }\n\n .d-sm-inline-block {\n display: inline-block !important;\n }\n\n .d-sm-block {\n display: block !important;\n }\n\n .d-sm-grid {\n display: grid !important;\n }\n\n .d-sm-table {\n display: table !important;\n }\n\n .d-sm-table-row {\n display: table-row !important;\n }\n\n .d-sm-table-cell {\n display: table-cell !important;\n }\n\n .d-sm-flex {\n display: flex !important;\n }\n\n .d-sm-inline-flex {\n display: inline-flex !important;\n }\n\n .d-sm-none {\n display: none !important;\n }\n\n .flex-sm-fill {\n flex: 1 1 auto !important;\n }\n\n .flex-sm-row {\n flex-direction: row !important;\n }\n\n .flex-sm-column {\n flex-direction: column !important;\n }\n\n .flex-sm-row-reverse {\n flex-direction: row-reverse !important;\n }\n\n .flex-sm-column-reverse {\n flex-direction: column-reverse !important;\n }\n\n .flex-sm-grow-0 {\n flex-grow: 0 !important;\n }\n\n .flex-sm-grow-1 {\n flex-grow: 1 !important;\n }\n\n .flex-sm-shrink-0 {\n flex-shrink: 0 !important;\n }\n\n .flex-sm-shrink-1 {\n flex-shrink: 1 !important;\n }\n\n .flex-sm-wrap {\n flex-wrap: wrap !important;\n }\n\n .flex-sm-nowrap {\n flex-wrap: nowrap !important;\n }\n\n .flex-sm-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n\n .gap-sm-0 {\n gap: 0 !important;\n }\n\n .gap-sm-1 {\n gap: 0.25rem !important;\n }\n\n .gap-sm-2 {\n gap: 0.5rem !important;\n }\n\n .gap-sm-3 {\n gap: 1rem !important;\n }\n\n .gap-sm-4 {\n gap: 1.5rem !important;\n }\n\n .gap-sm-5 {\n gap: 3rem !important;\n }\n\n .justify-content-sm-start {\n justify-content: flex-start !important;\n }\n\n .justify-content-sm-end {\n justify-content: flex-end !important;\n }\n\n .justify-content-sm-center {\n justify-content: center !important;\n }\n\n .justify-content-sm-between {\n justify-content: space-between !important;\n }\n\n .justify-content-sm-around {\n justify-content: space-around !important;\n }\n\n .justify-content-sm-evenly {\n justify-content: space-evenly !important;\n }\n\n .align-items-sm-start {\n align-items: flex-start !important;\n }\n\n .align-items-sm-end {\n align-items: flex-end !important;\n }\n\n .align-items-sm-center {\n align-items: center !important;\n }\n\n .align-items-sm-baseline {\n align-items: baseline !important;\n }\n\n .align-items-sm-stretch {\n align-items: stretch !important;\n }\n\n .align-content-sm-start {\n align-content: flex-start !important;\n }\n\n .align-content-sm-end {\n align-content: flex-end !important;\n }\n\n .align-content-sm-center {\n align-content: center !important;\n }\n\n .align-content-sm-between {\n align-content: space-between !important;\n }\n\n .align-content-sm-around {\n align-content: space-around !important;\n }\n\n .align-content-sm-stretch {\n align-content: stretch !important;\n }\n\n .align-self-sm-auto {\n align-self: auto !important;\n }\n\n .align-self-sm-start {\n align-self: flex-start !important;\n }\n\n .align-self-sm-end {\n align-self: flex-end !important;\n }\n\n .align-self-sm-center {\n align-self: center !important;\n }\n\n .align-self-sm-baseline {\n align-self: baseline !important;\n }\n\n .align-self-sm-stretch {\n align-self: stretch !important;\n }\n\n .order-sm-first {\n order: -1 !important;\n }\n\n .order-sm-0 {\n order: 0 !important;\n }\n\n .order-sm-1 {\n order: 1 !important;\n }\n\n .order-sm-2 {\n order: 2 !important;\n }\n\n .order-sm-3 {\n order: 3 !important;\n }\n\n .order-sm-4 {\n order: 4 !important;\n }\n\n .order-sm-5 {\n order: 5 !important;\n }\n\n .order-sm-last {\n order: 6 !important;\n }\n\n .m-sm-0 {\n margin: 0 !important;\n }\n\n .m-sm-1 {\n margin: 0.25rem !important;\n }\n\n .m-sm-2 {\n margin: 0.5rem !important;\n }\n\n .m-sm-3 {\n margin: 1rem !important;\n }\n\n .m-sm-4 {\n margin: 1.5rem !important;\n }\n\n .m-sm-5 {\n margin: 3rem !important;\n }\n\n .m-sm-auto {\n margin: auto !important;\n }\n\n .mx-sm-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n\n .mx-sm-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n\n .mx-sm-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n\n .mx-sm-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n\n .mx-sm-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n\n .mx-sm-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n\n .mx-sm-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n\n .my-sm-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n\n .my-sm-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n\n .my-sm-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n\n .my-sm-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n\n .my-sm-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n\n .my-sm-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n\n .my-sm-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n\n .mt-sm-0 {\n margin-top: 0 !important;\n }\n\n .mt-sm-1 {\n margin-top: 0.25rem !important;\n }\n\n .mt-sm-2 {\n margin-top: 0.5rem !important;\n }\n\n .mt-sm-3 {\n margin-top: 1rem !important;\n }\n\n .mt-sm-4 {\n margin-top: 1.5rem !important;\n }\n\n .mt-sm-5 {\n margin-top: 3rem !important;\n }\n\n .mt-sm-auto {\n margin-top: auto !important;\n }\n\n .me-sm-0 {\n margin-right: 0 !important;\n }\n\n .me-sm-1 {\n margin-right: 0.25rem !important;\n }\n\n .me-sm-2 {\n margin-right: 0.5rem !important;\n }\n\n .me-sm-3 {\n margin-right: 1rem !important;\n }\n\n .me-sm-4 {\n margin-right: 1.5rem !important;\n }\n\n .me-sm-5 {\n margin-right: 3rem !important;\n }\n\n .me-sm-auto {\n margin-right: auto !important;\n }\n\n .mb-sm-0 {\n margin-bottom: 0 !important;\n }\n\n .mb-sm-1 {\n margin-bottom: 0.25rem !important;\n }\n\n .mb-sm-2 {\n margin-bottom: 0.5rem !important;\n }\n\n .mb-sm-3 {\n margin-bottom: 1rem !important;\n }\n\n .mb-sm-4 {\n margin-bottom: 1.5rem !important;\n }\n\n .mb-sm-5 {\n margin-bottom: 3rem !important;\n }\n\n .mb-sm-auto {\n margin-bottom: auto !important;\n }\n\n .ms-sm-0 {\n margin-left: 0 !important;\n }\n\n .ms-sm-1 {\n margin-left: 0.25rem !important;\n }\n\n .ms-sm-2 {\n margin-left: 0.5rem !important;\n }\n\n .ms-sm-3 {\n margin-left: 1rem !important;\n }\n\n .ms-sm-4 {\n margin-left: 1.5rem !important;\n }\n\n .ms-sm-5 {\n margin-left: 3rem !important;\n }\n\n .ms-sm-auto {\n margin-left: auto !important;\n }\n\n .p-sm-0 {\n padding: 0 !important;\n }\n\n .p-sm-1 {\n padding: 0.25rem !important;\n }\n\n .p-sm-2 {\n padding: 0.5rem !important;\n }\n\n .p-sm-3 {\n padding: 1rem !important;\n }\n\n .p-sm-4 {\n padding: 1.5rem !important;\n }\n\n .p-sm-5 {\n padding: 3rem !important;\n }\n\n .px-sm-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n\n .px-sm-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n\n .px-sm-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n\n .px-sm-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n\n .px-sm-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n\n .px-sm-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n\n .py-sm-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n\n .py-sm-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n\n .py-sm-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n\n .py-sm-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n\n .py-sm-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n\n .py-sm-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n\n .pt-sm-0 {\n padding-top: 0 !important;\n }\n\n .pt-sm-1 {\n padding-top: 0.25rem !important;\n }\n\n .pt-sm-2 {\n padding-top: 0.5rem !important;\n }\n\n .pt-sm-3 {\n padding-top: 1rem !important;\n }\n\n .pt-sm-4 {\n padding-top: 1.5rem !important;\n }\n\n .pt-sm-5 {\n padding-top: 3rem !important;\n }\n\n .pe-sm-0 {\n padding-right: 0 !important;\n }\n\n .pe-sm-1 {\n padding-right: 0.25rem !important;\n }\n\n .pe-sm-2 {\n padding-right: 0.5rem !important;\n }\n\n .pe-sm-3 {\n padding-right: 1rem !important;\n }\n\n .pe-sm-4 {\n padding-right: 1.5rem !important;\n }\n\n .pe-sm-5 {\n padding-right: 3rem !important;\n }\n\n .pb-sm-0 {\n padding-bottom: 0 !important;\n }\n\n .pb-sm-1 {\n padding-bottom: 0.25rem !important;\n }\n\n .pb-sm-2 {\n padding-bottom: 0.5rem !important;\n }\n\n .pb-sm-3 {\n padding-bottom: 1rem !important;\n }\n\n .pb-sm-4 {\n padding-bottom: 1.5rem !important;\n }\n\n .pb-sm-5 {\n padding-bottom: 3rem !important;\n }\n\n .ps-sm-0 {\n padding-left: 0 !important;\n }\n\n .ps-sm-1 {\n padding-left: 0.25rem !important;\n }\n\n .ps-sm-2 {\n padding-left: 0.5rem !important;\n }\n\n .ps-sm-3 {\n padding-left: 1rem !important;\n }\n\n .ps-sm-4 {\n padding-left: 1.5rem !important;\n }\n\n .ps-sm-5 {\n padding-left: 3rem !important;\n }\n\n .text-sm-start {\n text-align: left !important;\n }\n\n .text-sm-end {\n text-align: right !important;\n }\n\n .text-sm-center {\n text-align: center !important;\n }\n}\n@media (min-width: 768px) {\n .float-md-start {\n float: left !important;\n }\n\n .float-md-end {\n float: right !important;\n }\n\n .float-md-none {\n float: none !important;\n }\n\n .d-md-inline {\n display: inline !important;\n }\n\n .d-md-inline-block {\n display: inline-block !important;\n }\n\n .d-md-block {\n display: block !important;\n }\n\n .d-md-grid {\n display: grid !important;\n }\n\n .d-md-table {\n display: table !important;\n }\n\n .d-md-table-row {\n display: table-row !important;\n }\n\n .d-md-table-cell {\n display: table-cell !important;\n }\n\n .d-md-flex {\n display: flex !important;\n }\n\n .d-md-inline-flex {\n display: inline-flex !important;\n }\n\n .d-md-none {\n display: none !important;\n }\n\n .flex-md-fill {\n flex: 1 1 auto !important;\n }\n\n .flex-md-row {\n flex-direction: row !important;\n }\n\n .flex-md-column {\n flex-direction: column !important;\n }\n\n .flex-md-row-reverse {\n flex-direction: row-reverse !important;\n }\n\n .flex-md-column-reverse {\n flex-direction: column-reverse !important;\n }\n\n .flex-md-grow-0 {\n flex-grow: 0 !important;\n }\n\n .flex-md-grow-1 {\n flex-grow: 1 !important;\n }\n\n .flex-md-shrink-0 {\n flex-shrink: 0 !important;\n }\n\n .flex-md-shrink-1 {\n flex-shrink: 1 !important;\n }\n\n .flex-md-wrap {\n flex-wrap: wrap !important;\n }\n\n .flex-md-nowrap {\n flex-wrap: nowrap !important;\n }\n\n .flex-md-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n\n .gap-md-0 {\n gap: 0 !important;\n }\n\n .gap-md-1 {\n gap: 0.25rem !important;\n }\n\n .gap-md-2 {\n gap: 0.5rem !important;\n }\n\n .gap-md-3 {\n gap: 1rem !important;\n }\n\n .gap-md-4 {\n gap: 1.5rem !important;\n }\n\n .gap-md-5 {\n gap: 3rem !important;\n }\n\n .justify-content-md-start {\n justify-content: flex-start !important;\n }\n\n .justify-content-md-end {\n justify-content: flex-end !important;\n }\n\n .justify-content-md-center {\n justify-content: center !important;\n }\n\n .justify-content-md-between {\n justify-content: space-between !important;\n }\n\n .justify-content-md-around {\n justify-content: space-around !important;\n }\n\n .justify-content-md-evenly {\n justify-content: space-evenly !important;\n }\n\n .align-items-md-start {\n align-items: flex-start !important;\n }\n\n .align-items-md-end {\n align-items: flex-end !important;\n }\n\n .align-items-md-center {\n align-items: center !important;\n }\n\n .align-items-md-baseline {\n align-items: baseline !important;\n }\n\n .align-items-md-stretch {\n align-items: stretch !important;\n }\n\n .align-content-md-start {\n align-content: flex-start !important;\n }\n\n .align-content-md-end {\n align-content: flex-end !important;\n }\n\n .align-content-md-center {\n align-content: center !important;\n }\n\n .align-content-md-between {\n align-content: space-between !important;\n }\n\n .align-content-md-around {\n align-content: space-around !important;\n }\n\n .align-content-md-stretch {\n align-content: stretch !important;\n }\n\n .align-self-md-auto {\n align-self: auto !important;\n }\n\n .align-self-md-start {\n align-self: flex-start !important;\n }\n\n .align-self-md-end {\n align-self: flex-end !important;\n }\n\n .align-self-md-center {\n align-self: center !important;\n }\n\n .align-self-md-baseline {\n align-self: baseline !important;\n }\n\n .align-self-md-stretch {\n align-self: stretch !important;\n }\n\n .order-md-first {\n order: -1 !important;\n }\n\n .order-md-0 {\n order: 0 !important;\n }\n\n .order-md-1 {\n order: 1 !important;\n }\n\n .order-md-2 {\n order: 2 !important;\n }\n\n .order-md-3 {\n order: 3 !important;\n }\n\n .order-md-4 {\n order: 4 !important;\n }\n\n .order-md-5 {\n order: 5 !important;\n }\n\n .order-md-last {\n order: 6 !important;\n }\n\n .m-md-0 {\n margin: 0 !important;\n }\n\n .m-md-1 {\n margin: 0.25rem !important;\n }\n\n .m-md-2 {\n margin: 0.5rem !important;\n }\n\n .m-md-3 {\n margin: 1rem !important;\n }\n\n .m-md-4 {\n margin: 1.5rem !important;\n }\n\n .m-md-5 {\n margin: 3rem !important;\n }\n\n .m-md-auto {\n margin: auto !important;\n }\n\n .mx-md-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n\n .mx-md-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n\n .mx-md-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n\n .mx-md-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n\n .mx-md-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n\n .mx-md-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n\n .mx-md-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n\n .my-md-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n\n .my-md-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n\n .my-md-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n\n .my-md-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n\n .my-md-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n\n .my-md-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n\n .my-md-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n\n .mt-md-0 {\n margin-top: 0 !important;\n }\n\n .mt-md-1 {\n margin-top: 0.25rem !important;\n }\n\n .mt-md-2 {\n margin-top: 0.5rem !important;\n }\n\n .mt-md-3 {\n margin-top: 1rem !important;\n }\n\n .mt-md-4 {\n margin-top: 1.5rem !important;\n }\n\n .mt-md-5 {\n margin-top: 3rem !important;\n }\n\n .mt-md-auto {\n margin-top: auto !important;\n }\n\n .me-md-0 {\n margin-right: 0 !important;\n }\n\n .me-md-1 {\n margin-right: 0.25rem !important;\n }\n\n .me-md-2 {\n margin-right: 0.5rem !important;\n }\n\n .me-md-3 {\n margin-right: 1rem !important;\n }\n\n .me-md-4 {\n margin-right: 1.5rem !important;\n }\n\n .me-md-5 {\n margin-right: 3rem !important;\n }\n\n .me-md-auto {\n margin-right: auto !important;\n }\n\n .mb-md-0 {\n margin-bottom: 0 !important;\n }\n\n .mb-md-1 {\n margin-bottom: 0.25rem !important;\n }\n\n .mb-md-2 {\n margin-bottom: 0.5rem !important;\n }\n\n .mb-md-3 {\n margin-bottom: 1rem !important;\n }\n\n .mb-md-4 {\n margin-bottom: 1.5rem !important;\n }\n\n .mb-md-5 {\n margin-bottom: 3rem !important;\n }\n\n .mb-md-auto {\n margin-bottom: auto !important;\n }\n\n .ms-md-0 {\n margin-left: 0 !important;\n }\n\n .ms-md-1 {\n margin-left: 0.25rem !important;\n }\n\n .ms-md-2 {\n margin-left: 0.5rem !important;\n }\n\n .ms-md-3 {\n margin-left: 1rem !important;\n }\n\n .ms-md-4 {\n margin-left: 1.5rem !important;\n }\n\n .ms-md-5 {\n margin-left: 3rem !important;\n }\n\n .ms-md-auto {\n margin-left: auto !important;\n }\n\n .p-md-0 {\n padding: 0 !important;\n }\n\n .p-md-1 {\n padding: 0.25rem !important;\n }\n\n .p-md-2 {\n padding: 0.5rem !important;\n }\n\n .p-md-3 {\n padding: 1rem !important;\n }\n\n .p-md-4 {\n padding: 1.5rem !important;\n }\n\n .p-md-5 {\n padding: 3rem !important;\n }\n\n .px-md-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n\n .px-md-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n\n .px-md-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n\n .px-md-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n\n .px-md-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n\n .px-md-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n\n .py-md-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n\n .py-md-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n\n .py-md-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n\n .py-md-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n\n .py-md-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n\n .py-md-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n\n .pt-md-0 {\n padding-top: 0 !important;\n }\n\n .pt-md-1 {\n padding-top: 0.25rem !important;\n }\n\n .pt-md-2 {\n padding-top: 0.5rem !important;\n }\n\n .pt-md-3 {\n padding-top: 1rem !important;\n }\n\n .pt-md-4 {\n padding-top: 1.5rem !important;\n }\n\n .pt-md-5 {\n padding-top: 3rem !important;\n }\n\n .pe-md-0 {\n padding-right: 0 !important;\n }\n\n .pe-md-1 {\n padding-right: 0.25rem !important;\n }\n\n .pe-md-2 {\n padding-right: 0.5rem !important;\n }\n\n .pe-md-3 {\n padding-right: 1rem !important;\n }\n\n .pe-md-4 {\n padding-right: 1.5rem !important;\n }\n\n .pe-md-5 {\n padding-right: 3rem !important;\n }\n\n .pb-md-0 {\n padding-bottom: 0 !important;\n }\n\n .pb-md-1 {\n padding-bottom: 0.25rem !important;\n }\n\n .pb-md-2 {\n padding-bottom: 0.5rem !important;\n }\n\n .pb-md-3 {\n padding-bottom: 1rem !important;\n }\n\n .pb-md-4 {\n padding-bottom: 1.5rem !important;\n }\n\n .pb-md-5 {\n padding-bottom: 3rem !important;\n }\n\n .ps-md-0 {\n padding-left: 0 !important;\n }\n\n .ps-md-1 {\n padding-left: 0.25rem !important;\n }\n\n .ps-md-2 {\n padding-left: 0.5rem !important;\n }\n\n .ps-md-3 {\n padding-left: 1rem !important;\n }\n\n .ps-md-4 {\n padding-left: 1.5rem !important;\n }\n\n .ps-md-5 {\n padding-left: 3rem !important;\n }\n\n .text-md-start {\n text-align: left !important;\n }\n\n .text-md-end {\n text-align: right !important;\n }\n\n .text-md-center {\n text-align: center !important;\n }\n}\n@media (min-width: 992px) {\n .float-lg-start {\n float: left !important;\n }\n\n .float-lg-end {\n float: right !important;\n }\n\n .float-lg-none {\n float: none !important;\n }\n\n .d-lg-inline {\n display: inline !important;\n }\n\n .d-lg-inline-block {\n display: inline-block !important;\n }\n\n .d-lg-block {\n display: block !important;\n }\n\n .d-lg-grid {\n display: grid !important;\n }\n\n .d-lg-table {\n display: table !important;\n }\n\n .d-lg-table-row {\n display: table-row !important;\n }\n\n .d-lg-table-cell {\n display: table-cell !important;\n }\n\n .d-lg-flex {\n display: flex !important;\n }\n\n .d-lg-inline-flex {\n display: inline-flex !important;\n }\n\n .d-lg-none {\n display: none !important;\n }\n\n .flex-lg-fill {\n flex: 1 1 auto !important;\n }\n\n .flex-lg-row {\n flex-direction: row !important;\n }\n\n .flex-lg-column {\n flex-direction: column !important;\n }\n\n .flex-lg-row-reverse {\n flex-direction: row-reverse !important;\n }\n\n .flex-lg-column-reverse {\n flex-direction: column-reverse !important;\n }\n\n .flex-lg-grow-0 {\n flex-grow: 0 !important;\n }\n\n .flex-lg-grow-1 {\n flex-grow: 1 !important;\n }\n\n .flex-lg-shrink-0 {\n flex-shrink: 0 !important;\n }\n\n .flex-lg-shrink-1 {\n flex-shrink: 1 !important;\n }\n\n .flex-lg-wrap {\n flex-wrap: wrap !important;\n }\n\n .flex-lg-nowrap {\n flex-wrap: nowrap !important;\n }\n\n .flex-lg-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n\n .gap-lg-0 {\n gap: 0 !important;\n }\n\n .gap-lg-1 {\n gap: 0.25rem !important;\n }\n\n .gap-lg-2 {\n gap: 0.5rem !important;\n }\n\n .gap-lg-3 {\n gap: 1rem !important;\n }\n\n .gap-lg-4 {\n gap: 1.5rem !important;\n }\n\n .gap-lg-5 {\n gap: 3rem !important;\n }\n\n .justify-content-lg-start {\n justify-content: flex-start !important;\n }\n\n .justify-content-lg-end {\n justify-content: flex-end !important;\n }\n\n .justify-content-lg-center {\n justify-content: center !important;\n }\n\n .justify-content-lg-between {\n justify-content: space-between !important;\n }\n\n .justify-content-lg-around {\n justify-content: space-around !important;\n }\n\n .justify-content-lg-evenly {\n justify-content: space-evenly !important;\n }\n\n .align-items-lg-start {\n align-items: flex-start !important;\n }\n\n .align-items-lg-end {\n align-items: flex-end !important;\n }\n\n .align-items-lg-center {\n align-items: center !important;\n }\n\n .align-items-lg-baseline {\n align-items: baseline !important;\n }\n\n .align-items-lg-stretch {\n align-items: stretch !important;\n }\n\n .align-content-lg-start {\n align-content: flex-start !important;\n }\n\n .align-content-lg-end {\n align-content: flex-end !important;\n }\n\n .align-content-lg-center {\n align-content: center !important;\n }\n\n .align-content-lg-between {\n align-content: space-between !important;\n }\n\n .align-content-lg-around {\n align-content: space-around !important;\n }\n\n .align-content-lg-stretch {\n align-content: stretch !important;\n }\n\n .align-self-lg-auto {\n align-self: auto !important;\n }\n\n .align-self-lg-start {\n align-self: flex-start !important;\n }\n\n .align-self-lg-end {\n align-self: flex-end !important;\n }\n\n .align-self-lg-center {\n align-self: center !important;\n }\n\n .align-self-lg-baseline {\n align-self: baseline !important;\n }\n\n .align-self-lg-stretch {\n align-self: stretch !important;\n }\n\n .order-lg-first {\n order: -1 !important;\n }\n\n .order-lg-0 {\n order: 0 !important;\n }\n\n .order-lg-1 {\n order: 1 !important;\n }\n\n .order-lg-2 {\n order: 2 !important;\n }\n\n .order-lg-3 {\n order: 3 !important;\n }\n\n .order-lg-4 {\n order: 4 !important;\n }\n\n .order-lg-5 {\n order: 5 !important;\n }\n\n .order-lg-last {\n order: 6 !important;\n }\n\n .m-lg-0 {\n margin: 0 !important;\n }\n\n .m-lg-1 {\n margin: 0.25rem !important;\n }\n\n .m-lg-2 {\n margin: 0.5rem !important;\n }\n\n .m-lg-3 {\n margin: 1rem !important;\n }\n\n .m-lg-4 {\n margin: 1.5rem !important;\n }\n\n .m-lg-5 {\n margin: 3rem !important;\n }\n\n .m-lg-auto {\n margin: auto !important;\n }\n\n .mx-lg-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n\n .mx-lg-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n\n .mx-lg-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n\n .mx-lg-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n\n .mx-lg-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n\n .mx-lg-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n\n .mx-lg-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n\n .my-lg-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n\n .my-lg-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n\n .my-lg-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n\n .my-lg-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n\n .my-lg-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n\n .my-lg-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n\n .my-lg-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n\n .mt-lg-0 {\n margin-top: 0 !important;\n }\n\n .mt-lg-1 {\n margin-top: 0.25rem !important;\n }\n\n .mt-lg-2 {\n margin-top: 0.5rem !important;\n }\n\n .mt-lg-3 {\n margin-top: 1rem !important;\n }\n\n .mt-lg-4 {\n margin-top: 1.5rem !important;\n }\n\n .mt-lg-5 {\n margin-top: 3rem !important;\n }\n\n .mt-lg-auto {\n margin-top: auto !important;\n }\n\n .me-lg-0 {\n margin-right: 0 !important;\n }\n\n .me-lg-1 {\n margin-right: 0.25rem !important;\n }\n\n .me-lg-2 {\n margin-right: 0.5rem !important;\n }\n\n .me-lg-3 {\n margin-right: 1rem !important;\n }\n\n .me-lg-4 {\n margin-right: 1.5rem !important;\n }\n\n .me-lg-5 {\n margin-right: 3rem !important;\n }\n\n .me-lg-auto {\n margin-right: auto !important;\n }\n\n .mb-lg-0 {\n margin-bottom: 0 !important;\n }\n\n .mb-lg-1 {\n margin-bottom: 0.25rem !important;\n }\n\n .mb-lg-2 {\n margin-bottom: 0.5rem !important;\n }\n\n .mb-lg-3 {\n margin-bottom: 1rem !important;\n }\n\n .mb-lg-4 {\n margin-bottom: 1.5rem !important;\n }\n\n .mb-lg-5 {\n margin-bottom: 3rem !important;\n }\n\n .mb-lg-auto {\n margin-bottom: auto !important;\n }\n\n .ms-lg-0 {\n margin-left: 0 !important;\n }\n\n .ms-lg-1 {\n margin-left: 0.25rem !important;\n }\n\n .ms-lg-2 {\n margin-left: 0.5rem !important;\n }\n\n .ms-lg-3 {\n margin-left: 1rem !important;\n }\n\n .ms-lg-4 {\n margin-left: 1.5rem !important;\n }\n\n .ms-lg-5 {\n margin-left: 3rem !important;\n }\n\n .ms-lg-auto {\n margin-left: auto !important;\n }\n\n .p-lg-0 {\n padding: 0 !important;\n }\n\n .p-lg-1 {\n padding: 0.25rem !important;\n }\n\n .p-lg-2 {\n padding: 0.5rem !important;\n }\n\n .p-lg-3 {\n padding: 1rem !important;\n }\n\n .p-lg-4 {\n padding: 1.5rem !important;\n }\n\n .p-lg-5 {\n padding: 3rem !important;\n }\n\n .px-lg-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n\n .px-lg-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n\n .px-lg-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n\n .px-lg-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n\n .px-lg-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n\n .px-lg-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n\n .py-lg-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n\n .py-lg-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n\n .py-lg-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n\n .py-lg-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n\n .py-lg-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n\n .py-lg-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n\n .pt-lg-0 {\n padding-top: 0 !important;\n }\n\n .pt-lg-1 {\n padding-top: 0.25rem !important;\n }\n\n .pt-lg-2 {\n padding-top: 0.5rem !important;\n }\n\n .pt-lg-3 {\n padding-top: 1rem !important;\n }\n\n .pt-lg-4 {\n padding-top: 1.5rem !important;\n }\n\n .pt-lg-5 {\n padding-top: 3rem !important;\n }\n\n .pe-lg-0 {\n padding-right: 0 !important;\n }\n\n .pe-lg-1 {\n padding-right: 0.25rem !important;\n }\n\n .pe-lg-2 {\n padding-right: 0.5rem !important;\n }\n\n .pe-lg-3 {\n padding-right: 1rem !important;\n }\n\n .pe-lg-4 {\n padding-right: 1.5rem !important;\n }\n\n .pe-lg-5 {\n padding-right: 3rem !important;\n }\n\n .pb-lg-0 {\n padding-bottom: 0 !important;\n }\n\n .pb-lg-1 {\n padding-bottom: 0.25rem !important;\n }\n\n .pb-lg-2 {\n padding-bottom: 0.5rem !important;\n }\n\n .pb-lg-3 {\n padding-bottom: 1rem !important;\n }\n\n .pb-lg-4 {\n padding-bottom: 1.5rem !important;\n }\n\n .pb-lg-5 {\n padding-bottom: 3rem !important;\n }\n\n .ps-lg-0 {\n padding-left: 0 !important;\n }\n\n .ps-lg-1 {\n padding-left: 0.25rem !important;\n }\n\n .ps-lg-2 {\n padding-left: 0.5rem !important;\n }\n\n .ps-lg-3 {\n padding-left: 1rem !important;\n }\n\n .ps-lg-4 {\n padding-left: 1.5rem !important;\n }\n\n .ps-lg-5 {\n padding-left: 3rem !important;\n }\n\n .text-lg-start {\n text-align: left !important;\n }\n\n .text-lg-end {\n text-align: right !important;\n }\n\n .text-lg-center {\n text-align: center !important;\n }\n}\n@media (min-width: 1200px) {\n .float-xl-start {\n float: left !important;\n }\n\n .float-xl-end {\n float: right !important;\n }\n\n .float-xl-none {\n float: none !important;\n }\n\n .d-xl-inline {\n display: inline !important;\n }\n\n .d-xl-inline-block {\n display: inline-block !important;\n }\n\n .d-xl-block {\n display: block !important;\n }\n\n .d-xl-grid {\n display: grid !important;\n }\n\n .d-xl-table {\n display: table !important;\n }\n\n .d-xl-table-row {\n display: table-row !important;\n }\n\n .d-xl-table-cell {\n display: table-cell !important;\n }\n\n .d-xl-flex {\n display: flex !important;\n }\n\n .d-xl-inline-flex {\n display: inline-flex !important;\n }\n\n .d-xl-none {\n display: none !important;\n }\n\n .flex-xl-fill {\n flex: 1 1 auto !important;\n }\n\n .flex-xl-row {\n flex-direction: row !important;\n }\n\n .flex-xl-column {\n flex-direction: column !important;\n }\n\n .flex-xl-row-reverse {\n flex-direction: row-reverse !important;\n }\n\n .flex-xl-column-reverse {\n flex-direction: column-reverse !important;\n }\n\n .flex-xl-grow-0 {\n flex-grow: 0 !important;\n }\n\n .flex-xl-grow-1 {\n flex-grow: 1 !important;\n }\n\n .flex-xl-shrink-0 {\n flex-shrink: 0 !important;\n }\n\n .flex-xl-shrink-1 {\n flex-shrink: 1 !important;\n }\n\n .flex-xl-wrap {\n flex-wrap: wrap !important;\n }\n\n .flex-xl-nowrap {\n flex-wrap: nowrap !important;\n }\n\n .flex-xl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n\n .gap-xl-0 {\n gap: 0 !important;\n }\n\n .gap-xl-1 {\n gap: 0.25rem !important;\n }\n\n .gap-xl-2 {\n gap: 0.5rem !important;\n }\n\n .gap-xl-3 {\n gap: 1rem !important;\n }\n\n .gap-xl-4 {\n gap: 1.5rem !important;\n }\n\n .gap-xl-5 {\n gap: 3rem !important;\n }\n\n .justify-content-xl-start {\n justify-content: flex-start !important;\n }\n\n .justify-content-xl-end {\n justify-content: flex-end !important;\n }\n\n .justify-content-xl-center {\n justify-content: center !important;\n }\n\n .justify-content-xl-between {\n justify-content: space-between !important;\n }\n\n .justify-content-xl-around {\n justify-content: space-around !important;\n }\n\n .justify-content-xl-evenly {\n justify-content: space-evenly !important;\n }\n\n .align-items-xl-start {\n align-items: flex-start !important;\n }\n\n .align-items-xl-end {\n align-items: flex-end !important;\n }\n\n .align-items-xl-center {\n align-items: center !important;\n }\n\n .align-items-xl-baseline {\n align-items: baseline !important;\n }\n\n .align-items-xl-stretch {\n align-items: stretch !important;\n }\n\n .align-content-xl-start {\n align-content: flex-start !important;\n }\n\n .align-content-xl-end {\n align-content: flex-end !important;\n }\n\n .align-content-xl-center {\n align-content: center !important;\n }\n\n .align-content-xl-between {\n align-content: space-between !important;\n }\n\n .align-content-xl-around {\n align-content: space-around !important;\n }\n\n .align-content-xl-stretch {\n align-content: stretch !important;\n }\n\n .align-self-xl-auto {\n align-self: auto !important;\n }\n\n .align-self-xl-start {\n align-self: flex-start !important;\n }\n\n .align-self-xl-end {\n align-self: flex-end !important;\n }\n\n .align-self-xl-center {\n align-self: center !important;\n }\n\n .align-self-xl-baseline {\n align-self: baseline !important;\n }\n\n .align-self-xl-stretch {\n align-self: stretch !important;\n }\n\n .order-xl-first {\n order: -1 !important;\n }\n\n .order-xl-0 {\n order: 0 !important;\n }\n\n .order-xl-1 {\n order: 1 !important;\n }\n\n .order-xl-2 {\n order: 2 !important;\n }\n\n .order-xl-3 {\n order: 3 !important;\n }\n\n .order-xl-4 {\n order: 4 !important;\n }\n\n .order-xl-5 {\n order: 5 !important;\n }\n\n .order-xl-last {\n order: 6 !important;\n }\n\n .m-xl-0 {\n margin: 0 !important;\n }\n\n .m-xl-1 {\n margin: 0.25rem !important;\n }\n\n .m-xl-2 {\n margin: 0.5rem !important;\n }\n\n .m-xl-3 {\n margin: 1rem !important;\n }\n\n .m-xl-4 {\n margin: 1.5rem !important;\n }\n\n .m-xl-5 {\n margin: 3rem !important;\n }\n\n .m-xl-auto {\n margin: auto !important;\n }\n\n .mx-xl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n\n .mx-xl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n\n .mx-xl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n\n .mx-xl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n\n .mx-xl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n\n .mx-xl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n\n .mx-xl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n\n .my-xl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n\n .my-xl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n\n .my-xl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n\n .my-xl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n\n .my-xl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n\n .my-xl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n\n .my-xl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n\n .mt-xl-0 {\n margin-top: 0 !important;\n }\n\n .mt-xl-1 {\n margin-top: 0.25rem !important;\n }\n\n .mt-xl-2 {\n margin-top: 0.5rem !important;\n }\n\n .mt-xl-3 {\n margin-top: 1rem !important;\n }\n\n .mt-xl-4 {\n margin-top: 1.5rem !important;\n }\n\n .mt-xl-5 {\n margin-top: 3rem !important;\n }\n\n .mt-xl-auto {\n margin-top: auto !important;\n }\n\n .me-xl-0 {\n margin-right: 0 !important;\n }\n\n .me-xl-1 {\n margin-right: 0.25rem !important;\n }\n\n .me-xl-2 {\n margin-right: 0.5rem !important;\n }\n\n .me-xl-3 {\n margin-right: 1rem !important;\n }\n\n .me-xl-4 {\n margin-right: 1.5rem !important;\n }\n\n .me-xl-5 {\n margin-right: 3rem !important;\n }\n\n .me-xl-auto {\n margin-right: auto !important;\n }\n\n .mb-xl-0 {\n margin-bottom: 0 !important;\n }\n\n .mb-xl-1 {\n margin-bottom: 0.25rem !important;\n }\n\n .mb-xl-2 {\n margin-bottom: 0.5rem !important;\n }\n\n .mb-xl-3 {\n margin-bottom: 1rem !important;\n }\n\n .mb-xl-4 {\n margin-bottom: 1.5rem !important;\n }\n\n .mb-xl-5 {\n margin-bottom: 3rem !important;\n }\n\n .mb-xl-auto {\n margin-bottom: auto !important;\n }\n\n .ms-xl-0 {\n margin-left: 0 !important;\n }\n\n .ms-xl-1 {\n margin-left: 0.25rem !important;\n }\n\n .ms-xl-2 {\n margin-left: 0.5rem !important;\n }\n\n .ms-xl-3 {\n margin-left: 1rem !important;\n }\n\n .ms-xl-4 {\n margin-left: 1.5rem !important;\n }\n\n .ms-xl-5 {\n margin-left: 3rem !important;\n }\n\n .ms-xl-auto {\n margin-left: auto !important;\n }\n\n .p-xl-0 {\n padding: 0 !important;\n }\n\n .p-xl-1 {\n padding: 0.25rem !important;\n }\n\n .p-xl-2 {\n padding: 0.5rem !important;\n }\n\n .p-xl-3 {\n padding: 1rem !important;\n }\n\n .p-xl-4 {\n padding: 1.5rem !important;\n }\n\n .p-xl-5 {\n padding: 3rem !important;\n }\n\n .px-xl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n\n .px-xl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n\n .px-xl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n\n .px-xl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n\n .px-xl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n\n .px-xl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n\n .py-xl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n\n .py-xl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n\n .py-xl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n\n .py-xl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n\n .py-xl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n\n .py-xl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n\n .pt-xl-0 {\n padding-top: 0 !important;\n }\n\n .pt-xl-1 {\n padding-top: 0.25rem !important;\n }\n\n .pt-xl-2 {\n padding-top: 0.5rem !important;\n }\n\n .pt-xl-3 {\n padding-top: 1rem !important;\n }\n\n .pt-xl-4 {\n padding-top: 1.5rem !important;\n }\n\n .pt-xl-5 {\n padding-top: 3rem !important;\n }\n\n .pe-xl-0 {\n padding-right: 0 !important;\n }\n\n .pe-xl-1 {\n padding-right: 0.25rem !important;\n }\n\n .pe-xl-2 {\n padding-right: 0.5rem !important;\n }\n\n .pe-xl-3 {\n padding-right: 1rem !important;\n }\n\n .pe-xl-4 {\n padding-right: 1.5rem !important;\n }\n\n .pe-xl-5 {\n padding-right: 3rem !important;\n }\n\n .pb-xl-0 {\n padding-bottom: 0 !important;\n }\n\n .pb-xl-1 {\n padding-bottom: 0.25rem !important;\n }\n\n .pb-xl-2 {\n padding-bottom: 0.5rem !important;\n }\n\n .pb-xl-3 {\n padding-bottom: 1rem !important;\n }\n\n .pb-xl-4 {\n padding-bottom: 1.5rem !important;\n }\n\n .pb-xl-5 {\n padding-bottom: 3rem !important;\n }\n\n .ps-xl-0 {\n padding-left: 0 !important;\n }\n\n .ps-xl-1 {\n padding-left: 0.25rem !important;\n }\n\n .ps-xl-2 {\n padding-left: 0.5rem !important;\n }\n\n .ps-xl-3 {\n padding-left: 1rem !important;\n }\n\n .ps-xl-4 {\n padding-left: 1.5rem !important;\n }\n\n .ps-xl-5 {\n padding-left: 3rem !important;\n }\n\n .text-xl-start {\n text-align: left !important;\n }\n\n .text-xl-end {\n text-align: right !important;\n }\n\n .text-xl-center {\n text-align: center !important;\n }\n}\n@media (min-width: 1400px) {\n .float-xxl-start {\n float: left !important;\n }\n\n .float-xxl-end {\n float: right !important;\n }\n\n .float-xxl-none {\n float: none !important;\n }\n\n .d-xxl-inline {\n display: inline !important;\n }\n\n .d-xxl-inline-block {\n display: inline-block !important;\n }\n\n .d-xxl-block {\n display: block !important;\n }\n\n .d-xxl-grid {\n display: grid !important;\n }\n\n .d-xxl-table {\n display: table !important;\n }\n\n .d-xxl-table-row {\n display: table-row !important;\n }\n\n .d-xxl-table-cell {\n display: table-cell !important;\n }\n\n .d-xxl-flex {\n display: flex !important;\n }\n\n .d-xxl-inline-flex {\n display: inline-flex !important;\n }\n\n .d-xxl-none {\n display: none !important;\n }\n\n .flex-xxl-fill {\n flex: 1 1 auto !important;\n }\n\n .flex-xxl-row {\n flex-direction: row !important;\n }\n\n .flex-xxl-column {\n flex-direction: column !important;\n }\n\n .flex-xxl-row-reverse {\n flex-direction: row-reverse !important;\n }\n\n .flex-xxl-column-reverse {\n flex-direction: column-reverse !important;\n }\n\n .flex-xxl-grow-0 {\n flex-grow: 0 !important;\n }\n\n .flex-xxl-grow-1 {\n flex-grow: 1 !important;\n }\n\n .flex-xxl-shrink-0 {\n flex-shrink: 0 !important;\n }\n\n .flex-xxl-shrink-1 {\n flex-shrink: 1 !important;\n }\n\n .flex-xxl-wrap {\n flex-wrap: wrap !important;\n }\n\n .flex-xxl-nowrap {\n flex-wrap: nowrap !important;\n }\n\n .flex-xxl-wrap-reverse {\n flex-wrap: wrap-reverse !important;\n }\n\n .gap-xxl-0 {\n gap: 0 !important;\n }\n\n .gap-xxl-1 {\n gap: 0.25rem !important;\n }\n\n .gap-xxl-2 {\n gap: 0.5rem !important;\n }\n\n .gap-xxl-3 {\n gap: 1rem !important;\n }\n\n .gap-xxl-4 {\n gap: 1.5rem !important;\n }\n\n .gap-xxl-5 {\n gap: 3rem !important;\n }\n\n .justify-content-xxl-start {\n justify-content: flex-start !important;\n }\n\n .justify-content-xxl-end {\n justify-content: flex-end !important;\n }\n\n .justify-content-xxl-center {\n justify-content: center !important;\n }\n\n .justify-content-xxl-between {\n justify-content: space-between !important;\n }\n\n .justify-content-xxl-around {\n justify-content: space-around !important;\n }\n\n .justify-content-xxl-evenly {\n justify-content: space-evenly !important;\n }\n\n .align-items-xxl-start {\n align-items: flex-start !important;\n }\n\n .align-items-xxl-end {\n align-items: flex-end !important;\n }\n\n .align-items-xxl-center {\n align-items: center !important;\n }\n\n .align-items-xxl-baseline {\n align-items: baseline !important;\n }\n\n .align-items-xxl-stretch {\n align-items: stretch !important;\n }\n\n .align-content-xxl-start {\n align-content: flex-start !important;\n }\n\n .align-content-xxl-end {\n align-content: flex-end !important;\n }\n\n .align-content-xxl-center {\n align-content: center !important;\n }\n\n .align-content-xxl-between {\n align-content: space-between !important;\n }\n\n .align-content-xxl-around {\n align-content: space-around !important;\n }\n\n .align-content-xxl-stretch {\n align-content: stretch !important;\n }\n\n .align-self-xxl-auto {\n align-self: auto !important;\n }\n\n .align-self-xxl-start {\n align-self: flex-start !important;\n }\n\n .align-self-xxl-end {\n align-self: flex-end !important;\n }\n\n .align-self-xxl-center {\n align-self: center !important;\n }\n\n .align-self-xxl-baseline {\n align-self: baseline !important;\n }\n\n .align-self-xxl-stretch {\n align-self: stretch !important;\n }\n\n .order-xxl-first {\n order: -1 !important;\n }\n\n .order-xxl-0 {\n order: 0 !important;\n }\n\n .order-xxl-1 {\n order: 1 !important;\n }\n\n .order-xxl-2 {\n order: 2 !important;\n }\n\n .order-xxl-3 {\n order: 3 !important;\n }\n\n .order-xxl-4 {\n order: 4 !important;\n }\n\n .order-xxl-5 {\n order: 5 !important;\n }\n\n .order-xxl-last {\n order: 6 !important;\n }\n\n .m-xxl-0 {\n margin: 0 !important;\n }\n\n .m-xxl-1 {\n margin: 0.25rem !important;\n }\n\n .m-xxl-2 {\n margin: 0.5rem !important;\n }\n\n .m-xxl-3 {\n margin: 1rem !important;\n }\n\n .m-xxl-4 {\n margin: 1.5rem !important;\n }\n\n .m-xxl-5 {\n margin: 3rem !important;\n }\n\n .m-xxl-auto {\n margin: auto !important;\n }\n\n .mx-xxl-0 {\n margin-right: 0 !important;\n margin-left: 0 !important;\n }\n\n .mx-xxl-1 {\n margin-right: 0.25rem !important;\n margin-left: 0.25rem !important;\n }\n\n .mx-xxl-2 {\n margin-right: 0.5rem !important;\n margin-left: 0.5rem !important;\n }\n\n .mx-xxl-3 {\n margin-right: 1rem !important;\n margin-left: 1rem !important;\n }\n\n .mx-xxl-4 {\n margin-right: 1.5rem !important;\n margin-left: 1.5rem !important;\n }\n\n .mx-xxl-5 {\n margin-right: 3rem !important;\n margin-left: 3rem !important;\n }\n\n .mx-xxl-auto {\n margin-right: auto !important;\n margin-left: auto !important;\n }\n\n .my-xxl-0 {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n }\n\n .my-xxl-1 {\n margin-top: 0.25rem !important;\n margin-bottom: 0.25rem !important;\n }\n\n .my-xxl-2 {\n margin-top: 0.5rem !important;\n margin-bottom: 0.5rem !important;\n }\n\n .my-xxl-3 {\n margin-top: 1rem !important;\n margin-bottom: 1rem !important;\n }\n\n .my-xxl-4 {\n margin-top: 1.5rem !important;\n margin-bottom: 1.5rem !important;\n }\n\n .my-xxl-5 {\n margin-top: 3rem !important;\n margin-bottom: 3rem !important;\n }\n\n .my-xxl-auto {\n margin-top: auto !important;\n margin-bottom: auto !important;\n }\n\n .mt-xxl-0 {\n margin-top: 0 !important;\n }\n\n .mt-xxl-1 {\n margin-top: 0.25rem !important;\n }\n\n .mt-xxl-2 {\n margin-top: 0.5rem !important;\n }\n\n .mt-xxl-3 {\n margin-top: 1rem !important;\n }\n\n .mt-xxl-4 {\n margin-top: 1.5rem !important;\n }\n\n .mt-xxl-5 {\n margin-top: 3rem !important;\n }\n\n .mt-xxl-auto {\n margin-top: auto !important;\n }\n\n .me-xxl-0 {\n margin-right: 0 !important;\n }\n\n .me-xxl-1 {\n margin-right: 0.25rem !important;\n }\n\n .me-xxl-2 {\n margin-right: 0.5rem !important;\n }\n\n .me-xxl-3 {\n margin-right: 1rem !important;\n }\n\n .me-xxl-4 {\n margin-right: 1.5rem !important;\n }\n\n .me-xxl-5 {\n margin-right: 3rem !important;\n }\n\n .me-xxl-auto {\n margin-right: auto !important;\n }\n\n .mb-xxl-0 {\n margin-bottom: 0 !important;\n }\n\n .mb-xxl-1 {\n margin-bottom: 0.25rem !important;\n }\n\n .mb-xxl-2 {\n margin-bottom: 0.5rem !important;\n }\n\n .mb-xxl-3 {\n margin-bottom: 1rem !important;\n }\n\n .mb-xxl-4 {\n margin-bottom: 1.5rem !important;\n }\n\n .mb-xxl-5 {\n margin-bottom: 3rem !important;\n }\n\n .mb-xxl-auto {\n margin-bottom: auto !important;\n }\n\n .ms-xxl-0 {\n margin-left: 0 !important;\n }\n\n .ms-xxl-1 {\n margin-left: 0.25rem !important;\n }\n\n .ms-xxl-2 {\n margin-left: 0.5rem !important;\n }\n\n .ms-xxl-3 {\n margin-left: 1rem !important;\n }\n\n .ms-xxl-4 {\n margin-left: 1.5rem !important;\n }\n\n .ms-xxl-5 {\n margin-left: 3rem !important;\n }\n\n .ms-xxl-auto {\n margin-left: auto !important;\n }\n\n .p-xxl-0 {\n padding: 0 !important;\n }\n\n .p-xxl-1 {\n padding: 0.25rem !important;\n }\n\n .p-xxl-2 {\n padding: 0.5rem !important;\n }\n\n .p-xxl-3 {\n padding: 1rem !important;\n }\n\n .p-xxl-4 {\n padding: 1.5rem !important;\n }\n\n .p-xxl-5 {\n padding: 3rem !important;\n }\n\n .px-xxl-0 {\n padding-right: 0 !important;\n padding-left: 0 !important;\n }\n\n .px-xxl-1 {\n padding-right: 0.25rem !important;\n padding-left: 0.25rem !important;\n }\n\n .px-xxl-2 {\n padding-right: 0.5rem !important;\n padding-left: 0.5rem !important;\n }\n\n .px-xxl-3 {\n padding-right: 1rem !important;\n padding-left: 1rem !important;\n }\n\n .px-xxl-4 {\n padding-right: 1.5rem !important;\n padding-left: 1.5rem !important;\n }\n\n .px-xxl-5 {\n padding-right: 3rem !important;\n padding-left: 3rem !important;\n }\n\n .py-xxl-0 {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n }\n\n .py-xxl-1 {\n padding-top: 0.25rem !important;\n padding-bottom: 0.25rem !important;\n }\n\n .py-xxl-2 {\n padding-top: 0.5rem !important;\n padding-bottom: 0.5rem !important;\n }\n\n .py-xxl-3 {\n padding-top: 1rem !important;\n padding-bottom: 1rem !important;\n }\n\n .py-xxl-4 {\n padding-top: 1.5rem !important;\n padding-bottom: 1.5rem !important;\n }\n\n .py-xxl-5 {\n padding-top: 3rem !important;\n padding-bottom: 3rem !important;\n }\n\n .pt-xxl-0 {\n padding-top: 0 !important;\n }\n\n .pt-xxl-1 {\n padding-top: 0.25rem !important;\n }\n\n .pt-xxl-2 {\n padding-top: 0.5rem !important;\n }\n\n .pt-xxl-3 {\n padding-top: 1rem !important;\n }\n\n .pt-xxl-4 {\n padding-top: 1.5rem !important;\n }\n\n .pt-xxl-5 {\n padding-top: 3rem !important;\n }\n\n .pe-xxl-0 {\n padding-right: 0 !important;\n }\n\n .pe-xxl-1 {\n padding-right: 0.25rem !important;\n }\n\n .pe-xxl-2 {\n padding-right: 0.5rem !important;\n }\n\n .pe-xxl-3 {\n padding-right: 1rem !important;\n }\n\n .pe-xxl-4 {\n padding-right: 1.5rem !important;\n }\n\n .pe-xxl-5 {\n padding-right: 3rem !important;\n }\n\n .pb-xxl-0 {\n padding-bottom: 0 !important;\n }\n\n .pb-xxl-1 {\n padding-bottom: 0.25rem !important;\n }\n\n .pb-xxl-2 {\n padding-bottom: 0.5rem !important;\n }\n\n .pb-xxl-3 {\n padding-bottom: 1rem !important;\n }\n\n .pb-xxl-4 {\n padding-bottom: 1.5rem !important;\n }\n\n .pb-xxl-5 {\n padding-bottom: 3rem !important;\n }\n\n .ps-xxl-0 {\n padding-left: 0 !important;\n }\n\n .ps-xxl-1 {\n padding-left: 0.25rem !important;\n }\n\n .ps-xxl-2 {\n padding-left: 0.5rem !important;\n }\n\n .ps-xxl-3 {\n padding-left: 1rem !important;\n }\n\n .ps-xxl-4 {\n padding-left: 1.5rem !important;\n }\n\n .ps-xxl-5 {\n padding-left: 3rem !important;\n }\n\n .text-xxl-start {\n text-align: left !important;\n }\n\n .text-xxl-end {\n text-align: right !important;\n }\n\n .text-xxl-center {\n text-align: center !important;\n }\n}\n@media (min-width: 1200px) {\n .fs-1 {\n font-size: 2.5rem !important;\n }\n\n .fs-2 {\n font-size: 2rem !important;\n }\n\n .fs-3 {\n font-size: 1.75rem !important;\n }\n\n .fs-4 {\n font-size: 1.5rem !important;\n }\n}\n@media print {\n .d-print-inline {\n display: inline !important;\n }\n\n .d-print-inline-block {\n display: inline-block !important;\n }\n\n .d-print-block {\n display: block !important;\n }\n\n .d-print-grid {\n display: grid !important;\n }\n\n .d-print-table {\n display: table !important;\n }\n\n .d-print-table-row {\n display: table-row !important;\n }\n\n .d-print-table-cell {\n display: table-cell !important;\n }\n\n .d-print-flex {\n display: flex !important;\n }\n\n .d-print-inline-flex {\n display: inline-flex !important;\n }\n\n .d-print-none {\n display: none !important;\n }\n}\n\n/*# sourceMappingURL=bootstrap.css.map */","// stylelint-disable property-blacklist, scss/dollar-variable-default\n\n// SCSS RFS mixin\n//\n// Automated responsive values for font sizes, paddings, margins and much more\n//\n// Licensed under MIT (https://github.com/twbs/rfs/blob/main/LICENSE)\n\n// Configuration\n\n// Base value\n$rfs-base-value: 1.25rem !default;\n$rfs-unit: rem !default;\n\n@if $rfs-unit != rem and $rfs-unit != px {\n @error \"`#{$rfs-unit}` is not a valid unit for $rfs-unit. Use `px` or `rem`.\";\n}\n\n// Breakpoint at where values start decreasing if screen width is smaller\n$rfs-breakpoint: 1200px !default;\n$rfs-breakpoint-unit: px !default;\n\n@if $rfs-breakpoint-unit != px and $rfs-breakpoint-unit != em and $rfs-breakpoint-unit != rem {\n @error \"`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`.\";\n}\n\n// Resize values based on screen height and width\n$rfs-two-dimensional: false !default;\n\n// Factor of decrease\n$rfs-factor: 10 !default;\n\n@if type-of($rfs-factor) != number or $rfs-factor <= 1 {\n @error \"`#{$rfs-factor}` is not a valid $rfs-factor, it must be greater than 1.\";\n}\n\n// Mode. Possibilities: \"min-media-query\", \"max-media-query\"\n$rfs-mode: min-media-query !default;\n\n// Generate enable or disable classes. Possibilities: false, \"enable\" or \"disable\"\n$rfs-class: false !default;\n\n// 1 rem = $rfs-rem-value px\n$rfs-rem-value: 16 !default;\n\n// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14\n$rfs-safari-iframe-resize-bug-fix: false !default;\n\n// Disable RFS by setting $enable-rfs to false\n$enable-rfs: true !default;\n\n// Cache $rfs-base-value unit\n$rfs-base-value-unit: unit($rfs-base-value);\n\n@function divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n $remainder: $dividend;\n $result: 0;\n $factor: 10;\n @while ($remainder > 0 and $precision >= 0) {\n $quotient: 0;\n @while ($remainder >= $divisor) {\n $remainder: $remainder - $divisor;\n $quotient: $quotient + 1;\n }\n $result: $result * 10 + $quotient;\n $factor: $factor * .1;\n $remainder: $remainder * 10;\n $precision: $precision - 1;\n @if ($precision < 0 and $remainder >= $divisor * 5) {\n $result: $result + 1;\n }\n }\n $result: $result * $factor * $sign;\n $dividend-unit: unit($dividend);\n $divisor-unit: unit($divisor);\n $unit-map: (\n \"px\": 1px,\n \"rem\": 1rem,\n \"em\": 1em,\n \"%\": 1%\n );\n @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {\n $result: $result * map-get($unit-map, $dividend-unit);\n }\n @return $result;\n}\n\n// Remove px-unit from $rfs-base-value for calculations\n@if $rfs-base-value-unit == px {\n $rfs-base-value: divide($rfs-base-value, $rfs-base-value * 0 + 1);\n}\n@else if $rfs-base-value-unit == rem {\n $rfs-base-value: divide($rfs-base-value, divide($rfs-base-value * 0 + 1, $rfs-rem-value));\n}\n\n// Cache $rfs-breakpoint unit to prevent multiple calls\n$rfs-breakpoint-unit-cache: unit($rfs-breakpoint);\n\n// Remove unit from $rfs-breakpoint for calculations\n@if $rfs-breakpoint-unit-cache == px {\n $rfs-breakpoint: divide($rfs-breakpoint, $rfs-breakpoint * 0 + 1);\n}\n@else if $rfs-breakpoint-unit-cache == rem or $rfs-breakpoint-unit-cache == \"em\" {\n $rfs-breakpoint: divide($rfs-breakpoint, divide($rfs-breakpoint * 0 + 1, $rfs-rem-value));\n}\n\n// Calculate the media query value\n$rfs-mq-value: if($rfs-breakpoint-unit == px, #{$rfs-breakpoint}px, #{divide($rfs-breakpoint, $rfs-rem-value)}#{$rfs-breakpoint-unit});\n$rfs-mq-property-width: if($rfs-mode == max-media-query, max-width, min-width);\n$rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height);\n\n// Internal mixin used to determine which media query needs to be used\n@mixin _rfs-media-query {\n @if $rfs-two-dimensional {\n @if $rfs-mode == max-media-query {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}), (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {\n @content;\n }\n }\n @else {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) and (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {\n @content;\n }\n }\n }\n @else {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) {\n @content;\n }\n }\n}\n\n// Internal mixin that adds disable classes to the selector if needed.\n@mixin _rfs-rule {\n @if $rfs-class == disable and $rfs-mode == max-media-query {\n // Adding an extra class increases specificity, which prevents the media query to override the property\n &,\n .disable-rfs &,\n &.disable-rfs {\n @content;\n }\n }\n @else if $rfs-class == enable and $rfs-mode == min-media-query {\n .enable-rfs &,\n &.enable-rfs {\n @content;\n }\n }\n @else {\n @content;\n }\n}\n\n// Internal mixin that adds enable classes to the selector if needed.\n@mixin _rfs-media-query-rule {\n\n @if $rfs-class == enable {\n @if $rfs-mode == min-media-query {\n @content;\n }\n\n @include _rfs-media-query {\n .enable-rfs &,\n &.enable-rfs {\n @content;\n }\n }\n }\n @else {\n @if $rfs-class == disable and $rfs-mode == min-media-query {\n .disable-rfs &,\n &.disable-rfs {\n @content;\n }\n }\n @include _rfs-media-query {\n @content;\n }\n }\n}\n\n// Helper function to get the formatted non-responsive value\n@function rfs-value($values) {\n // Convert to list\n $values: if(type-of($values) != list, ($values,), $values);\n\n $val: '';\n\n // Loop over each value and calculate value\n @each $value in $values {\n @if $value == 0 {\n $val: $val + ' 0';\n }\n @else {\n // Cache $value unit\n $unit: if(type-of($value) == \"number\", unit($value), false);\n\n @if $unit == px {\n // Convert to rem if needed\n $val: $val + ' ' + if($rfs-unit == rem, #{divide($value, $value * 0 + $rfs-rem-value)}rem, $value);\n }\n @else if $unit == rem {\n // Convert to px if needed\n $val: $val + ' ' + if($rfs-unit == px, #{divide($value, $value * 0 + 1) * $rfs-rem-value}px, $value);\n }\n @else {\n // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value\n $val: $val + ' ' + $value;\n }\n }\n }\n\n // Remove first space\n @return unquote(str-slice($val, 2));\n}\n\n// Helper function to get the responsive value calculated by RFS\n@function rfs-fluid-value($values) {\n // Convert to list\n $values: if(type-of($values) != list, ($values,), $values);\n\n $val: '';\n\n // Loop over each value and calculate value\n @each $value in $values {\n @if $value == 0 {\n $val: $val + ' 0';\n }\n\n @else {\n // Cache $value unit\n $unit: if(type-of($value) == \"number\", unit($value), false);\n\n // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value\n @if not $unit or $unit != px and $unit != rem {\n $val: $val + ' ' + $value;\n }\n\n @else {\n // Remove unit from $value for calculations\n $value: divide($value, $value * 0 + if($unit == px, 1, divide(1, $rfs-rem-value)));\n\n // Only add the media query if the value is greater than the minimum value\n @if abs($value) <= $rfs-base-value or not $enable-rfs {\n $val: $val + ' ' + if($rfs-unit == rem, #{divide($value, $rfs-rem-value)}rem, #{$value}px);\n }\n @else {\n // Calculate the minimum value\n $value-min: $rfs-base-value + divide(abs($value) - $rfs-base-value, $rfs-factor);\n\n // Calculate difference between $value and the minimum value\n $value-diff: abs($value) - $value-min;\n\n // Base value formatting\n $min-width: if($rfs-unit == rem, #{divide($value-min, $rfs-rem-value)}rem, #{$value-min}px);\n\n // Use negative value if needed\n $min-width: if($value < 0, -$min-width, $min-width);\n\n // Use `vmin` if two-dimensional is enabled\n $variable-unit: if($rfs-two-dimensional, vmin, vw);\n\n // Calculate the variable width between 0 and $rfs-breakpoint\n $variable-width: #{divide($value-diff * 100, $rfs-breakpoint)}#{$variable-unit};\n\n // Return the calculated value\n $val: $val + ' calc(' + $min-width + if($value < 0, ' - ', ' + ') + $variable-width + ')';\n }\n }\n }\n }\n\n // Remove first space\n @return unquote(str-slice($val, 2));\n}\n\n// RFS mixin\n@mixin rfs($values, $property: font-size) {\n @if $values != null {\n $val: rfs-value($values);\n $fluidVal: rfs-fluid-value($values);\n\n // Do not print the media query if responsive & non-responsive values are the same\n @if $val == $fluidVal {\n #{$property}: $val;\n }\n @else {\n @include _rfs-rule {\n #{$property}: if($rfs-mode == max-media-query, $val, $fluidVal);\n\n // Include safari iframe resize fix if needed\n min-width: if($rfs-safari-iframe-resize-bug-fix, (0 * 1vw), null);\n }\n\n @include _rfs-media-query-rule {\n #{$property}: if($rfs-mode == max-media-query, $fluidVal, $val);\n }\n }\n }\n}\n\n// Shorthand helper mixins\n@mixin font-size($value) {\n @include rfs($value);\n}\n\n@mixin padding($value) {\n @include rfs($value, padding);\n}\n\n@mixin padding-top($value) {\n @include rfs($value, padding-top);\n}\n\n@mixin padding-right($value) {\n @include rfs($value, padding-right);\n}\n\n@mixin padding-bottom($value) {\n @include rfs($value, padding-bottom);\n}\n\n@mixin padding-left($value) {\n @include rfs($value, padding-left);\n}\n\n@mixin margin($value) {\n @include rfs($value, margin);\n}\n\n@mixin margin-top($value) {\n @include rfs($value, margin-top);\n}\n\n@mixin margin-right($value) {\n @include rfs($value, margin-right);\n}\n\n@mixin margin-bottom($value) {\n @include rfs($value, margin-bottom);\n}\n\n@mixin margin-left($value) {\n @include rfs($value, margin-left);\n}\n","// stylelint-disable property-disallowed-list\n// Single side border-radius\n\n// Helper function to replace negative values with 0\n@function valid-radius($radius) {\n $return: ();\n @each $value in $radius {\n @if type-of($value) == number {\n $return: append($return, max($value, 0));\n } @else {\n $return: append($return, $value);\n }\n }\n @return $return;\n}\n\n// scss-docs-start border-radius-mixins\n@mixin border-radius($radius: $border-radius, $fallback-border-radius: false) {\n @if $enable-rounded {\n border-radius: valid-radius($radius);\n }\n @else if $fallback-border-radius != false {\n border-radius: $fallback-border-radius;\n }\n}\n\n@mixin border-top-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-top-left-radius: valid-radius($radius);\n border-top-right-radius: valid-radius($radius);\n }\n}\n\n@mixin border-end-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-top-right-radius: valid-radius($radius);\n border-bottom-right-radius: valid-radius($radius);\n }\n}\n\n@mixin border-bottom-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-bottom-right-radius: valid-radius($radius);\n border-bottom-left-radius: valid-radius($radius);\n }\n}\n\n@mixin border-start-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-top-left-radius: valid-radius($radius);\n border-bottom-left-radius: valid-radius($radius);\n }\n}\n\n@mixin border-top-start-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-top-left-radius: valid-radius($radius);\n }\n}\n\n@mixin border-top-end-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-top-right-radius: valid-radius($radius);\n }\n}\n\n@mixin border-bottom-end-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-bottom-right-radius: valid-radius($radius);\n }\n}\n\n@mixin border-bottom-start-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-bottom-left-radius: valid-radius($radius);\n }\n}\n// scss-docs-end border-radius-mixins\n","//\n// Headings\n//\n.h1 {\n @extend h1;\n}\n\n.h2 {\n @extend h2;\n}\n\n.h3 {\n @extend h3;\n}\n\n.h4 {\n @extend h4;\n}\n\n.h5 {\n @extend h5;\n}\n\n.h6 {\n @extend h6;\n}\n\n\n.lead {\n @include font-size($lead-font-size);\n font-weight: $lead-font-weight;\n}\n\n// Type display classes\n@each $display, $font-size in $display-font-sizes {\n .display-#{$display} {\n @include font-size($font-size);\n font-weight: $display-font-weight;\n line-height: $display-line-height;\n }\n}\n\n//\n// Emphasis\n//\n.small {\n @extend small;\n}\n\n.mark {\n @extend mark;\n}\n\n//\n// Lists\n//\n\n.list-unstyled {\n @include list-unstyled();\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n @include list-unstyled();\n}\n.list-inline-item {\n display: inline-block;\n\n &:not(:last-child) {\n margin-right: $list-inline-padding;\n }\n}\n\n\n//\n// Misc\n//\n\n// Builds on `abbr`\n.initialism {\n @include font-size($initialism-font-size);\n text-transform: uppercase;\n}\n\n// Blockquotes\n.blockquote {\n margin-bottom: $blockquote-margin-y;\n @include font-size($blockquote-font-size);\n\n > :last-child {\n margin-bottom: 0;\n }\n}\n\n.blockquote-footer {\n margin-top: -$blockquote-margin-y;\n margin-bottom: $blockquote-margin-y;\n @include font-size($blockquote-footer-font-size);\n color: $blockquote-footer-color;\n\n &::before {\n content: \"\\2014\\00A0\"; // em dash, nbsp\n }\n}\n","// Lists\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n@mixin list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n","// Responsive images (ensure images don't scale beyond their parents)\n//\n// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s.\n// We previously tried the \"images are responsive by default\" approach in Bootstrap v2,\n// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)\n// which weren't expecting the images within themselves to be involuntarily resized.\n// See also https://github.com/twbs/bootstrap/issues/18178\n.img-fluid {\n @include img-fluid();\n}\n\n\n// Image thumbnails\n.img-thumbnail {\n padding: $thumbnail-padding;\n background-color: $thumbnail-bg;\n border: $thumbnail-border-width solid $thumbnail-border-color;\n @include border-radius($thumbnail-border-radius);\n @include box-shadow($thumbnail-box-shadow);\n\n // Keep them at most 100% wide\n @include img-fluid();\n}\n\n//\n// Figures\n//\n\n.figure {\n // Ensures the caption's text aligns with the image.\n display: inline-block;\n}\n\n.figure-img {\n margin-bottom: $spacer * .5;\n line-height: 1;\n}\n\n.figure-caption {\n @include font-size($figure-caption-font-size);\n color: $figure-caption-color;\n}\n","// Image Mixins\n// - Responsive image\n// - Retina image\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n\n@mixin img-fluid {\n // Part 1: Set a maximum relative to the parent\n max-width: 100%;\n // Part 2: Override the height to auto, otherwise images will be stretched\n // when setting a width and height attribute on the img element.\n height: auto;\n}\n","// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n@if $enable-grid-classes {\n // Single container class with breakpoint max-widths\n .container,\n // 100% wide container at all breakpoints\n .container-fluid {\n @include make-container();\n }\n\n // Responsive containers that are 100% wide until a breakpoint\n @each $breakpoint, $container-max-width in $container-max-widths {\n .container-#{$breakpoint} {\n @extend .container-fluid;\n }\n\n @include media-breakpoint-up($breakpoint, $grid-breakpoints) {\n %responsive-container-#{$breakpoint} {\n max-width: $container-max-width;\n }\n\n // Extend each breakpoint which is smaller or equal to the current breakpoint\n $extend-breakpoint: true;\n\n @each $name, $width in $grid-breakpoints {\n @if ($extend-breakpoint) {\n .container#{breakpoint-infix($name, $grid-breakpoints)} {\n @extend %responsive-container-#{$breakpoint};\n }\n\n // Once the current breakpoint is reached, stop extending\n @if ($breakpoint == $name) {\n $extend-breakpoint: false;\n }\n }\n }\n }\n }\n}\n","// Container mixins\n\n@mixin make-container($gutter: $container-padding-x) {\n width: 100%;\n padding-right: var(--#{$variable-prefix}gutter-x, #{$gutter});\n padding-left: var(--#{$variable-prefix}gutter-x, #{$gutter});\n margin-right: auto;\n margin-left: auto;\n}\n","// Breakpoint viewport sizes and media queries.\n//\n// Breakpoints are defined as a map of (name: minimum width), order from small to large:\n//\n// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)\n//\n// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.\n\n// Name of the next breakpoint, or null for the last breakpoint.\n//\n// >> breakpoint-next(sm)\n// md\n// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// md\n// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl))\n// md\n@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {\n $n: index($breakpoint-names, $name);\n @if not $n {\n @error \"breakpoint `#{$name}` not found in `#{$breakpoints}`\";\n }\n @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);\n}\n\n// Minimum breakpoint width. Null for the smallest (first) breakpoint.\n//\n// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// 576px\n@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {\n $min: map-get($breakpoints, $name);\n @return if($min != 0, $min, null);\n}\n\n// Maximum breakpoint width.\n// The maximum value is reduced by 0.02px to work around the limitations of\n// `min-` and `max-` prefixes and viewports with fractional widths.\n// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max\n// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari.\n// See https://bugs.webkit.org/show_bug.cgi?id=178261\n//\n// >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// 767.98px\n@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {\n $max: map-get($breakpoints, $name);\n @return if($max and $max > 0, $max - .02, null);\n}\n\n// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.\n// Useful for making responsive utilities.\n//\n// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// \"\" (Returns a blank string)\n// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// \"-sm\"\n@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {\n @return if(breakpoint-min($name, $breakpoints) == null, \"\", \"-#{$name}\");\n}\n\n// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.\n// Makes the @content apply to the given breakpoint and wider.\n@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n @if $min {\n @media (min-width: $min) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media of at most the maximum breakpoint width. No query for the largest breakpoint.\n// Makes the @content apply to the given breakpoint and narrower.\n@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {\n $max: breakpoint-max($name, $breakpoints);\n @if $max {\n @media (max-width: $max) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media that spans multiple breakpoint widths.\n// Makes the @content apply between the min and max breakpoints\n@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($lower, $breakpoints);\n $max: breakpoint-max($upper, $breakpoints);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($lower, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($upper, $breakpoints) {\n @content;\n }\n }\n}\n\n// Media between the breakpoint's minimum and maximum widths.\n// No minimum for the smallest breakpoint, and no maximum for the largest one.\n// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower.\n@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n $next: breakpoint-next($name, $breakpoints);\n $max: breakpoint-max($next);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($name, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($next, $breakpoints) {\n @content;\n }\n }\n}\n","// Row\n//\n// Rows contain your columns.\n\n@if $enable-grid-classes {\n .row {\n @include make-row();\n\n > * {\n @include make-col-ready();\n }\n }\n}\n\n@if $enable-cssgrid {\n .grid {\n display: grid;\n grid-template-rows: repeat(var(--#{$variable-prefix}rows, 1), 1fr);\n grid-template-columns: repeat(var(--#{$variable-prefix}columns, #{$grid-columns}), 1fr);\n gap: var(--#{$variable-prefix}gap, #{$grid-gutter-width});\n\n @include make-cssgrid();\n }\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n@if $enable-grid-classes {\n @include make-grid-columns();\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n@mixin make-row($gutter: $grid-gutter-width) {\n --#{$variable-prefix}gutter-x: #{$gutter};\n --#{$variable-prefix}gutter-y: 0;\n display: flex;\n flex-wrap: wrap;\n // TODO: Revisit calc order after https://github.com/react-bootstrap/react-bootstrap/issues/6039 is fixed\n margin-top: calc(-1 * var(--#{$variable-prefix}gutter-y)); // stylelint-disable-line function-disallowed-list\n margin-right: calc(-.5 * var(--#{$variable-prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\n margin-left: calc(-.5 * var(--#{$variable-prefix}gutter-x)); // stylelint-disable-line function-disallowed-list\n}\n\n@mixin make-col-ready($gutter: $grid-gutter-width) {\n // Add box sizing if only the grid is loaded\n box-sizing: if(variable-exists(include-column-box-sizing) and $include-column-box-sizing, border-box, null);\n // Prevent columns from becoming too narrow when at smaller grid tiers by\n // always setting `width: 100%;`. This works because we set the width\n // later on to override this initial width.\n flex-shrink: 0;\n width: 100%;\n max-width: 100%; // Prevent `.col-auto`, `.col` (& responsive variants) from breaking out the grid\n padding-right: calc(var(--#{$variable-prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n padding-left: calc(var(--#{$variable-prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n margin-top: var(--#{$variable-prefix}gutter-y);\n}\n\n@mixin make-col($size: false, $columns: $grid-columns) {\n @if $size {\n flex: 0 0 auto;\n width: percentage(divide($size, $columns));\n\n } @else {\n flex: 1 1 0;\n max-width: 100%;\n }\n}\n\n@mixin make-col-auto() {\n flex: 0 0 auto;\n width: auto;\n}\n\n@mixin make-col-offset($size, $columns: $grid-columns) {\n $num: divide($size, $columns);\n margin-left: if($num == 0, 0, percentage($num));\n}\n\n// Row columns\n//\n// Specify on a parent element(e.g., .row) to force immediate children into NN\n// numberof columns. Supports wrapping to new lines, but does not do a Masonry\n// style grid.\n@mixin row-cols($count) {\n > * {\n flex: 0 0 auto;\n width: divide(100%, $count);\n }\n}\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `$grid-columns`.\n\n@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) {\n @each $breakpoint in map-keys($breakpoints) {\n $infix: breakpoint-infix($breakpoint, $breakpoints);\n\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n // Provide basic `.col-{bp}` classes for equal-width flexbox columns\n .col#{$infix} {\n flex: 1 0 0%; // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4\n }\n\n .row-cols#{$infix}-auto > * {\n @include make-col-auto();\n }\n\n @if $grid-row-columns > 0 {\n @for $i from 1 through $grid-row-columns {\n .row-cols#{$infix}-#{$i} {\n @include row-cols($i);\n }\n }\n }\n\n .col#{$infix}-auto {\n @include make-col-auto();\n }\n\n @if $columns > 0 {\n @for $i from 1 through $columns {\n .col#{$infix}-#{$i} {\n @include make-col($i, $columns);\n }\n }\n\n // `$columns - 1` because offsetting by the width of an entire row isn't possible\n @for $i from 0 through ($columns - 1) {\n @if not ($infix == \"\" and $i == 0) { // Avoid emitting useless .offset-0\n .offset#{$infix}-#{$i} {\n @include make-col-offset($i, $columns);\n }\n }\n }\n }\n\n // Gutters\n //\n // Make use of `.g-*`, `.gx-*` or `.gy-*` utilities to change spacing between the columns.\n @each $key, $value in $gutters {\n .g#{$infix}-#{$key},\n .gx#{$infix}-#{$key} {\n --#{$variable-prefix}gutter-x: #{$value};\n }\n\n .g#{$infix}-#{$key},\n .gy#{$infix}-#{$key} {\n --#{$variable-prefix}gutter-y: #{$value};\n }\n }\n }\n }\n}\n\n@mixin make-cssgrid($columns: $grid-columns, $breakpoints: $grid-breakpoints) {\n @each $breakpoint in map-keys($breakpoints) {\n $infix: breakpoint-infix($breakpoint, $breakpoints);\n\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n @if $columns > 0 {\n @for $i from 1 through $columns {\n .g-col#{$infix}-#{$i} {\n grid-column: auto / span $i;\n }\n }\n\n // Start with `1` because `0` is and invalid value.\n // Ends with `$columns - 1` because offsetting by the width of an entire row isn't possible.\n @for $i from 1 through ($columns - 1) {\n .g-start#{$infix}-#{$i} {\n grid-column-start: $i;\n }\n }\n }\n }\n }\n}\n","//\n// Basic Bootstrap table\n//\n\n.table {\n --#{$variable-prefix}table-bg: #{$table-bg};\n --#{$variable-prefix}table-accent-bg: #{$table-accent-bg};\n --#{$variable-prefix}table-striped-color: #{$table-striped-color};\n --#{$variable-prefix}table-striped-bg: #{$table-striped-bg};\n --#{$variable-prefix}table-active-color: #{$table-active-color};\n --#{$variable-prefix}table-active-bg: #{$table-active-bg};\n --#{$variable-prefix}table-hover-color: #{$table-hover-color};\n --#{$variable-prefix}table-hover-bg: #{$table-hover-bg};\n\n width: 100%;\n margin-bottom: $spacer;\n color: $table-color;\n vertical-align: $table-cell-vertical-align;\n border-color: $table-border-color;\n\n // Target th & td\n // We need the child combinator to prevent styles leaking to nested tables which doesn't have a `.table` class.\n // We use the universal selectors here to simplify the selector (else we would need 6 different selectors).\n // Another advantage is that this generates less code and makes the selector less specific making it easier to override.\n // stylelint-disable-next-line selector-max-universal\n > :not(caption) > * > * {\n padding: $table-cell-padding-y $table-cell-padding-x;\n background-color: var(--#{$variable-prefix}table-bg);\n border-bottom-width: $table-border-width;\n box-shadow: inset 0 0 0 9999px var(--#{$variable-prefix}table-accent-bg);\n }\n\n > tbody {\n vertical-align: inherit;\n }\n\n > thead {\n vertical-align: bottom;\n }\n\n // Highlight border color between thead, tbody and tfoot.\n > :not(:first-child) {\n border-top: (2 * $table-border-width) solid $table-group-separator-color;\n }\n}\n\n\n//\n// Change placement of captions with a class\n//\n\n.caption-top {\n caption-side: top;\n}\n\n\n//\n// Condensed table w/ half padding\n//\n\n.table-sm {\n // stylelint-disable-next-line selector-max-universal\n > :not(caption) > * > * {\n padding: $table-cell-padding-y-sm $table-cell-padding-x-sm;\n }\n}\n\n\n// Border versions\n//\n// Add or remove borders all around the table and between all the columns.\n//\n// When borders are added on all sides of the cells, the corners can render odd when\n// these borders do not have the same color or if they are semi-transparent.\n// Therefor we add top and border bottoms to the `tr`s and left and right borders\n// to the `td`s or `th`s\n\n.table-bordered {\n > :not(caption) > * {\n border-width: $table-border-width 0;\n\n // stylelint-disable-next-line selector-max-universal\n > * {\n border-width: 0 $table-border-width;\n }\n }\n}\n\n.table-borderless {\n // stylelint-disable-next-line selector-max-universal\n > :not(caption) > * > * {\n border-bottom-width: 0;\n }\n\n > :not(:first-child) {\n border-top-width: 0;\n }\n}\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n > tbody > tr:nth-of-type(#{$table-striped-order}) > * {\n --#{$variable-prefix}table-accent-bg: var(--#{$variable-prefix}table-striped-bg);\n color: var(--#{$variable-prefix}table-striped-color);\n }\n}\n\n// Active table\n//\n// The `.table-active` class can be added to highlight rows or cells\n\n.table-active {\n --#{$variable-prefix}table-accent-bg: var(--#{$variable-prefix}table-active-bg);\n color: var(--#{$variable-prefix}table-active-color);\n}\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n > tbody > tr:hover > * {\n --#{$variable-prefix}table-accent-bg: var(--#{$variable-prefix}table-hover-bg);\n color: var(--#{$variable-prefix}table-hover-color);\n }\n}\n\n\n// Table variants\n//\n// Table variants set the table cell backgrounds, border colors\n// and the colors of the striped, hovered & active tables\n\n@each $color, $value in $table-variants {\n @include table-variant($color, $value);\n}\n\n// Responsive tables\n//\n// Generate series of `.table-responsive-*` classes for configuring the screen\n// size of where your table will overflow.\n\n@each $breakpoint in map-keys($grid-breakpoints) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n @include media-breakpoint-down($breakpoint) {\n .table-responsive#{$infix} {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n }\n }\n}\n","// scss-docs-start table-variant\n@mixin table-variant($state, $background) {\n .table-#{$state} {\n $color: color-contrast(opaque($body-bg, $background));\n $hover-bg: mix($color, $background, percentage($table-hover-bg-factor));\n $striped-bg: mix($color, $background, percentage($table-striped-bg-factor));\n $active-bg: mix($color, $background, percentage($table-active-bg-factor));\n\n --#{$variable-prefix}table-bg: #{$background};\n --#{$variable-prefix}table-striped-bg: #{$striped-bg};\n --#{$variable-prefix}table-striped-color: #{color-contrast($striped-bg)};\n --#{$variable-prefix}table-active-bg: #{$active-bg};\n --#{$variable-prefix}table-active-color: #{color-contrast($active-bg)};\n --#{$variable-prefix}table-hover-bg: #{$hover-bg};\n --#{$variable-prefix}table-hover-color: #{color-contrast($hover-bg)};\n\n color: $color;\n border-color: mix($color, $background, percentage($table-border-factor));\n }\n}\n// scss-docs-end table-variant\n","//\n// Labels\n//\n\n.form-label {\n margin-bottom: $form-label-margin-bottom;\n @include font-size($form-label-font-size);\n font-style: $form-label-font-style;\n font-weight: $form-label-font-weight;\n color: $form-label-color;\n}\n\n// For use with horizontal and inline forms, when you need the label (or legend)\n// text to align with the form controls.\n.col-form-label {\n padding-top: add($input-padding-y, $input-border-width);\n padding-bottom: add($input-padding-y, $input-border-width);\n margin-bottom: 0; // Override the `<legend>` default\n @include font-size(inherit); // Override the `<legend>` default\n font-style: $form-label-font-style;\n font-weight: $form-label-font-weight;\n line-height: $input-line-height;\n color: $form-label-color;\n}\n\n.col-form-label-lg {\n padding-top: add($input-padding-y-lg, $input-border-width);\n padding-bottom: add($input-padding-y-lg, $input-border-width);\n @include font-size($input-font-size-lg);\n}\n\n.col-form-label-sm {\n padding-top: add($input-padding-y-sm, $input-border-width);\n padding-bottom: add($input-padding-y-sm, $input-border-width);\n @include font-size($input-font-size-sm);\n}\n","//\n// Form text\n//\n\n.form-text {\n margin-top: $form-text-margin-top;\n @include font-size($form-text-font-size);\n font-style: $form-text-font-style;\n font-weight: $form-text-font-weight;\n color: $form-text-color;\n}\n","//\n// General form controls (plus a few specific high-level interventions)\n//\n\n.form-control {\n display: block;\n width: 100%;\n padding: $input-padding-y $input-padding-x;\n font-family: $input-font-family;\n @include font-size($input-font-size);\n font-weight: $input-font-weight;\n line-height: $input-line-height;\n color: $input-color;\n background-color: $input-bg;\n background-clip: padding-box;\n border: $input-border-width solid $input-border-color;\n appearance: none; // Fix appearance for date inputs in Safari\n\n // Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS.\n @include border-radius($input-border-radius, 0);\n\n @include box-shadow($input-box-shadow);\n @include transition($input-transition);\n\n &[type=\"file\"] {\n overflow: hidden; // prevent pseudo element button overlap\n\n &:not(:disabled):not([readonly]) {\n cursor: pointer;\n }\n }\n\n // Customize the `:focus` state to imitate native WebKit styles.\n &:focus {\n color: $input-focus-color;\n background-color: $input-focus-bg;\n border-color: $input-focus-border-color;\n outline: 0;\n @if $enable-shadows {\n @include box-shadow($input-box-shadow, $input-focus-box-shadow);\n } @else {\n // Avoid using mixin so we can pass custom focus shadow properly\n box-shadow: $input-focus-box-shadow;\n }\n }\n\n // Add some height to date inputs on iOS\n // https://github.com/twbs/bootstrap/issues/23307\n // TODO: we can remove this workaround once https://bugs.webkit.org/show_bug.cgi?id=198959 is resolved\n &::-webkit-date-and-time-value {\n // Multiply line-height by 1em if it has no unit\n height: if(unit($input-line-height) == \"\", $input-line-height * 1em, $input-line-height);\n }\n\n // Placeholder\n &::placeholder {\n color: $input-placeholder-color;\n // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526.\n opacity: 1;\n }\n\n // Disabled and read-only inputs\n //\n // HTML5 says that controls under a fieldset > legend:first-child won't be\n // disabled if the fieldset is disabled. Due to implementation difficulty, we\n // don't honor that edge case; we style them as disabled anyway.\n &:disabled,\n &[readonly] {\n background-color: $input-disabled-bg;\n border-color: $input-disabled-border-color;\n // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655.\n opacity: 1;\n }\n\n // File input buttons theming\n &::file-selector-button {\n padding: $input-padding-y $input-padding-x;\n margin: (-$input-padding-y) (-$input-padding-x);\n margin-inline-end: $input-padding-x;\n color: $form-file-button-color;\n @include gradient-bg($form-file-button-bg);\n pointer-events: none;\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n border-inline-end-width: $input-border-width;\n border-radius: 0; // stylelint-disable-line property-disallowed-list\n @include transition($btn-transition);\n }\n\n &:hover:not(:disabled):not([readonly])::file-selector-button {\n background-color: $form-file-button-hover-bg;\n }\n\n &::-webkit-file-upload-button {\n padding: $input-padding-y $input-padding-x;\n margin: (-$input-padding-y) (-$input-padding-x);\n margin-inline-end: $input-padding-x;\n color: $form-file-button-color;\n @include gradient-bg($form-file-button-bg);\n pointer-events: none;\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n border-inline-end-width: $input-border-width;\n border-radius: 0; // stylelint-disable-line property-disallowed-list\n @include transition($btn-transition);\n }\n\n &:hover:not(:disabled):not([readonly])::-webkit-file-upload-button {\n background-color: $form-file-button-hover-bg;\n }\n}\n\n// Readonly controls as plain text\n//\n// Apply class to a readonly input to make it appear like regular plain\n// text (without any border, background color, focus indicator)\n\n.form-control-plaintext {\n display: block;\n width: 100%;\n padding: $input-padding-y 0;\n margin-bottom: 0; // match inputs if this class comes on inputs with default margins\n line-height: $input-line-height;\n color: $input-plaintext-color;\n background-color: transparent;\n border: solid transparent;\n border-width: $input-border-width 0;\n\n &.form-control-sm,\n &.form-control-lg {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n//\n// Repeated in `_input_group.scss` to avoid Sass extend issues.\n\n.form-control-sm {\n min-height: $input-height-sm;\n padding: $input-padding-y-sm $input-padding-x-sm;\n @include font-size($input-font-size-sm);\n @include border-radius($input-border-radius-sm);\n\n &::file-selector-button {\n padding: $input-padding-y-sm $input-padding-x-sm;\n margin: (-$input-padding-y-sm) (-$input-padding-x-sm);\n margin-inline-end: $input-padding-x-sm;\n }\n\n &::-webkit-file-upload-button {\n padding: $input-padding-y-sm $input-padding-x-sm;\n margin: (-$input-padding-y-sm) (-$input-padding-x-sm);\n margin-inline-end: $input-padding-x-sm;\n }\n}\n\n.form-control-lg {\n min-height: $input-height-lg;\n padding: $input-padding-y-lg $input-padding-x-lg;\n @include font-size($input-font-size-lg);\n @include border-radius($input-border-radius-lg);\n\n &::file-selector-button {\n padding: $input-padding-y-lg $input-padding-x-lg;\n margin: (-$input-padding-y-lg) (-$input-padding-x-lg);\n margin-inline-end: $input-padding-x-lg;\n }\n\n &::-webkit-file-upload-button {\n padding: $input-padding-y-lg $input-padding-x-lg;\n margin: (-$input-padding-y-lg) (-$input-padding-x-lg);\n margin-inline-end: $input-padding-x-lg;\n }\n}\n\n// Make sure textareas don't shrink too much when resized\n// https://github.com/twbs/bootstrap/pull/29124\n// stylelint-disable selector-no-qualifying-type\ntextarea {\n &.form-control {\n min-height: $input-height;\n }\n\n &.form-control-sm {\n min-height: $input-height-sm;\n }\n\n &.form-control-lg {\n min-height: $input-height-lg;\n }\n}\n// stylelint-enable selector-no-qualifying-type\n\n.form-control-color {\n width: $form-color-width;\n height: auto; // Override fixed browser height\n padding: $input-padding-y;\n\n &:not(:disabled):not([readonly]) {\n cursor: pointer;\n }\n\n &::-moz-color-swatch {\n height: if(unit($input-line-height) == \"\", $input-line-height * 1em, $input-line-height);\n @include border-radius($input-border-radius);\n }\n\n &::-webkit-color-swatch {\n height: if(unit($input-line-height) == \"\", $input-line-height * 1em, $input-line-height);\n @include border-radius($input-border-radius);\n }\n}\n","// stylelint-disable property-disallowed-list\n@mixin transition($transition...) {\n @if length($transition) == 0 {\n $transition: $transition-base;\n }\n\n @if length($transition) > 1 {\n @each $value in $transition {\n @if $value == null or $value == none {\n @warn \"The keyword 'none' or 'null' must be used as a single argument.\";\n }\n }\n }\n\n @if $enable-transitions {\n @if nth($transition, 1) != null {\n transition: $transition;\n }\n\n @if $enable-reduced-motion and nth($transition, 1) != null and nth($transition, 1) != none {\n @media (prefers-reduced-motion: reduce) {\n transition: none;\n }\n }\n }\n}\n","// Gradients\n\n// scss-docs-start gradient-bg-mixin\n@mixin gradient-bg($color: null) {\n background-color: $color;\n\n @if $enable-gradients {\n background-image: var(--#{$variable-prefix}gradient);\n }\n}\n// scss-docs-end gradient-bg-mixin\n\n// scss-docs-start gradient-mixins\n// Horizontal gradient, from left to right\n//\n// Creates two color stops, start and end, by specifying a color and position for each color stop.\n@mixin gradient-x($start-color: $gray-700, $end-color: $gray-800, $start-percent: 0%, $end-percent: 100%) {\n background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent);\n}\n\n// Vertical gradient, from top to bottom\n//\n// Creates two color stops, start and end, by specifying a color and position for each color stop.\n@mixin gradient-y($start-color: $gray-700, $end-color: $gray-800, $start-percent: null, $end-percent: null) {\n background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent);\n}\n\n@mixin gradient-directional($start-color: $gray-700, $end-color: $gray-800, $deg: 45deg) {\n background-image: linear-gradient($deg, $start-color, $end-color);\n}\n\n@mixin gradient-x-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) {\n background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color);\n}\n\n@mixin gradient-y-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) {\n background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color);\n}\n\n@mixin gradient-radial($inner-color: $gray-700, $outer-color: $gray-800) {\n background-image: radial-gradient(circle, $inner-color, $outer-color);\n}\n\n@mixin gradient-striped($color: rgba($white, .15), $angle: 45deg) {\n background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent);\n}\n// scss-docs-end gradient-mixins\n","// Select\n//\n// Replaces the browser default select with a custom one, mostly pulled from\n// https://primer.github.io/.\n\n.form-select {\n display: block;\n width: 100%;\n padding: $form-select-padding-y $form-select-indicator-padding $form-select-padding-y $form-select-padding-x;\n // stylelint-disable-next-line property-no-vendor-prefix\n -moz-padding-start: subtract($form-select-padding-x, 3px); // See https://github.com/twbs/bootstrap/issues/32636\n font-family: $form-select-font-family;\n @include font-size($form-select-font-size);\n font-weight: $form-select-font-weight;\n line-height: $form-select-line-height;\n color: $form-select-color;\n background-color: $form-select-bg;\n background-image: escape-svg($form-select-indicator);\n background-repeat: no-repeat;\n background-position: $form-select-bg-position;\n background-size: $form-select-bg-size;\n border: $form-select-border-width solid $form-select-border-color;\n @include border-radius($form-select-border-radius, 0);\n @include box-shadow($form-select-box-shadow);\n @include transition($form-select-transition);\n appearance: none;\n\n &:focus {\n border-color: $form-select-focus-border-color;\n outline: 0;\n @if $enable-shadows {\n @include box-shadow($form-select-box-shadow, $form-select-focus-box-shadow);\n } @else {\n // Avoid using mixin so we can pass custom focus shadow properly\n box-shadow: $form-select-focus-box-shadow;\n }\n }\n\n &[multiple],\n &[size]:not([size=\"1\"]) {\n padding-right: $form-select-padding-x;\n background-image: none;\n }\n\n &:disabled {\n color: $form-select-disabled-color;\n background-color: $form-select-disabled-bg;\n border-color: $form-select-disabled-border-color;\n }\n\n // Remove outline from select box in FF\n &:-moz-focusring {\n color: transparent;\n text-shadow: 0 0 0 $form-select-color;\n }\n}\n\n.form-select-sm {\n padding-top: $form-select-padding-y-sm;\n padding-bottom: $form-select-padding-y-sm;\n padding-left: $form-select-padding-x-sm;\n @include font-size($form-select-font-size-sm);\n @include border-radius($form-select-border-radius-sm);\n}\n\n.form-select-lg {\n padding-top: $form-select-padding-y-lg;\n padding-bottom: $form-select-padding-y-lg;\n padding-left: $form-select-padding-x-lg;\n @include font-size($form-select-font-size-lg);\n @include border-radius($form-select-border-radius-lg);\n}\n","//\n// Check/radio\n//\n\n.form-check {\n display: block;\n min-height: $form-check-min-height;\n padding-left: $form-check-padding-start;\n margin-bottom: $form-check-margin-bottom;\n\n .form-check-input {\n float: left;\n margin-left: $form-check-padding-start * -1;\n }\n}\n\n.form-check-input {\n width: $form-check-input-width;\n height: $form-check-input-width;\n margin-top: ($line-height-base - $form-check-input-width) * .5; // line-height minus check height\n vertical-align: top;\n background-color: $form-check-input-bg;\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n border: $form-check-input-border;\n appearance: none;\n color-adjust: exact; // Keep themed appearance for print\n @include transition($form-check-transition);\n\n &[type=\"checkbox\"] {\n @include border-radius($form-check-input-border-radius);\n }\n\n &[type=\"radio\"] {\n // stylelint-disable-next-line property-disallowed-list\n border-radius: $form-check-radio-border-radius;\n }\n\n &:active {\n filter: $form-check-input-active-filter;\n }\n\n &:focus {\n border-color: $form-check-input-focus-border;\n outline: 0;\n box-shadow: $form-check-input-focus-box-shadow;\n }\n\n &:checked {\n background-color: $form-check-input-checked-bg-color;\n border-color: $form-check-input-checked-border-color;\n\n &[type=\"checkbox\"] {\n @if $enable-gradients {\n background-image: escape-svg($form-check-input-checked-bg-image), var(--#{$variable-prefix}gradient);\n } @else {\n background-image: escape-svg($form-check-input-checked-bg-image);\n }\n }\n\n &[type=\"radio\"] {\n @if $enable-gradients {\n background-image: escape-svg($form-check-radio-checked-bg-image), var(--#{$variable-prefix}gradient);\n } @else {\n background-image: escape-svg($form-check-radio-checked-bg-image);\n }\n }\n }\n\n &[type=\"checkbox\"]:indeterminate {\n background-color: $form-check-input-indeterminate-bg-color;\n border-color: $form-check-input-indeterminate-border-color;\n\n @if $enable-gradients {\n background-image: escape-svg($form-check-input-indeterminate-bg-image), var(--#{$variable-prefix}gradient);\n } @else {\n background-image: escape-svg($form-check-input-indeterminate-bg-image);\n }\n }\n\n &:disabled {\n pointer-events: none;\n filter: none;\n opacity: $form-check-input-disabled-opacity;\n }\n\n // Use disabled attribute in addition of :disabled pseudo-class\n // See: https://github.com/twbs/bootstrap/issues/28247\n &[disabled],\n &:disabled {\n ~ .form-check-label {\n opacity: $form-check-label-disabled-opacity;\n }\n }\n}\n\n.form-check-label {\n color: $form-check-label-color;\n cursor: $form-check-label-cursor;\n}\n\n//\n// Switch\n//\n\n.form-switch {\n padding-left: $form-switch-padding-start;\n\n .form-check-input {\n width: $form-switch-width;\n margin-left: $form-switch-padding-start * -1;\n background-image: escape-svg($form-switch-bg-image);\n background-position: left center;\n @include border-radius($form-switch-border-radius);\n @include transition($form-switch-transition);\n\n &:focus {\n background-image: escape-svg($form-switch-focus-bg-image);\n }\n\n &:checked {\n background-position: $form-switch-checked-bg-position;\n\n @if $enable-gradients {\n background-image: escape-svg($form-switch-checked-bg-image), var(--#{$variable-prefix}gradient);\n } @else {\n background-image: escape-svg($form-switch-checked-bg-image);\n }\n }\n }\n}\n\n.form-check-inline {\n display: inline-block;\n margin-right: $form-check-inline-margin-end;\n}\n\n.btn-check {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n\n &[disabled],\n &:disabled {\n + .btn {\n pointer-events: none;\n filter: none;\n opacity: $form-check-btn-check-disabled-opacity;\n }\n }\n}\n","// Range\n//\n// Style range inputs the same across browsers. Vendor-specific rules for pseudo\n// elements cannot be mixed. As such, there are no shared styles for focus or\n// active states on prefixed selectors.\n\n.form-range {\n width: 100%;\n height: add($form-range-thumb-height, $form-range-thumb-focus-box-shadow-width * 2);\n padding: 0; // Need to reset padding\n background-color: transparent;\n appearance: none;\n\n &:focus {\n outline: 0;\n\n // Pseudo-elements must be split across multiple rulesets to have an effect.\n // No box-shadow() mixin for focus accessibility.\n &::-webkit-slider-thumb { box-shadow: $form-range-thumb-focus-box-shadow; }\n &::-moz-range-thumb { box-shadow: $form-range-thumb-focus-box-shadow; }\n }\n\n &::-moz-focus-outer {\n border: 0;\n }\n\n &::-webkit-slider-thumb {\n width: $form-range-thumb-width;\n height: $form-range-thumb-height;\n margin-top: ($form-range-track-height - $form-range-thumb-height) * .5; // Webkit specific\n @include gradient-bg($form-range-thumb-bg);\n border: $form-range-thumb-border;\n @include border-radius($form-range-thumb-border-radius);\n @include box-shadow($form-range-thumb-box-shadow);\n @include transition($form-range-thumb-transition);\n appearance: none;\n\n &:active {\n @include gradient-bg($form-range-thumb-active-bg);\n }\n }\n\n &::-webkit-slider-runnable-track {\n width: $form-range-track-width;\n height: $form-range-track-height;\n color: transparent; // Why?\n cursor: $form-range-track-cursor;\n background-color: $form-range-track-bg;\n border-color: transparent;\n @include border-radius($form-range-track-border-radius);\n @include box-shadow($form-range-track-box-shadow);\n }\n\n &::-moz-range-thumb {\n width: $form-range-thumb-width;\n height: $form-range-thumb-height;\n @include gradient-bg($form-range-thumb-bg);\n border: $form-range-thumb-border;\n @include border-radius($form-range-thumb-border-radius);\n @include box-shadow($form-range-thumb-box-shadow);\n @include transition($form-range-thumb-transition);\n appearance: none;\n\n &:active {\n @include gradient-bg($form-range-thumb-active-bg);\n }\n }\n\n &::-moz-range-track {\n width: $form-range-track-width;\n height: $form-range-track-height;\n color: transparent;\n cursor: $form-range-track-cursor;\n background-color: $form-range-track-bg;\n border-color: transparent; // Firefox specific?\n @include border-radius($form-range-track-border-radius);\n @include box-shadow($form-range-track-box-shadow);\n }\n\n &:disabled {\n pointer-events: none;\n\n &::-webkit-slider-thumb {\n background-color: $form-range-thumb-disabled-bg;\n }\n\n &::-moz-range-thumb {\n background-color: $form-range-thumb-disabled-bg;\n }\n }\n}\n",".form-floating {\n position: relative;\n\n > .form-control,\n > .form-select {\n height: $form-floating-height;\n line-height: $form-floating-line-height;\n }\n\n > label {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%; // allow textareas\n padding: $form-floating-padding-y $form-floating-padding-x;\n pointer-events: none;\n border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model\n transform-origin: 0 0;\n @include transition($form-floating-transition);\n }\n\n // stylelint-disable no-duplicate-selectors\n > .form-control {\n padding: $form-floating-padding-y $form-floating-padding-x;\n\n &::placeholder {\n color: transparent;\n }\n\n &:focus,\n &:not(:placeholder-shown) {\n padding-top: $form-floating-input-padding-t;\n padding-bottom: $form-floating-input-padding-b;\n }\n // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped\n &:-webkit-autofill {\n padding-top: $form-floating-input-padding-t;\n padding-bottom: $form-floating-input-padding-b;\n }\n }\n\n > .form-select {\n padding-top: $form-floating-input-padding-t;\n padding-bottom: $form-floating-input-padding-b;\n }\n\n > .form-control:focus,\n > .form-control:not(:placeholder-shown),\n > .form-select {\n ~ label {\n opacity: $form-floating-label-opacity;\n transform: $form-floating-label-transform;\n }\n }\n // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped\n > .form-control:-webkit-autofill {\n ~ label {\n opacity: $form-floating-label-opacity;\n transform: $form-floating-label-transform;\n }\n }\n // stylelint-enable no-duplicate-selectors\n}\n","//\n// Base styles\n//\n\n.input-group {\n position: relative;\n display: flex;\n flex-wrap: wrap; // For form validation feedback\n align-items: stretch;\n width: 100%;\n\n > .form-control,\n > .form-select {\n position: relative; // For focus state's z-index\n flex: 1 1 auto;\n width: 1%;\n min-width: 0; // https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size\n }\n\n // Bring the \"active\" form control to the top of surrounding elements\n > .form-control:focus,\n > .form-select:focus {\n z-index: 3;\n }\n\n // Ensure buttons are always above inputs for more visually pleasing borders.\n // This isn't needed for `.input-group-text` since it shares the same border-color\n // as our inputs.\n .btn {\n position: relative;\n z-index: 2;\n\n &:focus {\n z-index: 3;\n }\n }\n}\n\n\n// Textual addons\n//\n// Serves as a catch-all element for any text or radio/checkbox input you wish\n// to prepend or append to an input.\n\n.input-group-text {\n display: flex;\n align-items: center;\n padding: $input-group-addon-padding-y $input-group-addon-padding-x;\n @include font-size($input-font-size); // Match inputs\n font-weight: $input-group-addon-font-weight;\n line-height: $input-line-height;\n color: $input-group-addon-color;\n text-align: center;\n white-space: nowrap;\n background-color: $input-group-addon-bg;\n border: $input-border-width solid $input-group-addon-border-color;\n @include border-radius($input-border-radius);\n}\n\n\n// Sizing\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .form-select,\n.input-group-lg > .input-group-text,\n.input-group-lg > .btn {\n padding: $input-padding-y-lg $input-padding-x-lg;\n @include font-size($input-font-size-lg);\n @include border-radius($input-border-radius-lg);\n}\n\n.input-group-sm > .form-control,\n.input-group-sm > .form-select,\n.input-group-sm > .input-group-text,\n.input-group-sm > .btn {\n padding: $input-padding-y-sm $input-padding-x-sm;\n @include font-size($input-font-size-sm);\n @include border-radius($input-border-radius-sm);\n}\n\n.input-group-lg > .form-select,\n.input-group-sm > .form-select {\n padding-right: $form-select-padding-x + $form-select-indicator-padding;\n}\n\n\n// Rounded corners\n//\n// These rulesets must come after the sizing ones to properly override sm and lg\n// border-radius values when extending. They're more specific than we'd like\n// with the `.input-group >` part, but without it, we cannot override the sizing.\n\n// stylelint-disable-next-line no-duplicate-selectors\n.input-group {\n &:not(.has-validation) {\n > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu),\n > .dropdown-toggle:nth-last-child(n + 3) {\n @include border-end-radius(0);\n }\n }\n\n &.has-validation {\n > :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu),\n > .dropdown-toggle:nth-last-child(n + 4) {\n @include border-end-radius(0);\n }\n }\n\n $validation-messages: \"\";\n @each $state in map-keys($form-validation-states) {\n $validation-messages: $validation-messages + \":not(.\" + unquote($state) + \"-tooltip)\" + \":not(.\" + unquote($state) + \"-feedback)\";\n }\n\n > :not(:first-child):not(.dropdown-menu)#{$validation-messages} {\n margin-left: -$input-border-width;\n @include border-start-radius(0);\n }\n}\n","// This mixin uses an `if()` technique to be compatible with Dart Sass\n// See https://github.com/sass/sass/issues/1873#issuecomment-152293725 for more details\n\n// scss-docs-start form-validation-mixins\n@mixin form-validation-state-selector($state) {\n @if ($state == \"valid\" or $state == \"invalid\") {\n .was-validated #{if(&, \"&\", \"\")}:#{$state},\n #{if(&, \"&\", \"\")}.is-#{$state} {\n @content;\n }\n } @else {\n #{if(&, \"&\", \"\")}.is-#{$state} {\n @content;\n }\n }\n}\n\n@mixin form-validation-state(\n $state,\n $color,\n $icon,\n $tooltip-color: color-contrast($color),\n $tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity),\n $focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity)\n) {\n .#{$state}-feedback {\n display: none;\n width: 100%;\n margin-top: $form-feedback-margin-top;\n @include font-size($form-feedback-font-size);\n font-style: $form-feedback-font-style;\n color: $color;\n }\n\n .#{$state}-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n max-width: 100%; // Contain to parent when possible\n padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x;\n margin-top: .1rem;\n @include font-size($form-feedback-tooltip-font-size);\n line-height: $form-feedback-tooltip-line-height;\n color: $tooltip-color;\n background-color: $tooltip-bg-color;\n @include border-radius($form-feedback-tooltip-border-radius);\n }\n\n @include form-validation-state-selector($state) {\n ~ .#{$state}-feedback,\n ~ .#{$state}-tooltip {\n display: block;\n }\n }\n\n .form-control {\n @include form-validation-state-selector($state) {\n border-color: $color;\n\n @if $enable-validation-icons {\n padding-right: $input-height-inner;\n background-image: escape-svg($icon);\n background-repeat: no-repeat;\n background-position: right $input-height-inner-quarter center;\n background-size: $input-height-inner-half $input-height-inner-half;\n }\n\n &:focus {\n border-color: $color;\n box-shadow: $focus-box-shadow;\n }\n }\n }\n\n // stylelint-disable-next-line selector-no-qualifying-type\n textarea.form-control {\n @include form-validation-state-selector($state) {\n @if $enable-validation-icons {\n padding-right: $input-height-inner;\n background-position: top $input-height-inner-quarter right $input-height-inner-quarter;\n }\n }\n }\n\n .form-select {\n @include form-validation-state-selector($state) {\n border-color: $color;\n\n @if $enable-validation-icons {\n &:not([multiple]):not([size]),\n &:not([multiple])[size=\"1\"] {\n padding-right: $form-select-feedback-icon-padding-end;\n background-image: escape-svg($form-select-indicator), escape-svg($icon);\n background-position: $form-select-bg-position, $form-select-feedback-icon-position;\n background-size: $form-select-bg-size, $form-select-feedback-icon-size;\n }\n }\n\n &:focus {\n border-color: $color;\n box-shadow: $focus-box-shadow;\n }\n }\n }\n\n .form-check-input {\n @include form-validation-state-selector($state) {\n border-color: $color;\n\n &:checked {\n background-color: $color;\n }\n\n &:focus {\n box-shadow: $focus-box-shadow;\n }\n\n ~ .form-check-label {\n color: $color;\n }\n }\n }\n .form-check-inline .form-check-input {\n ~ .#{$state}-feedback {\n margin-left: .5em;\n }\n }\n\n .input-group .form-control,\n .input-group .form-select {\n @include form-validation-state-selector($state) {\n @if $state == \"valid\" {\n z-index: 1;\n } @else if $state == \"invalid\" {\n z-index: 2;\n }\n &:focus {\n z-index: 3;\n }\n }\n }\n}\n// scss-docs-end form-validation-mixins\n","//\n// Base styles\n//\n\n.btn {\n display: inline-block;\n font-family: $btn-font-family;\n font-weight: $btn-font-weight;\n line-height: $btn-line-height;\n color: $body-color;\n text-align: center;\n text-decoration: if($link-decoration == none, null, none);\n white-space: $btn-white-space;\n vertical-align: middle;\n cursor: if($enable-button-pointers, pointer, null);\n user-select: none;\n background-color: transparent;\n border: $btn-border-width solid transparent;\n @include button-size($btn-padding-y, $btn-padding-x, $btn-font-size, $btn-border-radius);\n @include transition($btn-transition);\n\n &:hover {\n color: $body-color;\n text-decoration: if($link-hover-decoration == underline, none, null);\n }\n\n .btn-check:focus + &,\n &:focus {\n outline: 0;\n box-shadow: $btn-focus-box-shadow;\n }\n\n .btn-check:checked + &,\n .btn-check:active + &,\n &:active,\n &.active {\n @include box-shadow($btn-active-box-shadow);\n\n &:focus {\n @include box-shadow($btn-focus-box-shadow, $btn-active-box-shadow);\n }\n }\n\n &:disabled,\n &.disabled,\n fieldset:disabled & {\n pointer-events: none;\n opacity: $btn-disabled-opacity;\n @include box-shadow(none);\n }\n}\n\n\n//\n// Alternate buttons\n//\n\n// scss-docs-start btn-variant-loops\n@each $color, $value in $theme-colors {\n .btn-#{$color} {\n @include button-variant($value, $value);\n }\n}\n\n@each $color, $value in $theme-colors {\n .btn-outline-#{$color} {\n @include button-outline-variant($value);\n }\n}\n// scss-docs-end btn-variant-loops\n\n\n//\n// Link buttons\n//\n\n// Make a button look and behave like a link\n.btn-link {\n font-weight: $font-weight-normal;\n color: $btn-link-color;\n text-decoration: $link-decoration;\n\n &:hover {\n color: $btn-link-hover-color;\n text-decoration: $link-hover-decoration;\n }\n\n &:focus {\n text-decoration: $link-hover-decoration;\n }\n\n &:disabled,\n &.disabled {\n color: $btn-link-disabled-color;\n }\n\n // No need for an active state here\n}\n\n\n//\n// Button Sizes\n//\n\n.btn-lg {\n @include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg);\n}\n\n.btn-sm {\n @include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm);\n}\n","// Button variants\n//\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n\n// scss-docs-start btn-variant-mixin\n@mixin button-variant(\n $background,\n $border,\n $color: color-contrast($background),\n $hover-background: if($color == $color-contrast-light, shade-color($background, $btn-hover-bg-shade-amount), tint-color($background, $btn-hover-bg-tint-amount)),\n $hover-border: if($color == $color-contrast-light, shade-color($border, $btn-hover-border-shade-amount), tint-color($border, $btn-hover-border-tint-amount)),\n $hover-color: color-contrast($hover-background),\n $active-background: if($color == $color-contrast-light, shade-color($background, $btn-active-bg-shade-amount), tint-color($background, $btn-active-bg-tint-amount)),\n $active-border: if($color == $color-contrast-light, shade-color($border, $btn-active-border-shade-amount), tint-color($border, $btn-active-border-tint-amount)),\n $active-color: color-contrast($active-background),\n $disabled-background: $background,\n $disabled-border: $border,\n $disabled-color: color-contrast($disabled-background)\n) {\n color: $color;\n @include gradient-bg($background);\n border-color: $border;\n @include box-shadow($btn-box-shadow);\n\n &:hover {\n color: $hover-color;\n @include gradient-bg($hover-background);\n border-color: $hover-border;\n }\n\n .btn-check:focus + &,\n &:focus {\n color: $hover-color;\n @include gradient-bg($hover-background);\n border-color: $hover-border;\n @if $enable-shadows {\n @include box-shadow($btn-box-shadow, 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5));\n } @else {\n // Avoid using mixin so we can pass custom focus shadow properly\n box-shadow: 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5);\n }\n }\n\n .btn-check:checked + &,\n .btn-check:active + &,\n &:active,\n &.active,\n .show > &.dropdown-toggle {\n color: $active-color;\n background-color: $active-background;\n // Remove CSS gradients if they're enabled\n background-image: if($enable-gradients, none, null);\n border-color: $active-border;\n\n &:focus {\n @if $enable-shadows {\n @include box-shadow($btn-active-box-shadow, 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5));\n } @else {\n // Avoid using mixin so we can pass custom focus shadow properly\n box-shadow: 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5);\n }\n }\n }\n\n &:disabled,\n &.disabled {\n color: $disabled-color;\n background-color: $disabled-background;\n // Remove CSS gradients if they're enabled\n background-image: if($enable-gradients, none, null);\n border-color: $disabled-border;\n }\n}\n// scss-docs-end btn-variant-mixin\n\n// scss-docs-start btn-outline-variant-mixin\n@mixin button-outline-variant(\n $color,\n $color-hover: color-contrast($color),\n $active-background: $color,\n $active-border: $color,\n $active-color: color-contrast($active-background)\n) {\n color: $color;\n border-color: $color;\n\n &:hover {\n color: $color-hover;\n background-color: $active-background;\n border-color: $active-border;\n }\n\n .btn-check:focus + &,\n &:focus {\n box-shadow: 0 0 0 $btn-focus-width rgba($color, .5);\n }\n\n .btn-check:checked + &,\n .btn-check:active + &,\n &:active,\n &.active,\n &.dropdown-toggle.show {\n color: $active-color;\n background-color: $active-background;\n border-color: $active-border;\n\n &:focus {\n @if $enable-shadows {\n @include box-shadow($btn-active-box-shadow, 0 0 0 $btn-focus-width rgba($color, .5));\n } @else {\n // Avoid using mixin so we can pass custom focus shadow properly\n box-shadow: 0 0 0 $btn-focus-width rgba($color, .5);\n }\n }\n }\n\n &:disabled,\n &.disabled {\n color: $color;\n background-color: transparent;\n }\n}\n// scss-docs-end btn-outline-variant-mixin\n\n// scss-docs-start btn-size-mixin\n@mixin button-size($padding-y, $padding-x, $font-size, $border-radius) {\n padding: $padding-y $padding-x;\n @include font-size($font-size);\n // Manually declare to provide an override to the browser default\n @include border-radius($border-radius, 0);\n}\n// scss-docs-end btn-size-mixin\n",".fade {\n @include transition($transition-fade);\n\n &:not(.show) {\n opacity: 0;\n }\n}\n\n// scss-docs-start collapse-classes\n.collapse {\n &:not(.show) {\n display: none;\n }\n}\n\n.collapsing {\n height: 0;\n overflow: hidden;\n @include transition($transition-collapse);\n\n &.collapse-horizontal {\n width: 0;\n height: auto;\n @include transition($transition-collapse-width);\n }\n}\n// scss-docs-end collapse-classes\n","// The dropdown wrapper (`<div>`)\n.dropup,\n.dropend,\n.dropdown,\n.dropstart {\n position: relative;\n}\n\n.dropdown-toggle {\n white-space: nowrap;\n\n // Generate the caret automatically\n @include caret();\n}\n\n// The dropdown menu\n.dropdown-menu {\n position: absolute;\n z-index: $zindex-dropdown;\n display: none; // none by default, but block on \"open\" of the menu\n min-width: $dropdown-min-width;\n padding: $dropdown-padding-y $dropdown-padding-x;\n margin: 0; // Override default margin of ul\n @include font-size($dropdown-font-size);\n color: $dropdown-color;\n text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)\n list-style: none;\n background-color: $dropdown-bg;\n background-clip: padding-box;\n border: $dropdown-border-width solid $dropdown-border-color;\n @include border-radius($dropdown-border-radius);\n @include box-shadow($dropdown-box-shadow);\n\n &[data-bs-popper] {\n top: 100%;\n left: 0;\n margin-top: $dropdown-spacer;\n }\n}\n\n// scss-docs-start responsive-breakpoints\n// We deliberately hardcode the `bs-` prefix because we check\n// this custom property in JS to determine Popper's positioning\n\n@each $breakpoint in map-keys($grid-breakpoints) {\n @include media-breakpoint-up($breakpoint) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n .dropdown-menu#{$infix}-start {\n --bs-position: start;\n\n &[data-bs-popper] {\n right: auto;\n left: 0;\n }\n }\n\n .dropdown-menu#{$infix}-end {\n --bs-position: end;\n\n &[data-bs-popper] {\n right: 0;\n left: auto;\n }\n }\n }\n}\n// scss-docs-end responsive-breakpoints\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n// Just add .dropup after the standard .dropdown class and you're set.\n.dropup {\n .dropdown-menu[data-bs-popper] {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: $dropdown-spacer;\n }\n\n .dropdown-toggle {\n @include caret(up);\n }\n}\n\n.dropend {\n .dropdown-menu[data-bs-popper] {\n top: 0;\n right: auto;\n left: 100%;\n margin-top: 0;\n margin-left: $dropdown-spacer;\n }\n\n .dropdown-toggle {\n @include caret(end);\n &::after {\n vertical-align: 0;\n }\n }\n}\n\n.dropstart {\n .dropdown-menu[data-bs-popper] {\n top: 0;\n right: 100%;\n left: auto;\n margin-top: 0;\n margin-right: $dropdown-spacer;\n }\n\n .dropdown-toggle {\n @include caret(start);\n &::before {\n vertical-align: 0;\n }\n }\n}\n\n\n// Dividers (basically an `<hr>`) within the dropdown\n.dropdown-divider {\n height: 0;\n margin: $dropdown-divider-margin-y 0;\n overflow: hidden;\n border-top: 1px solid $dropdown-divider-bg;\n}\n\n// Links, buttons, and more within the dropdown menu\n//\n// `<button>`-specific styles are denoted with `// For <button>s`\n.dropdown-item {\n display: block;\n width: 100%; // For `<button>`s\n padding: $dropdown-item-padding-y $dropdown-item-padding-x;\n clear: both;\n font-weight: $font-weight-normal;\n color: $dropdown-link-color;\n text-align: inherit; // For `<button>`s\n text-decoration: if($link-decoration == none, null, none);\n white-space: nowrap; // prevent links from randomly breaking onto new lines\n background-color: transparent; // For `<button>`s\n border: 0; // For `<button>`s\n\n // Prevent dropdown overflow if there's no padding\n // See https://github.com/twbs/bootstrap/pull/27703\n @if $dropdown-padding-y == 0 {\n &:first-child {\n @include border-top-radius($dropdown-inner-border-radius);\n }\n\n &:last-child {\n @include border-bottom-radius($dropdown-inner-border-radius);\n }\n }\n\n &:hover,\n &:focus {\n color: $dropdown-link-hover-color;\n text-decoration: if($link-hover-decoration == underline, none, null);\n @include gradient-bg($dropdown-link-hover-bg);\n }\n\n &.active,\n &:active {\n color: $dropdown-link-active-color;\n text-decoration: none;\n @include gradient-bg($dropdown-link-active-bg);\n }\n\n &.disabled,\n &:disabled {\n color: $dropdown-link-disabled-color;\n pointer-events: none;\n background-color: transparent;\n // Remove CSS gradients if they're enabled\n background-image: if($enable-gradients, none, null);\n }\n}\n\n.dropdown-menu.show {\n display: block;\n}\n\n// Dropdown section headers\n.dropdown-header {\n display: block;\n padding: $dropdown-header-padding;\n margin-bottom: 0; // for use with heading elements\n @include font-size($font-size-sm);\n color: $dropdown-header-color;\n white-space: nowrap; // as with > li > a\n}\n\n// Dropdown text\n.dropdown-item-text {\n display: block;\n padding: $dropdown-item-padding-y $dropdown-item-padding-x;\n color: $dropdown-link-color;\n}\n\n// Dark dropdowns\n.dropdown-menu-dark {\n color: $dropdown-dark-color;\n background-color: $dropdown-dark-bg;\n border-color: $dropdown-dark-border-color;\n @include box-shadow($dropdown-dark-box-shadow);\n\n .dropdown-item {\n color: $dropdown-dark-link-color;\n\n &:hover,\n &:focus {\n color: $dropdown-dark-link-hover-color;\n @include gradient-bg($dropdown-dark-link-hover-bg);\n }\n\n &.active,\n &:active {\n color: $dropdown-dark-link-active-color;\n @include gradient-bg($dropdown-dark-link-active-bg);\n }\n\n &.disabled,\n &:disabled {\n color: $dropdown-dark-link-disabled-color;\n }\n }\n\n .dropdown-divider {\n border-color: $dropdown-dark-divider-bg;\n }\n\n .dropdown-item-text {\n color: $dropdown-dark-link-color;\n }\n\n .dropdown-header {\n color: $dropdown-dark-header-color;\n }\n}\n","// scss-docs-start caret-mixins\n@mixin caret-down {\n border-top: $caret-width solid;\n border-right: $caret-width solid transparent;\n border-bottom: 0;\n border-left: $caret-width solid transparent;\n}\n\n@mixin caret-up {\n border-top: 0;\n border-right: $caret-width solid transparent;\n border-bottom: $caret-width solid;\n border-left: $caret-width solid transparent;\n}\n\n@mixin caret-end {\n border-top: $caret-width solid transparent;\n border-right: 0;\n border-bottom: $caret-width solid transparent;\n border-left: $caret-width solid;\n}\n\n@mixin caret-start {\n border-top: $caret-width solid transparent;\n border-right: $caret-width solid;\n border-bottom: $caret-width solid transparent;\n}\n\n@mixin caret($direction: down) {\n @if $enable-caret {\n &::after {\n display: inline-block;\n margin-left: $caret-spacing;\n vertical-align: $caret-vertical-align;\n content: \"\";\n @if $direction == down {\n @include caret-down();\n } @else if $direction == up {\n @include caret-up();\n } @else if $direction == end {\n @include caret-end();\n }\n }\n\n @if $direction == start {\n &::after {\n display: none;\n }\n\n &::before {\n display: inline-block;\n margin-right: $caret-spacing;\n vertical-align: $caret-vertical-align;\n content: \"\";\n @include caret-start();\n }\n }\n\n &:empty::after {\n margin-left: 0;\n }\n }\n}\n// scss-docs-end caret-mixins\n","// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-flex;\n vertical-align: middle; // match .btn alignment given font-size hack above\n\n > .btn {\n position: relative;\n flex: 1 1 auto;\n }\n\n // Bring the hover, focused, and \"active\" buttons to the front to overlay\n // the borders properly\n > .btn-check:checked + .btn,\n > .btn-check:focus + .btn,\n > .btn:hover,\n > .btn:focus,\n > .btn:active,\n > .btn.active {\n z-index: 1;\n }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-start;\n\n .input-group {\n width: auto;\n }\n}\n\n.btn-group {\n // Prevent double borders when buttons are next to each other\n > .btn:not(:first-child),\n > .btn-group:not(:first-child) {\n margin-left: -$btn-border-width;\n }\n\n // Reset rounded corners\n > .btn:not(:last-child):not(.dropdown-toggle),\n > .btn-group:not(:last-child) > .btn {\n @include border-end-radius(0);\n }\n\n // The left radius should be 0 if the button is:\n // - the \"third or more\" child\n // - the second child and the previous element isn't `.btn-check` (making it the first child visually)\n // - part of a btn-group which isn't the first child\n > .btn:nth-child(n + 3),\n > :not(.btn-check) + .btn,\n > .btn-group:not(:first-child) > .btn {\n @include border-start-radius(0);\n }\n}\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-sm > .btn { @extend .btn-sm; }\n.btn-group-lg > .btn { @extend .btn-lg; }\n\n\n//\n// Split button dropdowns\n//\n\n.dropdown-toggle-split {\n padding-right: $btn-padding-x * .75;\n padding-left: $btn-padding-x * .75;\n\n &::after,\n .dropup &::after,\n .dropend &::after {\n margin-left: 0;\n }\n\n .dropstart &::before {\n margin-right: 0;\n }\n}\n\n.btn-sm + .dropdown-toggle-split {\n padding-right: $btn-padding-x-sm * .75;\n padding-left: $btn-padding-x-sm * .75;\n}\n\n.btn-lg + .dropdown-toggle-split {\n padding-right: $btn-padding-x-lg * .75;\n padding-left: $btn-padding-x-lg * .75;\n}\n\n\n// The clickable button for toggling the menu\n// Set the same inset shadow as the :active state\n.btn-group.show .dropdown-toggle {\n @include box-shadow($btn-active-box-shadow);\n\n // Show no shadow for `.btn-link` since it has no other button styles.\n &.btn-link {\n @include box-shadow(none);\n }\n}\n\n\n//\n// Vertical button groups\n//\n\n.btn-group-vertical {\n flex-direction: column;\n align-items: flex-start;\n justify-content: center;\n\n > .btn,\n > .btn-group {\n width: 100%;\n }\n\n > .btn:not(:first-child),\n > .btn-group:not(:first-child) {\n margin-top: -$btn-border-width;\n }\n\n // Reset rounded corners\n > .btn:not(:last-child):not(.dropdown-toggle),\n > .btn-group:not(:last-child) > .btn {\n @include border-bottom-radius(0);\n }\n\n > .btn ~ .btn,\n > .btn-group:not(:first-child) > .btn {\n @include border-top-radius(0);\n }\n}\n","// Base class\n//\n// Kickstart any navigation component with a set of style resets. Works with\n// `<nav>`s, `<ul>`s or `<ol>`s.\n\n.nav {\n display: flex;\n flex-wrap: wrap;\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n\n.nav-link {\n display: block;\n padding: $nav-link-padding-y $nav-link-padding-x;\n @include font-size($nav-link-font-size);\n font-weight: $nav-link-font-weight;\n color: $nav-link-color;\n text-decoration: if($link-decoration == none, null, none);\n @include transition($nav-link-transition);\n\n &:hover,\n &:focus {\n color: $nav-link-hover-color;\n text-decoration: if($link-hover-decoration == underline, none, null);\n }\n\n // Disabled state lightens text\n &.disabled {\n color: $nav-link-disabled-color;\n pointer-events: none;\n cursor: default;\n }\n}\n\n//\n// Tabs\n//\n\n.nav-tabs {\n border-bottom: $nav-tabs-border-width solid $nav-tabs-border-color;\n\n .nav-link {\n margin-bottom: -$nav-tabs-border-width;\n background: none;\n border: $nav-tabs-border-width solid transparent;\n @include border-top-radius($nav-tabs-border-radius);\n\n &:hover,\n &:focus {\n border-color: $nav-tabs-link-hover-border-color;\n // Prevents active .nav-link tab overlapping focus outline of previous/next .nav-link\n isolation: isolate;\n }\n\n &.disabled {\n color: $nav-link-disabled-color;\n background-color: transparent;\n border-color: transparent;\n }\n }\n\n .nav-link.active,\n .nav-item.show .nav-link {\n color: $nav-tabs-link-active-color;\n background-color: $nav-tabs-link-active-bg;\n border-color: $nav-tabs-link-active-border-color;\n }\n\n .dropdown-menu {\n // Make dropdown border overlap tab border\n margin-top: -$nav-tabs-border-width;\n // Remove the top rounded corners here since there is a hard edge above the menu\n @include border-top-radius(0);\n }\n}\n\n\n//\n// Pills\n//\n\n.nav-pills {\n .nav-link {\n background: none;\n border: 0;\n @include border-radius($nav-pills-border-radius);\n }\n\n .nav-link.active,\n .show > .nav-link {\n color: $nav-pills-link-active-color;\n @include gradient-bg($nav-pills-link-active-bg);\n }\n}\n\n\n//\n// Justified variants\n//\n\n.nav-fill {\n > .nav-link,\n .nav-item {\n flex: 1 1 auto;\n text-align: center;\n }\n}\n\n.nav-justified {\n > .nav-link,\n .nav-item {\n flex-basis: 0;\n flex-grow: 1;\n text-align: center;\n }\n}\n\n.nav-fill,\n.nav-justified {\n .nav-item .nav-link {\n width: 100%; // Make sure button will grow\n }\n}\n\n\n// Tabbable tabs\n//\n// Hide tabbable panes to start, show them when `.active`\n\n.tab-content {\n > .tab-pane {\n display: none;\n }\n > .active {\n display: block;\n }\n}\n","// Contents\n//\n// Navbar\n// Navbar brand\n// Navbar nav\n// Navbar text\n// Responsive navbar\n// Navbar position\n// Navbar themes\n\n\n// Navbar\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n position: relative;\n display: flex;\n flex-wrap: wrap; // allow us to do the line break for collapsing content\n align-items: center;\n justify-content: space-between; // space out brand from logo\n padding-top: $navbar-padding-y;\n padding-right: $navbar-padding-x; // default: null\n padding-bottom: $navbar-padding-y;\n padding-left: $navbar-padding-x; // default: null\n @include gradient-bg();\n\n // Because flex properties aren't inherited, we need to redeclare these first\n // few properties so that content nested within behave properly.\n // The `flex-wrap` property is inherited to simplify the expanded navbars\n %container-flex-properties {\n display: flex;\n flex-wrap: inherit;\n align-items: center;\n justify-content: space-between;\n }\n\n > .container,\n > .container-fluid {\n @extend %container-flex-properties;\n }\n\n @each $breakpoint, $container-max-width in $container-max-widths {\n > .container#{breakpoint-infix($breakpoint, $container-max-widths)} {\n @extend %container-flex-properties;\n }\n }\n}\n\n\n// Navbar brand\n//\n// Used for brand, project, or site names.\n\n.navbar-brand {\n padding-top: $navbar-brand-padding-y;\n padding-bottom: $navbar-brand-padding-y;\n margin-right: $navbar-brand-margin-end;\n @include font-size($navbar-brand-font-size);\n text-decoration: if($link-decoration == none, null, none);\n white-space: nowrap;\n\n &:hover,\n &:focus {\n text-decoration: if($link-hover-decoration == underline, none, null);\n }\n}\n\n\n// Navbar nav\n//\n// Custom navbar navigation (doesn't require `.nav`, but does make use of `.nav-link`).\n\n.navbar-nav {\n display: flex;\n flex-direction: column; // cannot use `inherit` to get the `.navbar`s value\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n\n .nav-link {\n padding-right: 0;\n padding-left: 0;\n }\n\n .dropdown-menu {\n position: static;\n }\n}\n\n\n// Navbar text\n//\n//\n\n.navbar-text {\n padding-top: $nav-link-padding-y;\n padding-bottom: $nav-link-padding-y;\n}\n\n\n// Responsive navbar\n//\n// Custom styles for responsive collapsing and toggling of navbar contents.\n// Powered by the collapse Bootstrap JavaScript plugin.\n\n// When collapsed, prevent the toggleable navbar contents from appearing in\n// the default flexbox row orientation. Requires the use of `flex-wrap: wrap`\n// on the `.navbar` parent.\n.navbar-collapse {\n flex-basis: 100%;\n flex-grow: 1;\n // For always expanded or extra full navbars, ensure content aligns itself\n // properly vertically. Can be easily overridden with flex utilities.\n align-items: center;\n}\n\n// Button for toggling the navbar when in its collapsed state\n.navbar-toggler {\n padding: $navbar-toggler-padding-y $navbar-toggler-padding-x;\n @include font-size($navbar-toggler-font-size);\n line-height: 1;\n background-color: transparent; // remove default button style\n border: $border-width solid transparent; // remove default button style\n @include border-radius($navbar-toggler-border-radius);\n @include transition($navbar-toggler-transition);\n\n &:hover {\n text-decoration: none;\n }\n\n &:focus {\n text-decoration: none;\n outline: 0;\n box-shadow: 0 0 0 $navbar-toggler-focus-width;\n }\n}\n\n// Keep as a separate element so folks can easily override it with another icon\n// or image file as needed.\n.navbar-toggler-icon {\n display: inline-block;\n width: 1.5em;\n height: 1.5em;\n vertical-align: middle;\n background-repeat: no-repeat;\n background-position: center;\n background-size: 100%;\n}\n\n.navbar-nav-scroll {\n max-height: var(--#{$variable-prefix}scroll-height, 75vh);\n overflow-y: auto;\n}\n\n// scss-docs-start navbar-expand-loop\n// Generate series of `.navbar-expand-*` responsive classes for configuring\n// where your navbar collapses.\n.navbar-expand {\n @each $breakpoint in map-keys($grid-breakpoints) {\n $next: breakpoint-next($breakpoint, $grid-breakpoints);\n $infix: breakpoint-infix($next, $grid-breakpoints);\n\n // stylelint-disable-next-line scss/selector-no-union-class-name\n &#{$infix} {\n @include media-breakpoint-up($next) {\n flex-wrap: nowrap;\n justify-content: flex-start;\n\n .navbar-nav {\n flex-direction: row;\n\n .dropdown-menu {\n position: absolute;\n }\n\n .nav-link {\n padding-right: $navbar-nav-link-padding-x;\n padding-left: $navbar-nav-link-padding-x;\n }\n }\n\n .navbar-nav-scroll {\n overflow: visible;\n }\n\n .navbar-collapse {\n display: flex !important; // stylelint-disable-line declaration-no-important\n flex-basis: auto;\n }\n\n .navbar-toggler {\n display: none;\n }\n\n .offcanvas-header {\n display: none;\n }\n\n .offcanvas {\n position: inherit;\n bottom: 0;\n z-index: 1000;\n flex-grow: 1;\n visibility: visible !important; // stylelint-disable-line declaration-no-important\n background-color: transparent;\n border-right: 0;\n border-left: 0;\n @include transition(none);\n transform: none;\n }\n .offcanvas-top,\n .offcanvas-bottom {\n height: auto;\n border-top: 0;\n border-bottom: 0;\n }\n\n .offcanvas-body {\n display: flex;\n flex-grow: 0;\n padding: 0;\n overflow-y: visible;\n }\n }\n }\n }\n}\n// scss-docs-end navbar-expand-loop\n\n// Navbar themes\n//\n// Styles for switching between navbars with light or dark background.\n\n// Dark links against a light background\n.navbar-light {\n .navbar-brand {\n color: $navbar-light-brand-color;\n\n &:hover,\n &:focus {\n color: $navbar-light-brand-hover-color;\n }\n }\n\n .navbar-nav {\n .nav-link {\n color: $navbar-light-color;\n\n &:hover,\n &:focus {\n color: $navbar-light-hover-color;\n }\n\n &.disabled {\n color: $navbar-light-disabled-color;\n }\n }\n\n .show > .nav-link,\n .nav-link.active {\n color: $navbar-light-active-color;\n }\n }\n\n .navbar-toggler {\n color: $navbar-light-color;\n border-color: $navbar-light-toggler-border-color;\n }\n\n .navbar-toggler-icon {\n background-image: escape-svg($navbar-light-toggler-icon-bg);\n }\n\n .navbar-text {\n color: $navbar-light-color;\n\n a,\n a:hover,\n a:focus {\n color: $navbar-light-active-color;\n }\n }\n}\n\n// White links against a dark background\n.navbar-dark {\n .navbar-brand {\n color: $navbar-dark-brand-color;\n\n &:hover,\n &:focus {\n color: $navbar-dark-brand-hover-color;\n }\n }\n\n .navbar-nav {\n .nav-link {\n color: $navbar-dark-color;\n\n &:hover,\n &:focus {\n color: $navbar-dark-hover-color;\n }\n\n &.disabled {\n color: $navbar-dark-disabled-color;\n }\n }\n\n .show > .nav-link,\n .nav-link.active {\n color: $navbar-dark-active-color;\n }\n }\n\n .navbar-toggler {\n color: $navbar-dark-color;\n border-color: $navbar-dark-toggler-border-color;\n }\n\n .navbar-toggler-icon {\n background-image: escape-svg($navbar-dark-toggler-icon-bg);\n }\n\n .navbar-text {\n color: $navbar-dark-color;\n a,\n a:hover,\n a:focus {\n color: $navbar-dark-active-color;\n }\n }\n}\n","//\n// Base styles\n//\n\n.card {\n position: relative;\n display: flex;\n flex-direction: column;\n min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106\n height: $card-height;\n word-wrap: break-word;\n background-color: $card-bg;\n background-clip: border-box;\n border: $card-border-width solid $card-border-color;\n @include border-radius($card-border-radius);\n @include box-shadow($card-box-shadow);\n\n > hr {\n margin-right: 0;\n margin-left: 0;\n }\n\n > .list-group {\n border-top: inherit;\n border-bottom: inherit;\n\n &:first-child {\n border-top-width: 0;\n @include border-top-radius($card-inner-border-radius);\n }\n\n &:last-child {\n border-bottom-width: 0;\n @include border-bottom-radius($card-inner-border-radius);\n }\n }\n\n // Due to specificity of the above selector (`.card > .list-group`), we must\n // use a child selector here to prevent double borders.\n > .card-header + .list-group,\n > .list-group + .card-footer {\n border-top: 0;\n }\n}\n\n.card-body {\n // Enable `flex-grow: 1` for decks and groups so that card blocks take up\n // as much space as possible, ensuring footers are aligned to the bottom.\n flex: 1 1 auto;\n padding: $card-spacer-y $card-spacer-x;\n color: $card-color;\n}\n\n.card-title {\n margin-bottom: $card-title-spacer-y;\n}\n\n.card-subtitle {\n margin-top: -$card-title-spacer-y * .5;\n margin-bottom: 0;\n}\n\n.card-text:last-child {\n margin-bottom: 0;\n}\n\n.card-link {\n &:hover {\n text-decoration: if($link-hover-decoration == underline, none, null);\n }\n\n + .card-link {\n margin-left: $card-spacer-x;\n }\n}\n\n//\n// Optional textual caps\n//\n\n.card-header {\n padding: $card-cap-padding-y $card-cap-padding-x;\n margin-bottom: 0; // Removes the default margin-bottom of <hN>\n color: $card-cap-color;\n background-color: $card-cap-bg;\n border-bottom: $card-border-width solid $card-border-color;\n\n &:first-child {\n @include border-radius($card-inner-border-radius $card-inner-border-radius 0 0);\n }\n}\n\n.card-footer {\n padding: $card-cap-padding-y $card-cap-padding-x;\n color: $card-cap-color;\n background-color: $card-cap-bg;\n border-top: $card-border-width solid $card-border-color;\n\n &:last-child {\n @include border-radius(0 0 $card-inner-border-radius $card-inner-border-radius);\n }\n}\n\n\n//\n// Header navs\n//\n\n.card-header-tabs {\n margin-right: -$card-cap-padding-x * .5;\n margin-bottom: -$card-cap-padding-y;\n margin-left: -$card-cap-padding-x * .5;\n border-bottom: 0;\n\n @if $nav-tabs-link-active-bg != $card-bg {\n .nav-link.active {\n background-color: $card-bg;\n border-bottom-color: $card-bg;\n }\n }\n}\n\n.card-header-pills {\n margin-right: -$card-cap-padding-x * .5;\n margin-left: -$card-cap-padding-x * .5;\n}\n\n// Card image\n.card-img-overlay {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n padding: $card-img-overlay-padding;\n @include border-radius($card-inner-border-radius);\n}\n\n.card-img,\n.card-img-top,\n.card-img-bottom {\n width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch\n}\n\n.card-img,\n.card-img-top {\n @include border-top-radius($card-inner-border-radius);\n}\n\n.card-img,\n.card-img-bottom {\n @include border-bottom-radius($card-inner-border-radius);\n}\n\n\n//\n// Card groups\n//\n\n.card-group {\n // The child selector allows nested `.card` within `.card-group`\n // to display properly.\n > .card {\n margin-bottom: $card-group-margin;\n }\n\n @include media-breakpoint-up(sm) {\n display: flex;\n flex-flow: row wrap;\n // The child selector allows nested `.card` within `.card-group`\n // to display properly.\n > .card {\n // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4\n flex: 1 0 0%;\n margin-bottom: 0;\n\n + .card {\n margin-left: 0;\n border-left: 0;\n }\n\n // Handle rounded corners\n @if $enable-rounded {\n &:not(:last-child) {\n @include border-end-radius(0);\n\n .card-img-top,\n .card-header {\n // stylelint-disable-next-line property-disallowed-list\n border-top-right-radius: 0;\n }\n .card-img-bottom,\n .card-footer {\n // stylelint-disable-next-line property-disallowed-list\n border-bottom-right-radius: 0;\n }\n }\n\n &:not(:first-child) {\n @include border-start-radius(0);\n\n .card-img-top,\n .card-header {\n // stylelint-disable-next-line property-disallowed-list\n border-top-left-radius: 0;\n }\n .card-img-bottom,\n .card-footer {\n // stylelint-disable-next-line property-disallowed-list\n border-bottom-left-radius: 0;\n }\n }\n }\n }\n }\n}\n","//\n// Base styles\n//\n\n.accordion-button {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n padding: $accordion-button-padding-y $accordion-button-padding-x;\n @include font-size($font-size-base);\n color: $accordion-button-color;\n text-align: left; // Reset button style\n background-color: $accordion-button-bg;\n border: 0;\n @include border-radius(0);\n overflow-anchor: none;\n @include transition($accordion-transition);\n\n &:not(.collapsed) {\n color: $accordion-button-active-color;\n background-color: $accordion-button-active-bg;\n box-shadow: inset 0 ($accordion-border-width * -1) 0 $accordion-border-color;\n\n &::after {\n background-image: escape-svg($accordion-button-active-icon);\n transform: $accordion-icon-transform;\n }\n }\n\n // Accordion icon\n &::after {\n flex-shrink: 0;\n width: $accordion-icon-width;\n height: $accordion-icon-width;\n margin-left: auto;\n content: \"\";\n background-image: escape-svg($accordion-button-icon);\n background-repeat: no-repeat;\n background-size: $accordion-icon-width;\n @include transition($accordion-icon-transition);\n }\n\n &:hover {\n z-index: 2;\n }\n\n &:focus {\n z-index: 3;\n border-color: $accordion-button-focus-border-color;\n outline: 0;\n box-shadow: $accordion-button-focus-box-shadow;\n }\n}\n\n.accordion-header {\n margin-bottom: 0;\n}\n\n.accordion-item {\n background-color: $accordion-bg;\n border: $accordion-border-width solid $accordion-border-color;\n\n &:first-of-type {\n @include border-top-radius($accordion-border-radius);\n\n .accordion-button {\n @include border-top-radius($accordion-inner-border-radius);\n }\n }\n\n &:not(:first-of-type) {\n border-top: 0;\n }\n\n // Only set a border-radius on the last item if the accordion is collapsed\n &:last-of-type {\n @include border-bottom-radius($accordion-border-radius);\n\n .accordion-button {\n &.collapsed {\n @include border-bottom-radius($accordion-inner-border-radius);\n }\n }\n\n .accordion-collapse {\n @include border-bottom-radius($accordion-border-radius);\n }\n }\n}\n\n.accordion-body {\n padding: $accordion-body-padding-y $accordion-body-padding-x;\n}\n\n\n// Flush accordion items\n//\n// Remove borders and border-radius to keep accordion items edge-to-edge.\n\n.accordion-flush {\n .accordion-collapse {\n border-width: 0;\n }\n\n .accordion-item {\n border-right: 0;\n border-left: 0;\n @include border-radius(0);\n\n &:first-child { border-top: 0; }\n &:last-child { border-bottom: 0; }\n\n .accordion-button {\n @include border-radius(0);\n }\n }\n}\n",".breadcrumb {\n display: flex;\n flex-wrap: wrap;\n padding: $breadcrumb-padding-y $breadcrumb-padding-x;\n margin-bottom: $breadcrumb-margin-bottom;\n @include font-size($breadcrumb-font-size);\n list-style: none;\n background-color: $breadcrumb-bg;\n @include border-radius($breadcrumb-border-radius);\n}\n\n.breadcrumb-item {\n // The separator between breadcrumbs (by default, a forward-slash: \"/\")\n + .breadcrumb-item {\n padding-left: $breadcrumb-item-padding-x;\n\n &::before {\n float: left; // Suppress inline spacings and underlining of the separator\n padding-right: $breadcrumb-item-padding-x;\n color: $breadcrumb-divider-color;\n content: var(--#{$variable-prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{\"/* rtl:\"} var(--#{$variable-prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{\"*/\"};\n }\n }\n\n &.active {\n color: $breadcrumb-active-color;\n }\n}\n",".pagination {\n display: flex;\n @include list-unstyled();\n}\n\n.page-link {\n position: relative;\n display: block;\n color: $pagination-color;\n text-decoration: if($link-decoration == none, null, none);\n background-color: $pagination-bg;\n border: $pagination-border-width solid $pagination-border-color;\n @include transition($pagination-transition);\n\n &:hover {\n z-index: 2;\n color: $pagination-hover-color;\n text-decoration: if($link-hover-decoration == underline, none, null);\n background-color: $pagination-hover-bg;\n border-color: $pagination-hover-border-color;\n }\n\n &:focus {\n z-index: 3;\n color: $pagination-focus-color;\n background-color: $pagination-focus-bg;\n outline: $pagination-focus-outline;\n box-shadow: $pagination-focus-box-shadow;\n }\n}\n\n.page-item {\n &:not(:first-child) .page-link {\n margin-left: $pagination-margin-start;\n }\n\n &.active .page-link {\n z-index: 3;\n color: $pagination-active-color;\n @include gradient-bg($pagination-active-bg);\n border-color: $pagination-active-border-color;\n }\n\n &.disabled .page-link {\n color: $pagination-disabled-color;\n pointer-events: none;\n background-color: $pagination-disabled-bg;\n border-color: $pagination-disabled-border-color;\n }\n}\n\n\n//\n// Sizing\n//\n@include pagination-size($pagination-padding-y, $pagination-padding-x, null, $pagination-border-radius);\n\n.pagination-lg {\n @include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $pagination-border-radius-lg);\n}\n\n.pagination-sm {\n @include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $pagination-border-radius-sm);\n}\n","// Pagination\n\n// scss-docs-start pagination-mixin\n@mixin pagination-size($padding-y, $padding-x, $font-size, $border-radius) {\n .page-link {\n padding: $padding-y $padding-x;\n @include font-size($font-size);\n }\n\n .page-item {\n @if $pagination-margin-start == (-$pagination-border-width) {\n &:first-child {\n .page-link {\n @include border-start-radius($border-radius);\n }\n }\n\n &:last-child {\n .page-link {\n @include border-end-radius($border-radius);\n }\n }\n } @else {\n //Add border-radius to all pageLinks in case they have left margin\n .page-link {\n @include border-radius($border-radius);\n }\n }\n }\n}\n// scss-docs-end pagination-mixin\n","// Base class\n//\n// Requires one of the contextual, color modifier classes for `color` and\n// `background-color`.\n\n.badge {\n display: inline-block;\n padding: $badge-padding-y $badge-padding-x;\n @include font-size($badge-font-size);\n font-weight: $badge-font-weight;\n line-height: 1;\n color: $badge-color;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n @include border-radius($badge-border-radius);\n @include gradient-bg();\n\n // Empty badges collapse automatically\n &:empty {\n display: none;\n }\n}\n\n// Quick fix for badges in buttons\n.btn .badge {\n position: relative;\n top: -1px;\n}\n","//\n// Base styles\n//\n\n.alert {\n position: relative;\n padding: $alert-padding-y $alert-padding-x;\n margin-bottom: $alert-margin-bottom;\n border: $alert-border-width solid transparent;\n @include border-radius($alert-border-radius);\n}\n\n// Headings for larger alerts\n.alert-heading {\n // Specified to prevent conflicts of changing $headings-color\n color: inherit;\n}\n\n// Provide class for links that match alerts\n.alert-link {\n font-weight: $alert-link-font-weight;\n}\n\n\n// Dismissible alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissible {\n padding-right: $alert-dismissible-padding-r;\n\n // Adjust close link position\n .btn-close {\n position: absolute;\n top: 0;\n right: 0;\n z-index: $stretched-link-z-index + 1;\n padding: $alert-padding-y * 1.25 $alert-padding-x;\n }\n}\n\n\n// scss-docs-start alert-modifiers\n// Generate contextual modifier classes for colorizing the alert.\n\n@each $state, $value in $theme-colors {\n $alert-background: shift-color($value, $alert-bg-scale);\n $alert-border: shift-color($value, $alert-border-scale);\n $alert-color: shift-color($value, $alert-color-scale);\n @if (contrast-ratio($alert-background, $alert-color) < $min-contrast-ratio) {\n $alert-color: mix($value, color-contrast($alert-background), abs($alert-color-scale));\n }\n .alert-#{$state} {\n @include alert-variant($alert-background, $alert-border, $alert-color);\n }\n}\n// scss-docs-end alert-modifiers\n","// scss-docs-start alert-variant-mixin\n@mixin alert-variant($background, $border, $color) {\n color: $color;\n @include gradient-bg($background);\n border-color: $border;\n\n .alert-link {\n color: shade-color($color, 20%);\n }\n}\n// scss-docs-end alert-variant-mixin\n","// Disable animation if transitions are disabled\n\n// scss-docs-start progress-keyframes\n@if $enable-transitions {\n @keyframes progress-bar-stripes {\n 0% { background-position-x: $progress-height; }\n }\n}\n// scss-docs-end progress-keyframes\n\n.progress {\n display: flex;\n height: $progress-height;\n overflow: hidden; // force rounded corners by cropping it\n @include font-size($progress-font-size);\n background-color: $progress-bg;\n @include border-radius($progress-border-radius);\n @include box-shadow($progress-box-shadow);\n}\n\n.progress-bar {\n display: flex;\n flex-direction: column;\n justify-content: center;\n overflow: hidden;\n color: $progress-bar-color;\n text-align: center;\n white-space: nowrap;\n background-color: $progress-bar-bg;\n @include transition($progress-bar-transition);\n}\n\n.progress-bar-striped {\n @include gradient-striped();\n background-size: $progress-height $progress-height;\n}\n\n@if $enable-transitions {\n .progress-bar-animated {\n animation: $progress-bar-animation-timing progress-bar-stripes;\n\n @if $enable-reduced-motion {\n @media (prefers-reduced-motion: reduce) {\n animation: none;\n }\n }\n }\n}\n","// Base class\n//\n// Easily usable on <ul>, <ol>, or <div>.\n\n.list-group {\n display: flex;\n flex-direction: column;\n\n // No need to set list-style: none; since .list-group-item is block level\n padding-left: 0; // reset padding because ul and ol\n margin-bottom: 0;\n @include border-radius($list-group-border-radius);\n}\n\n.list-group-numbered {\n list-style-type: none;\n counter-reset: section;\n\n > li::before {\n // Increments only this instance of the section counter\n content: counters(section, \".\") \". \";\n counter-increment: section;\n }\n}\n\n\n// Interactive list items\n//\n// Use anchor or button elements instead of `li`s or `div`s to create interactive\n// list items. Includes an extra `.active` modifier class for selected items.\n\n.list-group-item-action {\n width: 100%; // For `<button>`s (anchors become 100% by default though)\n color: $list-group-action-color;\n text-align: inherit; // For `<button>`s (anchors inherit)\n\n // Hover state\n &:hover,\n &:focus {\n z-index: 1; // Place hover/focus items above their siblings for proper border styling\n color: $list-group-action-hover-color;\n text-decoration: none;\n background-color: $list-group-hover-bg;\n }\n\n &:active {\n color: $list-group-action-active-color;\n background-color: $list-group-action-active-bg;\n }\n}\n\n\n// Individual list items\n//\n// Use on `li`s or `div`s within the `.list-group` parent.\n\n.list-group-item {\n position: relative;\n display: block;\n padding: $list-group-item-padding-y $list-group-item-padding-x;\n color: $list-group-color;\n text-decoration: if($link-decoration == none, null, none);\n background-color: $list-group-bg;\n border: $list-group-border-width solid $list-group-border-color;\n\n &:first-child {\n @include border-top-radius(inherit);\n }\n\n &:last-child {\n @include border-bottom-radius(inherit);\n }\n\n &.disabled,\n &:disabled {\n color: $list-group-disabled-color;\n pointer-events: none;\n background-color: $list-group-disabled-bg;\n }\n\n // Include both here for `<a>`s and `<button>`s\n &.active {\n z-index: 2; // Place active items above their siblings for proper border styling\n color: $list-group-active-color;\n background-color: $list-group-active-bg;\n border-color: $list-group-active-border-color;\n }\n\n & + & {\n border-top-width: 0;\n\n &.active {\n margin-top: -$list-group-border-width;\n border-top-width: $list-group-border-width;\n }\n }\n}\n\n\n// Horizontal\n//\n// Change the layout of list group items from vertical (default) to horizontal.\n\n@each $breakpoint in map-keys($grid-breakpoints) {\n @include media-breakpoint-up($breakpoint) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n .list-group-horizontal#{$infix} {\n flex-direction: row;\n\n > .list-group-item {\n &:first-child {\n @include border-bottom-start-radius($list-group-border-radius);\n @include border-top-end-radius(0);\n }\n\n &:last-child {\n @include border-top-end-radius($list-group-border-radius);\n @include border-bottom-start-radius(0);\n }\n\n &.active {\n margin-top: 0;\n }\n\n + .list-group-item {\n border-top-width: $list-group-border-width;\n border-left-width: 0;\n\n &.active {\n margin-left: -$list-group-border-width;\n border-left-width: $list-group-border-width;\n }\n }\n }\n }\n }\n}\n\n\n// Flush list items\n//\n// Remove borders and border-radius to keep list group items edge-to-edge. Most\n// useful within other components (e.g., cards).\n\n.list-group-flush {\n @include border-radius(0);\n\n > .list-group-item {\n border-width: 0 0 $list-group-border-width;\n\n &:last-child {\n border-bottom-width: 0;\n }\n }\n}\n\n\n// scss-docs-start list-group-modifiers\n// List group contextual variants\n//\n// Add modifier classes to change text and background color on individual items.\n// Organizationally, this must come after the `:hover` states.\n\n@each $state, $value in $theme-colors {\n $list-group-variant-bg: shift-color($value, $list-group-item-bg-scale);\n $list-group-variant-color: shift-color($value, $list-group-item-color-scale);\n @if (contrast-ratio($list-group-variant-bg, $list-group-variant-color) < $min-contrast-ratio) {\n $list-group-variant-color: mix($value, color-contrast($list-group-variant-bg), abs($list-group-item-color-scale));\n }\n\n @include list-group-item-variant($state, $list-group-variant-bg, $list-group-variant-color);\n}\n// scss-docs-end list-group-modifiers\n","// List Groups\n\n// scss-docs-start list-group-mixin\n@mixin list-group-item-variant($state, $background, $color) {\n .list-group-item-#{$state} {\n color: $color;\n background-color: $background;\n\n &.list-group-item-action {\n &:hover,\n &:focus {\n color: $color;\n background-color: shade-color($background, 10%);\n }\n\n &.active {\n color: $white;\n background-color: $color;\n border-color: $color;\n }\n }\n }\n}\n// scss-docs-end list-group-mixin\n","// transparent background and border properties included for button version.\n// iOS requires the button element instead of an anchor tag.\n// If you want the anchor version, it requires `href=\"#\"`.\n// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n\n.btn-close {\n box-sizing: content-box;\n width: $btn-close-width;\n height: $btn-close-height;\n padding: $btn-close-padding-y $btn-close-padding-x;\n color: $btn-close-color;\n background: transparent escape-svg($btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements\n border: 0; // for button elements\n @include border-radius();\n opacity: $btn-close-opacity;\n\n // Override <a>'s hover style\n &:hover {\n color: $btn-close-color;\n text-decoration: none;\n opacity: $btn-close-hover-opacity;\n }\n\n &:focus {\n outline: 0;\n box-shadow: $btn-close-focus-shadow;\n opacity: $btn-close-focus-opacity;\n }\n\n &:disabled,\n &.disabled {\n pointer-events: none;\n user-select: none;\n opacity: $btn-close-disabled-opacity;\n }\n}\n\n.btn-close-white {\n filter: $btn-close-white-filter;\n}\n",".toast {\n width: $toast-max-width;\n max-width: 100%;\n @include font-size($toast-font-size);\n color: $toast-color;\n pointer-events: auto;\n background-color: $toast-background-color;\n background-clip: padding-box;\n border: $toast-border-width solid $toast-border-color;\n box-shadow: $toast-box-shadow;\n @include border-radius($toast-border-radius);\n\n &.showing {\n opacity: 0;\n }\n\n &:not(.show) {\n display: none;\n }\n}\n\n.toast-container {\n width: max-content;\n max-width: 100%;\n pointer-events: none;\n\n > :not(:last-child) {\n margin-bottom: $toast-spacing;\n }\n}\n\n.toast-header {\n display: flex;\n align-items: center;\n padding: $toast-padding-y $toast-padding-x;\n color: $toast-header-color;\n background-color: $toast-header-background-color;\n background-clip: padding-box;\n border-bottom: $toast-border-width solid $toast-header-border-color;\n @include border-top-radius(subtract($toast-border-radius, $toast-border-width));\n\n .btn-close {\n margin-right: $toast-padding-x * -.5;\n margin-left: $toast-padding-x;\n }\n}\n\n.toast-body {\n padding: $toast-padding-x; // apply to both vertical and horizontal\n word-wrap: break-word;\n}\n","// .modal-open - body class for killing the scroll\n// .modal - container to scroll within\n// .modal-dialog - positioning shell for the actual modal\n// .modal-content - actual modal w/ bg and corners and stuff\n\n\n// Container that the modal scrolls within\n.modal {\n position: fixed;\n top: 0;\n left: 0;\n z-index: $zindex-modal;\n display: none;\n width: 100%;\n height: 100%;\n overflow-x: hidden;\n overflow-y: auto;\n // Prevent Chrome on Windows from adding a focus outline. For details, see\n // https://github.com/twbs/bootstrap/pull/10951.\n outline: 0;\n // We deliberately don't use `-webkit-overflow-scrolling: touch;` due to a\n // gnarly iOS Safari bug: https://bugs.webkit.org/show_bug.cgi?id=158342\n // See also https://github.com/twbs/bootstrap/issues/17695\n}\n\n// Shell div to position the modal with bottom padding\n.modal-dialog {\n position: relative;\n width: auto;\n margin: $modal-dialog-margin;\n // allow clicks to pass through for custom click handling to close modal\n pointer-events: none;\n\n // When fading in the modal, animate it to slide down\n .modal.fade & {\n @include transition($modal-transition);\n transform: $modal-fade-transform;\n }\n .modal.show & {\n transform: $modal-show-transform;\n }\n\n // When trying to close, animate focus to scale\n .modal.modal-static & {\n transform: $modal-scale-transform;\n }\n}\n\n.modal-dialog-scrollable {\n height: subtract(100%, $modal-dialog-margin * 2);\n\n .modal-content {\n max-height: 100%;\n overflow: hidden;\n }\n\n .modal-body {\n overflow-y: auto;\n }\n}\n\n.modal-dialog-centered {\n display: flex;\n align-items: center;\n min-height: subtract(100%, $modal-dialog-margin * 2);\n}\n\n// Actual modal\n.modal-content {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%; // Ensure `.modal-content` extends the full width of the parent `.modal-dialog`\n // counteract the pointer-events: none; in the .modal-dialog\n color: $modal-content-color;\n pointer-events: auto;\n background-color: $modal-content-bg;\n background-clip: padding-box;\n border: $modal-content-border-width solid $modal-content-border-color;\n @include border-radius($modal-content-border-radius);\n @include box-shadow($modal-content-box-shadow-xs);\n // Remove focus outline from opened modal\n outline: 0;\n}\n\n// Modal background\n.modal-backdrop {\n @include overlay-backdrop($zindex-modal-backdrop, $modal-backdrop-bg, $modal-backdrop-opacity);\n}\n\n// Modal header\n// Top section of the modal w/ title and dismiss\n.modal-header {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: space-between; // Put modal header elements (title and dismiss) on opposite ends\n padding: $modal-header-padding;\n border-bottom: $modal-header-border-width solid $modal-header-border-color;\n @include border-top-radius($modal-content-inner-border-radius);\n\n .btn-close {\n padding: ($modal-header-padding-y * .5) ($modal-header-padding-x * .5);\n margin: ($modal-header-padding-y * -.5) ($modal-header-padding-x * -.5) ($modal-header-padding-y * -.5) auto;\n }\n}\n\n// Title text within header\n.modal-title {\n margin-bottom: 0;\n line-height: $modal-title-line-height;\n}\n\n// Modal body\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\n.modal-body {\n position: relative;\n // Enable `flex-grow: 1` so that the body take up as much space as possible\n // when there should be a fixed height on `.modal-dialog`.\n flex: 1 1 auto;\n padding: $modal-inner-padding;\n}\n\n// Footer (for actions)\n.modal-footer {\n display: flex;\n flex-wrap: wrap;\n flex-shrink: 0;\n align-items: center; // vertically center\n justify-content: flex-end; // Right align buttons with flex property because text-align doesn't work on flex items\n padding: $modal-inner-padding - $modal-footer-margin-between * .5;\n border-top: $modal-footer-border-width solid $modal-footer-border-color;\n @include border-bottom-radius($modal-content-inner-border-radius);\n\n // Place margin between footer elements\n // This solution is far from ideal because of the universal selector usage,\n // but is needed to fix https://github.com/twbs/bootstrap/issues/24800\n > * {\n margin: $modal-footer-margin-between * .5;\n }\n}\n\n// Scale up the modal\n@include media-breakpoint-up(sm) {\n // Automatically set modal's width for larger viewports\n .modal-dialog {\n max-width: $modal-md;\n margin: $modal-dialog-margin-y-sm-up auto;\n }\n\n .modal-dialog-scrollable {\n height: subtract(100%, $modal-dialog-margin-y-sm-up * 2);\n }\n\n .modal-dialog-centered {\n min-height: subtract(100%, $modal-dialog-margin-y-sm-up * 2);\n }\n\n .modal-content {\n @include box-shadow($modal-content-box-shadow-sm-up);\n }\n\n .modal-sm { max-width: $modal-sm; }\n}\n\n@include media-breakpoint-up(lg) {\n .modal-lg,\n .modal-xl {\n max-width: $modal-lg;\n }\n}\n\n@include media-breakpoint-up(xl) {\n .modal-xl { max-width: $modal-xl; }\n}\n\n// scss-docs-start modal-fullscreen-loop\n@each $breakpoint in map-keys($grid-breakpoints) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n $postfix: if($infix != \"\", $infix + \"-down\", \"\");\n\n @include media-breakpoint-down($breakpoint) {\n .modal-fullscreen#{$postfix} {\n width: 100vw;\n max-width: none;\n height: 100%;\n margin: 0;\n\n .modal-content {\n height: 100%;\n border: 0;\n @include border-radius(0);\n }\n\n .modal-header {\n @include border-radius(0);\n }\n\n .modal-body {\n overflow-y: auto;\n }\n\n .modal-footer {\n @include border-radius(0);\n }\n }\n }\n}\n// scss-docs-end modal-fullscreen-loop\n","// Shared between modals and offcanvases\n@mixin overlay-backdrop($zindex, $backdrop-bg, $backdrop-opacity) {\n position: fixed;\n top: 0;\n left: 0;\n z-index: $zindex;\n width: 100vw;\n height: 100vh;\n background-color: $backdrop-bg;\n\n // Fade for backdrop\n &.fade { opacity: 0; }\n &.show { opacity: $backdrop-opacity; }\n}\n","// Base class\n.tooltip {\n position: absolute;\n z-index: $zindex-tooltip;\n display: block;\n margin: $tooltip-margin;\n // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.\n // So reset our font and text properties to avoid inheriting weird values.\n @include reset-text();\n @include font-size($tooltip-font-size);\n // Allow breaking very long words so they don't overflow the tooltip's bounds\n word-wrap: break-word;\n opacity: 0;\n\n &.show { opacity: $tooltip-opacity; }\n\n .tooltip-arrow {\n position: absolute;\n display: block;\n width: $tooltip-arrow-width;\n height: $tooltip-arrow-height;\n\n &::before {\n position: absolute;\n content: \"\";\n border-color: transparent;\n border-style: solid;\n }\n }\n}\n\n.bs-tooltip-top {\n padding: $tooltip-arrow-height 0;\n\n .tooltip-arrow {\n bottom: 0;\n\n &::before {\n top: -1px;\n border-width: $tooltip-arrow-height ($tooltip-arrow-width * .5) 0;\n border-top-color: $tooltip-arrow-color;\n }\n }\n}\n\n.bs-tooltip-end {\n padding: 0 $tooltip-arrow-height;\n\n .tooltip-arrow {\n left: 0;\n width: $tooltip-arrow-height;\n height: $tooltip-arrow-width;\n\n &::before {\n right: -1px;\n border-width: ($tooltip-arrow-width * .5) $tooltip-arrow-height ($tooltip-arrow-width * .5) 0;\n border-right-color: $tooltip-arrow-color;\n }\n }\n}\n\n.bs-tooltip-bottom {\n padding: $tooltip-arrow-height 0;\n\n .tooltip-arrow {\n top: 0;\n\n &::before {\n bottom: -1px;\n border-width: 0 ($tooltip-arrow-width * .5) $tooltip-arrow-height;\n border-bottom-color: $tooltip-arrow-color;\n }\n }\n}\n\n.bs-tooltip-start {\n padding: 0 $tooltip-arrow-height;\n\n .tooltip-arrow {\n right: 0;\n width: $tooltip-arrow-height;\n height: $tooltip-arrow-width;\n\n &::before {\n left: -1px;\n border-width: ($tooltip-arrow-width * .5) 0 ($tooltip-arrow-width * .5) $tooltip-arrow-height;\n border-left-color: $tooltip-arrow-color;\n }\n }\n}\n\n.bs-tooltip-auto {\n &[data-popper-placement^=\"top\"] {\n @extend .bs-tooltip-top;\n }\n &[data-popper-placement^=\"right\"] {\n @extend .bs-tooltip-end;\n }\n &[data-popper-placement^=\"bottom\"] {\n @extend .bs-tooltip-bottom;\n }\n &[data-popper-placement^=\"left\"] {\n @extend .bs-tooltip-start;\n }\n}\n\n// Wrapper for the tooltip content\n.tooltip-inner {\n max-width: $tooltip-max-width;\n padding: $tooltip-padding-y $tooltip-padding-x;\n color: $tooltip-color;\n text-align: center;\n background-color: $tooltip-bg;\n @include border-radius($tooltip-border-radius);\n}\n","@mixin reset-text {\n font-family: $font-family-base;\n // We deliberately do NOT reset font-size or overflow-wrap / word-wrap.\n font-style: normal;\n font-weight: $font-weight-normal;\n line-height: $line-height-base;\n text-align: left; // Fallback for where `start` is not supported\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n white-space: normal;\n line-break: auto;\n}\n",".popover {\n position: absolute;\n top: 0;\n left: 0 #{\"/* rtl:ignore */\"};\n z-index: $zindex-popover;\n display: block;\n max-width: $popover-max-width;\n // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.\n // So reset our font and text properties to avoid inheriting weird values.\n @include reset-text();\n @include font-size($popover-font-size);\n // Allow breaking very long words so they don't overflow the popover's bounds\n word-wrap: break-word;\n background-color: $popover-bg;\n background-clip: padding-box;\n border: $popover-border-width solid $popover-border-color;\n @include border-radius($popover-border-radius);\n @include box-shadow($popover-box-shadow);\n\n .popover-arrow {\n position: absolute;\n display: block;\n width: $popover-arrow-width;\n height: $popover-arrow-height;\n\n &::before,\n &::after {\n position: absolute;\n display: block;\n content: \"\";\n border-color: transparent;\n border-style: solid;\n }\n }\n}\n\n.bs-popover-top {\n > .popover-arrow {\n bottom: subtract(-$popover-arrow-height, $popover-border-width);\n\n &::before {\n bottom: 0;\n border-width: $popover-arrow-height ($popover-arrow-width * .5) 0;\n border-top-color: $popover-arrow-outer-color;\n }\n\n &::after {\n bottom: $popover-border-width;\n border-width: $popover-arrow-height ($popover-arrow-width * .5) 0;\n border-top-color: $popover-arrow-color;\n }\n }\n}\n\n.bs-popover-end {\n > .popover-arrow {\n left: subtract(-$popover-arrow-height, $popover-border-width);\n width: $popover-arrow-height;\n height: $popover-arrow-width;\n\n &::before {\n left: 0;\n border-width: ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5) 0;\n border-right-color: $popover-arrow-outer-color;\n }\n\n &::after {\n left: $popover-border-width;\n border-width: ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5) 0;\n border-right-color: $popover-arrow-color;\n }\n }\n}\n\n.bs-popover-bottom {\n > .popover-arrow {\n top: subtract(-$popover-arrow-height, $popover-border-width);\n\n &::before {\n top: 0;\n border-width: 0 ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5);\n border-bottom-color: $popover-arrow-outer-color;\n }\n\n &::after {\n top: $popover-border-width;\n border-width: 0 ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5);\n border-bottom-color: $popover-arrow-color;\n }\n }\n\n // This will remove the popover-header's border just below the arrow\n .popover-header::before {\n position: absolute;\n top: 0;\n left: 50%;\n display: block;\n width: $popover-arrow-width;\n margin-left: -$popover-arrow-width * .5;\n content: \"\";\n border-bottom: $popover-border-width solid $popover-header-bg;\n }\n}\n\n.bs-popover-start {\n > .popover-arrow {\n right: subtract(-$popover-arrow-height, $popover-border-width);\n width: $popover-arrow-height;\n height: $popover-arrow-width;\n\n &::before {\n right: 0;\n border-width: ($popover-arrow-width * .5) 0 ($popover-arrow-width * .5) $popover-arrow-height;\n border-left-color: $popover-arrow-outer-color;\n }\n\n &::after {\n right: $popover-border-width;\n border-width: ($popover-arrow-width * .5) 0 ($popover-arrow-width * .5) $popover-arrow-height;\n border-left-color: $popover-arrow-color;\n }\n }\n}\n\n.bs-popover-auto {\n &[data-popper-placement^=\"top\"] {\n @extend .bs-popover-top;\n }\n &[data-popper-placement^=\"right\"] {\n @extend .bs-popover-end;\n }\n &[data-popper-placement^=\"bottom\"] {\n @extend .bs-popover-bottom;\n }\n &[data-popper-placement^=\"left\"] {\n @extend .bs-popover-start;\n }\n}\n\n// Offset the popover to account for the popover arrow\n.popover-header {\n padding: $popover-header-padding-y $popover-header-padding-x;\n margin-bottom: 0; // Reset the default from Reboot\n @include font-size($font-size-base);\n color: $popover-header-color;\n background-color: $popover-header-bg;\n border-bottom: $popover-border-width solid $popover-border-color;\n @include border-top-radius($popover-inner-border-radius);\n\n &:empty {\n display: none;\n }\n}\n\n.popover-body {\n padding: $popover-body-padding-y $popover-body-padding-x;\n color: $popover-body-color;\n}\n","// Notes on the classes:\n//\n// 1. .carousel.pointer-event should ideally be pan-y (to allow for users to scroll vertically)\n// even when their scroll action started on a carousel, but for compatibility (with Firefox)\n// we're preventing all actions instead\n// 2. The .carousel-item-start and .carousel-item-end is used to indicate where\n// the active slide is heading.\n// 3. .active.carousel-item is the current slide.\n// 4. .active.carousel-item-start and .active.carousel-item-end is the current\n// slide in its in-transition state. Only one of these occurs at a time.\n// 5. .carousel-item-next.carousel-item-start and .carousel-item-prev.carousel-item-end\n// is the upcoming slide in transition.\n\n.carousel {\n position: relative;\n}\n\n.carousel.pointer-event {\n touch-action: pan-y;\n}\n\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n @include clearfix();\n}\n\n.carousel-item {\n position: relative;\n display: none;\n float: left;\n width: 100%;\n margin-right: -100%;\n backface-visibility: hidden;\n @include transition($carousel-transition);\n}\n\n.carousel-item.active,\n.carousel-item-next,\n.carousel-item-prev {\n display: block;\n}\n\n/* rtl:begin:ignore */\n.carousel-item-next:not(.carousel-item-start),\n.active.carousel-item-end {\n transform: translateX(100%);\n}\n\n.carousel-item-prev:not(.carousel-item-end),\n.active.carousel-item-start {\n transform: translateX(-100%);\n}\n\n/* rtl:end:ignore */\n\n\n//\n// Alternate transitions\n//\n\n.carousel-fade {\n .carousel-item {\n opacity: 0;\n transition-property: opacity;\n transform: none;\n }\n\n .carousel-item.active,\n .carousel-item-next.carousel-item-start,\n .carousel-item-prev.carousel-item-end {\n z-index: 1;\n opacity: 1;\n }\n\n .active.carousel-item-start,\n .active.carousel-item-end {\n z-index: 0;\n opacity: 0;\n @include transition(opacity 0s $carousel-transition-duration);\n }\n}\n\n\n//\n// Left/right controls for nav\n//\n\n.carousel-control-prev,\n.carousel-control-next {\n position: absolute;\n top: 0;\n bottom: 0;\n z-index: 1;\n // Use flex for alignment (1-3)\n display: flex; // 1. allow flex styles\n align-items: center; // 2. vertically center contents\n justify-content: center; // 3. horizontally center contents\n width: $carousel-control-width;\n padding: 0;\n color: $carousel-control-color;\n text-align: center;\n background: none;\n border: 0;\n opacity: $carousel-control-opacity;\n @include transition($carousel-control-transition);\n\n // Hover/focus state\n &:hover,\n &:focus {\n color: $carousel-control-color;\n text-decoration: none;\n outline: 0;\n opacity: $carousel-control-hover-opacity;\n }\n}\n.carousel-control-prev {\n left: 0;\n background-image: if($enable-gradients, linear-gradient(90deg, rgba($black, .25), rgba($black, .001)), null);\n}\n.carousel-control-next {\n right: 0;\n background-image: if($enable-gradients, linear-gradient(270deg, rgba($black, .25), rgba($black, .001)), null);\n}\n\n// Icons for within\n.carousel-control-prev-icon,\n.carousel-control-next-icon {\n display: inline-block;\n width: $carousel-control-icon-width;\n height: $carousel-control-icon-width;\n background-repeat: no-repeat;\n background-position: 50%;\n background-size: 100% 100%;\n}\n\n/* rtl:options: {\n \"autoRename\": true,\n \"stringMap\":[ {\n \"name\" : \"prev-next\",\n \"search\" : \"prev\",\n \"replace\" : \"next\"\n } ]\n} */\n.carousel-control-prev-icon {\n background-image: escape-svg($carousel-control-prev-icon-bg);\n}\n.carousel-control-next-icon {\n background-image: escape-svg($carousel-control-next-icon-bg);\n}\n\n// Optional indicator pips/controls\n//\n// Add a container (such as a list) with the following class and add an item (ideally a focusable control,\n// like a button) with data-bs-target for each slide your carousel holds.\n\n.carousel-indicators {\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 2;\n display: flex;\n justify-content: center;\n padding: 0;\n // Use the .carousel-control's width as margin so we don't overlay those\n margin-right: $carousel-control-width;\n margin-bottom: 1rem;\n margin-left: $carousel-control-width;\n list-style: none;\n\n [data-bs-target] {\n box-sizing: content-box;\n flex: 0 1 auto;\n width: $carousel-indicator-width;\n height: $carousel-indicator-height;\n padding: 0;\n margin-right: $carousel-indicator-spacer;\n margin-left: $carousel-indicator-spacer;\n text-indent: -999px;\n cursor: pointer;\n background-color: $carousel-indicator-active-bg;\n background-clip: padding-box;\n border: 0;\n // Use transparent borders to increase the hit area by 10px on top and bottom.\n border-top: $carousel-indicator-hit-area-height solid transparent;\n border-bottom: $carousel-indicator-hit-area-height solid transparent;\n opacity: $carousel-indicator-opacity;\n @include transition($carousel-indicator-transition);\n }\n\n .active {\n opacity: $carousel-indicator-active-opacity;\n }\n}\n\n\n// Optional captions\n//\n//\n\n.carousel-caption {\n position: absolute;\n right: (100% - $carousel-caption-width) * .5;\n bottom: $carousel-caption-spacer;\n left: (100% - $carousel-caption-width) * .5;\n padding-top: $carousel-caption-padding-y;\n padding-bottom: $carousel-caption-padding-y;\n color: $carousel-caption-color;\n text-align: center;\n}\n\n// Dark mode carousel\n\n.carousel-dark {\n .carousel-control-prev-icon,\n .carousel-control-next-icon {\n filter: $carousel-dark-control-icon-filter;\n }\n\n .carousel-indicators [data-bs-target] {\n background-color: $carousel-dark-indicator-active-bg;\n }\n\n .carousel-caption {\n color: $carousel-dark-caption-color;\n }\n}\n","// scss-docs-start clearfix\n@mixin clearfix() {\n &::after {\n display: block;\n clear: both;\n content: \"\";\n }\n}\n// scss-docs-end clearfix\n","//\n// Rotating border\n//\n\n// scss-docs-start spinner-border-keyframes\n@keyframes spinner-border {\n to { transform: rotate(360deg) #{\"/* rtl:ignore */\"}; }\n}\n// scss-docs-end spinner-border-keyframes\n\n.spinner-border {\n display: inline-block;\n width: $spinner-width;\n height: $spinner-height;\n vertical-align: $spinner-vertical-align;\n border: $spinner-border-width solid currentColor;\n border-right-color: transparent;\n // stylelint-disable-next-line property-disallowed-list\n border-radius: 50%;\n animation: $spinner-animation-speed linear infinite spinner-border;\n}\n\n.spinner-border-sm {\n width: $spinner-width-sm;\n height: $spinner-height-sm;\n border-width: $spinner-border-width-sm;\n}\n\n//\n// Growing circle\n//\n\n// scss-docs-start spinner-grow-keyframes\n@keyframes spinner-grow {\n 0% {\n transform: scale(0);\n }\n 50% {\n opacity: 1;\n transform: none;\n }\n}\n// scss-docs-end spinner-grow-keyframes\n\n.spinner-grow {\n display: inline-block;\n width: $spinner-width;\n height: $spinner-height;\n vertical-align: $spinner-vertical-align;\n background-color: currentColor;\n // stylelint-disable-next-line property-disallowed-list\n border-radius: 50%;\n opacity: 0;\n animation: $spinner-animation-speed linear infinite spinner-grow;\n}\n\n.spinner-grow-sm {\n width: $spinner-width-sm;\n height: $spinner-height-sm;\n}\n\n@if $enable-reduced-motion {\n @media (prefers-reduced-motion: reduce) {\n .spinner-border,\n .spinner-grow {\n animation-duration: $spinner-animation-speed * 2;\n }\n }\n}\n",".offcanvas {\n position: fixed;\n bottom: 0;\n z-index: $zindex-offcanvas;\n display: flex;\n flex-direction: column;\n max-width: 100%;\n color: $offcanvas-color;\n visibility: hidden;\n background-color: $offcanvas-bg-color;\n background-clip: padding-box;\n outline: 0;\n @include box-shadow($offcanvas-box-shadow);\n @include transition(transform $offcanvas-transition-duration ease-in-out);\n}\n\n.offcanvas-backdrop {\n @include overlay-backdrop($zindex-offcanvas-backdrop, $offcanvas-backdrop-bg, $offcanvas-backdrop-opacity);\n}\n\n.offcanvas-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: $offcanvas-padding-y $offcanvas-padding-x;\n\n .btn-close {\n padding: ($offcanvas-padding-y * .5) ($offcanvas-padding-x * .5);\n margin-top: $offcanvas-padding-y * -.5;\n margin-right: $offcanvas-padding-x * -.5;\n margin-bottom: $offcanvas-padding-y * -.5;\n }\n}\n\n.offcanvas-title {\n margin-bottom: 0;\n line-height: $offcanvas-title-line-height;\n}\n\n.offcanvas-body {\n flex-grow: 1;\n padding: $offcanvas-padding-y $offcanvas-padding-x;\n overflow-y: auto;\n}\n\n.offcanvas-start {\n top: 0;\n left: 0;\n width: $offcanvas-horizontal-width;\n border-right: $offcanvas-border-width solid $offcanvas-border-color;\n transform: translateX(-100%);\n}\n\n.offcanvas-end {\n top: 0;\n right: 0;\n width: $offcanvas-horizontal-width;\n border-left: $offcanvas-border-width solid $offcanvas-border-color;\n transform: translateX(100%);\n}\n\n.offcanvas-top {\n top: 0;\n right: 0;\n left: 0;\n height: $offcanvas-vertical-height;\n max-height: 100%;\n border-bottom: $offcanvas-border-width solid $offcanvas-border-color;\n transform: translateY(-100%);\n}\n\n.offcanvas-bottom {\n right: 0;\n left: 0;\n height: $offcanvas-vertical-height;\n max-height: 100%;\n border-top: $offcanvas-border-width solid $offcanvas-border-color;\n transform: translateY(100%);\n}\n\n.offcanvas.show {\n transform: none;\n}\n",".placeholder {\n display: inline-block;\n min-height: 1em;\n vertical-align: middle;\n cursor: wait;\n background-color: currentColor;\n opacity: $placeholder-opacity-max;\n\n &.btn::before {\n display: inline-block;\n content: \"\";\n }\n}\n\n// Sizing\n.placeholder-xs {\n min-height: .6em;\n}\n\n.placeholder-sm {\n min-height: .8em;\n}\n\n.placeholder-lg {\n min-height: 1.2em;\n}\n\n// Animation\n.placeholder-glow {\n .placeholder {\n animation: placeholder-glow 2s ease-in-out infinite;\n }\n}\n\n@keyframes placeholder-glow {\n 50% {\n opacity: $placeholder-opacity-min;\n }\n}\n\n.placeholder-wave {\n mask-image: linear-gradient(130deg, $black 55%, rgba(0, 0, 0, (1 - $placeholder-opacity-min)) 75%, $black 95%);\n mask-size: 200% 100%;\n animation: placeholder-wave 2s linear infinite;\n}\n\n@keyframes placeholder-wave {\n 100% {\n mask-position: -200% 0%;\n }\n}\n","@each $color, $value in $theme-colors {\n .link-#{$color} {\n color: $value;\n\n @if $link-shade-percentage != 0 {\n &:hover,\n &:focus {\n color: if(color-contrast($value) == $color-contrast-light, shade-color($value, $link-shade-percentage), tint-color($value, $link-shade-percentage));\n }\n }\n }\n}\n","// Credit: Nicolas Gallagher and SUIT CSS.\n\n.ratio {\n position: relative;\n width: 100%;\n\n &::before {\n display: block;\n padding-top: var(--#{$variable-prefix}aspect-ratio);\n content: \"\";\n }\n\n > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n}\n\n@each $key, $ratio in $aspect-ratios {\n .ratio-#{$key} {\n --#{$variable-prefix}aspect-ratio: #{$ratio};\n }\n}\n","// Shorthand\n\n.fixed-top {\n position: fixed;\n top: 0;\n right: 0;\n left: 0;\n z-index: $zindex-fixed;\n}\n\n.fixed-bottom {\n position: fixed;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: $zindex-fixed;\n}\n\n// Responsive sticky top\n@each $breakpoint in map-keys($grid-breakpoints) {\n @include media-breakpoint-up($breakpoint) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n .sticky#{$infix}-top {\n position: sticky;\n top: 0;\n z-index: $zindex-sticky;\n }\n }\n}\n","// scss-docs-start stacks\n.hstack {\n display: flex;\n flex-direction: row;\n align-items: center;\n align-self: stretch;\n}\n\n.vstack {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n align-self: stretch;\n}\n// scss-docs-end stacks\n","//\n// Visually hidden\n//\n\n.visually-hidden,\n.visually-hidden-focusable:not(:focus):not(:focus-within) {\n @include visually-hidden();\n}\n","// stylelint-disable declaration-no-important\n\n// Hide content visually while keeping it accessible to assistive technologies\n//\n// See: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/\n// See: https://kittygiraudel.com/2016/10/13/css-hide-and-seek/\n\n@mixin visually-hidden() {\n position: absolute !important;\n width: 1px !important;\n height: 1px !important;\n padding: 0 !important;\n margin: -1px !important; // Fix for https://github.com/twbs/bootstrap/issues/25686\n overflow: hidden !important;\n clip: rect(0, 0, 0, 0) !important;\n white-space: nowrap !important;\n border: 0 !important;\n}\n\n// Use to only display content when it's focused, or one of its child elements is focused\n// (i.e. when focus is within the element/container that the class was applied to)\n//\n// Useful for \"Skip to main content\" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n\n@mixin visually-hidden-focusable() {\n &:not(:focus):not(:focus-within) {\n @include visually-hidden();\n }\n}\n","//\n// Stretched link\n//\n\n.stretched-link {\n &::#{$stretched-link-pseudo-element} {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: $stretched-link-z-index;\n content: \"\";\n }\n}\n","//\n// Text truncation\n//\n\n.text-truncate {\n @include text-truncate();\n}\n","// Text truncate\n// Requires inline-block or block for proper styling\n\n@mixin text-truncate() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n",".vr {\n display: inline-block;\n align-self: stretch;\n width: 1px;\n min-height: 1em;\n background-color: currentColor;\n opacity: $hr-opacity;\n}\n","// Utility generator\n// Used to generate utilities & print utilities\n@mixin generate-utility($utility, $infix, $is-rfs-media-query: false) {\n $values: map-get($utility, values);\n\n // If the values are a list or string, convert it into a map\n @if type-of($values) == \"string\" or type-of(nth($values, 1)) != \"list\" {\n $values: zip($values, $values);\n }\n\n @each $key, $value in $values {\n $properties: map-get($utility, property);\n\n // Multiple properties are possible, for example with vertical or horizontal margins or paddings\n @if type-of($properties) == \"string\" {\n $properties: append((), $properties);\n }\n\n // Use custom class if present\n $property-class: if(map-has-key($utility, class), map-get($utility, class), nth($properties, 1));\n $property-class: if($property-class == null, \"\", $property-class);\n\n // State params to generate pseudo-classes\n $state: if(map-has-key($utility, state), map-get($utility, state), ());\n\n $infix: if($property-class == \"\" and str-slice($infix, 1, 1) == \"-\", str-slice($infix, 2), $infix);\n\n // Don't prefix if value key is null (eg. with shadow class)\n $property-class-modifier: if($key, if($property-class == \"\" and $infix == \"\", \"\", \"-\") + $key, \"\");\n\n @if map-get($utility, rfs) {\n // Inside the media query\n @if $is-rfs-media-query {\n $val: rfs-value($value);\n\n // Do not render anything if fluid and non fluid values are the same\n $value: if($val == rfs-fluid-value($value), null, $val);\n }\n @else {\n $value: rfs-fluid-value($value);\n }\n }\n\n $is-css-var: map-get($utility, css-var);\n $is-local-vars: map-get($utility, local-vars);\n $is-rtl: map-get($utility, rtl);\n\n @if $value != null {\n @if $is-rtl == false {\n /* rtl:begin:remove */\n }\n\n @if $is-css-var {\n .#{$property-class + $infix + $property-class-modifier} {\n --#{$variable-prefix}#{$property-class}: #{$value};\n }\n\n @each $pseudo in $state {\n .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\n --#{$variable-prefix}#{$property-class}: #{$value};\n }\n }\n } @else {\n .#{$property-class + $infix + $property-class-modifier} {\n @each $property in $properties {\n @if $is-local-vars {\n @each $local-var, $value in $is-local-vars {\n --#{$variable-prefix}#{$local-var}: #{$value};\n }\n }\n #{$property}: $value if($enable-important-utilities, !important, null);\n }\n }\n\n @each $pseudo in $state {\n .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\n @each $property in $properties {\n #{$property}: $value if($enable-important-utilities, !important, null);\n }\n }\n }\n }\n\n @if $is-rtl == false {\n /* rtl:end:remove */\n }\n }\n }\n}\n","// Loop over each breakpoint\n@each $breakpoint in map-keys($grid-breakpoints) {\n\n // Generate media query if needed\n @include media-breakpoint-up($breakpoint) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n // Loop over each utility property\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Only proceed if responsive media queries are enabled or if it's the base media query\n @if type-of($utility) == \"map\" and (map-get($utility, responsive) or $infix == \"\") {\n @include generate-utility($utility, $infix);\n }\n }\n }\n}\n\n// RFS rescaling\n@media (min-width: $rfs-mq-value) {\n @each $breakpoint in map-keys($grid-breakpoints) {\n $infix: breakpoint-infix($breakpoint, $grid-breakpoints);\n\n @if (map-get($grid-breakpoints, $breakpoint) < $rfs-breakpoint) {\n // Loop over each utility property\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Only proceed if responsive media queries are enabled or if it's the base media query\n @if type-of($utility) == \"map\" and map-get($utility, rfs) and (map-get($utility, responsive) or $infix == \"\") {\n @include generate-utility($utility, $infix, true);\n }\n }\n }\n }\n}\n\n\n// Print utilities\n@media print {\n @each $key, $utility in $utilities {\n // The utility can be disabled with `false`, thus check if the utility is a map first\n // Then check if the utility needs print styles\n @if type-of($utility) == \"map\" and map-get($utility, print) == true {\n @include generate-utility($utility, \"-print\");\n }\n }\n}\n"]} \ No newline at end of file diff --git a/src/base/theme/bootsier/assets/fonts/nunito.css b/src/base/theme/bootsier/assets/fonts/nunito.css new file mode 100644 index 00000000..f444a08f --- /dev/null +++ b/src/base/theme/bootsier/assets/fonts/nunito.css @@ -0,0 +1,70 @@ +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 400; + src: url(/pagetop/fonts/nunito/cyrillic_ext_400.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 400; + src: url(/pagetop/fonts/nunito/cyrillic_400.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 400; + src: url(/pagetop/fonts/nunito/vietnamese_400.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 400; + src: url(/pagetop/fonts/nunito/latin_ext_400.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 400; + src: url(/pagetop/fonts/nunito/latin_400.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 700; + src: url(/pagetop/fonts/nunito/cyrillic_ext_700.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 700; + src: url(/pagetop/fonts/nunito/cyrillic_700.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 700; + src: url(/pagetop/fonts/nunito/vietnamese_700.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 700; + src: url(/pagetop/fonts/nunito/latin_ext_700.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +@font-face { + font-family: 'Nunito'; + font-style: normal; + font-weight: 700; + src: url(/pagetop/fonts/nunito/latin_700.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_400.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_400.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..cadafd359ff244c60bc4ad72a6f06d38e8e31eba GIT binary patch literal 11248 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 ax^!^s)asj|cl@`}rFsASFY(Yp?G6B4bx>*m literal 0 HcmV?d00001 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_700.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_700.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..2b4950ff24895b57fc66398bad2f892916d8bb00 GIT binary patch literal 11208 zcmV;(D>u}4Pew8T0RR9104vA<5dZ)H0A;iQ04rty0RR9100000000000000000000 z0000Qd>fZ69BKw&0D=$*fg}l^EfEL`^lap83xXm50X7081B5IDAO(Yd2Z|>QfmR!5 zTL;)Sow(WU;4$BQ9%dxMo~NO9qX;$*kYT-9@c;icxiLhr9kjB(g>q(Tin5?ZLT<ra zf#4nX3GTe);NK`O{o<k{?m9TqYcfOyp)XEh(p~xKHVRuc@pc!sv$5t^Eyz$C8WW4f z5*@tAIG-^NHm)g;**sZRG`HyucCethBK1LubK&NtmeRcB+7)<RN@#qBA6tW8C_$`& z_rOnmP_RZD3jc~O6bRQtcd(Zu|J*Se8c9rx@_N2{k_DXA1Bh>&Xq^B-@_*vx^84x= z@c?v86RYqz{`bpw=bT&K+tj)#k3=Y%N~X)5Aepbi(mo%BLU-w^cE}J^x4oZ(x3?tW zytxSjPQsojkN~&=+~!l{#o-DnSjj+%8ZgF~n3SN$0;91oDjxbW|MuZ4d}jN@Q>wjE zl3i3G!C~Qbz9AiwLR=md;{9{NIszi~YnNBlaHu-ZJkaUv_f69omsaOIw*uO4KuY~C zt*msp#}k6`%z~JFD8ApCO*X}3$%`@wU6-+cY{?Sd8GX;g@pJagJjhGZ0C3ywGUO9< zKd^#3mM0ve5+uwyeS>ogHKUTB5fR-T26d{`b|kMSa>66Jflf&tFg$M<1esG{aBK?K z!u>+Tr91~!M%B21jBUwaiH4#N+dU9LHMA@b{U*E5IDpORLN}GAtXX^XY4QKJX>WVq zjAZ;t3?IB3`iMm*>mxO7PXFdU&CG)t!N}f~WtP1lt&=Zl!F<*u*?VMtg#aoxCGpWG z#||+SWlp*(W!f6+B7KoM`umOQ#@-OL2u5qMMMXZM^Oq|Z^2K&M1ox_Dy<}SuLLQNQ zS-syi!Nvj$R<OjOb_+{=-KVwBB*T`594~P!FR~CqTr}4|OM6T;D3CRfGEC3@9b{Ym za9GW`X4T+(BnYE+`=4kEqd_>t#f5lyk$_YrT?UdbA1P9f)T&3CG$U;$k!dr?vSnn= z8nR&vIdq5+22cW&2tWY22x+*Zq^b$Vd$lkH;~X!|z=#K6kDBugFU&v+;x0UPK_bQa ztN$f|?38!FPk<-1oQwpkr=5$-AVRkh5G@MjQC{<ey!mMwuM2sJ?(=_I+B==x4VY{6 z=k}!BG|s&3!T~6N_7Gg15xOgdnQcStDOI+s@NTh5c3s>jksAjYS!;{kL4n3HgFx+5 z)}7z-F;z?_!eT7D1-2CeY?xRuv)@`sVr#&n43GF@_o;Q)sH$Wo%46w^MF~Z#7k_Mj zye5t$u@ZDN2%F|v6uaUM4Q^wY(WfE21!uO(Db%dX5Y#Rob9^?%lo9-mzB-LE4D0K9 z>DOUs?dngN)e|3?wc0NkoWoR0eAj_LI+TNTl~j_b;oIHQfomT@Pu6a*mI?Qa!HO0; z;<I~;pm)39b*vh@jvU;;sH)dT(s7NX8IfItEt{C`1J)H7bNJ|&+L1Xge&Vdh=)&&R z9S+Ny`E9mT6&^j7p6>PYWcp3UDAd0PXJp1yu5+Ic86EQW%8WpnxpSdp$x0_~RU10y z(`pa{I~f0P|C2M=;S5{MI|ui+BG%ITr|JJRghABayd=WKhYgk`;orvtwN~(Wg2_Ll zGM{4nN&RBP@B!$*rzg@Y=6nbs5;A@vMj*m?VU%bZ@x>K&5~b2hZ@0*7x5|FsY;xtX zD^S9zTqUpSoA!X(&va0|4k5bqiZftRl4%=qY}ry}$DV2jj?^Ipolfxm;Z{B>YU&g* z3TcIrAp|{2++$YG$xs{(SOB6dbcnEiFS#KH2uy-O>jMse9!Eh|bn=vE0Sb&jXNt>N zEjtO02Fw^9LW2ksZl&U^tO4Ufl3d$R6jxlcs5DZeCseL$ToF^!@#O#mEm@DIp16rc z09aElrp(d7VHTZs{CR*3Q%VZ*u3{+9sH4)l3O(4^(EAxN11lQ}5bNTZb5woFuDcuK zG#plqWdgbEGQBd**}<tV<4-2|Jdk7R93o7qO?+!%4?+a&RRU1S-vqi474FbjgB1TZ z{7)H|X6Ie(%P$W6M&KCq0Ra6z1|ZBF=`14-we$W_`jx29((bMfx{UAT&-T`)`nwk% zzq*?X9p%q*YKec`(wU|Ud@_URNzqv|u5|VPL<<U0&8t|EQf0~&C{!U@q*OUv+&lz+ z0inW#ix4GEx=b0eWXqE;SBXkh>NRN8q*a?vUApz?GiBPW8FS_>S+;1yu08EK>}$4e z&898eR;=35uh*mnJ}qh;cosWH=*5vr`ZSx5#^;&+mY>V<ZLua=K~2m4umqpI*XJ^v zqNVvH`X8Y(ks%D-us<@j{X>e~r(;sP00ekQlZ)It!qCk<q`U7DyYtLm@~PBk&yZ05 zm!(G<vpx<n0xtk{yMhX{^&qIyX%B%$jXe~y{6#08>ukiO<ZO*hjMn;gLip7|&>X_C zEU@dtO4{0(jk@_ttQM}u<e9x!<Wzy$>gu>=Jq51Q6JG;uduLz;G~zQIs1*Y9%q<65 zg#UK1?7MZQgPi6G=^#Z@Hu(PgbSMn<rSb6kEisbEp)hgy;?gi$7G}v5sZQIJn+EtV zPfn$NUz`F}<ch2`QWdm)*iU8mOX@%Z8fV}(0cTl6nTMnm#l=}US~4r|<H)6SUy6g# zy%X>)5>U;1IAju7D2pIi%(VlA8?sx7(ZSRs*_|T9Toa|qfO<PY4}6&pPty#~WBte} zwfg=`W83Tuu<Rt|T_}4`>d}SqE};m&$C7EI9sv|?R%r7#$RCyBrUJMXNO=l2z=X(q z6o}IK2InJ_vIyAIV{+7F-frHTid7jBPWFC`Aei_g%F(#pH%0{r3t6Vx7P45~gL%)~ zMK#Z8xfC=6ovo-^bT$dPZUSW?7^vB2?Js>m+7EUq295rH>@m?u+X3$t+a3#G62atM zMn)s$<|a;(TV;g}Y^pHpY$``4joKF2%u?T&q)yOH9o+jWHTG-kZ=yH#V1PS*lJ0$Z zNQ5}+?)g157#qLlj+g-!h8<nE90}IUBeAA{Q!3D~$!5o5Sg`uNi66D{sCjG333xz^ zJ3AkAOx~JkG0YNPTZ}L7v4I$L3li8`QT6m$^U<~14!%k_ZZcuGp*uX8<o~+*85!-K z>CDU#;B6T!n%5KgA<n<yJpmd_ZhEwYQbUL|0<lIR(HNu}hfI?o*8~)r45g+FvAP8` z3~M5#dtW7$0sJT$I#sSBH3os-p=*sp;LlsELdT8fj)TQN2LwJdNllD2#7Ikwbi_zc zj10uclo**2BXeS8h1l3S<Z|S~Mq#E)GHP3mzRh4_J$2)o2=O?-ee#|yh}@E(X0)8w z3cq+v8Jqyyk$t8aT?dJ`9$R_iIyt2e-B@?WPK(AJ+l72)z~CM_a5o2YKYK8$grDoe z)ZZWgimvMUwyTpSzeV;Tm*tijDS+c2P|pE|7cTc4lElG)k(+viMr7(O88{7i(Hy)} zzd!O@u1I<un(tJ%^-y*4+4pPVF@Pz;Bf-Lzp>N(a*<-@Zle+FAm+RpW=A=gkzHubO zqDl*ITFcb&CjG_iX$vBkJw4~va1W`J+ES+UW*)0DZ)I+Jk;Q2h#=Iz;Wm!0TilE8d z@JiD56_u{FGQC;O2Sw%0g)6CYwkMkfN(Dj#GJB<uhjK58oQ7r6XhBe6Hq-@kazCP{ zE)in(@(iT(@_A3=SrQeG-vktn!Hk~cFs&jEr^XfT(;$~M2J0Y2J(nRSq@XUl^9>X6 zX4#}SgC;%pqZc;}f_0X8rBhOO%h#z98b@c+`{p6jF6=$YWgpt6PHaNmuiSngc6Wc3 z$D%1;<7?nJ3eLX{PGYSLOtq)59+DIwabU9(ZX{tUO`R+N69vu91{kSav-@Pw^Yawn zL{mG0ffF6ue;2os8BN1>_KKJFe28h&8(m$vH3VxL=ZM=XU3;UBXq3+u<c>3$|K19P z&Y!WH_VcT9_uxG=&}M=I<oBcE=n2dB1XGjBAUA7UIL*66WG7g*3Lao>HsFv+okmdK zLLdzqL1Q~`M4B{$<`x2J(WtN$TLB@FHl3iol|VXlg3b;=NtaI0-AW)mI?3L-$${2~ z1N65L$bd#L*bW?%A&p?Tg+N9$QlsjTeSHi!Fy2Za6FR9$fPhTt1k<eqGNaR7v)GI* zPpY}e#Gf|>=1IO>us$0|0bg{KJK<u<q-7IUzR2dz)yn2tWoI3nS8lW`Hci+v-P^~I z!=1|EZsl;Va=70B4oo;S-A6FcbDLk)HovZIepB20wgG%+#P>!}$9_O-@`am+G{3So z<^Ge#5Z!Hq+=SM5hptU0_%U5uTfdHuN-GY7HRh~ceC?l5#RSWlhWX1jO~(v2GIG4p zS8#F8{)`_GKdxVCR>n8YK<N}TTu{}R$MOY_==adkpQVv`@WmF=i|fmtU!aIvpAUcd z93`mV)UPpgyzbcw^M9<=7@}GjQ+(zaD*S>#F*El3_N#GWsaJnMzl(my|54^grIqEg zab!|GW%kT(ag{&t?_LYr=EiJ*gM51ikK?(aev_}0G#gRw4wQECsO*8@3G|uvC#uMe zIEkbrDajx&Sbvvg+hnl(26ZE%aaoSMR$A*u6X5p;XDh9-^FOrne~qg`0f7&`&!zqP zk>W7`euBxj(Eo$K0)K@2KS3T|y&wY~39%)AX)Br@7|@6UK3d7z*yiUg%->E@#*(FH z$r2Ga8Pvjp%F+ol1M_fPFj)hBFS>6tSBTR%Qr*hZEU{%*K{shqv8rkdbE}pXYin)j z31cl22U~HSIbo_O2XS1*mhgn7iY5v%oAtStiOoWDl}k1~+>PqEiX3~;v_8(-+@^T) zR+J;9kmvJM%axr*OEk64>3B`_@af&rUGJIL^Yvn1IFZ(&wY&?DD`B+mO|*a@>gmzi zp1o^Tb`-Ga6-7}An11bt;;17|K#wGP>GQ}KhCvC_^u{mnSMmq!!a&gDyu@?OOLFjk z#5$rgdt*reUr_9xRUIK001^V+p$m{=2H78}GZ}FfNsGnAV4qCKmt%O{oqJ(PJ;JSh z=J|@E`fiyihH7`|G??bClIRsjg0XUKiZAA3#o?||`Dq>Ay3){&WKZfI8<@OY=PjNb zbmOpU*~(Hd0ugJtcQ+K5FybO=5vK5{_4b`$gz>1G;zBaUSSUa51yR<GGQ)lyB|n9r zpU;R`+%i6Y5;&`<w;m2D!3?zJBh0dS{8C<zM>>~<n0P~@GM4;c5QX2(%xG1P1_5LP zP&Ajmu~7ikCE>o)rf|>C@uyVu2vg8c;|<-1=7}dPkf{Zj$NfHwn6wN}hii%cI1m87 z&m84m*bVF+GJ2;qoQG)}a)PG^GTpf)m@pxRVYfr2BA%@ynrEj|FyV0z^S*(;2K8>N zKZahpxAuO3MX8w}PGetLM{x_$8A(|C1JIcMm#|}Q$r-7$dkKqk2J_;~<2bM|rZuRh ztP|sdwmS;DZE5#4JQ}s)(b5SLEQ~DG(>^0T?Z}Kkg#w4tDI-}PG^E+ZX*t%@QbU(# zM|!qr2#XgfKg2W!B6sUNWDoJDt7(>{JH8{x09s#h?wI;gvu4|*^Yx)8n1U2`M@b78 z!M%vHM-u74ZRJDm10bC}??RWdcy-D%ACaPI9dMFohFq!qX$?$5vFZ$y`x!)hQ4L-z zgmbCjN0SmSgHn<*Hf~qWM?^QXD#r-*4UUowOIAP&%dCUdp4C{Z86k9VT*iLeY`jyC zOPVsuR>eFuJ|>bsj$v57diA<nyO9$kOE77T3;KqjYYgd3p?oQ;5BBX{aVB_A|IIjH zPD#8}5AvKj)Sc7fvdf!|1;zrd)q>Q)+Ckt{wV5BS3l=)@`0RoEmI4%)+xhs+>A~6l zgw-N8c5&;dD5^KIN#=C>1CaXm6etLQ>4_&)HH(`@oZ7%ZaoRFAkU+B|JL!U<7Hv!? z5Eog}*OeIgIFT{v42GB)&Mwfoxw}gOZCYCE+F2-n0vbnx9$PodH4c(DMVoaK)o{7o zLjj%#V3c)?%I9dJifKjWIY`)%Ji$!1;`B+oU{mK5L+@5rPRS>202V9=yB)(8s4E)V z#MNhWpsJE%sn<v&s4d0w-TeG55RUma@hw7xa=_gl!?DRa_LNQXJeGx3;LVkwMW5mO zgW(5+7_@5wLa-^;1+lN=rdbZBFI)22V2bG^!R`AQGT)V5bUHK<M>x39naPESNCx(N zK)wgLJk+1GjMQE#)^I93Zpp~lT_7h`DE#bVTH9-gO0?d9@o?NKF+?oYo88+4{q_$c zncVVsQ<6n=_r-F7$(*ZyS!Umg-<gt!<HLk<IDxPUV{#m9@~{z#j}O)nZy=L<w7$Rf zp&B(jJQ}V2N8uj&5c^Bn#&Z7}#P$!sI2n>Pd0rLWRKj+PUv_zUZ9>1B?Mjx4#}M+t z*txv#7TTdHF5Aet9-B>94fN0#r(I)r=BF((wieDQjAa0Lz(<R5eeekrcs9_6^w^SR z;OG4=l-GM0`Fg+nvm+D4RlpcN-Fq&I3O=nLb4ueP1OkoACPXJSRHc}Y%wJxgoLs;B z|F5HrjD~ICJZyHqUb`$ON4r#hKC*e~<kC5V5qp<D3BbFXa%zf;b81Z<L4@&3`q1*Y zifjij_Vtq4Og5W-*oMtwv2D)Lk5kwk7#L9?FsI*|-U2rD=<lZQ2!Mf`PmA64P5*b@ zO!X!G#F)cU7?vI~B&NnsbZ)_bqDYa*_VAA9Yp3*%Ew=ADSU$X=JrQ$^GiKz@-lJP7 zVzyvY7DZ~8W#?#@F4U){B9(@=^0I}IDOvHR#^REU`UFVTmlT7f&HewVa;fxFL1lhg zT4h1Omh(vAU|UIX+aOJXl~vil%kHyKR*l4yxT*lQkE`e1EaD!|9>hPsoTCw$?1#lA zgv>!S1P}Nt1io&+`!b0MR&kLb5}C1r?Zw5w2;~Tm%i&q@I9%Ql3gVW8vHczR^@8ar z<{SUFjr+~PJA-#_df5KrTO7rlxBkliZRhrC=-H}gue{k9Scbg@9P+wL_B^@b)yh}j zE}K1Da;^fFGWSPVPM8<nAK+G1k~3VbnS0pw$W*xO<BDf#mvuN-Q))umM;H{sM9Uz$ zO*jLVv578*K#GU+EyM+@Fhk;erBa-07Ac%V@m9iQ+|-a;RH<AY5-itAsW(GLFD_BX z2jRUKSZ%QwHY-CRb2c21R#Knm?nj?m*J1}xxiAQRSe4}-WyK%j$z<u@MIbDw!a(p# zz!v~~0TTJ2gTpj3X)YZA=yR)@wO*|Cr#{1w1b!=6PUFF-;0`RS3Uy6zbc%NkMvx$_ z!xyI<6q2AhPG4wM7L!k4SBJjIl=?}VPqJu?BW=KlL=xL{Lwxj1XGd&kj#!+hREo_~ zhE5SP<gE~5;LFr1wM@wet|VGgw5mP5e`UTBF(k2;Yw27#PRz+wDLHvYv6LMKgddlb zPT&5xOTS>LMtpck*ZFrrdH&N}{2r2h?j#bbNSS_Y|5$gi9`*1}c>g!(L#G|%5d~;X zB*2pq2{*_b=9MskcoH+QbxrkvHR&Xg^x<H9WkTh}2Sm~c#=5${ZH*P_6v=B&W{aui z!bR`BdtBx|;8(6~y|~$%v~9SUS_Z7UYU^Z8eD*nW#VxC}vYp5d9yM2`CMQ*;n~x-K zYe-9N*j88>e*}q7HE?yEr~mOfWP<_$xIl(XryySPVF5TO6itdPq!pm32}Ma>BH<v& z2f=(&J{V3=e*0sX<8>_U4+cU$$yf-Gr(AQ^@lxo2%@93a;oSR<e7EuEq+xu>XDK9> zehwMNPx{$-m)!TxEP``2L;r_MxVy?V`3RLM`-HH3u|XA1@3VVc%V#No46TyGOKhm* zvY6b=`gmWI8%&L`Vhv`EUlaSchyvAAXG91<4Pi+Q`ly?8!8#0Asuhcb;yp>1pKK!8 z93bl<p$OWWbmdE}r-@Qo8NAO)vfNqIT|0>JfP@nKc>Z>jdaqX&FErkq_<dc@FyBaC zXzoJM3>1~wi^~*w?;zk5Pp+Rvw<#Exv2JMNm{>e<w;eimMzvPiwT|rK$n^=XJ?pmH z$r0~FTrhTcV73|WU!;A+(;Z<czGv*3{yA~Vra1vgM8raC*=wmzPfJQoNq*Eb91KfM zPEFG5l~FM;a%)(J^J(qwo|i6ogT$op=y12dX&)xEzBkOew-E%3X2^xl#a<%ON^s`f zk4+K@Otk?T@izOw7uO5Gd>I}x$u0xqs)vKicko9RnH~9{2C$YKJ&;@-`;#}`??xIC zMF|6ZE{A^`MIY}+3+{`tIW#P-XszSvjI6oXZF3W2cR={uu`T+Ro@YGq?fZykJ<mW1 z1;kZ<EZpBEN~p*G^iga4JMub<qT0O9^l8i>->+`h^>37VsAIDerbJKYvRGWg<fPmb zgLlvj`I1=6f$RtYn}976d4~0tu}kD;+}jYMK}n$4;q<A|=?T$lf3J=Gy7ub#IrhBF zMUk4t<5~9W+3oy`HnLtj&8MxqYrfu*;3z@Dl4nMRyUC|K{ECPdU}M@sbsbn^!*>KW zY4gTOvAX8gpy=doy?SX*j%Jx$Au%g9rLnjqx!y3O>Pw2Xk5=M}fsuz1?iTp;L!*@K z(?;dBuf{5I;c4om%Ity<PX8=WY6hMRbeQw_ihWjJ-I@qVJ9Uq@Oy`IK<>AROQIU$u zue16kK3|6l=QDfJFK|R@c}*aeiY;oH-4Qgep|{4N)^PzdFtBT7yHhY;5f?l$CW0ps z8$gaJL?Oz}5-SZtSP>iqD}|s`;je&ItVRgRf}qpJFhuOJF!c8*ATb6-_c^w><vKW2 zxwWX~>SQwAT(A)%k!Hx{|2bO>&Pk=zc{=~Fl+WStV;g*<wQ{hkmCG*!!TqHCNPp&^ z=D3uo$}+@%d||0!eCW+N&w)URO(DM@1HoNP=a~$o;MMDH%U8lQr_7ARCQ>WuD5-Kt z*a$-sxKUU!L^|f#N=j-j&u|9QURieEeuWe`7dtV#VAdZj%Sg~fJ>6vA{!cm09X2=# zHIbx6)&N7{T0yq|Aa<2b87-aiU~|w`1D=zR5-4?FB)Uze%L-Ls4F;5zi3EHR;ja7o zUlajSF5(N0bp~E}Hew`j2`qu&#sE34!0RC;wwQvQTCrVism@ReIFAW_)m6QMc66!2 zX>GMzPbbC69Iuhf|H<Vh*trtJ6PBR@`!jR8{&f9Wc8V-O%Y;0haJ1-jpc7#RKA`yY zsE{dAmUX?prkhQ|laz_ib=~ZO0gO?TTrPVRKV3j|O$EEXEmoCr84RxZNt7*L=4E>z zWWT#2nyZ26c?u=ntPyi*QZK8=2qZxs&Okh=+%PfCtW?nQG!Rek8M+U-iK8-=VH%dw zhk9?)g!LGK>2@lWL19h(2nLcB4R<))xDqJcw#6`CMBW4RA`%EGkg?oaIXtZif(q2{ zSD#Wp7ZO211&`injyQgx2<eGet6zD+KI+4O+g_+83e{xgv1zk36u>o#$R$&#<%JFS z@$+M<jZe_1Leiq5Yc$!ud>?PFZ#L~Z1O+AV84UhX2ui9+h(~O%)?~dHbz&Bq$%F_4 z!DZIp^EZ;;W{F9?xz;0<x14hmHFEi%Yb=ItY##&#`F)Sx?_AY8j4_h}{6IOX<7OAE zi<IP`*$=BK;IB}gs<5-Ef*NkUMHDvm4R-MXdn5qfHo~FNI3s&PAu;8^M(mr>1ko0~ zHTwb<&=W5S6YSr{FGLY5pmn>>+_@-J1U23HyYoX4B%q|dsZa&w<wI;sY)Y+pO1!oU z7Mb|AizH1tTx?BR;tHynhknITwPYg(6c(}VFWm48|7*E$^w*QiAYQq3X@F53yITU4 zQ2y;7XX-aGe!98;;uj6?(mXk$|3X0oF9h9muJo@D3)Xw-yG8_Gm<Io3&*WdQr@C3^ z%^E)S#t>*`VfIKQsD{H}a^y?$S43MsYU^D4U|B&Rhsoe*PzgtHs0WSI%H@$u3e{_5 zeZ7`rUMhmLjt^}~abJ?o?_5RX=_v<nNK4i2Uf2cQc;He60F^E-9W+{}`kt4kr`PkR zytxK71c@g~UBB&d4#K{<6&B4muKns2R?&{&dDT4wTP^6mQfbP-n(B~wtBPdx7i}@| z3&HxGN41tpAgL6RIF5H6Z%q4CXJNjo$m>jxJBT088o&2oTzaP>@2c6N?i2o})PUk- z-WR1z>Y~Fgu3HvSnbM2ivj0ZZai23W)ygWBSV;rer_a$7isrjsn{<kR3l7E+PCZ>+ zSFhzej)5nmATe*((^Jl_a72VF?5y~ZhU&Tvpks)#5D37H9~1(yy?%uFq%i7&J~oI{ zQ{ex5fug@v`1Th?{=P?fN*k3)Xd+EK#*<T`ti>ehk#&+T-$tjDSPIl2zn}2;h4_@} zM|=l9_N{!HYAe2pk8;&Ef6etu{z~23pV9sG+vho9Av&01Imw#z38&!HN|n&xb))%S zzKSM=^6-V=6WRn<&F7=DJMw$t|I6S3@ZKN3(|dW~=2d-;YT%ZKs0M^GnM5$MknHJc z@RBYiva9{8Cvp`fYWBk<?oEfM>^DF3g(T(^0*)TEe}xL<bmA%2Z6qep66YM6_G3Z9 zd-^_e^e6hten3?o=ecuW;(YlgKMTmqW0he|ZkA(Y!DBD##x?m08Fg~YwUY4KCIW{l zuqW~s7esl$l757dvMKvJ|B|5U$cs}&`;&|8wSARViO(1J%JO-WrhmIX)cYJ|^pE8j z{ji4ul!1=Ih*&F(?LEYMNAU$9G8`0il}p=;aR3JevkxH8mLvr@gFB2kavf8zi2wsh z*;<ST8iqJP;I5d$jQ1d)FTowJC4d9C!>EcZi9_EN3=Z1DLH1|Kp~iWP?tOU6%(Ye$ zd5$8`V#~L3OQKAePwC7#t{ZU$-*qfQo9{X!4CP!c0?*9jv1SIN0q=Bu($x%xPN=I3 z8iCykJL@VyItEC*LxpDa`5L-tYzG^;uTUokIDw8&y)@CZbQ*PSL#w+>ETw%bV5a>6 zP8#pmwh%(!O6^n;Fu6=L9|TlWxH}-q<yC=3dy8+NA2N-KFSP4AT@#0zicQ@7Cu`dz zbieI=zQpCmba)Aag%)@>L+<O`fgChzs6}aPo0D#<@l@kZXd%7}&aw=pz(?O%*^3%^ z^7~In!JI*|5oQ-lSp?p)F63VO4q;{1t@rC?9*2e&3(J+533ox`&92>FV-0?@eFzW> zO$&FzfV6IwB9uj1XSHn#+MQq`=Z_J}$>D5LjHWmn@8@g@wdRP-i=~*Bm@)0^GD|`~ zys~rM*a8>oWgkPph(@w7*E=Vd^DAMS>gL23Ji(%wdLb7V6M+fmD=E7%>4Jnj!eY56 z($&4##<`5aEu^ji5gg@;PGY|B&X*Q~6EBH#b!OZpo#$w3W|WEsJGsJL>}skg7+A&C z#JNow8i5P#U{{{Hc4vdl{#s*#`h|8vivgVh23Yuy<Ze;1*HoM|zj_02IKxFph*&|x zm}?b7+^uubp+AcHS?wBS*lBZdt}dKzqs>M3-e2|ZWhz-psnB?yw1^C?Gh!dD5g#Hb z(&<>dd-jNDWI2908N<lS%d<ENyiw{7J|o3c5yxx}7D1f?7&=-?^3~nlE{iOQLQb)d z`$DwbT?-^OZXj$9N5qJTBOlou))=}p4qV%qblK0qaOca;caFTIRg`=5Nzj|QXq#Ke zs(Kd%F(k6x)lp<hTZI*~yjf2cf=uKyswo2%wabS{)rbwp2L7bbkGfaPGsLgkFjSpa zNtM~cRN79LI`CG-tD1JX+9xENf#T7tvF*AvMd(&<U9%x=b7dZdPN33VcymztX;UAm zj5G}}ASjJEiGrN9q1pPR1TxGdsmVNAV9zq+E0Fu|_Te2#{D??-mK4v?b9gx!-DPct zZR!hiHOxbrNK830uN;u@rX2Qpj%6-tB(mc;Q%g)DhD2(_DO9CFZcXGe6b{C(%(Bf^ z2pfM)na7C?kN~|fi(kiQh4>oL0yi9ZGgd%gCQmv>NiYORyIqGW=QA&5X%JQvmIv6? z7+{K%e7y_=DU?$uZdL@|k(Xk-XOoT<n)gQV-gqf9JEoVDF}AJsOe*j!EgH*r^}EYY z`?gNw&||l$u#|bq_A$#Iu%=Q5_*7z3H(9%~IvKAjQ&h=;3l30I^<~W<;IBZ&Uk1lk zMVdsu9YtL^=4z=m7a6sqg*B$B%y9{%Jb@`r1?^Jml2?~!6lrfhv||&~A0bE@;E=#_ zW^CBQyB*N(xRNr%n(45UnT(!-V=U$rrPx?Rw9Zjv;w>2rydpPsRz53cfoEIGwe&(| z!`wX!(Kw{SM)|Gz6`0Jka39v>P2}^srircH7?6|=q|$%_Vnwrbu$nLT($_gQ-^?`p zrpfeeUE~u*${B3n#(v$uk^lT*Gj2Lf-RkS1JycC)F{5vbc{vaLFoCqVRd-0QrJ|v| zX$<^*@=AM*OEOX6??J^U{!x}@%Y#L<p?{XIM)UBb#=WI6OkZLj8aFbvLt1)or;0-n z!N~`BaOLaa+P%!DMHcyvsm);rcm9QVp{>=i?kvQR%&uk&>6?A0Gs39+PeY)Eud0gw zX9DfYDu3U-s=Zxob|C$~07R_uEU<{s2_-DjNS0+v(b(A6XiII(TPDZD!0}Q|`EBiN zPX~mfgYC1Ov$e&rHQj2e|K^xU13mU#HLRz73~8Ata4eNDF*K=S(J#BV#qPtlp3q<3 z8Gk3KT?>0)m=>vZBp5aH`R+Km!G<U@?s943ld*gAcff15g=;q}3c~d_H;u1GyNd0` zo2q>P61JJ41CTLEr|y%>)6Us#j*Hu?G}?mWE6-S`SgfkGrSHj)Q|xj}8p2zoZ?8&w z6vz^0I1AU(Z5^#m1`KVEw)~<Lu6bE%$MJN?hIN~P6NUtnO?SIt7VO!Qc355JebIx? z46}oqD+r<=qA00i8rL~m0zix?Mg6>EygX^zYhKeWWO0~1bK6E@Agr_L4{jtvD{zmg zq;>r@)?Ifa^^Q{6LQ*w^a@riaMOJk*Q3^-@KHZKAAdL$$`z7Bb9g~0>AB@0@R}vpn zTNE(CTC#zz5r=!*Cp*Wx$XCF)*6aOmvRH!8?%&ee+i^yb0Gt>SZ+US8;*l~4bFr=} zHm49Q*^#Y=>;J0G$BTbui4(#CZIH}>LIQfkwg&@EvwB7V;w!?>n;sE6f3zX63DE5F zj68k5as#zC+DrX4Jb1gv0gdyPa$HEQaL_5Q02i8caM8tW$IL}9ex}Y(3VLy(f7Nhb z0C+6fF5kxI%|HBJ|GkdP<AET7fCd8iks*nz>>jeP;(vAg*H=uxz)()T6@{ze+RWpf zi00T$PuS-UQCoZ+PWuQfCdTQFdMTbxpw~}i-X%mgE?B<j{NGVHGyeaR=0UVc>%AnP zk66_(+ree5Wrc5<sUzz4Ca8SH?<j6!_Zthr<>`-b(J(5DNB(m=dccV3^O;(Xam%E{ zoqjKzMp1p}fM{lerSW=N5<RZ%%R<BV$h>H&+(yuEw;#tqsc-aH==4p9JA(Zq4DFv& zC4&TOh&GMVoGJ}G#%>hRSfLr1m7=f<HiEv{aMbK3F5-Zm&|TLQ%JQ7(ytn^!Vn(7R zSUrvub4YZS(!u}(vk7nTQcI%J+UdDyyIqj)sFF1w@QMnjY1RK<N4HmO-Mhx2m_d?l zdo!Q&kqWnudK%cW#64x-=mQLUyNX#W-f+Ey0B30;F-(LB=x_mGZ~O@!14xbFP|5&Y z4$?V9>2kre!JE(FM7jGMp4sQ;h_v|Q95Hh!KQn4ck%U6C=B!&VZq%41f&_8mB@r}L z$Z)pCvYAJ*WNH`GQ7$GFYS7k~Zy91N7cW>O2=g;Y%!z#&Vhc6uA;$FC0Wk)%nyykV zX1DB=VIxA}j3tX=X+hKF;SoeZIeW^GL@`pricFoTB~dK+QZ(A)uQm$(Ervs@@%GCF zXC-veKcc@sF`LzRM1)vT_QgmmNrFhWljy!7!*UJbL9C&eTmPcLp{u#BRZNt=DKY7T z^1_Z-wMtZBUJd<!ohbkFvj73l5kpXjFp;7}i<2Nxid31h6e&>_9ICv7Y7H8-=+yNw zTxz;uT5T?NS2qWn!{zY>LXlV^mB|%Km0F|K>AOgSshPPI3#-<w+puZNwjI0n>^pGi z$gvZr&YZh2l0wL!{K*9f6eL)PPzp*aY8qj*bizfLNiR~AXfa|L7{!T~AW@QJDN?0L zm%$`cmTWn4ndQk>piohhJ{E>ohWWHd|AM6OJs!s{!4<V8Q4BrT=tYE&%!XR;mEp;W zykUhL$QQNmv<6qyh@CH`37XU+UbJzWa}=SE_%ViPmrs(KZbi)eP^&rX{pE){%JV0G z-4ryIA=N(-70fGia}Yp81OgEeF*AdinHkIs01N=kxLFLGygjGW1jhQmWkuirg}2wk z|4-VjEdIH?B&1R^`B&5CFV(iMHqD+Emu_8B&5itIQyi5lKAflLkEB8E^x+HKJHoU3 zbQ{voUg3|&_~4h@KvEyT_H}F!aq^o}8CucG9z%~hSKr#9E`deV*0Ri-_m%Z`Pdq#o zo(J=crzwsl-8tkH6MXms2m7t_?aA}4<KLHZX{a*0xmU*V1@_&sIW#}HU*78|^=I$i mpD}s$=RBpd$P2g4GD&W%eChv2{Pd>tUjD_0+L)p(0001eDVO8` literal 0 HcmV?d00001 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_ext_400.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_ext_400.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..5539f2e13a28cb3ebe3d732580615fc471225e02 GIT binary patch literal 15308 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 literal 0 HcmV?d00001 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_ext_700.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_ext_700.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..9f49fc13de796acbfb3b31845fc87ef947b18ec3 GIT binary patch literal 15164 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 literal 0 HcmV?d00001 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/latin_400.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/latin_400.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..2f9cc5964455b8f5ca989db989250dbebb1a5f66 GIT binary patch literal 18972 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 H?T~5}mj8_i literal 0 HcmV?d00001 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/latin_700.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/latin_700.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..243810e4594c4c858d043e9dd3562bfd3b1adeff GIT binary patch literal 19088 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 Tc<SUY`Kt13Q$5xzdK&-${v60d literal 0 HcmV?d00001 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/latin_ext_400.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/latin_ext_400.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..d859e4d3ceba36192ab6b0ac4e6e2e8ed21795d4 GIT binary patch literal 18380 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 literal 0 HcmV?d00001 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/latin_ext_700.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/latin_ext_700.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..0f95acbcdd781cc2ffa1cb7ded7fe637b59a61d0 GIT binary patch literal 18416 zcmV)TK(W7fPew8T0RR9107viu5dZ)H0JanW07r}f0RR9100000000000000000000 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 XMu&d5c*nl`nZ5LXaGxZcodEy<7R<vu literal 0 HcmV?d00001 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/vietnamese_400.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/vietnamese_400.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..29df398069da61aee853e79efc918a5da50cfdf6 GIT binary patch literal 7568 zcmV;B9dF`yPew8T0RR9103DD35dZ)H07@hP039y?0RR9100000000000000000000 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 literal 0 HcmV?d00001 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/vietnamese_700.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/vietnamese_700.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..efcc26dc5c69f23564e2cdbdf101e7fdf1e5ee79 GIT binary patch literal 7596 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 O#wJ^t_sl^H8{Ggk@tke| literal 0 HcmV?d00001 diff --git a/src/base/theme/bootsier/assets/images/caution.png b/src/base/theme/bootsier/assets/images/caution.png new file mode 100644 index 0000000000000000000000000000000000000000..d059f6292c976a198c441cfda66e33ca79d3b76c GIT binary patch literal 12481 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 LNkvXXu0mjf`&SGI literal 0 HcmV?d00001 diff --git a/src/base/theme/bootsier/assets/js/bootstrap.bundle.min.js b/src/base/theme/bootsier/assets/js/bootstrap.bundle.min.js new file mode 100644 index 00000000..cc0a2556 --- /dev/null +++ b/src/base/theme/bootsier/assets/js/bootstrap.bundle.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.1.3 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t="transitionend",e=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,a=(t,e,i)=>{Object.keys(i).forEach((n=>{const s=i[n],r=e[n],a=r&&o(r)?"element":null==(l=r)?`${l}`:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}))},l=t=>!(!o(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",(()=>{p.forEach((t=>t()))})),p.push(e)):e()},_=t=>{"function"==typeof t&&t()},b=(e,i,n=!0)=>{if(!n)return void _(e);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),_(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},v=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,E=/::\d+$/,A={};let T=1;const O={mouseenter:"mouseover",mouseleave:"mouseout"},C=/^(mouseenter|mouseleave)/i,k=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function x(t){const e=L(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function D(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;s<o;s++){const o=t[n[s]];if(o.originalHandler===e&&o.delegationSelector===i)return o}return null}function S(t,e,i){const n="string"==typeof e,s=n?i:e;let o=P(t);return k.has(o)||(o=t),[n,s,o]}function N(t,e,i,n,s){if("string"!=typeof e||!t)return;if(i||(i=n,n=null),C.test(e)){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=S(e,i,n),l=x(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=L(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&j.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&j.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function I(t,e,i,n,s){const o=D(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function P(t){return t=t.replace(w,""),O[t]||t}const j={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void I(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach((o=>{if(o.includes(n)){const n=s[o];I(t,e,i,n.originalHandler,n.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const n=i.replace(E,"");if(!a||e.includes(n)){const e=h[i];I(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f(),s=P(e),o=e!==s,r=k.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},M=new Map,H={set(t,e,i){M.has(t)||M.set(t,new Map);const n=M.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>M.has(t)&&M.get(t).get(e)||null,remove(t,e){if(!M.has(t))return;const i=M.get(t);i.delete(e),0===i.size&&M.delete(t)}};class B{constructor(t){(t=r(t))&&(this._element=t,H.set(this._element,this.constructor.DATA_KEY,this))}dispose(){H.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){b(t,e,i)}static getInstance(t){return H.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const o=n(this)||this.closest(`.${s}`);t.getOrCreateInstance(o)[e]()}))};class W extends B{static get NAME(){return"alert"}close(){if(j.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(W,"close"),g(W);const $='[data-bs-toggle="button"]';class z extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=z.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function q(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function F(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}j.on(document,"click.bs.button.data-api",$,(t=>{t.preventDefault();const e=t.target.closest($);z.getOrCreateInstance(e).toggle()})),g(z);const U={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=q(t.dataset[i])})),e},getDataAttribute:(t,e)=>q(t.getAttribute(`data-bs-${F(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},V={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(", ");return this.find(e,t).filter((t=>!c(t)&&l(t)))}},K="carousel",X={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Y={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},Q="next",G="prev",Z="left",J="right",tt={ArrowLeft:J,ArrowRight:Z},et="slid.bs.carousel",it="active",nt=".active.carousel-item";class st extends B{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return X}static get NAME(){return K}next(){this._slide(Q)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(G)}pause(t){t||(this._isPaused=!0),V.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(s(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=V.findOne(nt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,et,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?Q:G;this._slide(i,this._items[t])}_getConfig(t){return t={...X,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(K,t,Y),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?J:Z)}_addEventListeners(){this._config.keyboard&&j.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),j.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};V.find(".carousel-item img",this._element).forEach((t=>{j.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?(j.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),j.on(this._element,"pointerup.bs.carousel",(t=>n(t))),this._element.classList.add("pointer-event")):(j.on(this._element,"touchstart.bs.carousel",(t=>e(t))),j.on(this._element,"touchmove.bs.carousel",(t=>i(t))),j.on(this._element,"touchend.bs.carousel",(t=>n(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=tt[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?V.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===Q;return v(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(V.findOne(nt,this._element));return j.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=V.findOne(".active",this._indicatorsElement);e.classList.remove(it),e.removeAttribute("aria-current");const i=V.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e<i.length;e++)if(Number.parseInt(i[e].getAttribute("data-bs-slide-to"),10)===this._getItemIndex(t)){i[e].classList.add(it),i[e].setAttribute("aria-current","true");break}}}_updateInterval(){const t=this._activeElement||V.findOne(nt,this._element);if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}_slide(t,e){const i=this._directionToOrder(t),n=V.findOne(nt,this._element),s=this._getItemIndex(n),o=e||this._getItemByOrder(i,n),r=this._getItemIndex(o),a=Boolean(this._interval),l=i===Q,c=l?"carousel-item-start":"carousel-item-end",h=l?"carousel-item-next":"carousel-item-prev",d=this._orderToDirection(i);if(o&&o.classList.contains(it))return void(this._isSliding=!1);if(this._isSliding)return;if(this._triggerSlideEvent(o,d).defaultPrevented)return;if(!n||!o)return;this._isSliding=!0,a&&this.pause(),this._setActiveIndicatorElement(o),this._activeElement=o;const f=()=>{j.trigger(this._element,et,{relatedTarget:o,direction:d,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),u(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(it),n.classList.remove(it,h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove(it),o.classList.add(it),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[J,Z].includes(t)?m()?t===Z?G:Q:t===Z?Q:G:t}_orderToDirection(t){return[Q,G].includes(t)?m()?t===G?Z:J:t===G?J:Z:t}static carouselInterface(t,e){const i=st.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){st.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=n(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),st.carouselInterface(e,i),s&&st.getInstance(e).to(s),t.preventDefault()}}j.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",st.dataApiClickHandler),j.on(window,"load.bs.carousel.data-api",(()=>{const t=V.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;e<i;e++)st.carouselInterface(t[e],st.getInstance(t[e]))})),g(st);const ot="collapse",rt={toggle:!0,parent:null},at={toggle:"boolean",parent:"(null|element)"},lt="show",ct="collapse",ht="collapsing",dt="collapsed",ut=":scope .collapse .collapse",ft='[data-bs-toggle="collapse"]';class pt extends B{constructor(t,e){super(t),this._isTransitioning=!1,this._config=this._getConfig(e),this._triggerArray=[];const n=V.find(ft);for(let t=0,e=n.length;t<e;t++){const e=n[t],s=i(e),o=V.find(s).filter((t=>t===this._element));null!==s&&o.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return rt}static get NAME(){return ot}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=V.find(ut,this._config.parent);e=V.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=V.findOne(this._selector);if(e.length){const n=e.find((t=>i!==t));if(t=n?pt.getInstance(n):null,t&&t._isTransitioning)return}if(j.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&pt.getOrCreateInstance(e,{toggle:!1}).hide(),t||H.set(e,"bs.collapse",null)}));const n=this._getDimension();this._element.classList.remove(ct),this._element.classList.add(ht),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s=`scroll${n[0].toUpperCase()+n.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct,lt),this._element.style[n]="",j.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[n]=`${this._element[s]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(ht),this._element.classList.remove(ct,lt);const e=this._triggerArray.length;for(let t=0;t<e;t++){const e=this._triggerArray[t],i=n(e);i&&!this._isShown(i)&&this._addAriaAndCollapsedClass([e],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct),j.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(lt)}_getConfig(t){return(t={...rt,...U.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=r(t.parent),a(ot,t,at),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=V.find(ut,this._config.parent);V.find(ft,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=n(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(dt):t.classList.add(dt),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=pt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,"click.bs.collapse.data-api",ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=i(this);V.find(e).forEach((t=>{pt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),g(pt);var mt="top",gt="bottom",_t="right",bt="left",vt="auto",yt=[mt,gt,_t,bt],wt="start",Et="end",At="clippingParents",Tt="viewport",Ot="popper",Ct="reference",kt=yt.reduce((function(t,e){return t.concat([e+"-"+wt,e+"-"+Et])}),[]),Lt=[].concat(yt,[vt]).reduce((function(t,e){return t.concat([e,e+"-"+wt,e+"-"+Et])}),[]),xt="beforeRead",Dt="read",St="afterRead",Nt="beforeMain",It="main",Pt="afterMain",jt="beforeWrite",Mt="write",Ht="afterWrite",Bt=[xt,Dt,St,Nt,It,Pt,jt,Mt,Ht];function Rt(t){return t?(t.nodeName||"").toLowerCase():null}function Wt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function $t(t){return t instanceof Wt(t).Element||t instanceof Element}function zt(t){return t instanceof Wt(t).HTMLElement||t instanceof HTMLElement}function qt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof Wt(t).ShadowRoot||t instanceof ShadowRoot)}const Ft={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];zt(s)&&Rt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});zt(n)&&Rt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function Ut(t){return t.split("-")[0]}function Vt(t,e){var i=t.getBoundingClientRect();return{width:i.width/1,height:i.height/1,top:i.top/1,right:i.right/1,bottom:i.bottom/1,left:i.left/1,x:i.left/1,y:i.top/1}}function Kt(t){var e=Vt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Xt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&qt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Yt(t){return Wt(t).getComputedStyle(t)}function Qt(t){return["table","td","th"].indexOf(Rt(t))>=0}function Gt(t){return(($t(t)?t.ownerDocument:t.document)||window.document).documentElement}function Zt(t){return"html"===Rt(t)?t:t.assignedSlot||t.parentNode||(qt(t)?t.host:null)||Gt(t)}function Jt(t){return zt(t)&&"fixed"!==Yt(t).position?t.offsetParent:null}function te(t){for(var e=Wt(t),i=Jt(t);i&&Qt(i)&&"static"===Yt(i).position;)i=Jt(i);return i&&("html"===Rt(i)||"body"===Rt(i)&&"static"===Yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&zt(t)&&"fixed"===Yt(t).position)return null;for(var i=Zt(t);zt(i)&&["html","body"].indexOf(Rt(i))<0;){var n=Yt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function ee(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var ie=Math.max,ne=Math.min,se=Math.round;function oe(t,e,i){return ie(t,ne(e,i))}function re(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function ae(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const le={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=Ut(i.placement),l=ee(a),c=[bt,_t].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return re("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:ae(t,yt))}(s.padding,i),d=Kt(o),u="y"===l?mt:bt,f="y"===l?gt:_t,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=te(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=oe(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Xt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ce(t){return t.split("-")[1]}var he={top:"auto",right:"auto",bottom:"auto",left:"auto"};function de(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:se(se(e*n)/n)||0,y:se(se(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=bt,v=mt,y=window;if(c){var w=te(i),E="clientHeight",A="clientWidth";w===Wt(i)&&"static"!==Yt(w=Gt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==mt&&(s!==bt&&s!==_t||o!==Et)||(v=gt,m-=w[E]-n.height,m*=l?1:-1),s!==bt&&(s!==mt&&s!==gt||o!==Et)||(b=_t,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&he);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}const ue={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:Ut(e.placement),variation:ce(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,de(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,de(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var fe={passive:!0};const pe={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=Wt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,fe)})),a&&l.addEventListener("resize",i.update,fe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,fe)})),a&&l.removeEventListener("resize",i.update,fe)}},data:{}};var me={left:"right",right:"left",bottom:"top",top:"bottom"};function ge(t){return t.replace(/left|right|bottom|top/g,(function(t){return me[t]}))}var _e={start:"end",end:"start"};function be(t){return t.replace(/start|end/g,(function(t){return _e[t]}))}function ve(t){var e=Wt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ye(t){return Vt(Gt(t)).left+ve(t).scrollLeft}function we(t){var e=Yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ee(t){return["html","body","#document"].indexOf(Rt(t))>=0?t.ownerDocument.body:zt(t)&&we(t)?t:Ee(Zt(t))}function Ae(t,e){var i;void 0===e&&(e=[]);var n=Ee(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=Wt(n),r=s?[o].concat(o.visualViewport||[],we(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Ae(Zt(r)))}function Te(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Oe(t,e){return e===Tt?Te(function(t){var e=Wt(t),i=Gt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+ye(t),y:a}}(t)):zt(e)?function(t){var e=Vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Te(function(t){var e,i=Gt(t),n=ve(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ie(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ie(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ye(t),l=-n.scrollTop;return"rtl"===Yt(s||i).direction&&(a+=ie(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Gt(t)))}function Ce(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?Ut(s):null,r=s?ce(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case mt:e={x:a,y:i.y-n.height};break;case gt:e={x:a,y:i.y+i.height};break;case _t:e={x:i.x+i.width,y:l};break;case bt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?ee(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case wt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Et:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ke(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?At:o,a=i.rootBoundary,l=void 0===a?Tt:a,c=i.elementContext,h=void 0===c?Ot:c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=re("number"!=typeof p?p:ae(p,yt)),g=h===Ot?Ct:Ot,_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Ae(Zt(t)),i=["absolute","fixed"].indexOf(Yt(t).position)>=0&&zt(t)?te(t):t;return $t(i)?e.filter((function(t){return $t(t)&&Xt(t,i)&&"body"!==Rt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Oe(t,i);return e.top=ie(n.top,e.top),e.right=ne(n.right,e.right),e.bottom=ne(n.bottom,e.bottom),e.left=ie(n.left,e.left),e}),Oe(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}($t(b)?b:b.contextElement||Gt(t.elements.popper),r,l),y=Vt(t.elements.reference),w=Ce({reference:y,element:_,strategy:"absolute",placement:s}),E=Te(Object.assign({},_,w)),A=h===Ot?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if(h===Ot&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[_t,gt].indexOf(t)>=0?1:-1,i=[mt,gt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function Le(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?Lt:l,h=ce(n),d=h?a?kt:kt.filter((function(t){return ce(t)===h})):yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ke(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[Ut(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const xe={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=Ut(g),b=l||(_!==g&&p?function(t){if(Ut(t)===vt)return[];var e=ge(t);return[be(t),e,be(e)]}(g):[ge(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(Ut(i)===vt?Le(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O<v.length;O++){var C=v[O],k=Ut(C),L=ce(C)===wt,x=[mt,gt].indexOf(k)>=0,D=x?"width":"height",S=ke(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?_t:bt:L?gt:mt;y[D]>w[D]&&(N=ge(N));var I=ge(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function De(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function Se(t){return[mt,_t,gt,bt].some((function(e){return t[e]>=0}))}const Ne={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ke(e,{elementContext:"reference"}),a=ke(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Se(l),d=Se(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},Ie={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=Lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=Ut(t),s=[bt,mt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[bt,_t].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},Pe={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Ce({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},je={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ke(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=Ut(e.placement),b=ce(e.placement),v=!b,y=ee(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?mt:bt,L="y"===y?gt:_t,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P=b===wt?A[x]:T[x],j=b===wt?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?Kt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],$=oe(0,A[x],H[x]),z=v?A[x]/2-I-$-R-O:P-$-R-O,q=v?-A[x]/2+I+$+W+O:j+$+W+O,F=e.elements.arrow&&te(e.elements.arrow),U=F?"y"===y?F.clientTop||0:F.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-U,X=E[y]+q-V;if(o){var Y=oe(f?ne(S,K):S,D,f?ie(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?mt:bt,G="x"===y?gt:_t,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=oe(f?ne(J,K):J,Z,f?ie(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function Me(t,e,i){void 0===i&&(i=!1);var n=zt(e);zt(e)&&function(t){var e=t.getBoundingClientRect();e.width,t.offsetWidth,e.height,t.offsetHeight}(e);var s,o,r=Gt(e),a=Vt(t),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(n||!n&&!i)&&(("body"!==Rt(e)||we(r))&&(l=(s=e)!==Wt(s)&&zt(s)?{scrollLeft:(o=s).scrollLeft,scrollTop:o.scrollTop}:ve(s)),zt(e)?((c=Vt(e)).x+=e.clientLeft,c.y+=e.clientTop):r&&(c.x=ye(r))),{x:a.left+l.scrollLeft-c.x,y:a.top+l.scrollTop-c.y,width:a.width,height:a.height}}function He(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var Be={placement:"bottom",modifiers:[],strategy:"absolute"};function Re(){for(var t=arguments.length,e=new Array(t),i=0;i<t;i++)e[i]=arguments[i];return!e.some((function(t){return!(t&&"function"==typeof t.getBoundingClientRect)}))}function We(t){void 0===t&&(t={});var e=t,i=e.defaultModifiers,n=void 0===i?[]:i,s=e.defaultOptions,o=void 0===s?Be:s;return function(t,e,i){void 0===i&&(i=o);var s,r,a={placement:"bottom",orderedModifiers:[],options:Object.assign({},Be,o),modifiersData:{},elements:{reference:t,popper:e},attributes:{},styles:{}},l=[],c=!1,h={state:a,setOptions:function(i){var s="function"==typeof i?i(a.options):i;d(),a.options=Object.assign({},o,a.options,s),a.scrollParents={reference:$t(t)?Ae(t):t.contextElement?Ae(t.contextElement):[],popper:Ae(e)};var r,c,u=function(t){var e=He(t);return Bt.reduce((function(t,i){return t.concat(e.filter((function(t){return t.phase===i})))}),[])}((r=[].concat(n,a.options.modifiers),c=r.reduce((function(t,e){var i=t[e.name];return t[e.name]=i?Object.assign({},i,e,{options:Object.assign({},i.options,e.options),data:Object.assign({},i.data,e.data)}):e,t}),{}),Object.keys(c).map((function(t){return c[t]}))));return a.orderedModifiers=u.filter((function(t){return t.enabled})),a.orderedModifiers.forEach((function(t){var e=t.name,i=t.options,n=void 0===i?{}:i,s=t.effect;if("function"==typeof s){var o=s({state:a,name:e,instance:h,options:n});l.push(o||function(){})}})),h.update()},forceUpdate:function(){if(!c){var t=a.elements,e=t.reference,i=t.popper;if(Re(e,i)){a.rects={reference:Me(e,te(i),"fixed"===a.options.strategy),popper:Kt(i)},a.reset=!1,a.placement=a.options.placement,a.orderedModifiers.forEach((function(t){return a.modifiersData[t.name]=Object.assign({},t.data)}));for(var n=0;n<a.orderedModifiers.length;n++)if(!0!==a.reset){var s=a.orderedModifiers[n],o=s.fn,r=s.options,l=void 0===r?{}:r,d=s.name;"function"==typeof o&&(a=o({state:a,options:l,name:d,instance:h})||a)}else a.reset=!1,n=-1}}},update:(s=function(){return new Promise((function(t){h.forceUpdate(),t(a)}))},function(){return r||(r=new Promise((function(t){Promise.resolve().then((function(){r=void 0,t(s())}))}))),r}),destroy:function(){d(),c=!0}};if(!Re(t,e))return h;function d(){l.forEach((function(t){return t()})),l=[]}return h.setOptions(i).then((function(t){!c&&i.onFirstUpdate&&i.onFirstUpdate(t)})),h}}var $e=We(),ze=We({defaultModifiers:[pe,Pe,ue,Ft]}),qe=We({defaultModifiers:[pe,Pe,ue,Ft,Ie,xe,je,le,Ne]});const Fe=Object.freeze({__proto__:null,popperGenerator:We,detectOverflow:ke,createPopperBase:$e,createPopper:qe,createPopperLite:ze,top:mt,bottom:gt,right:_t,left:bt,auto:vt,basePlacements:yt,start:wt,end:Et,clippingParents:At,viewport:Tt,popper:Ot,reference:Ct,variationPlacements:kt,placements:Lt,beforeRead:xt,read:Dt,afterRead:St,beforeMain:Nt,main:It,afterMain:Pt,beforeWrite:jt,write:Mt,afterWrite:Ht,modifierPhases:Bt,applyStyles:Ft,arrow:le,computeStyles:ue,eventListeners:pe,flip:xe,hide:Ne,offset:Ie,popperOffsets:Pe,preventOverflow:je}),Ue="dropdown",Ve="Escape",Ke="Space",Xe="ArrowUp",Ye="ArrowDown",Qe=new RegExp("ArrowUp|ArrowDown|Escape"),Ge="click.bs.dropdown.data-api",Ze="keydown.bs.dropdown.data-api",Je="show",ti='[data-bs-toggle="dropdown"]',ei=".dropdown-menu",ii=m()?"top-end":"top-start",ni=m()?"top-start":"top-end",si=m()?"bottom-end":"bottom-start",oi=m()?"bottom-start":"bottom-end",ri=m()?"left-start":"right-start",ai=m()?"right-start":"left-start",li={offset:[0,2],boundary:"clippingParents",reference:"toggle",display:"dynamic",popperConfig:null,autoClose:!0},ci={offset:"(array|string|function)",boundary:"(string|element)",reference:"(string|element|object)",display:"string",popperConfig:"(null|object|function)",autoClose:"(boolean|string)"};class hi extends B{constructor(t,e){super(t),this._popper=null,this._config=this._getConfig(e),this._menu=this._getMenuElement(),this._inNavbar=this._detectNavbar()}static get Default(){return li}static get DefaultType(){return ci}static get NAME(){return Ue}toggle(){return this._isShown()?this.hide():this.show()}show(){if(c(this._element)||this._isShown(this._menu))return;const t={relatedTarget:this._element};if(j.trigger(this._element,"show.bs.dropdown",t).defaultPrevented)return;const e=hi.getParentFromElement(this._element);this._inNavbar?U.setDataAttribute(this._menu,"popper","none"):this._createPopper(e),"ontouchstart"in document.documentElement&&!e.closest(".navbar-nav")&&[].concat(...document.body.children).forEach((t=>j.on(t,"mouseover",d))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Je),this._element.classList.add(Je),j.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(c(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){j.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._popper&&this._popper.destroy(),this._menu.classList.remove(Je),this._element.classList.remove(Je),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},a(Ue,t,this.constructor.DefaultType),"object"==typeof t.reference&&!o(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ue.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===Fe)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:o(this._config.reference)?e=r(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=qe(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(Je)}_getMenuElement(){return V.next(this._element,ei)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ri;if(t.classList.contains("dropstart"))return ai;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ni:ii:e?oi:si}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(l);i.length&&v(i,e,t===Ye,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=V.find(ti);for(let i=0,n=e.length;i<n;i++){const n=hi.getInstance(e[i]);if(!n||!1===n._config.autoClose)continue;if(!n._isShown())continue;const s={relatedTarget:n._element};if(t){const e=t.composedPath(),i=e.includes(n._menu);if(e.includes(n._element)||"inside"===n._config.autoClose&&!i||"outside"===n._config.autoClose&&i)continue;if(n._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;"click"===t.type&&(s.clickEvent=t)}n._completeHide(s)}}static getParentFromElement(t){return n(t)||t.parentNode}static dataApiKeydownHandler(t){if(/input|textarea/i.test(t.target.tagName)?t.key===Ke||t.key!==Ve&&(t.key!==Ye&&t.key!==Xe||t.target.closest(ei)):!Qe.test(t.key))return;const e=this.classList.contains(Je);if(!e&&t.key===Ve)return;if(t.preventDefault(),t.stopPropagation(),c(this))return;const i=this.matches(ti)?this:V.prev(this,ti)[0],n=hi.getOrCreateInstance(i);if(t.key!==Ve)return t.key===Xe||t.key===Ye?(e||n.show(),void n._selectMenuItem(t)):void(e&&t.key!==Ke||hi.clearMenus());n.hide()}}j.on(document,Ze,ti,hi.dataApiKeydownHandler),j.on(document,Ze,ei,hi.dataApiKeydownHandler),j.on(document,Ge,hi.clearMenus),j.on(document,"keyup.bs.dropdown.data-api",hi.clearMenus),j.on(document,Ge,ti,(function(t){t.preventDefault(),hi.getOrCreateInstance(this).toggle()})),g(hi);const di=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",ui=".sticky-top";class fi{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,"paddingRight",(e=>e+t)),this._setElementAttributes(di,"paddingRight",(e=>e+t)),this._setElementAttributes(ui,"marginRight",(e=>e-t))}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=`${i(Number.parseFloat(s))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(di,"paddingRight"),this._resetElementAttributes(ui,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){o(t)?e(t):V.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const pi={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},mi={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},gi="show",_i="mousedown.bs.backdrop";class bi{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&u(this._getElement()),this._getElement().classList.add(gi),this._emulateAnimation((()=>{_(t)}))):_(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(gi),this._emulateAnimation((()=>{this.dispose(),_(t)}))):_(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...pi,..."object"==typeof t?t:{}}).rootElement=r(t.rootElement),a("backdrop",t,mi),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),j.on(this._getElement(),_i,(()=>{_(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&(j.off(this._element,_i),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const vi={trapElement:null,autofocus:!0},yi={trapElement:"element",autofocus:"boolean"},wi=".bs.focustrap",Ei="backward";class Ai{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),j.off(document,wi),j.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),j.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,wi))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=V.focusableChildren(i);0===n.length?i.focus():this._lastTabNavDirection===Ei?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Ei:"forward")}_getConfig(t){return t={...vi,..."object"==typeof t?t:{}},a("focustrap",t,yi),t}}const Ti="modal",Oi="Escape",Ci={backdrop:!0,keyboard:!0,focus:!0},ki={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},Li="hidden.bs.modal",xi="show.bs.modal",Di="resize.bs.modal",Si="click.dismiss.bs.modal",Ni="keydown.dismiss.bs.modal",Ii="mousedown.dismiss.bs.modal",Pi="modal-open",ji="show",Mi="modal-static";class Hi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new fi}static get Default(){return Ci}static get NAME(){return Ti}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,xi,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(Pi),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),j.on(this._dialog,Ii,(()=>{j.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if(j.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(ji),j.off(this._element,Si),j.off(this._dialog,Ii),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>j.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_getConfig(t){return t={...Ci,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Ti,t,ki),t}_showElement(t){const e=this._isAnimated(),i=V.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&u(this._element),this._element.classList.add(ji),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?j.on(this._element,Ni,(t=>{this._config.keyboard&&t.key===Oi?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Oi||this._triggerBackdropTransition()})):j.off(this._element,Ni)}_setResizeEvent(){this._isShown?j.on(window,Di,(()=>this._adjustDialog())):j.off(window,Di)}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Pi),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,Li)}))}_showBackdrop(t){j.on(this._element,Si,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains(Mi)||(n||(i.overflowY="hidden"),t.add(Mi),this._queueCallback((()=>{t.remove(Mi),n||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!m()||i&&!t&&m())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!m()||!i&&t&&m())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=n(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,xi,(t=>{t.defaultPrevented||j.one(e,Li,(()=>{l(this)&&this.focus()}))}));const i=V.findOne(".modal.show");i&&Hi.getInstance(i).hide(),Hi.getOrCreateInstance(e).toggle(this)})),R(Hi),g(Hi);const Bi="offcanvas",Ri={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},$i="show",zi=".offcanvas.show",qi="hidden.bs.offcanvas";class Fi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return Bi}static get Default(){return Ri}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new fi).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add($i),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),j.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove($i),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new fi).reset(),j.trigger(this._element,qi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Ri,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Bi,t,Wi),t}_initializeBackDrop(){return new bi({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_addEventListeners(){j.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=Fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=n(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;j.one(e,qi,(()=>{l(this)&&this.focus()}));const i=V.findOne(zi);i&&i!==e&&Fi.getInstance(i).hide(),Fi.getOrCreateInstance(e).toggle(this)})),j.on(window,"load.bs.offcanvas.data-api",(()=>V.find(zi).forEach((t=>Fi.getOrCreateInstance(t).show())))),R(Fi),g(Fi);const Ui=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Vi=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,Ki=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Xi=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Ui.has(i)||Boolean(Vi.test(t.nodeValue)||Ki.test(t.nodeValue));const n=e.filter((t=>t instanceof RegExp));for(let t=0,e=n.length;t<e;t++)if(n[t].test(i))return!0;return!1};function Yi(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(let t=0,i=s.length;t<i;t++){const i=s[t],n=i.nodeName.toLowerCase();if(!Object.keys(e).includes(n)){i.remove();continue}const o=[].concat(...i.attributes),r=[].concat(e["*"]||[],e[n]||[]);o.forEach((t=>{Xi(t,r)||i.removeAttribute(t.nodeName)}))}return n.body.innerHTML}const Qi="tooltip",Gi=new Set(["sanitize","allowList","sanitizeFn"]),Zi={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ji={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},tn={animation:!0,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},en={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},nn="fade",sn="show",on="show",rn="out",an=".tooltip-inner",ln=".modal",cn="hide.bs.modal",hn="hover",dn="focus";class un extends B{constructor(t,e){if(void 0===Fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return tn}static get NAME(){return Qi}static get Event(){return en}static get DefaultType(){return Zi}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(sn))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ln),cn,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.Event.SHOW),e=h(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(an).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add(nn);const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;H.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),j.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=qe(this._element,n,this._getPopperConfig(r)),n.classList.add(sn);const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{j.on(t,"mouseover",d)}));const c=this.tip.classList.contains(nn);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,j.trigger(this._element,this.constructor.Event.SHOWN),t===rn&&this._leave(null,this)}),this.tip,c)}hide(){if(!this._popper)return;const t=this.getTipElement();if(j.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(sn),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(nn);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==on&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(nn,sn),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),an)}_sanitizeAndSetContent(t,e,i){const n=V.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return o(e)?(e=r(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Yi(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ji[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)j.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===hn?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===hn?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;j.on(this._element,e,this._config.selector,(t=>this._enter(t))),j.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ln),cn,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?dn:hn]=!0),e.getTipElement().classList.contains(sn)||e._hoverState===on?e._hoverState=on:(clearTimeout(e._timeout),e._hoverState=on,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===on&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?dn:hn]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=rn,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===rn&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Gi.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),a(Qi,t,this.constructor.DefaultType),t.sanitize&&(t.template=Yi(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=un.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(un);const fn={...un.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'},pn={...un.DefaultType,content:"(string|element|function)"},mn={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class gn extends un{static get Default(){return fn}static get NAME(){return"popover"}static get Event(){return mn}static get DefaultType(){return pn}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=gn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(gn);const _n="scrollspy",bn={offset:10,method:"auto",target:""},vn={offset:"number",method:"string",target:"(string|element)"},yn="active",wn=".nav-link, .list-group-item, .dropdown-item",En="position";class An extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,j.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return bn}static get NAME(){return _n}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":En,e="auto"===this._config.method?t:this._config.method,n=e===En?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),V.find(wn,this._config.target).map((t=>{const s=i(t),o=s?V.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[U[e](o).top+n,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){j.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...bn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=r(t.target)||document.documentElement,a(_n,t,vn),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t<this._offsets[0]&&this._offsets[0]>0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t<this._offsets[e+1])&&this._activate(this._targets[e])}}_activate(t){this._activeTarget=t,this._clear();const e=wn.split(",").map((e=>`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=V.findOne(e.join(","),this._config.target);i.classList.add(yn),i.classList.contains("dropdown-item")?V.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(yn):V.parents(i,".nav, .list-group").forEach((t=>{V.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(yn))),V.prev(t,".nav-item").forEach((t=>{V.children(t,".nav-link").forEach((t=>t.classList.add(yn)))}))})),j.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){V.find(wn,this._config.target).filter((t=>t.classList.contains(yn))).forEach((t=>t.classList.remove(yn)))}static jQueryInterface(t){return this.each((function(){const e=An.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,"load.bs.scrollspy.data-api",(()=>{V.find('[data-bs-spy="scroll"]').forEach((t=>new An(t)))})),g(An);const Tn="active",On="fade",Cn="show",kn=".active",Ln=":scope > li > .active";class xn extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Tn))return;let t;const e=n(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?Ln:kn;t=V.find(e,i),t=t[t.length-1]}const s=t?j.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(j.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const o=()=>{j.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),j.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?V.children(e,kn):V.find(Ln,e))[0],s=i&&n&&n.classList.contains(On),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove(Cn),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Tn);const t=V.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Tn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Tn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),u(t),t.classList.contains(On)&&t.classList.add(Cn);let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&V.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Tn))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=xn.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||xn.getOrCreateInstance(this).show()})),g(xn);const Dn="toast",Sn="hide",Nn="show",In="showing",Pn={animation:"boolean",autohide:"boolean",delay:"number"},jn={animation:!0,autohide:!0,delay:5e3};class Mn extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return Pn}static get Default(){return jn}static get NAME(){return Dn}show(){j.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Sn),u(this._element),this._element.classList.add(Nn),this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.remove(In),j.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(Nn)&&(j.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.add(Sn),this._element.classList.remove(In),this._element.classList.remove(Nn),j.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(Nn)&&this._element.classList.remove(Nn),super.dispose()}_getConfig(t){return t={...jn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},a(Dn,t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),j.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Mn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(Mn),g(Mn),{Alert:W,Button:z,Carousel:st,Collapse:pt,Dropdown:hi,Modal:Hi,Offcanvas:Fi,Popover:gn,ScrollSpy:An,Tab:xn,Toast:Mn,Tooltip:un}})); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/src/base/theme/bootsier/assets/js/bootstrap.bundle.min.js.map b/src/base/theme/bootsier/assets/js/bootstrap.bundle.min.js.map new file mode 100644 index 00000000..7d78e32a --- /dev/null +++ b/src/base/theme/bootsier/assets/js/bootstrap.bundle.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/data.js","../../js/src/base-component.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/dom/manipulator.js","../../js/src/dom/selector-engine.js","../../js/src/carousel.js","../../js/src/collapse.js","../../node_modules/@popperjs/core/lib/enums.js","../../node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","../../node_modules/@popperjs/core/lib/dom-utils/getWindow.js","../../node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","../../node_modules/@popperjs/core/lib/modifiers/applyStyles.js","../../node_modules/@popperjs/core/lib/utils/getBasePlacement.js","../../node_modules/@popperjs/core/lib/dom-utils/getBoundingClientRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getLayoutRect.js","../../node_modules/@popperjs/core/lib/dom-utils/contains.js","../../node_modules/@popperjs/core/lib/dom-utils/getComputedStyle.js","../../node_modules/@popperjs/core/lib/dom-utils/isTableElement.js","../../node_modules/@popperjs/core/lib/dom-utils/getDocumentElement.js","../../node_modules/@popperjs/core/lib/dom-utils/getParentNode.js","../../node_modules/@popperjs/core/lib/dom-utils/getOffsetParent.js","../../node_modules/@popperjs/core/lib/utils/getMainAxisFromPlacement.js","../../node_modules/@popperjs/core/lib/utils/math.js","../../node_modules/@popperjs/core/lib/utils/within.js","../../node_modules/@popperjs/core/lib/utils/mergePaddingObject.js","../../node_modules/@popperjs/core/lib/utils/getFreshSideObject.js","../../node_modules/@popperjs/core/lib/utils/expandToHashMap.js","../../node_modules/@popperjs/core/lib/modifiers/arrow.js","../../node_modules/@popperjs/core/lib/utils/getVariation.js","../../node_modules/@popperjs/core/lib/modifiers/computeStyles.js","../../node_modules/@popperjs/core/lib/modifiers/eventListeners.js","../../node_modules/@popperjs/core/lib/utils/getOppositePlacement.js","../../node_modules/@popperjs/core/lib/utils/getOppositeVariationPlacement.js","../../node_modules/@popperjs/core/lib/dom-utils/getWindowScroll.js","../../node_modules/@popperjs/core/lib/dom-utils/getWindowScrollBarX.js","../../node_modules/@popperjs/core/lib/dom-utils/isScrollParent.js","../../node_modules/@popperjs/core/lib/dom-utils/getScrollParent.js","../../node_modules/@popperjs/core/lib/dom-utils/listScrollParents.js","../../node_modules/@popperjs/core/lib/utils/rectToClientRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getClippingRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getViewportRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getDocumentRect.js","../../node_modules/@popperjs/core/lib/utils/computeOffsets.js","../../node_modules/@popperjs/core/lib/utils/detectOverflow.js","../../node_modules/@popperjs/core/lib/utils/computeAutoPlacement.js","../../node_modules/@popperjs/core/lib/modifiers/flip.js","../../node_modules/@popperjs/core/lib/modifiers/hide.js","../../node_modules/@popperjs/core/lib/modifiers/offset.js","../../node_modules/@popperjs/core/lib/modifiers/popperOffsets.js","../../node_modules/@popperjs/core/lib/modifiers/preventOverflow.js","../../node_modules/@popperjs/core/lib/utils/getAltAxis.js","../../node_modules/@popperjs/core/lib/dom-utils/getCompositeRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getNodeScroll.js","../../node_modules/@popperjs/core/lib/dom-utils/getHTMLElementScroll.js","../../node_modules/@popperjs/core/lib/utils/orderModifiers.js","../../node_modules/@popperjs/core/lib/createPopper.js","../../node_modules/@popperjs/core/lib/utils/debounce.js","../../node_modules/@popperjs/core/lib/utils/mergeByName.js","../../node_modules/@popperjs/core/lib/popper-lite.js","../../node_modules/@popperjs/core/lib/popper.js","../../js/src/dropdown.js","../../js/src/util/scrollbar.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"names":["TRANSITION_END","getSelector","element","selector","getAttribute","hrefAttr","includes","startsWith","split","trim","getSelectorFromElement","document","querySelector","getElementFromSelector","triggerTransitionEnd","dispatchEvent","Event","isElement","obj","jquery","nodeType","getElement","length","typeCheckConfig","componentName","config","configTypes","Object","keys","forEach","property","expectedTypes","value","valueType","toString","call","match","toLowerCase","RegExp","test","TypeError","toUpperCase","isVisible","getClientRects","getComputedStyle","getPropertyValue","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","parentNode","noop","reflow","offsetHeight","getjQuery","jQuery","window","body","DOMContentLoadedCallbacks","isRTL","dir","defineJQueryPlugin","plugin","callback","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","readyState","addEventListener","push","execute","executeAfterTransition","transitionElement","waitForTransition","emulatedDuration","transitionDuration","transitionDelay","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","getTransitionDurationFromElement","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","index","indexOf","listLength","Math","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","customEventsRegex","nativeEvents","Set","getUidEvent","uid","getEvent","findHandler","events","delegationSelector","uidEventList","i","len","event","originalHandler","normalizeParams","originalTypeEvent","delegationFn","delegation","typeEvent","getTypeEvent","has","addHandler","oneOff","wrapFn","relatedTarget","delegateTarget","this","handlers","previousFn","replace","domElements","querySelectorAll","EventHandler","off","type","apply","bootstrapDelegationHandler","bootstrapHandler","removeHandler","Boolean","on","one","inNamespace","isNamespace","elementEvent","namespace","storeElementEvent","handlerKey","removeNamespacedHandlers","slice","keyHandlers","trigger","args","isNative","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","evt","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","createEvent","initEvent","CustomEvent","cancelable","key","defineProperty","get","preventDefault","elementMap","Map","Data","set","instance","instanceMap","size","console","error","Array","from","remove","delete","BaseComponent","constructor","_element","DATA_KEY","dispose","EVENT_KEY","getOwnPropertyNames","propertyName","_queueCallback","isAnimated","static","getInstance","VERSION","Error","enableDismissTrigger","component","method","clickEvent","tagName","closest","getOrCreateInstance","Alert","close","_destroyElement","each","data","undefined","SELECTOR_DATA_TOGGLE","Button","toggle","setAttribute","normalizeData","val","normalizeDataKey","chr","button","Manipulator","setDataAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","dataset","filter","pureKey","charAt","getDataAttribute","offset","rect","getBoundingClientRect","top","pageYOffset","left","pageXOffset","position","offsetTop","offsetLeft","SelectorEngine","find","concat","Element","prototype","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","map","join","el","Default","interval","keyboard","slide","pause","wrap","touch","DefaultType","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","KEY_TO_DIRECTION","ArrowLeft","ArrowRight","EVENT_SLID","CLASS_NAME_ACTIVE","SELECTOR_ACTIVE_ITEM","Carousel","super","_items","_interval","_activeElement","_isPaused","_isSliding","touchTimeout","touchStartX","touchDeltaX","_config","_getConfig","_indicatorsElement","_touchSupported","navigator","maxTouchPoints","_pointerEvent","PointerEvent","_addEventListeners","_slide","nextWhenVisible","hidden","cycle","clearInterval","_updateInterval","setInterval","visibilityState","bind","to","activeIndex","_getItemIndex","order","_handleSwipe","absDeltax","abs","direction","_keydown","_addTouchEventListeners","hasPointerPenTouch","pointerType","start","clientX","touches","move","end","clearTimeout","itemImg","add","_getItemByOrder","isNext","_triggerSlideEvent","eventDirectionName","targetIndex","fromIndex","_setActiveIndicatorElement","activeIndicator","indicators","parseInt","elementInterval","defaultInterval","directionOrOrder","_directionToOrder","activeElementIndex","nextElement","nextElementIndex","isCycling","directionalClassName","orderClassName","_orderToDirection","triggerSlidEvent","completeCallBack","action","ride","carouselInterface","slideIndex","dataApiClickHandler","carousels","parent","CLASS_NAME_SHOW","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_COLLAPSED","CLASS_NAME_DEEPER_CHILDREN","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElem","_selector","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activesData","actives","container","tempActiveData","elemActive","dimension","_getDimension","style","scrollSize","triggerArrayLength","selected","triggerArray","isOpen","bottom","right","auto","basePlacements","clippingParents","viewport","popper","reference","variationPlacements","reduce","acc","placement","placements","beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite","modifierPhases","getNodeName","nodeName","getWindow","node","ownerDocument","defaultView","isHTMLElement","HTMLElement","isShadowRoot","applyStyles$1","enabled","phase","_ref","state","elements","styles","assign","effect","_ref2","initialStyles","options","strategy","margin","arrow","hasOwnProperty","attribute","requires","getBasePlacement","includeScale","width","height","x","y","getLayoutRect","clientRect","offsetWidth","rootNode","isSameNode","host","isTableElement","getDocumentElement","getParentNode","assignedSlot","getTrueOffsetParent","offsetParent","getOffsetParent","isFirefox","userAgent","currentNode","css","transform","perspective","contain","willChange","getContainingBlock","getMainAxisFromPlacement","round","within","mathMax","mathMin","mergePaddingObject","paddingObject","expandToHashMap","hashMap","arrow$1","_state$modifiersData$","arrowElement","popperOffsets","modifiersData","basePlacement","axis","padding","rects","toPaddingObject","arrowRect","minProp","maxProp","endDiff","startDiff","arrowOffsetParent","clientSize","clientHeight","clientWidth","centerToReference","center","axisProp","centerOffset","_options$element","requiresIfExists","getVariation","unsetSides","mapToStyles","_Object$assign2","popperRect","variation","offsets","gpuAcceleration","adaptive","roundOffsets","_ref3","dpr","devicePixelRatio","roundOffsetsByDPR","_ref3$x","_ref3$y","hasX","hasY","sideX","sideY","win","heightProp","widthProp","_Object$assign","commonStyles","computeStyles$1","_ref4","_options$gpuAccelerat","_options$adaptive","_options$roundOffsets","passive","eventListeners","_options$scroll","scroll","_options$resize","resize","scrollParents","scrollParent","update","hash","getOppositePlacement","matched","getOppositeVariationPlacement","getWindowScroll","scrollLeft","scrollTop","getWindowScrollBarX","isScrollParent","_getComputedStyle","overflow","overflowX","overflowY","getScrollParent","listScrollParents","_element$ownerDocumen","isBody","visualViewport","updatedList","rectToClientRect","getClientRectFromMixedType","clippingParent","html","getViewportRect","clientTop","clientLeft","getInnerBoundingClientRect","winScroll","scrollWidth","scrollHeight","getDocumentRect","computeOffsets","commonX","commonY","mainAxis","detectOverflow","_options","_options$placement","_options$boundary","boundary","_options$rootBoundary","rootBoundary","_options$elementConte","elementContext","_options$altBoundary","altBoundary","_options$padding","altContext","clippingClientRect","mainClippingParents","clipperElement","getClippingParents","firstClippingParent","clippingRect","accRect","getClippingRect","contextElement","referenceClientRect","popperClientRect","elementClientRect","overflowOffsets","offsetData","multiply","computeAutoPlacement","flipVariations","_options$allowedAutoP","allowedAutoPlacements","allPlacements","allowedPlacements","overflows","sort","a","b","flip$1","_skip","_options$mainAxis","checkMainAxis","_options$altAxis","altAxis","checkAltAxis","specifiedFallbackPlacements","fallbackPlacements","_options$flipVariatio","preferredPlacement","oppositePlacement","getExpandedFallbackPlacements","referenceRect","checksMap","makeFallbackChecks","firstFittingPlacement","_basePlacement","isStartVariation","isVertical","mainVariationSide","altVariationSide","checks","every","check","_loop","_i","fittingPlacement","reset","getSideOffsets","preventedOffsets","isAnySideFullyClipped","some","side","hide$1","preventOverflow","referenceOverflow","popperAltOverflow","referenceClippingOffsets","popperEscapeOffsets","isReferenceHidden","hasPopperEscaped","offset$1","_options$offset","invertDistance","skidding","distance","distanceAndSkiddingToXY","_data$state$placement","popperOffsets$1","preventOverflow$1","_options$tether","tether","_options$tetherOffset","tetherOffset","isBasePlacement","tetherOffsetValue","mainSide","altSide","additive","minLen","maxLen","arrowPaddingObject","arrowPaddingMin","arrowPaddingMax","arrowLen","minOffset","maxOffset","clientOffset","offsetModifierValue","tetherMin","tetherMax","preventedOffset","_mainSide","_altSide","_offset","_min","_max","_preventedOffset","getCompositeRect","elementOrVirtualElement","isFixed","isOffsetParentAnElement","isElementScaled","modifiers","visited","result","modifier","dep","depModifier","DEFAULT_OPTIONS","areValidElements","_len","arguments","_key","popperGenerator","generatorOptions","_generatorOptions","_generatorOptions$def","defaultModifiers","_generatorOptions$def2","defaultOptions","pending","orderedModifiers","effectCleanupFns","isDestroyed","setOptions","setOptionsAction","cleanupModifierEffects","merged","orderModifiers","current","existing","m","_ref3$options","cleanupFn","forceUpdate","_state$elements","_state$orderedModifie","_state$orderedModifie2","Promise","resolve","then","destroy","onFirstUpdate","createPopper","computeStyles","applyStyles","flip","ESCAPE_KEY","SPACE_KEY","ARROW_UP_KEY","ARROW_DOWN_KEY","REGEXP_KEYDOWN","EVENT_CLICK_DATA_API","EVENT_KEYDOWN_DATA_API","SELECTOR_MENU","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","display","popperConfig","autoClose","Dropdown","_popper","_menu","_getMenuElement","_inNavbar","_detectNavbar","getParentFromElement","_createPopper","focus","_completeHide","Popper","referenceElement","_getPopperConfig","isDisplayStatic","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","_selectMenuItem","items","toggles","context","composedPath","isMenuTarget","isActive","stopPropagation","getToggleButton","clearMenus","dataApiKeydownHandler","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","ScrollBarHelper","getWidth","documentWidth","innerWidth","_disableOverFlow","_setElementAttributes","calculatedValue","_saveInitialAttribute","styleProp","scrollbarWidth","_applyManipulationCallback","_resetElementAttributes","actualValue","removeProperty","callBack","isOverflowing","className","rootElement","clickCallback","EVENT_MOUSEDOWN","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","trapElement","autofocus","TAB_NAV_BACKWARD","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","shiftKey","EVENT_HIDDEN","EVENT_SHOW","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_KEYDOWN_DISMISS","EVENT_MOUSEDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_ignoreBackdropClick","_scrollBar","_isAnimated","_adjustDialog","_setEscapeEvent","_setResizeEvent","_showBackdrop","_showElement","_hideModal","htmlElement","handleUpdate","modalBody","_triggerBackdropTransition","_resetAdjustments","currentTarget","isModalOverflowing","isBodyOverflowing","paddingLeft","paddingRight","showEvent","allReadyOpen","OPEN_SELECTOR","Offcanvas","visibility","blur","uriAttributes","SAFE_URL_PATTERN","DATA_URL_PATTERN","allowedAttribute","allowedAttributeList","attributeName","nodeValue","regExp","attributeRegex","sanitizeHtml","unsafeHtml","allowList","sanitizeFn","createdDocument","DOMParser","parseFromString","elementName","attributeList","allowedAttributes","innerHTML","DISALLOWED_ATTRIBUTES","animation","template","title","delay","customClass","sanitize","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","area","br","col","code","div","em","hr","h1","h2","h3","h4","h5","h6","img","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","HIDE","HIDDEN","SHOW","SHOWN","INSERTED","CLICK","FOCUSIN","FOCUSOUT","MOUSEENTER","MOUSELEAVE","CLASS_NAME_FADE","HOVER_STATE_SHOW","HOVER_STATE_OUT","SELECTOR_TOOLTIP_INNER","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","Tooltip","_isEnabled","_timeout","_hoverState","_activeTrigger","tip","_setListeners","enable","disable","toggleEnabled","_initializeOnDelegatedTarget","click","_isWithActiveTrigger","_enter","_leave","getTipElement","_hideModalHandler","_disposePopper","isWithContent","shadowRoot","isInTheDom","getTitle","tipId","prefix","floor","random","getElementById","getUID","attachment","_getAttachment","_addAttachmentClass","_resolvePossibleFunction","prevHoverState","_cleanTipClass","setContent","_sanitizeAndSetContent","content","templateElement","setElementContent","textContent","updateAttachment","_getDelegateConfig","_handlePopperPlacementChange","_getBasicClassPrefix","eventIn","eventOut","_fixTitle","originalTitleType","dataAttributes","dataAttr","basicClassPrefixRegex","tabClass","token","tClass","Popover","_getContent","SELECTOR_LINK_ITEMS","METHOD_POSITION","ScrollSpy","_scrollElement","_offsets","_targets","_activeTarget","_scrollHeight","_process","refresh","autoMethod","offsetMethod","offsetBase","_getScrollTop","_getScrollHeight","targetSelector","targetBCR","item","_getOffsetHeight","innerHeight","maxScroll","_activate","_clear","queries","link","listGroup","navItem","spy","SELECTOR_ACTIVE","SELECTOR_ACTIVE_UL","Tab","listElement","itemSelector","hideEvent","complete","active","isTransitioning","_transitionComplete","dropdownChild","dropdownElement","dropdown","CLASS_NAME_HIDE","CLASS_NAME_SHOWING","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","_onInteraction","isInteracting"],"mappings":"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","sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1000000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n// Shoutout AngusCroll (https://goo.gl/pxwQGp)\nconst toType = obj => {\n if (obj === null || obj === undefined) {\n return `${obj}`\n }\n\n return {}.toString.call(obj).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * --------------------------------------------------------------------------\n * Public Util Api\n * --------------------------------------------------------------------------\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttr = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttr || (!hrefAttr.includes('#') && !hrefAttr.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {\n hrefAttr = `#${hrefAttr.split('#')[1]}`\n }\n\n selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null\n }\n\n return selector\n}\n\nconst getSelectorFromElement = element => {\n const selector = getSelector(element)\n\n if (selector) {\n return document.querySelector(selector) ? selector : null\n }\n\n return null\n}\n\nconst getElementFromSelector = element => {\n const selector = getSelector(element)\n\n return selector ? document.querySelector(selector) : null\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = obj => {\n if (!obj || typeof obj !== 'object') {\n return false\n }\n\n if (typeof obj.jquery !== 'undefined') {\n obj = obj[0]\n }\n\n return typeof obj.nodeType !== 'undefined'\n}\n\nconst getElement = obj => {\n if (isElement(obj)) { // it's a jQuery object or a node element\n return obj.jquery ? obj[0] : obj\n }\n\n if (typeof obj === 'string' && obj.length > 0) {\n return document.querySelector(obj)\n }\n\n return null\n}\n\nconst typeCheckConfig = (componentName, config, configTypes) => {\n Object.keys(configTypes).forEach(property => {\n const expectedTypes = configTypes[property]\n const value = config[property]\n const valueType = value && isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${componentName.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n })\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n return getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n // eslint-disable-next-line no-unused-expressions\n element.offsetHeight\n}\n\nconst getjQuery = () => {\n const { jQuery } = window\n\n if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n DOMContentLoadedCallbacks.forEach(callback => callback())\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = callback => {\n if (typeof callback === 'function') {\n callback()\n }\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element depending on the direction and if cycle is allowed\n if (index === -1) {\n return list[!shouldGetNext && isCycleAllowed ? list.length - 1 : 0]\n }\n\n const listLength = list.length\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n getElement,\n getUID,\n getSelectorFromElement,\n getElementFromSelector,\n getTransitionDurationFromElement,\n triggerTransitionEnd,\n isElement,\n typeCheckConfig,\n isVisible,\n isDisabled,\n findShadowRoot,\n noop,\n getNextActiveElement,\n reflow,\n getjQuery,\n onDOMContentLoaded,\n isRTL,\n defineJQueryPlugin,\n execute,\n executeAfterTransition\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\nconst customEventsRegex = /^(mouseenter|mouseleave)/i\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * ------------------------------------------------------------------------\n * Private methods\n * ------------------------------------------------------------------------\n */\n\nfunction getUidEvent(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getEvent(element) {\n const uid = getUidEvent(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n event.delegateTarget = element\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (let i = domElements.length; i--;) {\n if (domElements[i] === target) {\n event.delegateTarget = target\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n\n // To please ESLint\n return null\n }\n}\n\nfunction findHandler(events, handler, delegationSelector = null) {\n const uidEventList = Object.keys(events)\n\n for (let i = 0, len = uidEventList.length; i < len; i++) {\n const event = events[uidEventList[i]]\n\n if (event.originalHandler === handler && event.delegationSelector === delegationSelector) {\n return event\n }\n }\n\n return null\n}\n\nfunction normalizeParams(originalTypeEvent, handler, delegationFn) {\n const delegation = typeof handler === 'string'\n const originalHandler = delegation ? delegationFn : handler\n\n let typeEvent = getTypeEvent(originalTypeEvent)\n const isNative = nativeEvents.has(typeEvent)\n\n if (!isNative) {\n typeEvent = originalTypeEvent\n }\n\n return [delegation, originalHandler, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFn, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n if (!handler) {\n handler = delegationFn\n delegationFn = null\n }\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (customEventsRegex.test(originalTypeEvent)) {\n const wrapFn = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n if (delegationFn) {\n delegationFn = wrapFn(delegationFn)\n } else {\n handler = wrapFn(handler)\n }\n }\n\n const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn)\n const events = getEvent(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFn = findHandler(handlers, originalHandler, delegation ? handler : null)\n\n if (previousFn) {\n previousFn.oneOff = previousFn.oneOff && oneOff\n\n return\n }\n\n const uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = delegation ?\n bootstrapDelegationHandler(element, handler, delegationFn) :\n bootstrapHandler(element, handler)\n\n fn.delegationSelector = delegation ? handler : null\n fn.originalHandler = originalHandler\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, delegation)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n Object.keys(storeElementEvent).forEach(handlerKey => {\n if (handlerKey.includes(namespace)) {\n const event = storeElementEvent[handlerKey]\n\n removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector)\n }\n })\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFn) {\n addHandler(element, event, handler, delegationFn, false)\n },\n\n one(element, event, handler, delegationFn) {\n addHandler(element, event, handler, delegationFn, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFn) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getEvent(element)\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof originalHandler !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!events || !events[typeEvent]) {\n return\n }\n\n removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null)\n return\n }\n\n if (isNamespace) {\n Object.keys(events).forEach(elementEvent => {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n })\n }\n\n const storeElementEvent = events[typeEvent] || {}\n Object.keys(storeElementEvent).forEach(keyHandlers => {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n const event = storeElementEvent[keyHandlers]\n\n removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector)\n }\n })\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n const isNative = nativeEvents.has(typeEvent)\n\n let jQueryEvent\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n let evt = null\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n if (isNative) {\n evt = document.createEvent('HTMLEvents')\n evt.initEvent(typeEvent, bubbles, true)\n } else {\n evt = new CustomEvent(event, {\n bubbles,\n cancelable: true\n })\n }\n\n // merge custom information in our event\n if (typeof args !== 'undefined') {\n Object.keys(args).forEach(key => {\n Object.defineProperty(evt, key, {\n get() {\n return args[key]\n }\n })\n })\n }\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && typeof jQueryEvent !== 'undefined') {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data'\nimport {\n executeAfterTransition,\n getElement\n} from './util/index'\nimport EventHandler from './dom/event-handler'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst VERSION = '5.1.3'\n\nclass BaseComponent {\n constructor(element) {\n element = getElement(element)\n\n if (!element) {\n return\n }\n\n this._element = element\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n Object.getOwnPropertyNames(this).forEach(propertyName => {\n this[propertyName] = null\n })\n }\n\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n /** Static */\n\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler'\nimport { getElementFromSelector, isDisabled } from './index'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { defineJQueryPlugin } from './util/index'\nimport EventHandler from './dom/event-handler'\nimport BaseComponent from './base-component'\nimport { enableDismissTrigger } from './util/component-functions'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Alert extends BaseComponent {\n // Getters\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Alert to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { defineJQueryPlugin } from './util/index'\nimport EventHandler from './dom/event-handler'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\n\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Button extends BaseComponent {\n // Getters\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Button to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(val) {\n if (val === 'true') {\n return true\n }\n\n if (val === 'false') {\n return false\n }\n\n if (val === Number(val).toString()) {\n return Number(val)\n }\n\n if (val === '' || val === 'null') {\n return null\n }\n\n return val\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n\n Object.keys(element.dataset)\n .filter(key => key.startsWith('bs'))\n .forEach(key => {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)\n attributes[pureKey] = normalizeData(element.dataset[key])\n })\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n },\n\n offset(element) {\n const rect = element.getBoundingClientRect()\n\n return {\n top: rect.top + window.pageYOffset,\n left: rect.left + window.pageXOffset\n }\n },\n\n position(element) {\n return {\n top: element.offsetTop,\n left: element.offsetLeft\n }\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible } from '../util/index'\n\nconst NODE_TEXT = 3\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children)\n .filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n\n let ancestor = element.parentNode\n\n while (ancestor && ancestor.nodeType === Node.ELEMENT_NODE && ancestor.nodeType !== NODE_TEXT) {\n if (ancestor.matches(selector)) {\n parents.push(ancestor)\n }\n\n ancestor = ancestor.parentNode\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(', ')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElementFromSelector,\n isRTL,\n isVisible,\n getNextActiveElement,\n reflow,\n triggerTransitionEnd,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n slide: false,\n pause: 'hover',\n wrap: true,\n touch: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)',\n keyboard: 'boolean',\n slide: '(boolean|string)',\n pause: '(string|boolean)',\n wrap: 'boolean',\n touch: 'boolean'\n}\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ACTIVE_ITEM = '.active.carousel-item'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_INDICATOR = '[data-bs-target]'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._items = null\n this._interval = null\n this._activeElement = null\n this._isPaused = false\n this._isSliding = false\n this.touchTimeout = null\n this.touchStartX = 0\n this.touchDeltaX = 0\n\n this._config = this._getConfig(config)\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n this._pointerEvent = Boolean(window.PointerEvent)\n\n this._addEventListeners()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause(event) {\n if (!event) {\n this._isPaused = true\n }\n\n if (SelectorEngine.findOne(SELECTOR_NEXT_PREV, this._element)) {\n triggerTransitionEnd(this._element)\n this.cycle(true)\n }\n\n clearInterval(this._interval)\n this._interval = null\n }\n\n cycle(event) {\n if (!event) {\n this._isPaused = false\n }\n\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n\n if (this._config && this._config.interval && !this._isPaused) {\n this._updateInterval()\n\n this._interval = setInterval(\n (document.visibilityState ? this.nextWhenVisible : this.next).bind(this),\n this._config.interval\n )\n }\n }\n\n to(index) {\n this._activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n const activeIndex = this._getItemIndex(this._activeElement)\n\n if (index > this._items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n if (activeIndex === index) {\n this.pause()\n this.cycle()\n return\n }\n\n const order = index > activeIndex ?\n ORDER_NEXT :\n ORDER_PREV\n\n this._slide(order, this._items[index])\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' ? config : {})\n }\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _handleSwipe() {\n const absDeltax = Math.abs(this.touchDeltaX)\n\n if (absDeltax <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltax / this.touchDeltaX\n\n this.touchDeltaX = 0\n\n if (!direction) {\n return\n }\n\n this._slide(direction > 0 ? DIRECTION_RIGHT : DIRECTION_LEFT)\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, event => this.pause(event))\n EventHandler.on(this._element, EVENT_MOUSELEAVE, event => this.cycle(event))\n }\n\n if (this._config.touch && this._touchSupported) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n const hasPointerPenTouch = event => {\n return this._pointerEvent &&\n (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n const start = event => {\n if (hasPointerPenTouch(event)) {\n this.touchStartX = event.clientX\n } else if (!this._pointerEvent) {\n this.touchStartX = event.touches[0].clientX\n }\n }\n\n const move = event => {\n // ensure swiping with one touch and not pinching\n this.touchDeltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this.touchStartX\n }\n\n const end = event => {\n if (hasPointerPenTouch(event)) {\n this.touchDeltaX = event.clientX - this.touchStartX\n }\n\n this._handleSwipe()\n if (this._config.pause === 'hover') {\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(event => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n }\n\n SelectorEngine.find(SELECTOR_ITEM_IMG, this._element).forEach(itemImg => {\n EventHandler.on(itemImg, EVENT_DRAG_START, event => event.preventDefault())\n })\n\n if (this._pointerEvent) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => end(event))\n }\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(direction)\n }\n }\n\n _getItemIndex(element) {\n this._items = element && element.parentNode ?\n SelectorEngine.find(SELECTOR_ITEM, element.parentNode) :\n []\n\n return this._items.indexOf(element)\n }\n\n _getItemByOrder(order, activeElement) {\n const isNext = order === ORDER_NEXT\n return getNextActiveElement(this._items, activeElement, isNext, this._config.wrap)\n }\n\n _triggerSlideEvent(relatedTarget, eventDirectionName) {\n const targetIndex = this._getItemIndex(relatedTarget)\n const fromIndex = this._getItemIndex(SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element))\n\n return EventHandler.trigger(this._element, EVENT_SLIDE, {\n relatedTarget,\n direction: eventDirectionName,\n from: fromIndex,\n to: targetIndex\n })\n }\n\n _setActiveIndicatorElement(element) {\n if (this._indicatorsElement) {\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const indicators = SelectorEngine.find(SELECTOR_INDICATOR, this._indicatorsElement)\n\n for (let i = 0; i < indicators.length; i++) {\n if (Number.parseInt(indicators[i].getAttribute('data-bs-slide-to'), 10) === this._getItemIndex(element)) {\n indicators[i].classList.add(CLASS_NAME_ACTIVE)\n indicators[i].setAttribute('aria-current', 'true')\n break\n }\n }\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n if (elementInterval) {\n this._config.defaultInterval = this._config.defaultInterval || this._config.interval\n this._config.interval = elementInterval\n } else {\n this._config.interval = this._config.defaultInterval || this._config.interval\n }\n }\n\n _slide(directionOrOrder, element) {\n const order = this._directionToOrder(directionOrOrder)\n const activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n const activeElementIndex = this._getItemIndex(activeElement)\n const nextElement = element || this._getItemByOrder(order, activeElement)\n\n const nextElementIndex = this._getItemIndex(nextElement)\n const isCycling = Boolean(this._interval)\n\n const isNext = order === ORDER_NEXT\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n const eventDirectionName = this._orderToDirection(order)\n\n if (nextElement && nextElement.classList.contains(CLASS_NAME_ACTIVE)) {\n this._isSliding = false\n return\n }\n\n if (this._isSliding) {\n return\n }\n\n const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName)\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n return\n }\n\n this._isSliding = true\n\n if (isCycling) {\n this.pause()\n }\n\n this._setActiveIndicatorElement(nextElement)\n this._activeElement = nextElement\n\n const triggerSlidEvent = () => {\n EventHandler.trigger(this._element, EVENT_SLID, {\n relatedTarget: nextElement,\n direction: eventDirectionName,\n from: activeElementIndex,\n to: nextElementIndex\n })\n }\n\n if (this._element.classList.contains(CLASS_NAME_SLIDE)) {\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n setTimeout(triggerSlidEvent, 0)\n }\n\n this._queueCallback(completeCallBack, activeElement, true)\n } else {\n activeElement.classList.remove(CLASS_NAME_ACTIVE)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n this._isSliding = false\n triggerSlidEvent()\n }\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _directionToOrder(direction) {\n if (![DIRECTION_RIGHT, DIRECTION_LEFT].includes(direction)) {\n return direction\n }\n\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (![ORDER_NEXT, ORDER_PREV].includes(order)) {\n return order\n }\n\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n\n static carouselInterface(element, config) {\n const data = Carousel.getOrCreateInstance(element, config)\n\n let { _config } = data\n if (typeof config === 'object') {\n _config = {\n ..._config,\n ...config\n }\n }\n\n const action = typeof config === 'string' ? config : _config.slide\n\n if (typeof config === 'number') {\n data.to(config)\n } else if (typeof action === 'string') {\n if (typeof data[action] === 'undefined') {\n throw new TypeError(`No method named \"${action}\"`)\n }\n\n data[action]()\n } else if (_config.interval && _config.ride) {\n data.pause()\n data.cycle()\n }\n }\n\n static jQueryInterface(config) {\n return this.each(function () {\n Carousel.carouselInterface(this, config)\n })\n }\n\n static dataApiClickHandler(event) {\n const target = getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n const config = {\n ...Manipulator.getDataAttributes(target),\n ...Manipulator.getDataAttributes(this)\n }\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n config.interval = false\n }\n\n Carousel.carouselInterface(target, config)\n\n if (slideIndex) {\n Carousel.getInstance(target).to(slideIndex)\n }\n\n event.preventDefault()\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, Carousel.dataApiClickHandler)\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (let i = 0, len = carousels.length; i < len; i++) {\n Carousel.carouselInterface(carousels[i], Carousel.getInstance(carousels[i]))\n }\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Carousel to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElement,\n getSelectorFromElement,\n getElementFromSelector,\n reflow,\n typeCheckConfig\n} from './util/index'\nimport Data from './dom/data'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst Default = {\n toggle: true,\n parent: null\n}\n\nconst DefaultType = {\n toggle: 'boolean',\n parent: '(null|element)'\n}\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._isTransitioning = false\n this._config = this._getConfig(config)\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (let i = 0, len = toggleList.length; i < len; i++) {\n const elem = toggleList[i]\n const selector = getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElem => foundElem === this._element)\n\n if (selector !== null && filterElement.length) {\n this._selector = selector\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let actives = []\n let activesData\n\n if (this._config.parent) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n actives = SelectorEngine.find(SELECTOR_ACTIVES, this._config.parent).filter(elem => !children.includes(elem)) // remove children if greater depth\n }\n\n const container = SelectorEngine.findOne(this._selector)\n if (actives.length) {\n const tempActiveData = actives.find(elem => container !== elem)\n activesData = tempActiveData ? Collapse.getInstance(tempActiveData) : null\n\n if (activesData && activesData._isTransitioning) {\n return\n }\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n actives.forEach(elemActive => {\n if (container !== elemActive) {\n Collapse.getOrCreateInstance(elemActive, { toggle: false }).hide()\n }\n\n if (!activesData) {\n Data.set(elemActive, DATA_KEY, null)\n }\n })\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n const triggerArrayLength = this._triggerArray.length\n for (let i = 0; i < triggerArrayLength; i++) {\n const trigger = this._triggerArray[i]\n const elem = getElementFromSelector(trigger)\n\n if (elem && !this._isShown(elem)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...config\n }\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n SelectorEngine.find(SELECTOR_DATA_TOGGLE, this._config.parent).filter(elem => !children.includes(elem))\n .forEach(element => {\n const selected = getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n })\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n triggerArray.forEach(elem => {\n if (isOpen) {\n elem.classList.remove(CLASS_NAME_COLLAPSED)\n } else {\n elem.classList.add(CLASS_NAME_COLLAPSED)\n }\n\n elem.setAttribute('aria-expanded', isOpen)\n })\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n const selector = getSelectorFromElement(this)\n const selectorElements = SelectorEngine.find(selector)\n\n selectorElements.forEach(element => {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n })\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Collapse to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","export var top = 'top';\nexport var bottom = 'bottom';\nexport var right = 'right';\nexport var left = 'left';\nexport var auto = 'auto';\nexport var basePlacements = [top, bottom, right, left];\nexport var start = 'start';\nexport var end = 'end';\nexport var clippingParents = 'clippingParents';\nexport var viewport = 'viewport';\nexport var popper = 'popper';\nexport var reference = 'reference';\nexport var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {\n return acc.concat([placement + \"-\" + start, placement + \"-\" + end]);\n}, []);\nexport var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {\n return acc.concat([placement, placement + \"-\" + start, placement + \"-\" + end]);\n}, []); // modifiers that need to read the DOM\n\nexport var beforeRead = 'beforeRead';\nexport var read = 'read';\nexport var afterRead = 'afterRead'; // pure-logic modifiers\n\nexport var beforeMain = 'beforeMain';\nexport var main = 'main';\nexport var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)\n\nexport var beforeWrite = 'beforeWrite';\nexport var write = 'write';\nexport var afterWrite = 'afterWrite';\nexport var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];","export default function getNodeName(element) {\n return element ? (element.nodeName || '').toLowerCase() : null;\n}","export default function getWindow(node) {\n if (node == null) {\n return window;\n }\n\n if (node.toString() !== '[object Window]') {\n var ownerDocument = node.ownerDocument;\n return ownerDocument ? ownerDocument.defaultView || window : window;\n }\n\n return node;\n}","import getWindow from \"./getWindow.js\";\n\nfunction isElement(node) {\n var OwnElement = getWindow(node).Element;\n return node instanceof OwnElement || node instanceof Element;\n}\n\nfunction isHTMLElement(node) {\n var OwnElement = getWindow(node).HTMLElement;\n return node instanceof OwnElement || node instanceof HTMLElement;\n}\n\nfunction isShadowRoot(node) {\n // IE 11 has no ShadowRoot\n if (typeof ShadowRoot === 'undefined') {\n return false;\n }\n\n var OwnElement = getWindow(node).ShadowRoot;\n return node instanceof OwnElement || node instanceof ShadowRoot;\n}\n\nexport { isElement, isHTMLElement, isShadowRoot };","import getNodeName from \"../dom-utils/getNodeName.js\";\nimport { isHTMLElement } from \"../dom-utils/instanceOf.js\"; // This modifier takes the styles prepared by the `computeStyles` modifier\n// and applies them to the HTMLElements such as popper and arrow\n\nfunction applyStyles(_ref) {\n var state = _ref.state;\n Object.keys(state.elements).forEach(function (name) {\n var style = state.styles[name] || {};\n var attributes = state.attributes[name] || {};\n var element = state.elements[name]; // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n } // Flow doesn't support to extend this property, but it's the most\n // effective way to apply styles to an HTMLElement\n // $FlowFixMe[cannot-write]\n\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (name) {\n var value = attributes[name];\n\n if (value === false) {\n element.removeAttribute(name);\n } else {\n element.setAttribute(name, value === true ? '' : value);\n }\n });\n });\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state;\n var initialStyles = {\n popper: {\n position: state.options.strategy,\n left: '0',\n top: '0',\n margin: '0'\n },\n arrow: {\n position: 'absolute'\n },\n reference: {}\n };\n Object.assign(state.elements.popper.style, initialStyles.popper);\n state.styles = initialStyles;\n\n if (state.elements.arrow) {\n Object.assign(state.elements.arrow.style, initialStyles.arrow);\n }\n\n return function () {\n Object.keys(state.elements).forEach(function (name) {\n var element = state.elements[name];\n var attributes = state.attributes[name] || {};\n var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them\n\n var style = styleProperties.reduce(function (style, property) {\n style[property] = '';\n return style;\n }, {}); // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n }\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (attribute) {\n element.removeAttribute(attribute);\n });\n });\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'applyStyles',\n enabled: true,\n phase: 'write',\n fn: applyStyles,\n effect: effect,\n requires: ['computeStyles']\n};","import { auto } from \"../enums.js\";\nexport default function getBasePlacement(placement) {\n return placement.split('-')[0];\n}","// import { isHTMLElement } from './instanceOf';\nexport default function getBoundingClientRect(element, // eslint-disable-next-line unused-imports/no-unused-vars\nincludeScale) {\n if (includeScale === void 0) {\n includeScale = false;\n }\n\n var rect = element.getBoundingClientRect();\n var scaleX = 1;\n var scaleY = 1; // FIXME:\n // `offsetWidth` returns an integer while `getBoundingClientRect`\n // returns a float. This results in `scaleX` or `scaleY` being\n // non-1 when it should be for elements that aren't a full pixel in\n // width or height.\n // if (isHTMLElement(element) && includeScale) {\n // const offsetHeight = element.offsetHeight;\n // const offsetWidth = element.offsetWidth;\n // // Do not attempt to divide by 0, otherwise we get `Infinity` as scale\n // // Fallback to 1 in case both values are `0`\n // if (offsetWidth > 0) {\n // scaleX = rect.width / offsetWidth || 1;\n // }\n // if (offsetHeight > 0) {\n // scaleY = rect.height / offsetHeight || 1;\n // }\n // }\n\n return {\n width: rect.width / scaleX,\n height: rect.height / scaleY,\n top: rect.top / scaleY,\n right: rect.right / scaleX,\n bottom: rect.bottom / scaleY,\n left: rect.left / scaleX,\n x: rect.left / scaleX,\n y: rect.top / scaleY\n };\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\"; // Returns the layout rect of an element relative to its offsetParent. Layout\n// means it doesn't take into account transforms.\n\nexport default function getLayoutRect(element) {\n var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.\n // Fixes https://github.com/popperjs/popper-core/issues/1223\n\n var width = element.offsetWidth;\n var height = element.offsetHeight;\n\n if (Math.abs(clientRect.width - width) <= 1) {\n width = clientRect.width;\n }\n\n if (Math.abs(clientRect.height - height) <= 1) {\n height = clientRect.height;\n }\n\n return {\n x: element.offsetLeft,\n y: element.offsetTop,\n width: width,\n height: height\n };\n}","import { isShadowRoot } from \"./instanceOf.js\";\nexport default function contains(parent, child) {\n var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method\n\n if (parent.contains(child)) {\n return true;\n } // then fallback to custom implementation with Shadow DOM support\n else if (rootNode && isShadowRoot(rootNode)) {\n var next = child;\n\n do {\n if (next && parent.isSameNode(next)) {\n return true;\n } // $FlowFixMe[prop-missing]: need a better way to handle this...\n\n\n next = next.parentNode || next.host;\n } while (next);\n } // Give up, the result is false\n\n\n return false;\n}","import getWindow from \"./getWindow.js\";\nexport default function getComputedStyle(element) {\n return getWindow(element).getComputedStyle(element);\n}","import getNodeName from \"./getNodeName.js\";\nexport default function isTableElement(element) {\n return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;\n}","import { isElement } from \"./instanceOf.js\";\nexport default function getDocumentElement(element) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]\n element.document) || window.document).documentElement;\n}","import getNodeName from \"./getNodeName.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport { isShadowRoot } from \"./instanceOf.js\";\nexport default function getParentNode(element) {\n if (getNodeName(element) === 'html') {\n return element;\n }\n\n return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle\n // $FlowFixMe[incompatible-return]\n // $FlowFixMe[prop-missing]\n element.assignedSlot || // step into the shadow DOM of the parent of a slotted node\n element.parentNode || ( // DOM Element detected\n isShadowRoot(element) ? element.host : null) || // ShadowRoot detected\n // $FlowFixMe[incompatible-call]: HTMLElement is a Node\n getDocumentElement(element) // fallback\n\n );\n}","import getWindow from \"./getWindow.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport isTableElement from \"./isTableElement.js\";\nimport getParentNode from \"./getParentNode.js\";\n\nfunction getTrueOffsetParent(element) {\n if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837\n getComputedStyle(element).position === 'fixed') {\n return null;\n }\n\n return element.offsetParent;\n} // `.offsetParent` reports `null` for fixed elements, while absolute elements\n// return the containing block\n\n\nfunction getContainingBlock(element) {\n var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') !== -1;\n var isIE = navigator.userAgent.indexOf('Trident') !== -1;\n\n if (isIE && isHTMLElement(element)) {\n // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport\n var elementCss = getComputedStyle(element);\n\n if (elementCss.position === 'fixed') {\n return null;\n }\n }\n\n var currentNode = getParentNode(element);\n\n while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {\n var css = getComputedStyle(currentNode); // This is non-exhaustive but covers the most common CSS properties that\n // create a containing block.\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n\n if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {\n return currentNode;\n } else {\n currentNode = currentNode.parentNode;\n }\n }\n\n return null;\n} // Gets the closest ancestor positioned element. Handles some edge cases,\n// such as table ancestors and cross browser bugs.\n\n\nexport default function getOffsetParent(element) {\n var window = getWindow(element);\n var offsetParent = getTrueOffsetParent(element);\n\n while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') {\n offsetParent = getTrueOffsetParent(offsetParent);\n }\n\n if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static')) {\n return window;\n }\n\n return offsetParent || getContainingBlock(element) || window;\n}","export default function getMainAxisFromPlacement(placement) {\n return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';\n}","export var max = Math.max;\nexport var min = Math.min;\nexport var round = Math.round;","import { max as mathMax, min as mathMin } from \"./math.js\";\nexport default function within(min, value, max) {\n return mathMax(min, mathMin(value, max));\n}","import getFreshSideObject from \"./getFreshSideObject.js\";\nexport default function mergePaddingObject(paddingObject) {\n return Object.assign({}, getFreshSideObject(), paddingObject);\n}","export default function getFreshSideObject() {\n return {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0\n };\n}","export default function expandToHashMap(value, keys) {\n return keys.reduce(function (hashMap, key) {\n hashMap[key] = value;\n return hashMap;\n }, {});\n}","import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport contains from \"../dom-utils/contains.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport within from \"../utils/within.js\";\nimport mergePaddingObject from \"../utils/mergePaddingObject.js\";\nimport expandToHashMap from \"../utils/expandToHashMap.js\";\nimport { left, right, basePlacements, top, bottom } from \"../enums.js\";\nimport { isHTMLElement } from \"../dom-utils/instanceOf.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar toPaddingObject = function toPaddingObject(padding, state) {\n padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {\n placement: state.placement\n })) : padding;\n return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n};\n\nfunction arrow(_ref) {\n var _state$modifiersData$;\n\n var state = _ref.state,\n name = _ref.name,\n options = _ref.options;\n var arrowElement = state.elements.arrow;\n var popperOffsets = state.modifiersData.popperOffsets;\n var basePlacement = getBasePlacement(state.placement);\n var axis = getMainAxisFromPlacement(basePlacement);\n var isVertical = [left, right].indexOf(basePlacement) >= 0;\n var len = isVertical ? 'height' : 'width';\n\n if (!arrowElement || !popperOffsets) {\n return;\n }\n\n var paddingObject = toPaddingObject(options.padding, state);\n var arrowRect = getLayoutRect(arrowElement);\n var minProp = axis === 'y' ? top : left;\n var maxProp = axis === 'y' ? bottom : right;\n var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];\n var startDiff = popperOffsets[axis] - state.rects.reference[axis];\n var arrowOffsetParent = getOffsetParent(arrowElement);\n var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;\n var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is\n // outside of the popper bounds\n\n var min = paddingObject[minProp];\n var max = clientSize - arrowRect[len] - paddingObject[maxProp];\n var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;\n var offset = within(min, center, max); // Prevents breaking syntax highlighting...\n\n var axisProp = axis;\n state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state,\n options = _ref2.options;\n var _options$element = options.element,\n arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;\n\n if (arrowElement == null) {\n return;\n } // CSS selector\n\n\n if (typeof arrowElement === 'string') {\n arrowElement = state.elements.popper.querySelector(arrowElement);\n\n if (!arrowElement) {\n return;\n }\n }\n\n if (process.env.NODE_ENV !== \"production\") {\n if (!isHTMLElement(arrowElement)) {\n console.error(['Popper: \"arrow\" element must be an HTMLElement (not an SVGElement).', 'To use an SVG arrow, wrap it in an HTMLElement that will be used as', 'the arrow.'].join(' '));\n }\n }\n\n if (!contains(state.elements.popper, arrowElement)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(['Popper: \"arrow\" modifier\\'s `element` must be a child of the popper', 'element.'].join(' '));\n }\n\n return;\n }\n\n state.elements.arrow = arrowElement;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'arrow',\n enabled: true,\n phase: 'main',\n fn: arrow,\n effect: effect,\n requires: ['popperOffsets'],\n requiresIfExists: ['preventOverflow']\n};","export default function getVariation(placement) {\n return placement.split('-')[1];\n}","import { top, left, right, bottom, end } from \"../enums.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getWindow from \"../dom-utils/getWindow.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getComputedStyle from \"../dom-utils/getComputedStyle.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport { round } from \"../utils/math.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar unsetSides = {\n top: 'auto',\n right: 'auto',\n bottom: 'auto',\n left: 'auto'\n}; // Round the offsets to the nearest suitable subpixel based on the DPR.\n// Zooming can change the DPR, but it seems to report a value that will\n// cleanly divide the values into the appropriate subpixels.\n\nfunction roundOffsetsByDPR(_ref) {\n var x = _ref.x,\n y = _ref.y;\n var win = window;\n var dpr = win.devicePixelRatio || 1;\n return {\n x: round(round(x * dpr) / dpr) || 0,\n y: round(round(y * dpr) / dpr) || 0\n };\n}\n\nexport function mapToStyles(_ref2) {\n var _Object$assign2;\n\n var popper = _ref2.popper,\n popperRect = _ref2.popperRect,\n placement = _ref2.placement,\n variation = _ref2.variation,\n offsets = _ref2.offsets,\n position = _ref2.position,\n gpuAcceleration = _ref2.gpuAcceleration,\n adaptive = _ref2.adaptive,\n roundOffsets = _ref2.roundOffsets;\n\n var _ref3 = roundOffsets === true ? roundOffsetsByDPR(offsets) : typeof roundOffsets === 'function' ? roundOffsets(offsets) : offsets,\n _ref3$x = _ref3.x,\n x = _ref3$x === void 0 ? 0 : _ref3$x,\n _ref3$y = _ref3.y,\n y = _ref3$y === void 0 ? 0 : _ref3$y;\n\n var hasX = offsets.hasOwnProperty('x');\n var hasY = offsets.hasOwnProperty('y');\n var sideX = left;\n var sideY = top;\n var win = window;\n\n if (adaptive) {\n var offsetParent = getOffsetParent(popper);\n var heightProp = 'clientHeight';\n var widthProp = 'clientWidth';\n\n if (offsetParent === getWindow(popper)) {\n offsetParent = getDocumentElement(popper);\n\n if (getComputedStyle(offsetParent).position !== 'static' && position === 'absolute') {\n heightProp = 'scrollHeight';\n widthProp = 'scrollWidth';\n }\n } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it\n\n\n offsetParent = offsetParent;\n\n if (placement === top || (placement === left || placement === right) && variation === end) {\n sideY = bottom; // $FlowFixMe[prop-missing]\n\n y -= offsetParent[heightProp] - popperRect.height;\n y *= gpuAcceleration ? 1 : -1;\n }\n\n if (placement === left || (placement === top || placement === bottom) && variation === end) {\n sideX = right; // $FlowFixMe[prop-missing]\n\n x -= offsetParent[widthProp] - popperRect.width;\n x *= gpuAcceleration ? 1 : -1;\n }\n }\n\n var commonStyles = Object.assign({\n position: position\n }, adaptive && unsetSides);\n\n if (gpuAcceleration) {\n var _Object$assign;\n\n return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? \"translate(\" + x + \"px, \" + y + \"px)\" : \"translate3d(\" + x + \"px, \" + y + \"px, 0)\", _Object$assign));\n }\n\n return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + \"px\" : '', _Object$assign2[sideX] = hasX ? x + \"px\" : '', _Object$assign2.transform = '', _Object$assign2));\n}\n\nfunction computeStyles(_ref4) {\n var state = _ref4.state,\n options = _ref4.options;\n var _options$gpuAccelerat = options.gpuAcceleration,\n gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,\n _options$adaptive = options.adaptive,\n adaptive = _options$adaptive === void 0 ? true : _options$adaptive,\n _options$roundOffsets = options.roundOffsets,\n roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;\n\n if (process.env.NODE_ENV !== \"production\") {\n var transitionProperty = getComputedStyle(state.elements.popper).transitionProperty || '';\n\n if (adaptive && ['transform', 'top', 'right', 'bottom', 'left'].some(function (property) {\n return transitionProperty.indexOf(property) >= 0;\n })) {\n console.warn(['Popper: Detected CSS transitions on at least one of the following', 'CSS properties: \"transform\", \"top\", \"right\", \"bottom\", \"left\".', '\\n\\n', 'Disable the \"computeStyles\" modifier\\'s `adaptive` option to allow', 'for smooth transitions, or remove these properties from the CSS', 'transition declaration on the popper element if only transitioning', 'opacity or background-color for example.', '\\n\\n', 'We recommend using the popper element as a wrapper around an inner', 'element that can have any CSS property transitioned for animations.'].join(' '));\n }\n }\n\n var commonStyles = {\n placement: getBasePlacement(state.placement),\n variation: getVariation(state.placement),\n popper: state.elements.popper,\n popperRect: state.rects.popper,\n gpuAcceleration: gpuAcceleration\n };\n\n if (state.modifiersData.popperOffsets != null) {\n state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.popperOffsets,\n position: state.options.strategy,\n adaptive: adaptive,\n roundOffsets: roundOffsets\n })));\n }\n\n if (state.modifiersData.arrow != null) {\n state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.arrow,\n position: 'absolute',\n adaptive: false,\n roundOffsets: roundOffsets\n })));\n }\n\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-placement': state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'computeStyles',\n enabled: true,\n phase: 'beforeWrite',\n fn: computeStyles,\n data: {}\n};","import getWindow from \"../dom-utils/getWindow.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar passive = {\n passive: true\n};\n\nfunction effect(_ref) {\n var state = _ref.state,\n instance = _ref.instance,\n options = _ref.options;\n var _options$scroll = options.scroll,\n scroll = _options$scroll === void 0 ? true : _options$scroll,\n _options$resize = options.resize,\n resize = _options$resize === void 0 ? true : _options$resize;\n var window = getWindow(state.elements.popper);\n var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);\n\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.addEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.addEventListener('resize', instance.update, passive);\n }\n\n return function () {\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.removeEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.removeEventListener('resize', instance.update, passive);\n }\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'eventListeners',\n enabled: true,\n phase: 'write',\n fn: function fn() {},\n effect: effect,\n data: {}\n};","var hash = {\n left: 'right',\n right: 'left',\n bottom: 'top',\n top: 'bottom'\n};\nexport default function getOppositePlacement(placement) {\n return placement.replace(/left|right|bottom|top/g, function (matched) {\n return hash[matched];\n });\n}","var hash = {\n start: 'end',\n end: 'start'\n};\nexport default function getOppositeVariationPlacement(placement) {\n return placement.replace(/start|end/g, function (matched) {\n return hash[matched];\n });\n}","import getWindow from \"./getWindow.js\";\nexport default function getWindowScroll(node) {\n var win = getWindow(node);\n var scrollLeft = win.pageXOffset;\n var scrollTop = win.pageYOffset;\n return {\n scrollLeft: scrollLeft,\n scrollTop: scrollTop\n };\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nexport default function getWindowScrollBarX(element) {\n // If <html> has a CSS width greater than the viewport, then this will be\n // incorrect for RTL.\n // Popper 1 is broken in this case and never had a bug report so let's assume\n // it's not an issue. I don't think anyone ever specifies width on <html>\n // anyway.\n // Browsers where the left scrollbar doesn't cause an issue report `0` for\n // this (e.g. Edge 2019, IE11, Safari)\n return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;\n}","import getComputedStyle from \"./getComputedStyle.js\";\nexport default function isScrollParent(element) {\n // Firefox wants us to check `-x` and `-y` variations as well\n var _getComputedStyle = getComputedStyle(element),\n overflow = _getComputedStyle.overflow,\n overflowX = _getComputedStyle.overflowX,\n overflowY = _getComputedStyle.overflowY;\n\n return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);\n}","import getParentNode from \"./getParentNode.js\";\nimport isScrollParent from \"./isScrollParent.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nexport default function getScrollParent(node) {\n if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return node.ownerDocument.body;\n }\n\n if (isHTMLElement(node) && isScrollParent(node)) {\n return node;\n }\n\n return getScrollParent(getParentNode(node));\n}","import getScrollParent from \"./getScrollParent.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport getWindow from \"./getWindow.js\";\nimport isScrollParent from \"./isScrollParent.js\";\n/*\ngiven a DOM element, return the list of all scroll parents, up the list of ancesors\nuntil we get to the top window object. This list is what we attach scroll listeners\nto, because if any of these parent elements scroll, we'll need to re-calculate the\nreference element's position.\n*/\n\nexport default function listScrollParents(element, list) {\n var _element$ownerDocumen;\n\n if (list === void 0) {\n list = [];\n }\n\n var scrollParent = getScrollParent(element);\n var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);\n var win = getWindow(scrollParent);\n var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;\n var updatedList = list.concat(target);\n return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here\n updatedList.concat(listScrollParents(getParentNode(target)));\n}","export default function rectToClientRect(rect) {\n return Object.assign({}, rect, {\n left: rect.x,\n top: rect.y,\n right: rect.x + rect.width,\n bottom: rect.y + rect.height\n });\n}","import { viewport } from \"../enums.js\";\nimport getViewportRect from \"./getViewportRect.js\";\nimport getDocumentRect from \"./getDocumentRect.js\";\nimport listScrollParents from \"./listScrollParents.js\";\nimport getOffsetParent from \"./getOffsetParent.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isElement, isHTMLElement } from \"./instanceOf.js\";\nimport getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport contains from \"./contains.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport rectToClientRect from \"../utils/rectToClientRect.js\";\nimport { max, min } from \"../utils/math.js\";\n\nfunction getInnerBoundingClientRect(element) {\n var rect = getBoundingClientRect(element);\n rect.top = rect.top + element.clientTop;\n rect.left = rect.left + element.clientLeft;\n rect.bottom = rect.top + element.clientHeight;\n rect.right = rect.left + element.clientWidth;\n rect.width = element.clientWidth;\n rect.height = element.clientHeight;\n rect.x = rect.left;\n rect.y = rect.top;\n return rect;\n}\n\nfunction getClientRectFromMixedType(element, clippingParent) {\n return clippingParent === viewport ? rectToClientRect(getViewportRect(element)) : isHTMLElement(clippingParent) ? getInnerBoundingClientRect(clippingParent) : rectToClientRect(getDocumentRect(getDocumentElement(element)));\n} // A \"clipping parent\" is an overflowable container with the characteristic of\n// clipping (or hiding) overflowing elements with a position different from\n// `initial`\n\n\nfunction getClippingParents(element) {\n var clippingParents = listScrollParents(getParentNode(element));\n var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0;\n var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;\n\n if (!isElement(clipperElement)) {\n return [];\n } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414\n\n\n return clippingParents.filter(function (clippingParent) {\n return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';\n });\n} // Gets the maximum area that the element is visible in due to any number of\n// clipping parents\n\n\nexport default function getClippingRect(element, boundary, rootBoundary) {\n var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);\n var clippingParents = [].concat(mainClippingParents, [rootBoundary]);\n var firstClippingParent = clippingParents[0];\n var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {\n var rect = getClientRectFromMixedType(element, clippingParent);\n accRect.top = max(rect.top, accRect.top);\n accRect.right = min(rect.right, accRect.right);\n accRect.bottom = min(rect.bottom, accRect.bottom);\n accRect.left = max(rect.left, accRect.left);\n return accRect;\n }, getClientRectFromMixedType(element, firstClippingParent));\n clippingRect.width = clippingRect.right - clippingRect.left;\n clippingRect.height = clippingRect.bottom - clippingRect.top;\n clippingRect.x = clippingRect.left;\n clippingRect.y = clippingRect.top;\n return clippingRect;\n}","import getWindow from \"./getWindow.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nexport default function getViewportRect(element) {\n var win = getWindow(element);\n var html = getDocumentElement(element);\n var visualViewport = win.visualViewport;\n var width = html.clientWidth;\n var height = html.clientHeight;\n var x = 0;\n var y = 0; // NB: This isn't supported on iOS <= 12. If the keyboard is open, the popper\n // can be obscured underneath it.\n // Also, `html.clientHeight` adds the bottom bar height in Safari iOS, even\n // if it isn't open, so if this isn't available, the popper will be detected\n // to overflow the bottom of the screen too early.\n\n if (visualViewport) {\n width = visualViewport.width;\n height = visualViewport.height; // Uses Layout Viewport (like Chrome; Safari does not currently)\n // In Chrome, it returns a value very close to 0 (+/-) but contains rounding\n // errors due to floating point numbers, so we need to check precision.\n // Safari returns a number <= 0, usually < -1 when pinch-zoomed\n // Feature detection fails in mobile emulation mode in Chrome.\n // Math.abs(win.innerWidth / visualViewport.scale - visualViewport.width) <\n // 0.001\n // Fallback here: \"Not Safari\" userAgent\n\n if (!/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {\n x = visualViewport.offsetLeft;\n y = visualViewport.offsetTop;\n }\n }\n\n return {\n width: width,\n height: height,\n x: x + getWindowScrollBarX(element),\n y: y\n };\n}","import getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nimport { max } from \"../utils/math.js\"; // Gets the entire size of the scrollable document area, even extending outside\n// of the `<html>` and `<body>` rect bounds if horizontally scrollable\n\nexport default function getDocumentRect(element) {\n var _element$ownerDocumen;\n\n var html = getDocumentElement(element);\n var winScroll = getWindowScroll(element);\n var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;\n var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);\n var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);\n var x = -winScroll.scrollLeft + getWindowScrollBarX(element);\n var y = -winScroll.scrollTop;\n\n if (getComputedStyle(body || html).direction === 'rtl') {\n x += max(html.clientWidth, body ? body.clientWidth : 0) - width;\n }\n\n return {\n width: width,\n height: height,\n x: x,\n y: y\n };\n}","import getBasePlacement from \"./getBasePlacement.js\";\nimport getVariation from \"./getVariation.js\";\nimport getMainAxisFromPlacement from \"./getMainAxisFromPlacement.js\";\nimport { top, right, bottom, left, start, end } from \"../enums.js\";\nexport default function computeOffsets(_ref) {\n var reference = _ref.reference,\n element = _ref.element,\n placement = _ref.placement;\n var basePlacement = placement ? getBasePlacement(placement) : null;\n var variation = placement ? getVariation(placement) : null;\n var commonX = reference.x + reference.width / 2 - element.width / 2;\n var commonY = reference.y + reference.height / 2 - element.height / 2;\n var offsets;\n\n switch (basePlacement) {\n case top:\n offsets = {\n x: commonX,\n y: reference.y - element.height\n };\n break;\n\n case bottom:\n offsets = {\n x: commonX,\n y: reference.y + reference.height\n };\n break;\n\n case right:\n offsets = {\n x: reference.x + reference.width,\n y: commonY\n };\n break;\n\n case left:\n offsets = {\n x: reference.x - element.width,\n y: commonY\n };\n break;\n\n default:\n offsets = {\n x: reference.x,\n y: reference.y\n };\n }\n\n var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;\n\n if (mainAxis != null) {\n var len = mainAxis === 'y' ? 'height' : 'width';\n\n switch (variation) {\n case start:\n offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);\n break;\n\n case end:\n offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);\n break;\n\n default:\n }\n }\n\n return offsets;\n}","import getClippingRect from \"../dom-utils/getClippingRect.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getBoundingClientRect from \"../dom-utils/getBoundingClientRect.js\";\nimport computeOffsets from \"./computeOffsets.js\";\nimport rectToClientRect from \"./rectToClientRect.js\";\nimport { clippingParents, reference, popper, bottom, top, right, basePlacements, viewport } from \"../enums.js\";\nimport { isElement } from \"../dom-utils/instanceOf.js\";\nimport mergePaddingObject from \"./mergePaddingObject.js\";\nimport expandToHashMap from \"./expandToHashMap.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport default function detectOverflow(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n _options$placement = _options.placement,\n placement = _options$placement === void 0 ? state.placement : _options$placement,\n _options$boundary = _options.boundary,\n boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,\n _options$rootBoundary = _options.rootBoundary,\n rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,\n _options$elementConte = _options.elementContext,\n elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,\n _options$altBoundary = _options.altBoundary,\n altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,\n _options$padding = _options.padding,\n padding = _options$padding === void 0 ? 0 : _options$padding;\n var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n var altContext = elementContext === popper ? reference : popper;\n var popperRect = state.rects.popper;\n var element = state.elements[altBoundary ? altContext : elementContext];\n var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary);\n var referenceClientRect = getBoundingClientRect(state.elements.reference);\n var popperOffsets = computeOffsets({\n reference: referenceClientRect,\n element: popperRect,\n strategy: 'absolute',\n placement: placement\n });\n var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));\n var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect\n // 0 or negative = within the clipping rect\n\n var overflowOffsets = {\n top: clippingClientRect.top - elementClientRect.top + paddingObject.top,\n bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,\n left: clippingClientRect.left - elementClientRect.left + paddingObject.left,\n right: elementClientRect.right - clippingClientRect.right + paddingObject.right\n };\n var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element\n\n if (elementContext === popper && offsetData) {\n var offset = offsetData[placement];\n Object.keys(overflowOffsets).forEach(function (key) {\n var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;\n var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';\n overflowOffsets[key] += offset[axis] * multiply;\n });\n }\n\n return overflowOffsets;\n}","import getVariation from \"./getVariation.js\";\nimport { variationPlacements, basePlacements, placements as allPlacements } from \"../enums.js\";\nimport detectOverflow from \"./detectOverflow.js\";\nimport getBasePlacement from \"./getBasePlacement.js\";\nexport default function computeAutoPlacement(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n placement = _options.placement,\n boundary = _options.boundary,\n rootBoundary = _options.rootBoundary,\n padding = _options.padding,\n flipVariations = _options.flipVariations,\n _options$allowedAutoP = _options.allowedAutoPlacements,\n allowedAutoPlacements = _options$allowedAutoP === void 0 ? allPlacements : _options$allowedAutoP;\n var variation = getVariation(placement);\n var placements = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {\n return getVariation(placement) === variation;\n }) : basePlacements;\n var allowedPlacements = placements.filter(function (placement) {\n return allowedAutoPlacements.indexOf(placement) >= 0;\n });\n\n if (allowedPlacements.length === 0) {\n allowedPlacements = placements;\n\n if (process.env.NODE_ENV !== \"production\") {\n console.error(['Popper: The `allowedAutoPlacements` option did not allow any', 'placements. Ensure the `placement` option matches the variation', 'of the allowed placements.', 'For example, \"auto\" cannot be used to allow \"bottom-start\".', 'Use \"auto-start\" instead.'].join(' '));\n }\n } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...\n\n\n var overflows = allowedPlacements.reduce(function (acc, placement) {\n acc[placement] = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding\n })[getBasePlacement(placement)];\n return acc;\n }, {});\n return Object.keys(overflows).sort(function (a, b) {\n return overflows[a] - overflows[b];\n });\n}","import getOppositePlacement from \"../utils/getOppositePlacement.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getOppositeVariationPlacement from \"../utils/getOppositeVariationPlacement.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport computeAutoPlacement from \"../utils/computeAutoPlacement.js\";\nimport { bottom, top, start, right, left, auto } from \"../enums.js\";\nimport getVariation from \"../utils/getVariation.js\"; // eslint-disable-next-line import/no-unused-modules\n\nfunction getExpandedFallbackPlacements(placement) {\n if (getBasePlacement(placement) === auto) {\n return [];\n }\n\n var oppositePlacement = getOppositePlacement(placement);\n return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];\n}\n\nfunction flip(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n\n if (state.modifiersData[name]._skip) {\n return;\n }\n\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,\n specifiedFallbackPlacements = options.fallbackPlacements,\n padding = options.padding,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n _options$flipVariatio = options.flipVariations,\n flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,\n allowedAutoPlacements = options.allowedAutoPlacements;\n var preferredPlacement = state.options.placement;\n var basePlacement = getBasePlacement(preferredPlacement);\n var isBasePlacement = basePlacement === preferredPlacement;\n var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));\n var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {\n return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n flipVariations: flipVariations,\n allowedAutoPlacements: allowedAutoPlacements\n }) : placement);\n }, []);\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var checksMap = new Map();\n var makeFallbackChecks = true;\n var firstFittingPlacement = placements[0];\n\n for (var i = 0; i < placements.length; i++) {\n var placement = placements[i];\n\n var _basePlacement = getBasePlacement(placement);\n\n var isStartVariation = getVariation(placement) === start;\n var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;\n var len = isVertical ? 'width' : 'height';\n var overflow = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n altBoundary: altBoundary,\n padding: padding\n });\n var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;\n\n if (referenceRect[len] > popperRect[len]) {\n mainVariationSide = getOppositePlacement(mainVariationSide);\n }\n\n var altVariationSide = getOppositePlacement(mainVariationSide);\n var checks = [];\n\n if (checkMainAxis) {\n checks.push(overflow[_basePlacement] <= 0);\n }\n\n if (checkAltAxis) {\n checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);\n }\n\n if (checks.every(function (check) {\n return check;\n })) {\n firstFittingPlacement = placement;\n makeFallbackChecks = false;\n break;\n }\n\n checksMap.set(placement, checks);\n }\n\n if (makeFallbackChecks) {\n // `2` may be desired in some cases – research later\n var numberOfChecks = flipVariations ? 3 : 1;\n\n var _loop = function _loop(_i) {\n var fittingPlacement = placements.find(function (placement) {\n var checks = checksMap.get(placement);\n\n if (checks) {\n return checks.slice(0, _i).every(function (check) {\n return check;\n });\n }\n });\n\n if (fittingPlacement) {\n firstFittingPlacement = fittingPlacement;\n return \"break\";\n }\n };\n\n for (var _i = numberOfChecks; _i > 0; _i--) {\n var _ret = _loop(_i);\n\n if (_ret === \"break\") break;\n }\n }\n\n if (state.placement !== firstFittingPlacement) {\n state.modifiersData[name]._skip = true;\n state.placement = firstFittingPlacement;\n state.reset = true;\n }\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'flip',\n enabled: true,\n phase: 'main',\n fn: flip,\n requiresIfExists: ['offset'],\n data: {\n _skip: false\n }\n};","import { top, bottom, left, right } from \"../enums.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\n\nfunction getSideOffsets(overflow, rect, preventedOffsets) {\n if (preventedOffsets === void 0) {\n preventedOffsets = {\n x: 0,\n y: 0\n };\n }\n\n return {\n top: overflow.top - rect.height - preventedOffsets.y,\n right: overflow.right - rect.width + preventedOffsets.x,\n bottom: overflow.bottom - rect.height + preventedOffsets.y,\n left: overflow.left - rect.width - preventedOffsets.x\n };\n}\n\nfunction isAnySideFullyClipped(overflow) {\n return [top, right, bottom, left].some(function (side) {\n return overflow[side] >= 0;\n });\n}\n\nfunction hide(_ref) {\n var state = _ref.state,\n name = _ref.name;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var preventedOffsets = state.modifiersData.preventOverflow;\n var referenceOverflow = detectOverflow(state, {\n elementContext: 'reference'\n });\n var popperAltOverflow = detectOverflow(state, {\n altBoundary: true\n });\n var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);\n var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);\n var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);\n var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);\n state.modifiersData[name] = {\n referenceClippingOffsets: referenceClippingOffsets,\n popperEscapeOffsets: popperEscapeOffsets,\n isReferenceHidden: isReferenceHidden,\n hasPopperEscaped: hasPopperEscaped\n };\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-reference-hidden': isReferenceHidden,\n 'data-popper-escaped': hasPopperEscaped\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'hide',\n enabled: true,\n phase: 'main',\n requiresIfExists: ['preventOverflow'],\n fn: hide\n};","import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport { top, left, right, placements } from \"../enums.js\";\nexport function distanceAndSkiddingToXY(placement, rects, offset) {\n var basePlacement = getBasePlacement(placement);\n var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;\n\n var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {\n placement: placement\n })) : offset,\n skidding = _ref[0],\n distance = _ref[1];\n\n skidding = skidding || 0;\n distance = (distance || 0) * invertDistance;\n return [left, right].indexOf(basePlacement) >= 0 ? {\n x: distance,\n y: skidding\n } : {\n x: skidding,\n y: distance\n };\n}\n\nfunction offset(_ref2) {\n var state = _ref2.state,\n options = _ref2.options,\n name = _ref2.name;\n var _options$offset = options.offset,\n offset = _options$offset === void 0 ? [0, 0] : _options$offset;\n var data = placements.reduce(function (acc, placement) {\n acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);\n return acc;\n }, {});\n var _data$state$placement = data[state.placement],\n x = _data$state$placement.x,\n y = _data$state$placement.y;\n\n if (state.modifiersData.popperOffsets != null) {\n state.modifiersData.popperOffsets.x += x;\n state.modifiersData.popperOffsets.y += y;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'offset',\n enabled: true,\n phase: 'main',\n requires: ['popperOffsets'],\n fn: offset\n};","import computeOffsets from \"../utils/computeOffsets.js\";\n\nfunction popperOffsets(_ref) {\n var state = _ref.state,\n name = _ref.name;\n // Offsets are the actual position the popper needs to have to be\n // properly positioned near its reference element\n // This is the most basic placement, and will be adjusted by\n // the modifiers in the next step\n state.modifiersData[name] = computeOffsets({\n reference: state.rects.reference,\n element: state.rects.popper,\n strategy: 'absolute',\n placement: state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'popperOffsets',\n enabled: true,\n phase: 'read',\n fn: popperOffsets,\n data: {}\n};","import { top, left, right, bottom, start } from \"../enums.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport getAltAxis from \"../utils/getAltAxis.js\";\nimport within from \"../utils/within.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport getFreshSideObject from \"../utils/getFreshSideObject.js\";\nimport { max as mathMax, min as mathMin } from \"../utils/math.js\";\n\nfunction preventOverflow(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n padding = options.padding,\n _options$tether = options.tether,\n tether = _options$tether === void 0 ? true : _options$tether,\n _options$tetherOffset = options.tetherOffset,\n tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;\n var overflow = detectOverflow(state, {\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n altBoundary: altBoundary\n });\n var basePlacement = getBasePlacement(state.placement);\n var variation = getVariation(state.placement);\n var isBasePlacement = !variation;\n var mainAxis = getMainAxisFromPlacement(basePlacement);\n var altAxis = getAltAxis(mainAxis);\n var popperOffsets = state.modifiersData.popperOffsets;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {\n placement: state.placement\n })) : tetherOffset;\n var data = {\n x: 0,\n y: 0\n };\n\n if (!popperOffsets) {\n return;\n }\n\n if (checkMainAxis || checkAltAxis) {\n var mainSide = mainAxis === 'y' ? top : left;\n var altSide = mainAxis === 'y' ? bottom : right;\n var len = mainAxis === 'y' ? 'height' : 'width';\n var offset = popperOffsets[mainAxis];\n var min = popperOffsets[mainAxis] + overflow[mainSide];\n var max = popperOffsets[mainAxis] - overflow[altSide];\n var additive = tether ? -popperRect[len] / 2 : 0;\n var minLen = variation === start ? referenceRect[len] : popperRect[len];\n var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go\n // outside the reference bounds\n\n var arrowElement = state.elements.arrow;\n var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {\n width: 0,\n height: 0\n };\n var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();\n var arrowPaddingMin = arrowPaddingObject[mainSide];\n var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want\n // to include its full size in the calculation. If the reference is small\n // and near the edge of a boundary, the popper can overflow even if the\n // reference is not overflowing as well (e.g. virtual elements with no\n // width or height)\n\n var arrowLen = within(0, referenceRect[len], arrowRect[len]);\n var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - tetherOffsetValue : minLen - arrowLen - arrowPaddingMin - tetherOffsetValue;\n var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + tetherOffsetValue : maxLen + arrowLen + arrowPaddingMax + tetherOffsetValue;\n var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);\n var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;\n var offsetModifierValue = state.modifiersData.offset ? state.modifiersData.offset[state.placement][mainAxis] : 0;\n var tetherMin = popperOffsets[mainAxis] + minOffset - offsetModifierValue - clientOffset;\n var tetherMax = popperOffsets[mainAxis] + maxOffset - offsetModifierValue;\n\n if (checkMainAxis) {\n var preventedOffset = within(tether ? mathMin(min, tetherMin) : min, offset, tether ? mathMax(max, tetherMax) : max);\n popperOffsets[mainAxis] = preventedOffset;\n data[mainAxis] = preventedOffset - offset;\n }\n\n if (checkAltAxis) {\n var _mainSide = mainAxis === 'x' ? top : left;\n\n var _altSide = mainAxis === 'x' ? bottom : right;\n\n var _offset = popperOffsets[altAxis];\n\n var _min = _offset + overflow[_mainSide];\n\n var _max = _offset - overflow[_altSide];\n\n var _preventedOffset = within(tether ? mathMin(_min, tetherMin) : _min, _offset, tether ? mathMax(_max, tetherMax) : _max);\n\n popperOffsets[altAxis] = _preventedOffset;\n data[altAxis] = _preventedOffset - _offset;\n }\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'preventOverflow',\n enabled: true,\n phase: 'main',\n fn: preventOverflow,\n requiresIfExists: ['offset']\n};","export default function getAltAxis(axis) {\n return axis === 'x' ? 'y' : 'x';\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getNodeScroll from \"./getNodeScroll.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport isScrollParent from \"./isScrollParent.js\";\n\nfunction isElementScaled(element) {\n var rect = element.getBoundingClientRect();\n var scaleX = rect.width / element.offsetWidth || 1;\n var scaleY = rect.height / element.offsetHeight || 1;\n return scaleX !== 1 || scaleY !== 1;\n} // Returns the composite rect of an element relative to its offsetParent.\n// Composite means it takes into account transforms as well as layout.\n\n\nexport default function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {\n if (isFixed === void 0) {\n isFixed = false;\n }\n\n var isOffsetParentAnElement = isHTMLElement(offsetParent);\n var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);\n var documentElement = getDocumentElement(offsetParent);\n var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled);\n var scroll = {\n scrollLeft: 0,\n scrollTop: 0\n };\n var offsets = {\n x: 0,\n y: 0\n };\n\n if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {\n if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078\n isScrollParent(documentElement)) {\n scroll = getNodeScroll(offsetParent);\n }\n\n if (isHTMLElement(offsetParent)) {\n offsets = getBoundingClientRect(offsetParent, true);\n offsets.x += offsetParent.clientLeft;\n offsets.y += offsetParent.clientTop;\n } else if (documentElement) {\n offsets.x = getWindowScrollBarX(documentElement);\n }\n }\n\n return {\n x: rect.left + scroll.scrollLeft - offsets.x,\n y: rect.top + scroll.scrollTop - offsets.y,\n width: rect.width,\n height: rect.height\n };\n}","import getWindowScroll from \"./getWindowScroll.js\";\nimport getWindow from \"./getWindow.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getHTMLElementScroll from \"./getHTMLElementScroll.js\";\nexport default function getNodeScroll(node) {\n if (node === getWindow(node) || !isHTMLElement(node)) {\n return getWindowScroll(node);\n } else {\n return getHTMLElementScroll(node);\n }\n}","export default function getHTMLElementScroll(element) {\n return {\n scrollLeft: element.scrollLeft,\n scrollTop: element.scrollTop\n };\n}","import { modifierPhases } from \"../enums.js\"; // source: https://stackoverflow.com/questions/49875255\n\nfunction order(modifiers) {\n var map = new Map();\n var visited = new Set();\n var result = [];\n modifiers.forEach(function (modifier) {\n map.set(modifier.name, modifier);\n }); // On visiting object, check for its dependencies and visit them recursively\n\n function sort(modifier) {\n visited.add(modifier.name);\n var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);\n requires.forEach(function (dep) {\n if (!visited.has(dep)) {\n var depModifier = map.get(dep);\n\n if (depModifier) {\n sort(depModifier);\n }\n }\n });\n result.push(modifier);\n }\n\n modifiers.forEach(function (modifier) {\n if (!visited.has(modifier.name)) {\n // check for visited object\n sort(modifier);\n }\n });\n return result;\n}\n\nexport default function orderModifiers(modifiers) {\n // order based on dependencies\n var orderedModifiers = order(modifiers); // order based on phase\n\n return modifierPhases.reduce(function (acc, phase) {\n return acc.concat(orderedModifiers.filter(function (modifier) {\n return modifier.phase === phase;\n }));\n }, []);\n}","import getCompositeRect from \"./dom-utils/getCompositeRect.js\";\nimport getLayoutRect from \"./dom-utils/getLayoutRect.js\";\nimport listScrollParents from \"./dom-utils/listScrollParents.js\";\nimport getOffsetParent from \"./dom-utils/getOffsetParent.js\";\nimport getComputedStyle from \"./dom-utils/getComputedStyle.js\";\nimport orderModifiers from \"./utils/orderModifiers.js\";\nimport debounce from \"./utils/debounce.js\";\nimport validateModifiers from \"./utils/validateModifiers.js\";\nimport uniqueBy from \"./utils/uniqueBy.js\";\nimport getBasePlacement from \"./utils/getBasePlacement.js\";\nimport mergeByName from \"./utils/mergeByName.js\";\nimport detectOverflow from \"./utils/detectOverflow.js\";\nimport { isElement } from \"./dom-utils/instanceOf.js\";\nimport { auto } from \"./enums.js\";\nvar INVALID_ELEMENT_ERROR = 'Popper: Invalid reference or popper argument provided. They must be either a DOM element or virtual element.';\nvar INFINITE_LOOP_ERROR = 'Popper: An infinite loop in the modifiers cycle has been detected! The cycle has been interrupted to prevent a browser crash.';\nvar DEFAULT_OPTIONS = {\n placement: 'bottom',\n modifiers: [],\n strategy: 'absolute'\n};\n\nfunction areValidElements() {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n return !args.some(function (element) {\n return !(element && typeof element.getBoundingClientRect === 'function');\n });\n}\n\nexport function popperGenerator(generatorOptions) {\n if (generatorOptions === void 0) {\n generatorOptions = {};\n }\n\n var _generatorOptions = generatorOptions,\n _generatorOptions$def = _generatorOptions.defaultModifiers,\n defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,\n _generatorOptions$def2 = _generatorOptions.defaultOptions,\n defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;\n return function createPopper(reference, popper, options) {\n if (options === void 0) {\n options = defaultOptions;\n }\n\n var state = {\n placement: 'bottom',\n orderedModifiers: [],\n options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),\n modifiersData: {},\n elements: {\n reference: reference,\n popper: popper\n },\n attributes: {},\n styles: {}\n };\n var effectCleanupFns = [];\n var isDestroyed = false;\n var instance = {\n state: state,\n setOptions: function setOptions(setOptionsAction) {\n var options = typeof setOptionsAction === 'function' ? setOptionsAction(state.options) : setOptionsAction;\n cleanupModifierEffects();\n state.options = Object.assign({}, defaultOptions, state.options, options);\n state.scrollParents = {\n reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],\n popper: listScrollParents(popper)\n }; // Orders the modifiers based on their dependencies and `phase`\n // properties\n\n var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers\n\n state.orderedModifiers = orderedModifiers.filter(function (m) {\n return m.enabled;\n }); // Validate the provided modifiers so that the consumer will get warned\n // if one of the modifiers is invalid for any reason\n\n if (process.env.NODE_ENV !== \"production\") {\n var modifiers = uniqueBy([].concat(orderedModifiers, state.options.modifiers), function (_ref) {\n var name = _ref.name;\n return name;\n });\n validateModifiers(modifiers);\n\n if (getBasePlacement(state.options.placement) === auto) {\n var flipModifier = state.orderedModifiers.find(function (_ref2) {\n var name = _ref2.name;\n return name === 'flip';\n });\n\n if (!flipModifier) {\n console.error(['Popper: \"auto\" placements require the \"flip\" modifier be', 'present and enabled to work.'].join(' '));\n }\n }\n\n var _getComputedStyle = getComputedStyle(popper),\n marginTop = _getComputedStyle.marginTop,\n marginRight = _getComputedStyle.marginRight,\n marginBottom = _getComputedStyle.marginBottom,\n marginLeft = _getComputedStyle.marginLeft; // We no longer take into account `margins` on the popper, and it can\n // cause bugs with positioning, so we'll warn the consumer\n\n\n if ([marginTop, marginRight, marginBottom, marginLeft].some(function (margin) {\n return parseFloat(margin);\n })) {\n console.warn(['Popper: CSS \"margin\" styles cannot be used to apply padding', 'between the popper and its reference element or boundary.', 'To replicate margin, use the `offset` modifier, as well as', 'the `padding` option in the `preventOverflow` and `flip`', 'modifiers.'].join(' '));\n }\n }\n\n runModifierEffects();\n return instance.update();\n },\n // Sync update – it will always be executed, even if not necessary. This\n // is useful for low frequency updates where sync behavior simplifies the\n // logic.\n // For high frequency updates (e.g. `resize` and `scroll` events), always\n // prefer the async Popper#update method\n forceUpdate: function forceUpdate() {\n if (isDestroyed) {\n return;\n }\n\n var _state$elements = state.elements,\n reference = _state$elements.reference,\n popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements\n // anymore\n\n if (!areValidElements(reference, popper)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(INVALID_ELEMENT_ERROR);\n }\n\n return;\n } // Store the reference and popper rects to be read by modifiers\n\n\n state.rects = {\n reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),\n popper: getLayoutRect(popper)\n }; // Modifiers have the ability to reset the current update cycle. The\n // most common use case for this is the `flip` modifier changing the\n // placement, which then needs to re-run all the modifiers, because the\n // logic was previously ran for the previous placement and is therefore\n // stale/incorrect\n\n state.reset = false;\n state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier\n // is filled with the initial data specified by the modifier. This means\n // it doesn't persist and is fresh on each update.\n // To ensure persistent data, use `${name}#persistent`\n\n state.orderedModifiers.forEach(function (modifier) {\n return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);\n });\n var __debug_loops__ = 0;\n\n for (var index = 0; index < state.orderedModifiers.length; index++) {\n if (process.env.NODE_ENV !== \"production\") {\n __debug_loops__ += 1;\n\n if (__debug_loops__ > 100) {\n console.error(INFINITE_LOOP_ERROR);\n break;\n }\n }\n\n if (state.reset === true) {\n state.reset = false;\n index = -1;\n continue;\n }\n\n var _state$orderedModifie = state.orderedModifiers[index],\n fn = _state$orderedModifie.fn,\n _state$orderedModifie2 = _state$orderedModifie.options,\n _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,\n name = _state$orderedModifie.name;\n\n if (typeof fn === 'function') {\n state = fn({\n state: state,\n options: _options,\n name: name,\n instance: instance\n }) || state;\n }\n }\n },\n // Async and optimistically optimized update – it will not be executed if\n // not necessary (debounced to run at most once-per-tick)\n update: debounce(function () {\n return new Promise(function (resolve) {\n instance.forceUpdate();\n resolve(state);\n });\n }),\n destroy: function destroy() {\n cleanupModifierEffects();\n isDestroyed = true;\n }\n };\n\n if (!areValidElements(reference, popper)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(INVALID_ELEMENT_ERROR);\n }\n\n return instance;\n }\n\n instance.setOptions(options).then(function (state) {\n if (!isDestroyed && options.onFirstUpdate) {\n options.onFirstUpdate(state);\n }\n }); // Modifiers have the ability to execute arbitrary code before the first\n // update cycle runs. They will be executed in the same order as the update\n // cycle. This is useful when a modifier adds some persistent data that\n // other modifiers need to use, but the modifier is run after the dependent\n // one.\n\n function runModifierEffects() {\n state.orderedModifiers.forEach(function (_ref3) {\n var name = _ref3.name,\n _ref3$options = _ref3.options,\n options = _ref3$options === void 0 ? {} : _ref3$options,\n effect = _ref3.effect;\n\n if (typeof effect === 'function') {\n var cleanupFn = effect({\n state: state,\n name: name,\n instance: instance,\n options: options\n });\n\n var noopFn = function noopFn() {};\n\n effectCleanupFns.push(cleanupFn || noopFn);\n }\n });\n }\n\n function cleanupModifierEffects() {\n effectCleanupFns.forEach(function (fn) {\n return fn();\n });\n effectCleanupFns = [];\n }\n\n return instance;\n };\n}\nexport var createPopper = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules\n\nexport { detectOverflow };","export default function debounce(fn) {\n var pending;\n return function () {\n if (!pending) {\n pending = new Promise(function (resolve) {\n Promise.resolve().then(function () {\n pending = undefined;\n resolve(fn());\n });\n });\n }\n\n return pending;\n };\n}","export default function mergeByName(modifiers) {\n var merged = modifiers.reduce(function (merged, current) {\n var existing = merged[current.name];\n merged[current.name] = existing ? Object.assign({}, existing, current, {\n options: Object.assign({}, existing.options, current.options),\n data: Object.assign({}, existing.data, current.data)\n }) : current;\n return merged;\n }, {}); // IE11 does not support Object.values\n\n return Object.keys(merged).map(function (key) {\n return merged[key];\n });\n}","import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow };","import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nimport offset from \"./modifiers/offset.js\";\nimport flip from \"./modifiers/flip.js\";\nimport preventOverflow from \"./modifiers/preventOverflow.js\";\nimport arrow from \"./modifiers/arrow.js\";\nimport hide from \"./modifiers/hide.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles, offset, flip, preventOverflow, arrow, hide];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow }; // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper as createPopperLite } from \"./popper-lite.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport * from \"./modifiers/index.js\";","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\n\nimport {\n defineJQueryPlugin,\n getElement,\n getElementFromSelector,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst SPACE_KEY = 'Space'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEY}|${ARROW_DOWN_KEY}|${ESCAPE_KEY}`)\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_NAVBAR = 'navbar'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]'\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\n\nconst Default = {\n offset: [0, 2],\n boundary: 'clippingParents',\n reference: 'toggle',\n display: 'dynamic',\n popperConfig: null,\n autoClose: true\n}\n\nconst DefaultType = {\n offset: '(array|string|function)',\n boundary: '(string|element)',\n reference: '(string|element|object)',\n display: 'string',\n popperConfig: '(null|object|function)',\n autoClose: '(boolean|string)'\n}\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._popper = null\n this._config = this._getConfig(config)\n this._menu = this._getMenuElement()\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown(this._menu)) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n const parent = Dropdown.getParentFromElement(this._element)\n // Totally disable Popper for Dropdowns in Navbar\n if (this._inNavbar) {\n Manipulator.setDataAttribute(this._menu, 'popper', 'none')\n } else {\n this._createPopper(parent)\n }\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement &&\n !parent.closest(SELECTOR_NAVBAR_NAV)) {\n [].concat(...document.body.children)\n .forEach(elem => EventHandler.on(elem, 'mouseover', noop))\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown(this._menu)) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n [].concat(...document.body.children)\n .forEach(elem => EventHandler.off(elem, 'mouseover', noop))\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = {\n ...this.constructor.Default,\n ...Manipulator.getDataAttributes(this._element),\n ...config\n }\n\n typeCheckConfig(NAME, config, this.constructor.DefaultType)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper(parent) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n const isDisplayStatic = popperConfig.modifiers.find(modifier => modifier.name === 'applyStyles' && modifier.enabled === false)\n\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n\n if (isDisplayStatic) {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static')\n }\n }\n\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getMenuElement() {\n return SelectorEngine.next(this._element, SELECTOR_MENU)[0]\n }\n\n _getPlacement() {\n const parentDropdown = this._element.parentNode\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(`.${CLASS_NAME_NAVBAR}`) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(val => Number.parseInt(val, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display\n if (this._config.display === 'static') {\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible)\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event && (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY))) {\n return\n }\n\n const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (let i = 0, len = toggles.length; i < len; i++) {\n const context = Dropdown.getInstance(toggles[i])\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n if (!context._isShown()) {\n continue\n }\n\n const relatedTarget = {\n relatedTarget: context._element\n }\n\n if (event) {\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static getParentFromElement(element) {\n return getElementFromSelector(element) || element.parentNode\n }\n\n static dataApiKeydownHandler(event) {\n // If not input/textarea:\n // - And not a key in REGEXP_KEYDOWN => not a dropdown command\n // If input/textarea:\n // - If space key => not a dropdown command\n // - If key is other than escape\n // - If key is not up or down => not a dropdown command\n // - If trigger inside the menu => not a dropdown command\n if (/input|textarea/i.test(event.target.tagName) ?\n event.key === SPACE_KEY || (event.key !== ESCAPE_KEY &&\n ((event.key !== ARROW_DOWN_KEY && event.key !== ARROW_UP_KEY) ||\n event.target.closest(SELECTOR_MENU))) :\n !REGEXP_KEYDOWN.test(event.key)) {\n return\n }\n\n const isActive = this.classList.contains(CLASS_NAME_SHOW)\n\n if (!isActive && event.key === ESCAPE_KEY) {\n return\n }\n\n event.preventDefault()\n event.stopPropagation()\n\n if (isDisabled(this)) {\n return\n }\n\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0]\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (event.key === ESCAPE_KEY) {\n instance.hide()\n return\n }\n\n if (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY) {\n if (!isActive) {\n instance.show()\n }\n\n instance._selectMenuItem(event)\n return\n }\n\n if (!isActive || event.key === SPACE_KEY) {\n Dropdown.clearMenus()\n }\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Dropdown to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine'\nimport Manipulator from '../dom/manipulator'\nimport { isElement } from './index'\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, 'paddingRight', calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width)\n }\n\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProp, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProp)\n const calculatedValue = window.getComputedStyle(element)[styleProp]\n element.style[styleProp] = `${callback(Number.parseFloat(calculatedValue))}px`\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, 'paddingRight')\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight')\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight')\n }\n\n _saveInitialAttribute(element, styleProp) {\n const actualValue = element.style[styleProp]\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProp, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProp) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProp)\n if (typeof value === 'undefined') {\n element.style.removeProperty(styleProp)\n } else {\n Manipulator.removeDataAttribute(element, styleProp)\n element.style[styleProp] = value\n }\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n } else {\n SelectorEngine.find(selector, this._element).forEach(callBack)\n }\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler'\nimport { execute, executeAfterTransition, getElement, reflow, typeCheckConfig } from './index'\n\nconst Default = {\n className: 'modal-backdrop',\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n isAnimated: false,\n rootElement: 'body', // give the choice to place backdrop under different elements\n clickCallback: null\n}\n\nconst DefaultType = {\n className: 'string',\n isVisible: 'boolean',\n isAnimated: 'boolean',\n rootElement: '(element|string)',\n clickCallback: '(function|null)'\n}\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nclass Backdrop {\n constructor(config) {\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n if (this._config.isAnimated) {\n reflow(this._getElement())\n }\n\n this._getElement().classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n // Private\n\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _getConfig(config) {\n config = {\n ...Default,\n ...(typeof config === 'object' ? config : {})\n }\n\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n this._config.rootElement.append(this._getElement())\n\n EventHandler.on(this._getElement(), EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler'\nimport SelectorEngine from '../dom/selector-engine'\nimport { typeCheckConfig } from './index'\n\nconst Default = {\n trapElement: null, // The element to trap focus inside of\n autofocus: true\n}\n\nconst DefaultType = {\n trapElement: 'element',\n autofocus: 'boolean'\n}\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nclass FocusTrap {\n constructor(config) {\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n activate() {\n const { trapElement, autofocus } = this._config\n\n if (this._isActive) {\n return\n }\n\n if (autofocus) {\n trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n\n _handleFocusin(event) {\n const { target } = event\n const { trapElement } = this._config\n\n if (target === document || target === trapElement || trapElement.contains(target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n\n _getConfig(config) {\n config = {\n ...Default,\n ...(typeof config === 'object' ? config : {})\n }\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElementFromSelector,\n isRTL,\n isVisible,\n reflow,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport ScrollBarHelper from './util/scrollbar'\nimport BaseComponent from './base-component'\nimport Backdrop from './util/backdrop'\nimport FocusTrap from './util/focustrap'\nimport { enableDismissTrigger } from './util/component-functions'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n focus: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n focus: 'boolean'\n}\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEUP_DISMISS = `mouseup.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._config = this._getConfig(config)\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._ignoreBackdropClick = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n\n if (this._isAnimated()) {\n this._isTransitioning = true\n }\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._setEscapeEvent()\n this._setResizeEvent()\n\n EventHandler.on(this._dialog, EVENT_MOUSEDOWN_DISMISS, () => {\n EventHandler.one(this._element, EVENT_MOUSEUP_DISMISS, event => {\n if (event.target === this._element) {\n this._ignoreBackdropClick = true\n }\n })\n })\n\n this._showBackdrop(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n const isAnimated = this._isAnimated()\n\n if (isAnimated) {\n this._isTransitioning = true\n }\n\n this._setEscapeEvent()\n this._setResizeEvent()\n\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n EventHandler.off(this._element, EVENT_CLICK_DISMISS)\n EventHandler.off(this._dialog, EVENT_MOUSEDOWN_DISMISS)\n\n this._queueCallback(() => this._hideModal(), this._element, isAnimated)\n }\n\n dispose() {\n [window, this._dialog]\n .forEach(htmlElement => EventHandler.off(htmlElement, EVENT_KEY))\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' ? config : {})\n }\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _showElement(relatedTarget) {\n const isAnimated = this._isAnimated()\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n\n if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {\n // Don't move modal's DOM position\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n if (isAnimated) {\n reflow(this._element)\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, isAnimated)\n }\n\n _setEscapeEvent() {\n if (this._isShown) {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (this._config.keyboard && event.key === ESCAPE_KEY) {\n event.preventDefault()\n this.hide()\n } else if (!this._config.keyboard && event.key === ESCAPE_KEY) {\n this._triggerBackdropTransition()\n }\n })\n } else {\n EventHandler.off(this._element, EVENT_KEYDOWN_DISMISS)\n }\n }\n\n _setResizeEvent() {\n if (this._isShown) {\n EventHandler.on(window, EVENT_RESIZE, () => this._adjustDialog())\n } else {\n EventHandler.off(window, EVENT_RESIZE)\n }\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _showBackdrop(callback) {\n EventHandler.on(this._element, EVENT_CLICK_DISMISS, event => {\n if (this._ignoreBackdropClick) {\n this._ignoreBackdropClick = false\n return\n }\n\n if (event.target !== event.currentTarget) {\n return\n }\n\n if (this._config.backdrop === true) {\n this.hide()\n } else if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n }\n })\n\n this._backdrop.show(callback)\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const { classList, scrollHeight, style } = this._element\n const isModalOverflowing = scrollHeight > document.documentElement.clientHeight\n\n // return if the following background transition hasn't yet completed\n if ((!isModalOverflowing && style.overflowY === 'hidden') || classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n style.overflowY = 'hidden'\n }\n\n classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n classList.remove(CLASS_NAME_STATIC)\n if (!isModalOverflowing) {\n this._queueCallback(() => {\n style.overflowY = ''\n }, this._dialog)\n }\n }, this._dialog)\n\n this._element.focus()\n }\n\n // ----------------------------------------------------------------------\n // the following methods are used to handle overflowing modals\n // ----------------------------------------------------------------------\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if ((!isBodyOverflowing && isModalOverflowing && !isRTL()) || (isBodyOverflowing && !isModalOverflowing && isRTL())) {\n this._element.style.paddingLeft = `${scrollbarWidth}px`\n }\n\n if ((isBodyOverflowing && !isModalOverflowing && !isRTL()) || (!isBodyOverflowing && isModalOverflowing && isRTL())) {\n this._element.style.paddingRight = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking moddal toggler while another one is open\n const allReadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (allReadyOpen) {\n Modal.getInstance(allReadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Modal to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElementFromSelector,\n isDisabled,\n isVisible,\n typeCheckConfig\n} from './util/index'\nimport ScrollBarHelper from './util/scrollbar'\nimport EventHandler from './dom/event-handler'\nimport BaseComponent from './base-component'\nimport SelectorEngine from './dom/selector-engine'\nimport Manipulator from './dom/manipulator'\nimport Backdrop from './util/backdrop'\nimport FocusTrap from './util/focustrap'\nimport { enableDismissTrigger } from './util/component-functions'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: 'boolean',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._config = this._getConfig(config)\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n\n static get NAME() {\n return NAME\n }\n\n static get Default() {\n return Default\n }\n\n // Public\n\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._element.style.visibility = 'visible'\n\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const completeCallBack = () => {\n if (!this._config.scroll) {\n this._focustrap.activate()\n }\n\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._element.style.visibility = 'hidden'\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' ? config : {})\n }\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _initializeBackDrop() {\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible: this._config.backdrop,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: () => this.hide()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (this._config.keyboard && event.key === ESCAPE_KEY) {\n this.hide()\n }\n })\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const allReadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (allReadyOpen && allReadyOpen !== target) {\n Offcanvas.getInstance(allReadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () =>\n SelectorEngine.find(OPEN_SELECTOR).forEach(el => Offcanvas.getOrCreateInstance(el).show())\n)\n\nenableDismissTrigger(Offcanvas)\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\n/**\n * A pattern that recognizes a commonly useful subset of URLs that are safe.\n *\n * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts\n */\nconst SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i\n\n/**\n * A pattern that matches safe data URLs. Only matches image, video and audio types.\n *\n * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts\n */\nconst DATA_URL_PATTERN = /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[\\d+/a-z]+=*$/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue) || DATA_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n const regExp = allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n\n // Check if a regular expression validates the attribute.\n for (let i = 0, len = regExp.length; i < len; i++) {\n if (regExp[i].test(attributeName)) {\n return true\n }\n }\n\n return false\n}\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n div: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFn && typeof sanitizeFn === 'function') {\n return sanitizeFn(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (let i = 0, len = elements.length; i < len; i++) {\n const element = elements[i]\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n attributeList.forEach(attribute => {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n })\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\n\nimport {\n defineJQueryPlugin,\n findShadowRoot,\n getElement,\n getUID,\n isElement,\n isRTL,\n noop,\n typeCheckConfig\n} from './util/index'\nimport { DefaultAllowlist, sanitizeHtml } from './util/sanitizer'\nimport Data from './dom/data'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'tooltip'\nconst DATA_KEY = 'bs.tooltip'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst CLASS_PREFIX = 'bs-tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst DefaultType = {\n animation: 'boolean',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string',\n delay: '(number|object)',\n html: 'boolean',\n selector: '(string|boolean)',\n placement: '(string|function)',\n offset: '(array|string|function)',\n container: '(string|element|boolean)',\n fallbackPlacements: 'array',\n boundary: '(string|element)',\n customClass: '(string|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n allowList: 'object',\n popperConfig: '(null|object|function)'\n}\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n animation: true,\n template: '<div class=\"tooltip\" role=\"tooltip\">' +\n '<div class=\"tooltip-arrow\"></div>' +\n '<div class=\"tooltip-inner\"></div>' +\n '</div>',\n trigger: 'hover focus',\n title: '',\n delay: 0,\n html: false,\n selector: false,\n placement: 'top',\n offset: [0, 0],\n container: false,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n boundary: 'clippingParents',\n customClass: '',\n sanitize: true,\n sanitizeFn: null,\n allowList: DefaultAllowlist,\n popperConfig: null\n}\n\nconst Event = {\n HIDE: `hide${EVENT_KEY}`,\n HIDDEN: `hidden${EVENT_KEY}`,\n SHOW: `show${EVENT_KEY}`,\n SHOWN: `shown${EVENT_KEY}`,\n INSERTED: `inserted${EVENT_KEY}`,\n CLICK: `click${EVENT_KEY}`,\n FOCUSIN: `focusin${EVENT_KEY}`,\n FOCUSOUT: `focusout${EVENT_KEY}`,\n MOUSEENTER: `mouseenter${EVENT_KEY}`,\n MOUSELEAVE: `mouseleave${EVENT_KEY}`\n}\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst HOVER_STATE_SHOW = 'show'\nconst HOVER_STATE_OUT = 'out'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org)')\n }\n\n super(element)\n\n // private\n this._isEnabled = true\n this._timeout = 0\n this._hoverState = ''\n this._activeTrigger = {}\n this._popper = null\n\n // Protected\n this._config = this._getConfig(config)\n this.tip = null\n\n this._setListeners()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n static get Event() {\n return Event\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n // Public\n\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle(event) {\n if (!this._isEnabled) {\n return\n }\n\n if (event) {\n const context = this._initializeOnDelegatedTarget(event)\n\n context._activeTrigger.click = !context._activeTrigger.click\n\n if (context._isWithActiveTrigger()) {\n context._enter(null, context)\n } else {\n context._leave(null, context)\n }\n } else {\n if (this.getTipElement().classList.contains(CLASS_NAME_SHOW)) {\n this._leave(null, this)\n return\n }\n\n this._enter(null, this)\n }\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this.tip) {\n this.tip.remove()\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this.isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.Event.SHOW)\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = shadowRoot === null ?\n this._element.ownerDocument.documentElement.contains(this._element) :\n shadowRoot.contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // A trick to recreate a tooltip in case a new title is given by using the NOT documented `data-bs-original-title`\n // This will be removed later in favor of a `setContent` method\n if (this.constructor.NAME === 'tooltip' && this.tip && this.getTitle() !== this.tip.querySelector(SELECTOR_TOOLTIP_INNER).innerHTML) {\n this._disposePopper()\n this.tip.remove()\n this.tip = null\n }\n\n const tip = this.getTipElement()\n const tipId = getUID(this.constructor.NAME)\n\n tip.setAttribute('id', tipId)\n this._element.setAttribute('aria-describedby', tipId)\n\n if (this._config.animation) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n const placement = typeof this._config.placement === 'function' ?\n this._config.placement.call(this, tip, this._element) :\n this._config.placement\n\n const attachment = this._getAttachment(placement)\n this._addAttachmentClass(attachment)\n\n const { container } = this._config\n Data.set(tip, this.constructor.DATA_KEY, this)\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.Event.INSERTED)\n }\n\n if (this._popper) {\n this._popper.update()\n } else {\n this._popper = Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n const customClass = this._resolvePossibleFunction(this._config.customClass)\n if (customClass) {\n tip.classList.add(...customClass.split(' '))\n }\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n [].concat(...document.body.children).forEach(element => {\n EventHandler.on(element, 'mouseover', noop)\n })\n }\n\n const complete = () => {\n const prevHoverState = this._hoverState\n\n this._hoverState = null\n EventHandler.trigger(this._element, this.constructor.Event.SHOWN)\n\n if (prevHoverState === HOVER_STATE_OUT) {\n this._leave(null, this)\n }\n }\n\n const isAnimated = this.tip.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(complete, this.tip, isAnimated)\n }\n\n hide() {\n if (!this._popper) {\n return\n }\n\n const tip = this.getTipElement()\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (this._hoverState !== HOVER_STATE_SHOW) {\n tip.remove()\n }\n\n this._cleanTipClass()\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.Event.HIDDEN)\n\n this._disposePopper()\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.Event.HIDE)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n [].concat(...document.body.children)\n .forEach(element => EventHandler.off(element, 'mouseover', noop))\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n\n const isAnimated = this.tip.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(complete, this.tip, isAnimated)\n this._hoverState = ''\n }\n\n update() {\n if (this._popper !== null) {\n this._popper.update()\n }\n }\n\n // Protected\n\n isWithContent() {\n return Boolean(this.getTitle())\n }\n\n getTipElement() {\n if (this.tip) {\n return this.tip\n }\n\n const element = document.createElement('div')\n element.innerHTML = this._config.template\n\n const tip = element.children[0]\n this.setContent(tip)\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n\n this.tip = tip\n return this.tip\n }\n\n setContent(tip) {\n this._sanitizeAndSetContent(tip, this.getTitle(), SELECTOR_TOOLTIP_INNER)\n }\n\n _sanitizeAndSetContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!content && templateElement) {\n templateElement.remove()\n return\n }\n\n // we use append for html objects to maintain js events\n this.setElementContent(templateElement, content)\n }\n\n setElementContent(element, content) {\n if (element === null) {\n return\n }\n\n if (isElement(content)) {\n content = getElement(content)\n\n // content is a DOM node or a jQuery\n if (this._config.html) {\n if (content.parentNode !== element) {\n element.innerHTML = ''\n element.append(content)\n }\n } else {\n element.textContent = content.textContent\n }\n\n return\n }\n\n if (this._config.html) {\n if (this._config.sanitize) {\n content = sanitizeHtml(content, this._config.allowList, this._config.sanitizeFn)\n }\n\n element.innerHTML = content\n } else {\n element.textContent = content\n }\n }\n\n getTitle() {\n const title = this._element.getAttribute('data-bs-original-title') || this._config.title\n\n return this._resolvePossibleFunction(title)\n }\n\n updateAttachment(attachment) {\n if (attachment === 'right') {\n return 'end'\n }\n\n if (attachment === 'left') {\n return 'start'\n }\n\n return attachment\n }\n\n // Private\n\n _initializeOnDelegatedTarget(event, context) {\n return context || this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(val => Number.parseInt(val, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(content) {\n return typeof content === 'function' ? content.call(this._element) : content\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'onChange',\n enabled: true,\n phase: 'afterWrite',\n fn: data => this._handlePopperPlacementChange(data)\n }\n ],\n onFirstUpdate: data => {\n if (data.options.placement !== data.placement) {\n this._handlePopperPlacementChange(data)\n }\n }\n }\n\n return {\n ...defaultBsPopperConfig,\n ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)\n }\n }\n\n _addAttachmentClass(attachment) {\n this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(attachment)}`)\n }\n\n _getAttachment(placement) {\n return AttachmentMap[placement.toUpperCase()]\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n triggers.forEach(trigger => {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.Event.CLICK, this._config.selector, event => this.toggle(event))\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.Event.MOUSEENTER :\n this.constructor.Event.FOCUSIN\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.Event.MOUSELEAVE :\n this.constructor.Event.FOCUSOUT\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => this._enter(event))\n EventHandler.on(this._element, eventOut, this._config.selector, event => this._leave(event))\n }\n })\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._config.selector) {\n this._config = {\n ...this._config,\n trigger: 'manual',\n selector: ''\n }\n } else {\n this._fixTitle()\n }\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n const originalTitleType = typeof this._element.getAttribute('data-bs-original-title')\n\n if (title || originalTitleType !== 'string') {\n this._element.setAttribute('data-bs-original-title', title || '')\n if (title && !this._element.getAttribute('aria-label') && !this._element.textContent) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('title', '')\n }\n }\n\n _enter(event, context) {\n context = this._initializeOnDelegatedTarget(event, context)\n\n if (event) {\n context._activeTrigger[\n event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER\n ] = true\n }\n\n if (context.getTipElement().classList.contains(CLASS_NAME_SHOW) || context._hoverState === HOVER_STATE_SHOW) {\n context._hoverState = HOVER_STATE_SHOW\n return\n }\n\n clearTimeout(context._timeout)\n\n context._hoverState = HOVER_STATE_SHOW\n\n if (!context._config.delay || !context._config.delay.show) {\n context.show()\n return\n }\n\n context._timeout = setTimeout(() => {\n if (context._hoverState === HOVER_STATE_SHOW) {\n context.show()\n }\n }, context._config.delay.show)\n }\n\n _leave(event, context) {\n context = this._initializeOnDelegatedTarget(event, context)\n\n if (event) {\n context._activeTrigger[\n event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER\n ] = context._element.contains(event.relatedTarget)\n }\n\n if (context._isWithActiveTrigger()) {\n return\n }\n\n clearTimeout(context._timeout)\n\n context._hoverState = HOVER_STATE_OUT\n\n if (!context._config.delay || !context._config.delay.hide) {\n context.hide()\n return\n }\n\n context._timeout = setTimeout(() => {\n if (context._hoverState === HOVER_STATE_OUT) {\n context.hide()\n }\n }, context._config.delay.hide)\n }\n\n _isWithActiveTrigger() {\n for (const trigger in this._activeTrigger) {\n if (this._activeTrigger[trigger]) {\n return true\n }\n }\n\n return false\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n Object.keys(dataAttributes).forEach(dataAttr => {\n if (DISALLOWED_ATTRIBUTES.has(dataAttr)) {\n delete dataAttributes[dataAttr]\n }\n })\n\n config = {\n ...this.constructor.Default,\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n typeCheckConfig(NAME, config, this.constructor.DefaultType)\n\n if (config.sanitize) {\n config.template = sanitizeHtml(config.template, config.allowList, config.sanitizeFn)\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const key in this._config) {\n if (this.constructor.Default[key] !== this._config[key]) {\n config[key] = this._config[key]\n }\n }\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _cleanTipClass() {\n const tip = this.getTipElement()\n const basicClassPrefixRegex = new RegExp(`(^|\\\\s)${this._getBasicClassPrefix()}\\\\S+`, 'g')\n const tabClass = tip.getAttribute('class').match(basicClassPrefixRegex)\n if (tabClass !== null && tabClass.length > 0) {\n tabClass.map(token => token.trim())\n .forEach(tClass => tip.classList.remove(tClass))\n }\n }\n\n _getBasicClassPrefix() {\n return CLASS_PREFIX\n }\n\n _handlePopperPlacementChange(popperData) {\n const { state } = popperData\n\n if (!state) {\n return\n }\n\n this.tip = state.elements.popper\n this._cleanTipClass()\n this._addAttachmentClass(this._getAttachment(state.placement))\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Tooltip to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { defineJQueryPlugin } from './util/index'\nimport Tooltip from './tooltip'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'popover'\nconst DATA_KEY = 'bs.popover'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst CLASS_PREFIX = 'bs-popover'\n\nconst Default = {\n ...Tooltip.Default,\n placement: 'right',\n offset: [0, 8],\n trigger: 'click',\n content: '',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(string|element|function)'\n}\n\nconst Event = {\n HIDE: `hide${EVENT_KEY}`,\n HIDDEN: `hidden${EVENT_KEY}`,\n SHOW: `show${EVENT_KEY}`,\n SHOWN: `shown${EVENT_KEY}`,\n INSERTED: `inserted${EVENT_KEY}`,\n CLICK: `click${EVENT_KEY}`,\n FOCUSIN: `focusin${EVENT_KEY}`,\n FOCUSOUT: `focusout${EVENT_KEY}`,\n MOUSEENTER: `mouseenter${EVENT_KEY}`,\n MOUSELEAVE: `mouseleave${EVENT_KEY}`\n}\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Popover extends Tooltip {\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n static get Event() {\n return Event\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n // Overrides\n\n isWithContent() {\n return this.getTitle() || this._getContent()\n }\n\n setContent(tip) {\n this._sanitizeAndSetContent(tip, this.getTitle(), SELECTOR_TITLE)\n this._sanitizeAndSetContent(tip, this._getContent(), SELECTOR_CONTENT)\n }\n\n // Private\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n _getBasicClassPrefix() {\n return CLASS_PREFIX\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Popover to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElement,\n getSelectorFromElement,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst Default = {\n offset: 10,\n method: 'auto',\n target: ''\n}\n\nconst DefaultType = {\n offset: 'number',\n method: 'string',\n target: '(string|element)'\n}\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_SCROLL = `scroll${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}, .${CLASS_NAME_DROPDOWN_ITEM}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst METHOD_OFFSET = 'offset'\nconst METHOD_POSITION = 'position'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element)\n this._scrollElement = this._element.tagName === 'BODY' ? window : this._element\n this._config = this._getConfig(config)\n this._offsets = []\n this._targets = []\n this._activeTarget = null\n this._scrollHeight = 0\n\n EventHandler.on(this._scrollElement, EVENT_SCROLL, () => this._process())\n\n this.refresh()\n this._process()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n refresh() {\n const autoMethod = this._scrollElement === this._scrollElement.window ?\n METHOD_OFFSET :\n METHOD_POSITION\n\n const offsetMethod = this._config.method === 'auto' ?\n autoMethod :\n this._config.method\n\n const offsetBase = offsetMethod === METHOD_POSITION ?\n this._getScrollTop() :\n 0\n\n this._offsets = []\n this._targets = []\n this._scrollHeight = this._getScrollHeight()\n\n const targets = SelectorEngine.find(SELECTOR_LINK_ITEMS, this._config.target)\n\n targets.map(element => {\n const targetSelector = getSelectorFromElement(element)\n const target = targetSelector ? SelectorEngine.findOne(targetSelector) : null\n\n if (target) {\n const targetBCR = target.getBoundingClientRect()\n if (targetBCR.width || targetBCR.height) {\n return [\n Manipulator[offsetMethod](target).top + offsetBase,\n targetSelector\n ]\n }\n }\n\n return null\n })\n .filter(item => item)\n .sort((a, b) => a[0] - b[0])\n .forEach(item => {\n this._offsets.push(item[0])\n this._targets.push(item[1])\n })\n }\n\n dispose() {\n EventHandler.off(this._scrollElement, EVENT_KEY)\n super.dispose()\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' && config ? config : {})\n }\n\n config.target = getElement(config.target) || document.documentElement\n\n typeCheckConfig(NAME, config, DefaultType)\n\n return config\n }\n\n _getScrollTop() {\n return this._scrollElement === window ?\n this._scrollElement.pageYOffset :\n this._scrollElement.scrollTop\n }\n\n _getScrollHeight() {\n return this._scrollElement.scrollHeight || Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight\n )\n }\n\n _getOffsetHeight() {\n return this._scrollElement === window ?\n window.innerHeight :\n this._scrollElement.getBoundingClientRect().height\n }\n\n _process() {\n const scrollTop = this._getScrollTop() + this._config.offset\n const scrollHeight = this._getScrollHeight()\n const maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight()\n\n if (this._scrollHeight !== scrollHeight) {\n this.refresh()\n }\n\n if (scrollTop >= maxScroll) {\n const target = this._targets[this._targets.length - 1]\n\n if (this._activeTarget !== target) {\n this._activate(target)\n }\n\n return\n }\n\n if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {\n this._activeTarget = null\n this._clear()\n return\n }\n\n for (let i = this._offsets.length; i--;) {\n const isActiveTarget = this._activeTarget !== this._targets[i] &&\n scrollTop >= this._offsets[i] &&\n (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1])\n\n if (isActiveTarget) {\n this._activate(this._targets[i])\n }\n }\n }\n\n _activate(target) {\n this._activeTarget = target\n\n this._clear()\n\n const queries = SELECTOR_LINK_ITEMS.split(',')\n .map(selector => `${selector}[data-bs-target=\"${target}\"],${selector}[href=\"${target}\"]`)\n\n const link = SelectorEngine.findOne(queries.join(','), this._config.target)\n\n link.classList.add(CLASS_NAME_ACTIVE)\n if (link.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, link.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n } else {\n SelectorEngine.parents(link, SELECTOR_NAV_LIST_GROUP)\n .forEach(listGroup => {\n // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n SelectorEngine.prev(listGroup, `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`)\n .forEach(item => item.classList.add(CLASS_NAME_ACTIVE))\n\n // Handle special case when .nav-link is inside .nav-item\n SelectorEngine.prev(listGroup, SELECTOR_NAV_ITEMS)\n .forEach(navItem => {\n SelectorEngine.children(navItem, SELECTOR_NAV_LINKS)\n .forEach(item => item.classList.add(CLASS_NAME_ACTIVE))\n })\n })\n }\n\n EventHandler.trigger(this._scrollElement, EVENT_ACTIVATE, {\n relatedTarget: target\n })\n }\n\n _clear() {\n SelectorEngine.find(SELECTOR_LINK_ITEMS, this._config.target)\n .filter(node => node.classList.contains(CLASS_NAME_ACTIVE))\n .forEach(node => node.classList.remove(CLASS_NAME_ACTIVE))\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = ScrollSpy.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n SelectorEngine.find(SELECTOR_DATA_SPY)\n .forEach(spy => new ScrollSpy(spy))\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .ScrollSpy to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(ScrollSpy)\n\nexport default ScrollSpy\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): tab.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElementFromSelector,\n isDisabled,\n reflow\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'tab'\nconst DATA_KEY = 'bs.tab'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ACTIVE_UL = ':scope > li > .active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\nconst SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Tab extends BaseComponent {\n // Getters\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n show() {\n if ((this._element.parentNode &&\n this._element.parentNode.nodeType === Node.ELEMENT_NODE &&\n this._element.classList.contains(CLASS_NAME_ACTIVE))) {\n return\n }\n\n let previous\n const target = getElementFromSelector(this._element)\n const listElement = this._element.closest(SELECTOR_NAV_LIST_GROUP)\n\n if (listElement) {\n const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? SELECTOR_ACTIVE_UL : SELECTOR_ACTIVE\n previous = SelectorEngine.find(itemSelector, listElement)\n previous = previous[previous.length - 1]\n }\n\n const hideEvent = previous ?\n EventHandler.trigger(previous, EVENT_HIDE, {\n relatedTarget: this._element\n }) :\n null\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget: previous\n })\n\n if (showEvent.defaultPrevented || (hideEvent !== null && hideEvent.defaultPrevented)) {\n return\n }\n\n this._activate(this._element, listElement)\n\n const complete = () => {\n EventHandler.trigger(previous, EVENT_HIDDEN, {\n relatedTarget: this._element\n })\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget: previous\n })\n }\n\n if (target) {\n this._activate(target, target.parentNode, complete)\n } else {\n complete()\n }\n }\n\n // Private\n\n _activate(element, container, callback) {\n const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ?\n SelectorEngine.find(SELECTOR_ACTIVE_UL, container) :\n SelectorEngine.children(container, SELECTOR_ACTIVE)\n\n const active = activeElements[0]\n const isTransitioning = callback && (active && active.classList.contains(CLASS_NAME_FADE))\n\n const complete = () => this._transitionComplete(element, active, callback)\n\n if (active && isTransitioning) {\n active.classList.remove(CLASS_NAME_SHOW)\n this._queueCallback(complete, element, true)\n } else {\n complete()\n }\n }\n\n _transitionComplete(element, active, callback) {\n if (active) {\n active.classList.remove(CLASS_NAME_ACTIVE)\n\n const dropdownChild = SelectorEngine.findOne(SELECTOR_DROPDOWN_ACTIVE_CHILD, active.parentNode)\n\n if (dropdownChild) {\n dropdownChild.classList.remove(CLASS_NAME_ACTIVE)\n }\n\n if (active.getAttribute('role') === 'tab') {\n active.setAttribute('aria-selected', false)\n }\n }\n\n element.classList.add(CLASS_NAME_ACTIVE)\n if (element.getAttribute('role') === 'tab') {\n element.setAttribute('aria-selected', true)\n }\n\n reflow(element)\n\n if (element.classList.contains(CLASS_NAME_FADE)) {\n element.classList.add(CLASS_NAME_SHOW)\n }\n\n let parent = element.parentNode\n if (parent && parent.nodeName === 'LI') {\n parent = parent.parentNode\n }\n\n if (parent && parent.classList.contains(CLASS_NAME_DROPDOWN_MENU)) {\n const dropdownElement = element.closest(SELECTOR_DROPDOWN)\n\n if (dropdownElement) {\n SelectorEngine.find(SELECTOR_DROPDOWN_TOGGLE, dropdownElement)\n .forEach(dropdown => dropdown.classList.add(CLASS_NAME_ACTIVE))\n }\n\n element.setAttribute('aria-expanded', true)\n }\n\n if (callback) {\n callback()\n }\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tab.getOrCreateInstance(this)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const data = Tab.getOrCreateInstance(this)\n data.show()\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Tab to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Tab)\n\nexport default Tab\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): toast.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n reflow,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport BaseComponent from './base-component'\nimport { enableDismissTrigger } from './util/component-functions'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'toast'\nconst DATA_KEY = 'bs.toast'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\n\nconst DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n}\n\nconst Default = {\n animation: true,\n autohide: true,\n delay: 5000\n}\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Toast extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._config = this._getConfig(config)\n this._timeout = null\n this._hasMouseInteraction = false\n this._hasKeyboardInteraction = false\n this._setListeners()\n }\n\n // Getters\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n show() {\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._clearTimeout()\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE)\n }\n\n const complete = () => {\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN)\n\n this._maybeScheduleHide()\n }\n\n this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\n reflow(this._element)\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n hide() {\n if (!this._element.classList.contains(CLASS_NAME_SHOW)) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const complete = () => {\n this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\n this._element.classList.remove(CLASS_NAME_SHOWING)\n this._element.classList.remove(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.classList.add(CLASS_NAME_SHOWING)\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n dispose() {\n this._clearTimeout()\n\n if (this._element.classList.contains(CLASS_NAME_SHOW)) {\n this._element.classList.remove(CLASS_NAME_SHOW)\n }\n\n super.dispose()\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' && config ? config : {})\n }\n\n typeCheckConfig(NAME, config, this.constructor.DefaultType)\n\n return config\n }\n\n _maybeScheduleHide() {\n if (!this._config.autohide) {\n return\n }\n\n if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\n return\n }\n\n this._timeout = setTimeout(() => {\n this.hide()\n }, this._config.delay)\n }\n\n _onInteraction(event, isInteracting) {\n switch (event.type) {\n case 'mouseover':\n case 'mouseout':\n this._hasMouseInteraction = isInteracting\n break\n case 'focusin':\n case 'focusout':\n this._hasKeyboardInteraction = isInteracting\n break\n default:\n break\n }\n\n if (isInteracting) {\n this._clearTimeout()\n return\n }\n\n const nextElement = event.relatedTarget\n if (this._element === nextElement || this._element.contains(nextElement)) {\n return\n }\n\n this._maybeScheduleHide()\n }\n\n _setListeners() {\n EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\n EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\n }\n\n _clearTimeout() {\n clearTimeout(this._timeout)\n this._timeout = null\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Toast.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n }\n })\n }\n}\n\nenableDismissTrigger(Toast)\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Toast to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Toast)\n\nexport default Toast\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): index.umd.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './src/alert'\nimport Button from './src/button'\nimport Carousel from './src/carousel'\nimport Collapse from './src/collapse'\nimport Dropdown from './src/dropdown'\nimport Modal from './src/modal'\nimport Offcanvas from './src/offcanvas'\nimport Popover from './src/popover'\nimport ScrollSpy from './src/scrollspy'\nimport Tab from './src/tab'\nimport Toast from './src/toast'\nimport Tooltip from './src/tooltip'\n\nexport default {\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Offcanvas,\n Popover,\n ScrollSpy,\n Tab,\n Toast,\n Tooltip\n}\n"]} \ No newline at end of file diff --git a/src/base/theme/bootsier/assets/js/bootstrap.min.js b/src/base/theme/bootsier/assets/js/bootstrap.min.js new file mode 100644 index 00000000..d155068c --- /dev/null +++ b/src/base/theme/bootsier/assets/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.1.3 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e(t.Popper)}(this,(function(t){"use strict";function e(t){if(t&&t.__esModule)return t;const e=Object.create(null);if(t)for(const i in t)if("default"!==i){const s=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,s.get?s:{enumerable:!0,get:()=>t[i]})}return e.default=t,Object.freeze(e)}const i=e(t),s="transitionend",n=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},o=t=>{const e=n(t);return e&&document.querySelector(e)?e:null},r=t=>{const e=n(t);return e?document.querySelector(e):null},a=t=>{t.dispatchEvent(new Event(s))},l=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),c=t=>l(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,h=(t,e,i)=>{Object.keys(i).forEach((s=>{const n=i[s],o=e[s],r=o&&l(o)?"element":null==(a=o)?`${a}`:{}.toString.call(a).match(/\s([a-z]+)/i)[1].toLowerCase();var a;if(!new RegExp(n).test(r))throw new TypeError(`${t.toUpperCase()}: Option "${s}" provided type "${r}" but expected type "${n}".`)}))},d=t=>!(!l(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),u=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),g=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?g(t.parentNode):null},_=()=>{},f=t=>{t.offsetHeight},p=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},m=[],b=()=>"rtl"===document.documentElement.dir,v=t=>{var e;e=()=>{const e=p();if(e){const i=t.NAME,s=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=s,t.jQueryInterface)}},"loading"===document.readyState?(m.length||document.addEventListener("DOMContentLoaded",(()=>{m.forEach((t=>t()))})),m.push(e)):e()},y=t=>{"function"==typeof t&&t()},E=(t,e,i=!0)=>{if(!i)return void y(t);const n=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const s=Number.parseFloat(e),n=Number.parseFloat(i);return s||n?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let o=!1;const r=({target:i})=>{i===e&&(o=!0,e.removeEventListener(s,r),y(t))};e.addEventListener(s,r),setTimeout((()=>{o||a(e)}),n)},w=(t,e,i,s)=>{let n=t.indexOf(e);if(-1===n)return t[!i&&s?t.length-1:0];const o=t.length;return n+=i?1:-1,s&&(n=(n+o)%o),t[Math.max(0,Math.min(n,o-1))]},A=/[^.]*(?=\..*)\.|.*/,T=/\..*/,C=/::\d+$/,k={};let L=1;const S={mouseenter:"mouseover",mouseleave:"mouseout"},O=/^(mouseenter|mouseleave)/i,N=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function D(t,e){return e&&`${e}::${L++}`||t.uidEvent||L++}function I(t){const e=D(t);return t.uidEvent=e,k[e]=k[e]||{},k[e]}function P(t,e,i=null){const s=Object.keys(t);for(let n=0,o=s.length;n<o;n++){const o=t[s[n]];if(o.originalHandler===e&&o.delegationSelector===i)return o}return null}function x(t,e,i){const s="string"==typeof e,n=s?i:e;let o=H(t);return N.has(o)||(o=t),[s,n,o]}function M(t,e,i,s,n){if("string"!=typeof e||!t)return;if(i||(i=s,s=null),O.test(e)){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};s?s=t(s):i=t(i)}const[o,r,a]=x(e,i,s),l=I(t),c=l[a]||(l[a]={}),h=P(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&n);const d=D(r,e.replace(A,"")),u=o?function(t,e,i){return function s(n){const o=t.querySelectorAll(e);for(let{target:r}=n;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return n.delegateTarget=r,s.oneOff&&$.off(t,n.type,e,i),i.apply(r,[n]);return null}}(t,i,s):function(t,e){return function i(s){return s.delegateTarget=t,i.oneOff&&$.off(t,s.type,e),e.apply(t,[s])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=n,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function j(t,e,i,s,n){const o=P(e[i],s,n);o&&(t.removeEventListener(i,o,Boolean(n)),delete e[i][o.uidEvent])}function H(t){return t=t.replace(T,""),S[t]||t}const $={on(t,e,i,s){M(t,e,i,s,!1)},one(t,e,i,s){M(t,e,i,s,!0)},off(t,e,i,s){if("string"!=typeof e||!t)return;const[n,o,r]=x(e,i,s),a=r!==e,l=I(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void j(t,l,r,o,n?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,s){const n=e[i]||{};Object.keys(n).forEach((o=>{if(o.includes(s)){const s=n[o];j(t,e,i,s.originalHandler,s.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const s=i.replace(C,"");if(!a||e.includes(s)){const e=h[i];j(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const s=p(),n=H(e),o=e!==n,r=N.has(n);let a,l=!0,c=!0,h=!1,d=null;return o&&s&&(a=s.Event(e,i),s(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(n,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},B=new Map,z={set(t,e,i){B.has(t)||B.set(t,new Map);const s=B.get(t);s.has(e)||0===s.size?s.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(t,e)=>B.has(t)&&B.get(t).get(e)||null,remove(t,e){if(!B.has(t))return;const i=B.get(t);i.delete(e),0===i.size&&B.delete(t)}};class R{constructor(t){(t=c(t))&&(this._element=t,z.set(this._element,this.constructor.DATA_KEY,this))}dispose(){z.remove(this._element,this.constructor.DATA_KEY),$.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){E(t,e,i)}static getInstance(t){return z.get(c(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const F=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;$.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),u(this))return;const n=r(this)||this.closest(`.${s}`);t.getOrCreateInstance(n)[e]()}))};class q extends R{static get NAME(){return"alert"}close(){if($.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),$.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}F(q,"close"),v(q);const W='[data-bs-toggle="button"]';class U extends R{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=U.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function K(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function V(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}$.on(document,"click.bs.button.data-api",W,(t=>{t.preventDefault();const e=t.target.closest(W);U.getOrCreateInstance(e).toggle()})),v(U);const X={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${V(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${V(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let s=i.replace(/^bs/,"");s=s.charAt(0).toLowerCase()+s.slice(1,s.length),e[s]=K(t.dataset[i])})),e},getDataAttribute:(t,e)=>K(t.getAttribute(`data-bs-${V(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},Y={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let s=t.parentNode;for(;s&&s.nodeType===Node.ELEMENT_NODE&&3!==s.nodeType;)s.matches(e)&&i.push(s),s=s.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(", ");return this.find(e,t).filter((t=>!u(t)&&d(t)))}},Q="carousel",G={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Z={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},J="next",tt="prev",et="left",it="right",st={ArrowLeft:it,ArrowRight:et},nt="slid.bs.carousel",ot="active",rt=".active.carousel-item";class at extends R{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=Y.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return G}static get NAME(){return Q}next(){this._slide(J)}nextWhenVisible(){!document.hidden&&d(this._element)&&this.next()}prev(){this._slide(tt)}pause(t){t||(this._isPaused=!0),Y.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(a(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=Y.findOne(rt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void $.one(this._element,nt,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?J:tt;this._slide(i,this._items[t])}_getConfig(t){return t={...G,...X.getDataAttributes(this._element),..."object"==typeof t?t:{}},h(Q,t,Z),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?it:et)}_addEventListeners(){this._config.keyboard&&$.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&($.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),$.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},s=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};Y.find(".carousel-item img",this._element).forEach((t=>{$.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?($.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),$.on(this._element,"pointerup.bs.carousel",(t=>s(t))),this._element.classList.add("pointer-event")):($.on(this._element,"touchstart.bs.carousel",(t=>e(t))),$.on(this._element,"touchmove.bs.carousel",(t=>i(t))),$.on(this._element,"touchend.bs.carousel",(t=>s(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=st[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?Y.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===J;return w(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),s=this._getItemIndex(Y.findOne(rt,this._element));return $.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:s,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=Y.findOne(".active",this._indicatorsElement);e.classList.remove(ot),e.removeAttribute("aria-current");const i=Y.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e<i.length;e++)if(Number.parseInt(i[e].getAttribute("data-bs-slide-to"),10)===this._getItemIndex(t)){i[e].classList.add(ot),i[e].setAttribute("aria-current","true");break}}}_updateInterval(){const t=this._activeElement||Y.findOne(rt,this._element);if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}_slide(t,e){const i=this._directionToOrder(t),s=Y.findOne(rt,this._element),n=this._getItemIndex(s),o=e||this._getItemByOrder(i,s),r=this._getItemIndex(o),a=Boolean(this._interval),l=i===J,c=l?"carousel-item-start":"carousel-item-end",h=l?"carousel-item-next":"carousel-item-prev",d=this._orderToDirection(i);if(o&&o.classList.contains(ot))return void(this._isSliding=!1);if(this._isSliding)return;if(this._triggerSlideEvent(o,d).defaultPrevented)return;if(!s||!o)return;this._isSliding=!0,a&&this.pause(),this._setActiveIndicatorElement(o),this._activeElement=o;const u=()=>{$.trigger(this._element,nt,{relatedTarget:o,direction:d,from:n,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),f(o),s.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(ot),s.classList.remove(ot,h,c),this._isSliding=!1,setTimeout(u,0)};this._queueCallback(t,s,!0)}else s.classList.remove(ot),o.classList.add(ot),this._isSliding=!1,u();a&&this.cycle()}_directionToOrder(t){return[it,et].includes(t)?b()?t===et?tt:J:t===et?J:tt:t}_orderToDirection(t){return[J,tt].includes(t)?b()?t===tt?et:it:t===tt?it:et:t}static carouselInterface(t,e){const i=at.getOrCreateInstance(t,e);let{_config:s}=i;"object"==typeof e&&(s={...s,...e});const n="string"==typeof e?e:s.slide;if("number"==typeof e)i.to(e);else if("string"==typeof n){if(void 0===i[n])throw new TypeError(`No method named "${n}"`);i[n]()}else s.interval&&s.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){at.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=r(this);if(!e||!e.classList.contains("carousel"))return;const i={...X.getDataAttributes(e),...X.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),at.carouselInterface(e,i),s&&at.getInstance(e).to(s),t.preventDefault()}}$.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",at.dataApiClickHandler),$.on(window,"load.bs.carousel.data-api",(()=>{const t=Y.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;e<i;e++)at.carouselInterface(t[e],at.getInstance(t[e]))})),v(at);const lt="collapse",ct={toggle:!0,parent:null},ht={toggle:"boolean",parent:"(null|element)"},dt="show",ut="collapse",gt="collapsing",_t="collapsed",ft=":scope .collapse .collapse",pt='[data-bs-toggle="collapse"]';class mt extends R{constructor(t,e){super(t),this._isTransitioning=!1,this._config=this._getConfig(e),this._triggerArray=[];const i=Y.find(pt);for(let t=0,e=i.length;t<e;t++){const e=i[t],s=o(e),n=Y.find(s).filter((t=>t===this._element));null!==s&&n.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return ct}static get NAME(){return lt}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=Y.find(ft,this._config.parent);e=Y.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=Y.findOne(this._selector);if(e.length){const s=e.find((t=>i!==t));if(t=s?mt.getInstance(s):null,t&&t._isTransitioning)return}if($.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&mt.getOrCreateInstance(e,{toggle:!1}).hide(),t||z.set(e,"bs.collapse",null)}));const s=this._getDimension();this._element.classList.remove(ut),this._element.classList.add(gt),this._element.style[s]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const n=`scroll${s[0].toUpperCase()+s.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(gt),this._element.classList.add(ut,dt),this._element.style[s]="",$.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[s]=`${this._element[n]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if($.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,f(this._element),this._element.classList.add(gt),this._element.classList.remove(ut,dt);const e=this._triggerArray.length;for(let t=0;t<e;t++){const e=this._triggerArray[t],i=r(e);i&&!this._isShown(i)&&this._addAriaAndCollapsedClass([e],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(gt),this._element.classList.add(ut),$.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(dt)}_getConfig(t){return(t={...ct,...X.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=c(t.parent),h(lt,t,ht),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=Y.find(ft,this._config.parent);Y.find(pt,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=r(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(_t):t.classList.add(_t),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=mt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}$.on(document,"click.bs.collapse.data-api",pt,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=o(this);Y.find(e).forEach((t=>{mt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),v(mt);const bt="dropdown",vt="Escape",yt="Space",Et="ArrowUp",wt="ArrowDown",At=new RegExp("ArrowUp|ArrowDown|Escape"),Tt="click.bs.dropdown.data-api",Ct="keydown.bs.dropdown.data-api",kt="show",Lt='[data-bs-toggle="dropdown"]',St=".dropdown-menu",Ot=b()?"top-end":"top-start",Nt=b()?"top-start":"top-end",Dt=b()?"bottom-end":"bottom-start",It=b()?"bottom-start":"bottom-end",Pt=b()?"left-start":"right-start",xt=b()?"right-start":"left-start",Mt={offset:[0,2],boundary:"clippingParents",reference:"toggle",display:"dynamic",popperConfig:null,autoClose:!0},jt={offset:"(array|string|function)",boundary:"(string|element)",reference:"(string|element|object)",display:"string",popperConfig:"(null|object|function)",autoClose:"(boolean|string)"};class Ht extends R{constructor(t,e){super(t),this._popper=null,this._config=this._getConfig(e),this._menu=this._getMenuElement(),this._inNavbar=this._detectNavbar()}static get Default(){return Mt}static get DefaultType(){return jt}static get NAME(){return bt}toggle(){return this._isShown()?this.hide():this.show()}show(){if(u(this._element)||this._isShown(this._menu))return;const t={relatedTarget:this._element};if($.trigger(this._element,"show.bs.dropdown",t).defaultPrevented)return;const e=Ht.getParentFromElement(this._element);this._inNavbar?X.setDataAttribute(this._menu,"popper","none"):this._createPopper(e),"ontouchstart"in document.documentElement&&!e.closest(".navbar-nav")&&[].concat(...document.body.children).forEach((t=>$.on(t,"mouseover",_))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(kt),this._element.classList.add(kt),$.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(u(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){$.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>$.off(t,"mouseover",_))),this._popper&&this._popper.destroy(),this._menu.classList.remove(kt),this._element.classList.remove(kt),this._element.setAttribute("aria-expanded","false"),X.removeDataAttribute(this._menu,"popper"),$.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...X.getDataAttributes(this._element),...t},h(bt,t,this.constructor.DefaultType),"object"==typeof t.reference&&!l(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${bt.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===i)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:l(this._config.reference)?e=c(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const s=this._getPopperConfig(),n=s.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=i.createPopper(e,this._menu,s),n&&X.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(kt)}_getMenuElement(){return Y.next(this._element,St)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return Pt;if(t.classList.contains("dropstart"))return xt;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?Nt:Ot:e?It:Dt}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=Y.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(d);i.length&&w(i,e,t===wt,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=Ht.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=Y.find(Lt);for(let i=0,s=e.length;i<s;i++){const s=Ht.getInstance(e[i]);if(!s||!1===s._config.autoClose)continue;if(!s._isShown())continue;const n={relatedTarget:s._element};if(t){const e=t.composedPath(),i=e.includes(s._menu);if(e.includes(s._element)||"inside"===s._config.autoClose&&!i||"outside"===s._config.autoClose&&i)continue;if(s._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;"click"===t.type&&(n.clickEvent=t)}s._completeHide(n)}}static getParentFromElement(t){return r(t)||t.parentNode}static dataApiKeydownHandler(t){if(/input|textarea/i.test(t.target.tagName)?t.key===yt||t.key!==vt&&(t.key!==wt&&t.key!==Et||t.target.closest(St)):!At.test(t.key))return;const e=this.classList.contains(kt);if(!e&&t.key===vt)return;if(t.preventDefault(),t.stopPropagation(),u(this))return;const i=this.matches(Lt)?this:Y.prev(this,Lt)[0],s=Ht.getOrCreateInstance(i);if(t.key!==vt)return t.key===Et||t.key===wt?(e||s.show(),void s._selectMenuItem(t)):void(e&&t.key!==yt||Ht.clearMenus());s.hide()}}$.on(document,Ct,Lt,Ht.dataApiKeydownHandler),$.on(document,Ct,St,Ht.dataApiKeydownHandler),$.on(document,Tt,Ht.clearMenus),$.on(document,"keyup.bs.dropdown.data-api",Ht.clearMenus),$.on(document,Tt,Lt,(function(t){t.preventDefault(),Ht.getOrCreateInstance(this).toggle()})),v(Ht);const $t=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",Bt=".sticky-top";class zt{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,"paddingRight",(e=>e+t)),this._setElementAttributes($t,"paddingRight",(e=>e+t)),this._setElementAttributes(Bt,"marginRight",(e=>e-t))}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const s=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+s)return;this._saveInitialAttribute(t,e);const n=window.getComputedStyle(t)[e];t.style[e]=`${i(Number.parseFloat(n))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes($t,"paddingRight"),this._resetElementAttributes(Bt,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&X.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=X.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(X.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){l(t)?e(t):Y.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const Rt={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},Ft={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},qt="show",Wt="mousedown.bs.backdrop";class Ut{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&f(this._getElement()),this._getElement().classList.add(qt),this._emulateAnimation((()=>{y(t)}))):y(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(qt),this._emulateAnimation((()=>{this.dispose(),y(t)}))):y(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...Rt,..."object"==typeof t?t:{}}).rootElement=c(t.rootElement),h("backdrop",t,Ft),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),$.on(this._getElement(),Wt,(()=>{y(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&($.off(this._element,Wt),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){E(t,this._getElement(),this._config.isAnimated)}}const Kt={trapElement:null,autofocus:!0},Vt={trapElement:"element",autofocus:"boolean"},Xt=".bs.focustrap",Yt="backward";class Qt{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),$.off(document,Xt),$.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),$.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,$.off(document,Xt))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const s=Y.focusableChildren(i);0===s.length?i.focus():this._lastTabNavDirection===Yt?s[s.length-1].focus():s[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Yt:"forward")}_getConfig(t){return t={...Kt,..."object"==typeof t?t:{}},h("focustrap",t,Vt),t}}const Gt="modal",Zt="Escape",Jt={backdrop:!0,keyboard:!0,focus:!0},te={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},ee="hidden.bs.modal",ie="show.bs.modal",se="resize.bs.modal",ne="click.dismiss.bs.modal",oe="keydown.dismiss.bs.modal",re="mousedown.dismiss.bs.modal",ae="modal-open",le="show",ce="modal-static";class he extends R{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=Y.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new zt}static get Default(){return Jt}static get NAME(){return Gt}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||$.trigger(this._element,ie,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(ae),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),$.on(this._dialog,re,(()=>{$.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if($.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(le),$.off(this._element,ne),$.off(this._dialog,re),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>$.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ut({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Qt({trapElement:this._element})}_getConfig(t){return t={...Jt,...X.getDataAttributes(this._element),..."object"==typeof t?t:{}},h(Gt,t,te),t}_showElement(t){const e=this._isAnimated(),i=Y.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&f(this._element),this._element.classList.add(le),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,$.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?$.on(this._element,oe,(t=>{this._config.keyboard&&t.key===Zt?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Zt||this._triggerBackdropTransition()})):$.off(this._element,oe)}_setResizeEvent(){this._isShown?$.on(window,se,(()=>this._adjustDialog())):$.off(window,se)}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(ae),this._resetAdjustments(),this._scrollBar.reset(),$.trigger(this._element,ee)}))}_showBackdrop(t){$.on(this._element,ne,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if($.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,s=e>document.documentElement.clientHeight;!s&&"hidden"===i.overflowY||t.contains(ce)||(s||(i.overflowY="hidden"),t.add(ce),this._queueCallback((()=>{t.remove(ce),s||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!b()||i&&!t&&b())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!b()||!i&&t&&b())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=he.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}$.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=r(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),$.one(e,ie,(t=>{t.defaultPrevented||$.one(e,ee,(()=>{d(this)&&this.focus()}))}));const i=Y.findOne(".modal.show");i&&he.getInstance(i).hide(),he.getOrCreateInstance(e).toggle(this)})),F(he),v(he);const de="offcanvas",ue={backdrop:!0,keyboard:!0,scroll:!1},ge={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},_e="show",fe=".offcanvas.show",pe="hidden.bs.offcanvas";class me extends R{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return de}static get Default(){return ue}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||$.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new zt).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(_e),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),$.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&($.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove(_e),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new zt).reset(),$.trigger(this._element,pe)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...ue,...X.getDataAttributes(this._element),..."object"==typeof t?t:{}},h(de,t,ge),t}_initializeBackDrop(){return new Ut({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Qt({trapElement:this._element})}_addEventListeners(){$.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=me.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}$.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=r(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),u(this))return;$.one(e,pe,(()=>{d(this)&&this.focus()}));const i=Y.findOne(fe);i&&i!==e&&me.getInstance(i).hide(),me.getOrCreateInstance(e).toggle(this)})),$.on(window,"load.bs.offcanvas.data-api",(()=>Y.find(fe).forEach((t=>me.getOrCreateInstance(t).show())))),F(me),v(me);const be=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),ve=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,ye=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Ee=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!be.has(i)||Boolean(ve.test(t.nodeValue)||ye.test(t.nodeValue));const s=e.filter((t=>t instanceof RegExp));for(let t=0,e=s.length;t<e;t++)if(s[t].test(i))return!0;return!1};function we(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const s=(new window.DOMParser).parseFromString(t,"text/html"),n=[].concat(...s.body.querySelectorAll("*"));for(let t=0,i=n.length;t<i;t++){const i=n[t],s=i.nodeName.toLowerCase();if(!Object.keys(e).includes(s)){i.remove();continue}const o=[].concat(...i.attributes),r=[].concat(e["*"]||[],e[s]||[]);o.forEach((t=>{Ee(t,r)||i.removeAttribute(t.nodeName)}))}return s.body.innerHTML}const Ae="tooltip",Te=new Set(["sanitize","allowList","sanitizeFn"]),Ce={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},ke={AUTO:"auto",TOP:"top",RIGHT:b()?"left":"right",BOTTOM:"bottom",LEFT:b()?"right":"left"},Le={animation:!0,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Se={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Oe="fade",Ne="show",De="show",Ie="out",Pe=".tooltip-inner",xe=".modal",Me="hide.bs.modal",je="hover",He="focus";class $e extends R{constructor(t,e){if(void 0===i)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return Le}static get NAME(){return Ae}static get Event(){return Se}static get DefaultType(){return Ce}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(Ne))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),$.off(this._element.closest(xe),Me,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=$.trigger(this._element,this.constructor.Event.SHOW),e=g(this._element),s=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!s)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(Pe).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),o=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",o),this._element.setAttribute("aria-describedby",o),this._config.animation&&n.classList.add(Oe);const r="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,a=this._getAttachment(r);this._addAttachmentClass(a);const{container:l}=this._config;z.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(l.append(n),$.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=i.createPopper(this._element,n,this._getPopperConfig(a)),n.classList.add(Ne);const c=this._resolvePossibleFunction(this._config.customClass);c&&n.classList.add(...c.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{$.on(t,"mouseover",_)}));const h=this.tip.classList.contains(Oe);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,$.trigger(this._element,this.constructor.Event.SHOWN),t===Ie&&this._leave(null,this)}),this.tip,h)}hide(){if(!this._popper)return;const t=this.getTipElement();if($.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(Ne),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>$.off(t,"mouseover",_))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(Oe);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==De&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),$.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(Oe,Ne),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),Pe)}_sanitizeAndSetContent(t,e,i){const s=Y.findOne(i,t);e||!s?this.setElementContent(s,e):s.remove()}setElementContent(t,e){if(null!==t)return l(e)?(e=c(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=we(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return ke[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)$.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===je?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===je?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;$.on(this._element,e,this._config.selector,(t=>this._enter(t))),$.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},$.on(this._element.closest(xe),Me,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?He:je]=!0),e.getTipElement().classList.contains(Ne)||e._hoverState===De?e._hoverState=De:(clearTimeout(e._timeout),e._hoverState=De,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===De&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?He:je]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=Ie,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===Ie&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=X.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Te.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:c(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),h(Ae,t,this.constructor.DefaultType),t.sanitize&&(t.template=we(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=$e.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}v($e);const Be={...$e.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'},ze={...$e.DefaultType,content:"(string|element|function)"},Re={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class Fe extends $e{static get Default(){return Be}static get NAME(){return"popover"}static get Event(){return Re}static get DefaultType(){return ze}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=Fe.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}v(Fe);const qe="scrollspy",We={offset:10,method:"auto",target:""},Ue={offset:"number",method:"string",target:"(string|element)"},Ke="active",Ve=".nav-link, .list-group-item, .dropdown-item",Xe="position";class Ye extends R{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,$.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return We}static get NAME(){return qe}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":Xe,e="auto"===this._config.method?t:this._config.method,i=e===Xe?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),Y.find(Ve,this._config.target).map((t=>{const s=o(t),n=s?Y.findOne(s):null;if(n){const t=n.getBoundingClientRect();if(t.width||t.height)return[X[e](n).top+i,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){$.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...We,...X.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=c(t.target)||document.documentElement,h(qe,t,Ue),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t<this._offsets[0]&&this._offsets[0]>0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t<this._offsets[e+1])&&this._activate(this._targets[e])}}_activate(t){this._activeTarget=t,this._clear();const e=Ve.split(",").map((e=>`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=Y.findOne(e.join(","),this._config.target);i.classList.add(Ke),i.classList.contains("dropdown-item")?Y.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(Ke):Y.parents(i,".nav, .list-group").forEach((t=>{Y.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(Ke))),Y.prev(t,".nav-item").forEach((t=>{Y.children(t,".nav-link").forEach((t=>t.classList.add(Ke)))}))})),$.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){Y.find(Ve,this._config.target).filter((t=>t.classList.contains(Ke))).forEach((t=>t.classList.remove(Ke)))}static jQueryInterface(t){return this.each((function(){const e=Ye.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}$.on(window,"load.bs.scrollspy.data-api",(()=>{Y.find('[data-bs-spy="scroll"]').forEach((t=>new Ye(t)))})),v(Ye);const Qe="active",Ge="fade",Ze="show",Je=".active",ti=":scope > li > .active";class ei extends R{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Qe))return;let t;const e=r(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?ti:Je;t=Y.find(e,i),t=t[t.length-1]}const s=t?$.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if($.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const n=()=>{$.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),$.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,n):n()}_activate(t,e,i){const s=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?Y.children(e,Je):Y.find(ti,e))[0],n=i&&s&&s.classList.contains(Ge),o=()=>this._transitionComplete(t,s,i);s&&n?(s.classList.remove(Ze),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Qe);const t=Y.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Qe),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Qe),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),f(t),t.classList.contains(Ge)&&t.classList.add(Ze);let s=t.parentNode;if(s&&"LI"===s.nodeName&&(s=s.parentNode),s&&s.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&Y.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Qe))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=ei.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}$.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),u(this)||ei.getOrCreateInstance(this).show()})),v(ei);const ii="toast",si="hide",ni="show",oi="showing",ri={animation:"boolean",autohide:"boolean",delay:"number"},ai={animation:!0,autohide:!0,delay:5e3};class li extends R{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return ri}static get Default(){return ai}static get NAME(){return ii}show(){$.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(si),f(this._element),this._element.classList.add(ni),this._element.classList.add(oi),this._queueCallback((()=>{this._element.classList.remove(oi),$.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(ni)&&($.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(oi),this._queueCallback((()=>{this._element.classList.add(si),this._element.classList.remove(oi),this._element.classList.remove(ni),$.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(ni)&&this._element.classList.remove(ni),super.dispose()}_getConfig(t){return t={...ai,...X.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},h(ii,t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){$.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),$.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),$.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),$.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=li.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return F(li),v(li),{Alert:q,Button:U,Carousel:at,Collapse:mt,Dropdown:Ht,Modal:he,Offcanvas:me,Popover:Fe,ScrollSpy:Ye,Tab:ei,Toast:li,Tooltip:$e}})); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/src/base/theme/bootsier/assets/js/bootstrap.min.js.map b/src/base/theme/bootsier/assets/js/bootstrap.min.js.map new file mode 100644 index 00000000..835a3d6b --- /dev/null +++ b/src/base/theme/bootsier/assets/js/bootstrap.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/data.js","../../js/src/base-component.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/dom/manipulator.js","../../js/src/dom/selector-engine.js","../../js/src/carousel.js","../../js/src/collapse.js","../../js/src/dropdown.js","../../js/src/util/scrollbar.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"names":["TRANSITION_END","getSelector","element","selector","getAttribute","hrefAttr","includes","startsWith","split","trim","getSelectorFromElement","document","querySelector","getElementFromSelector","triggerTransitionEnd","dispatchEvent","Event","isElement","obj","jquery","nodeType","getElement","length","typeCheckConfig","componentName","config","configTypes","Object","keys","forEach","property","expectedTypes","value","valueType","toString","call","match","toLowerCase","RegExp","test","TypeError","toUpperCase","isVisible","getClientRects","getComputedStyle","getPropertyValue","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","parentNode","noop","reflow","offsetHeight","getjQuery","jQuery","window","body","DOMContentLoadedCallbacks","isRTL","dir","defineJQueryPlugin","plugin","callback","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","readyState","addEventListener","push","execute","executeAfterTransition","transitionElement","waitForTransition","emulatedDuration","transitionDuration","transitionDelay","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","getTransitionDurationFromElement","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","index","indexOf","listLength","Math","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","customEventsRegex","nativeEvents","Set","getUidEvent","uid","getEvent","findHandler","events","delegationSelector","uidEventList","i","len","event","originalHandler","normalizeParams","originalTypeEvent","delegationFn","delegation","typeEvent","getTypeEvent","has","addHandler","oneOff","wrapFn","relatedTarget","delegateTarget","this","handlers","previousFn","replace","domElements","querySelectorAll","EventHandler","off","type","apply","bootstrapDelegationHandler","bootstrapHandler","removeHandler","Boolean","on","one","inNamespace","isNamespace","elementEvent","namespace","storeElementEvent","handlerKey","removeNamespacedHandlers","slice","keyHandlers","trigger","args","isNative","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","evt","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","createEvent","initEvent","CustomEvent","cancelable","key","defineProperty","get","preventDefault","elementMap","Map","Data","set","instance","instanceMap","size","console","error","Array","from","remove","delete","BaseComponent","constructor","_element","DATA_KEY","dispose","EVENT_KEY","getOwnPropertyNames","propertyName","_queueCallback","isAnimated","static","getInstance","VERSION","Error","enableDismissTrigger","component","method","clickEvent","tagName","closest","getOrCreateInstance","Alert","close","_destroyElement","each","data","undefined","SELECTOR_DATA_TOGGLE","Button","toggle","setAttribute","normalizeData","val","normalizeDataKey","chr","button","Manipulator","setDataAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","dataset","filter","pureKey","charAt","getDataAttribute","offset","rect","getBoundingClientRect","top","pageYOffset","left","pageXOffset","position","offsetTop","offsetLeft","SelectorEngine","find","concat","Element","prototype","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","map","join","el","Default","interval","keyboard","slide","pause","wrap","touch","DefaultType","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","KEY_TO_DIRECTION","ArrowLeft","ArrowRight","EVENT_SLID","CLASS_NAME_ACTIVE","SELECTOR_ACTIVE_ITEM","Carousel","super","_items","_interval","_activeElement","_isPaused","_isSliding","touchTimeout","touchStartX","touchDeltaX","_config","_getConfig","_indicatorsElement","_touchSupported","navigator","maxTouchPoints","_pointerEvent","PointerEvent","_addEventListeners","_slide","nextWhenVisible","hidden","cycle","clearInterval","_updateInterval","setInterval","visibilityState","bind","to","activeIndex","_getItemIndex","order","_handleSwipe","absDeltax","abs","direction","_keydown","_addTouchEventListeners","hasPointerPenTouch","pointerType","start","clientX","touches","move","end","clearTimeout","itemImg","add","_getItemByOrder","isNext","_triggerSlideEvent","eventDirectionName","targetIndex","fromIndex","_setActiveIndicatorElement","activeIndicator","indicators","parseInt","elementInterval","defaultInterval","directionOrOrder","_directionToOrder","activeElementIndex","nextElement","nextElementIndex","isCycling","directionalClassName","orderClassName","_orderToDirection","triggerSlidEvent","completeCallBack","action","ride","carouselInterface","slideIndex","dataApiClickHandler","carousels","parent","CLASS_NAME_SHOW","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_COLLAPSED","CLASS_NAME_DEEPER_CHILDREN","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElem","_selector","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activesData","actives","container","tempActiveData","elemActive","dimension","_getDimension","style","scrollSize","triggerArrayLength","selected","triggerArray","isOpen","ESCAPE_KEY","SPACE_KEY","ARROW_UP_KEY","ARROW_DOWN_KEY","REGEXP_KEYDOWN","EVENT_CLICK_DATA_API","EVENT_KEYDOWN_DATA_API","SELECTOR_MENU","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","boundary","reference","display","popperConfig","autoClose","Dropdown","_popper","_menu","_getMenuElement","_inNavbar","_detectNavbar","getParentFromElement","_createPopper","focus","_completeHide","destroy","update","Popper","referenceElement","_getPopperConfig","isDisplayStatic","modifiers","modifier","enabled","createPopper","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","placement","options","_selectMenuItem","items","toggles","context","composedPath","isMenuTarget","isActive","stopPropagation","getToggleButton","clearMenus","dataApiKeydownHandler","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","ScrollBarHelper","getWidth","documentWidth","clientWidth","innerWidth","width","_disableOverFlow","_setElementAttributes","calculatedValue","_saveInitialAttribute","overflow","styleProp","scrollbarWidth","_applyManipulationCallback","reset","_resetElementAttributes","actualValue","removeProperty","callBack","isOverflowing","className","rootElement","clickCallback","EVENT_MOUSEDOWN","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","trapElement","autofocus","TAB_NAV_BACKWARD","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","elements","shiftKey","EVENT_HIDDEN","EVENT_SHOW","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_KEYDOWN_DISMISS","EVENT_MOUSEDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_ignoreBackdropClick","_scrollBar","_isAnimated","_adjustDialog","_setEscapeEvent","_setResizeEvent","_showBackdrop","_showElement","_hideModal","htmlElement","handleUpdate","modalBody","scrollTop","_triggerBackdropTransition","_resetAdjustments","currentTarget","scrollHeight","isModalOverflowing","clientHeight","overflowY","isBodyOverflowing","paddingLeft","paddingRight","showEvent","allReadyOpen","scroll","OPEN_SELECTOR","Offcanvas","visibility","blur","uriAttributes","SAFE_URL_PATTERN","DATA_URL_PATTERN","allowedAttribute","attribute","allowedAttributeList","attributeName","nodeName","nodeValue","regExp","attributeRegex","sanitizeHtml","unsafeHtml","allowList","sanitizeFn","createdDocument","DOMParser","parseFromString","elementName","attributeList","allowedAttributes","innerHTML","DISALLOWED_ATTRIBUTES","animation","template","title","delay","html","fallbackPlacements","customClass","sanitize","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","a","area","b","br","col","code","div","em","hr","h1","h2","h3","h4","h5","h6","img","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","HIDE","HIDDEN","SHOW","SHOWN","INSERTED","CLICK","FOCUSIN","FOCUSOUT","MOUSEENTER","MOUSELEAVE","CLASS_NAME_FADE","HOVER_STATE_SHOW","HOVER_STATE_OUT","SELECTOR_TOOLTIP_INNER","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","Tooltip","_isEnabled","_timeout","_hoverState","_activeTrigger","tip","_setListeners","enable","disable","toggleEnabled","_initializeOnDelegatedTarget","click","_isWithActiveTrigger","_enter","_leave","getTipElement","_hideModalHandler","_disposePopper","isWithContent","shadowRoot","isInTheDom","ownerDocument","getTitle","tipId","prefix","floor","random","getElementById","getUID","attachment","_getAttachment","_addAttachmentClass","_resolvePossibleFunction","prevHoverState","_cleanTipClass","setContent","_sanitizeAndSetContent","content","templateElement","setElementContent","textContent","updateAttachment","_getDelegateConfig","phase","_handlePopperPlacementChange","onFirstUpdate","_getBasicClassPrefix","eventIn","eventOut","_fixTitle","originalTitleType","dataAttributes","dataAttr","basicClassPrefixRegex","tabClass","token","tClass","state","popper","Popover","_getContent","SELECTOR_LINK_ITEMS","METHOD_POSITION","ScrollSpy","_scrollElement","_offsets","_targets","_activeTarget","_scrollHeight","_process","refresh","autoMethod","offsetMethod","offsetBase","_getScrollTop","_getScrollHeight","targetSelector","targetBCR","height","item","sort","_getOffsetHeight","innerHeight","maxScroll","_activate","_clear","queries","link","listGroup","navItem","node","spy","SELECTOR_ACTIVE","SELECTOR_ACTIVE_UL","Tab","listElement","itemSelector","hideEvent","complete","active","isTransitioning","_transitionComplete","dropdownChild","dropdownElement","dropdown","CLASS_NAME_HIDE","CLASS_NAME_SHOWING","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","_onInteraction","isInteracting"],"mappings":"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","sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1000000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n// Shoutout AngusCroll (https://goo.gl/pxwQGp)\nconst toType = obj => {\n if (obj === null || obj === undefined) {\n return `${obj}`\n }\n\n return {}.toString.call(obj).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * --------------------------------------------------------------------------\n * Public Util Api\n * --------------------------------------------------------------------------\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttr = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttr || (!hrefAttr.includes('#') && !hrefAttr.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {\n hrefAttr = `#${hrefAttr.split('#')[1]}`\n }\n\n selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null\n }\n\n return selector\n}\n\nconst getSelectorFromElement = element => {\n const selector = getSelector(element)\n\n if (selector) {\n return document.querySelector(selector) ? selector : null\n }\n\n return null\n}\n\nconst getElementFromSelector = element => {\n const selector = getSelector(element)\n\n return selector ? document.querySelector(selector) : null\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = obj => {\n if (!obj || typeof obj !== 'object') {\n return false\n }\n\n if (typeof obj.jquery !== 'undefined') {\n obj = obj[0]\n }\n\n return typeof obj.nodeType !== 'undefined'\n}\n\nconst getElement = obj => {\n if (isElement(obj)) { // it's a jQuery object or a node element\n return obj.jquery ? obj[0] : obj\n }\n\n if (typeof obj === 'string' && obj.length > 0) {\n return document.querySelector(obj)\n }\n\n return null\n}\n\nconst typeCheckConfig = (componentName, config, configTypes) => {\n Object.keys(configTypes).forEach(property => {\n const expectedTypes = configTypes[property]\n const value = config[property]\n const valueType = value && isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${componentName.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n })\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n return getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n // eslint-disable-next-line no-unused-expressions\n element.offsetHeight\n}\n\nconst getjQuery = () => {\n const { jQuery } = window\n\n if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n DOMContentLoadedCallbacks.forEach(callback => callback())\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = callback => {\n if (typeof callback === 'function') {\n callback()\n }\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element depending on the direction and if cycle is allowed\n if (index === -1) {\n return list[!shouldGetNext && isCycleAllowed ? list.length - 1 : 0]\n }\n\n const listLength = list.length\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n getElement,\n getUID,\n getSelectorFromElement,\n getElementFromSelector,\n getTransitionDurationFromElement,\n triggerTransitionEnd,\n isElement,\n typeCheckConfig,\n isVisible,\n isDisabled,\n findShadowRoot,\n noop,\n getNextActiveElement,\n reflow,\n getjQuery,\n onDOMContentLoaded,\n isRTL,\n defineJQueryPlugin,\n execute,\n executeAfterTransition\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\nconst customEventsRegex = /^(mouseenter|mouseleave)/i\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * ------------------------------------------------------------------------\n * Private methods\n * ------------------------------------------------------------------------\n */\n\nfunction getUidEvent(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getEvent(element) {\n const uid = getUidEvent(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n event.delegateTarget = element\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (let i = domElements.length; i--;) {\n if (domElements[i] === target) {\n event.delegateTarget = target\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n\n // To please ESLint\n return null\n }\n}\n\nfunction findHandler(events, handler, delegationSelector = null) {\n const uidEventList = Object.keys(events)\n\n for (let i = 0, len = uidEventList.length; i < len; i++) {\n const event = events[uidEventList[i]]\n\n if (event.originalHandler === handler && event.delegationSelector === delegationSelector) {\n return event\n }\n }\n\n return null\n}\n\nfunction normalizeParams(originalTypeEvent, handler, delegationFn) {\n const delegation = typeof handler === 'string'\n const originalHandler = delegation ? delegationFn : handler\n\n let typeEvent = getTypeEvent(originalTypeEvent)\n const isNative = nativeEvents.has(typeEvent)\n\n if (!isNative) {\n typeEvent = originalTypeEvent\n }\n\n return [delegation, originalHandler, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFn, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n if (!handler) {\n handler = delegationFn\n delegationFn = null\n }\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (customEventsRegex.test(originalTypeEvent)) {\n const wrapFn = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n if (delegationFn) {\n delegationFn = wrapFn(delegationFn)\n } else {\n handler = wrapFn(handler)\n }\n }\n\n const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn)\n const events = getEvent(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFn = findHandler(handlers, originalHandler, delegation ? handler : null)\n\n if (previousFn) {\n previousFn.oneOff = previousFn.oneOff && oneOff\n\n return\n }\n\n const uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = delegation ?\n bootstrapDelegationHandler(element, handler, delegationFn) :\n bootstrapHandler(element, handler)\n\n fn.delegationSelector = delegation ? handler : null\n fn.originalHandler = originalHandler\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, delegation)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n Object.keys(storeElementEvent).forEach(handlerKey => {\n if (handlerKey.includes(namespace)) {\n const event = storeElementEvent[handlerKey]\n\n removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector)\n }\n })\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFn) {\n addHandler(element, event, handler, delegationFn, false)\n },\n\n one(element, event, handler, delegationFn) {\n addHandler(element, event, handler, delegationFn, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFn) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getEvent(element)\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof originalHandler !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!events || !events[typeEvent]) {\n return\n }\n\n removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null)\n return\n }\n\n if (isNamespace) {\n Object.keys(events).forEach(elementEvent => {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n })\n }\n\n const storeElementEvent = events[typeEvent] || {}\n Object.keys(storeElementEvent).forEach(keyHandlers => {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n const event = storeElementEvent[keyHandlers]\n\n removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector)\n }\n })\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n const isNative = nativeEvents.has(typeEvent)\n\n let jQueryEvent\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n let evt = null\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n if (isNative) {\n evt = document.createEvent('HTMLEvents')\n evt.initEvent(typeEvent, bubbles, true)\n } else {\n evt = new CustomEvent(event, {\n bubbles,\n cancelable: true\n })\n }\n\n // merge custom information in our event\n if (typeof args !== 'undefined') {\n Object.keys(args).forEach(key => {\n Object.defineProperty(evt, key, {\n get() {\n return args[key]\n }\n })\n })\n }\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && typeof jQueryEvent !== 'undefined') {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data'\nimport {\n executeAfterTransition,\n getElement\n} from './util/index'\nimport EventHandler from './dom/event-handler'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst VERSION = '5.1.3'\n\nclass BaseComponent {\n constructor(element) {\n element = getElement(element)\n\n if (!element) {\n return\n }\n\n this._element = element\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n Object.getOwnPropertyNames(this).forEach(propertyName => {\n this[propertyName] = null\n })\n }\n\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n /** Static */\n\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler'\nimport { getElementFromSelector, isDisabled } from './index'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { defineJQueryPlugin } from './util/index'\nimport EventHandler from './dom/event-handler'\nimport BaseComponent from './base-component'\nimport { enableDismissTrigger } from './util/component-functions'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Alert extends BaseComponent {\n // Getters\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Alert to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { defineJQueryPlugin } from './util/index'\nimport EventHandler from './dom/event-handler'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\n\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Button extends BaseComponent {\n // Getters\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Button to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(val) {\n if (val === 'true') {\n return true\n }\n\n if (val === 'false') {\n return false\n }\n\n if (val === Number(val).toString()) {\n return Number(val)\n }\n\n if (val === '' || val === 'null') {\n return null\n }\n\n return val\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n\n Object.keys(element.dataset)\n .filter(key => key.startsWith('bs'))\n .forEach(key => {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)\n attributes[pureKey] = normalizeData(element.dataset[key])\n })\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n },\n\n offset(element) {\n const rect = element.getBoundingClientRect()\n\n return {\n top: rect.top + window.pageYOffset,\n left: rect.left + window.pageXOffset\n }\n },\n\n position(element) {\n return {\n top: element.offsetTop,\n left: element.offsetLeft\n }\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible } from '../util/index'\n\nconst NODE_TEXT = 3\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children)\n .filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n\n let ancestor = element.parentNode\n\n while (ancestor && ancestor.nodeType === Node.ELEMENT_NODE && ancestor.nodeType !== NODE_TEXT) {\n if (ancestor.matches(selector)) {\n parents.push(ancestor)\n }\n\n ancestor = ancestor.parentNode\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(', ')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElementFromSelector,\n isRTL,\n isVisible,\n getNextActiveElement,\n reflow,\n triggerTransitionEnd,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n slide: false,\n pause: 'hover',\n wrap: true,\n touch: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)',\n keyboard: 'boolean',\n slide: '(boolean|string)',\n pause: '(string|boolean)',\n wrap: 'boolean',\n touch: 'boolean'\n}\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ACTIVE_ITEM = '.active.carousel-item'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_INDICATOR = '[data-bs-target]'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._items = null\n this._interval = null\n this._activeElement = null\n this._isPaused = false\n this._isSliding = false\n this.touchTimeout = null\n this.touchStartX = 0\n this.touchDeltaX = 0\n\n this._config = this._getConfig(config)\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n this._pointerEvent = Boolean(window.PointerEvent)\n\n this._addEventListeners()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause(event) {\n if (!event) {\n this._isPaused = true\n }\n\n if (SelectorEngine.findOne(SELECTOR_NEXT_PREV, this._element)) {\n triggerTransitionEnd(this._element)\n this.cycle(true)\n }\n\n clearInterval(this._interval)\n this._interval = null\n }\n\n cycle(event) {\n if (!event) {\n this._isPaused = false\n }\n\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n\n if (this._config && this._config.interval && !this._isPaused) {\n this._updateInterval()\n\n this._interval = setInterval(\n (document.visibilityState ? this.nextWhenVisible : this.next).bind(this),\n this._config.interval\n )\n }\n }\n\n to(index) {\n this._activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n const activeIndex = this._getItemIndex(this._activeElement)\n\n if (index > this._items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n if (activeIndex === index) {\n this.pause()\n this.cycle()\n return\n }\n\n const order = index > activeIndex ?\n ORDER_NEXT :\n ORDER_PREV\n\n this._slide(order, this._items[index])\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' ? config : {})\n }\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _handleSwipe() {\n const absDeltax = Math.abs(this.touchDeltaX)\n\n if (absDeltax <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltax / this.touchDeltaX\n\n this.touchDeltaX = 0\n\n if (!direction) {\n return\n }\n\n this._slide(direction > 0 ? DIRECTION_RIGHT : DIRECTION_LEFT)\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, event => this.pause(event))\n EventHandler.on(this._element, EVENT_MOUSELEAVE, event => this.cycle(event))\n }\n\n if (this._config.touch && this._touchSupported) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n const hasPointerPenTouch = event => {\n return this._pointerEvent &&\n (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n const start = event => {\n if (hasPointerPenTouch(event)) {\n this.touchStartX = event.clientX\n } else if (!this._pointerEvent) {\n this.touchStartX = event.touches[0].clientX\n }\n }\n\n const move = event => {\n // ensure swiping with one touch and not pinching\n this.touchDeltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this.touchStartX\n }\n\n const end = event => {\n if (hasPointerPenTouch(event)) {\n this.touchDeltaX = event.clientX - this.touchStartX\n }\n\n this._handleSwipe()\n if (this._config.pause === 'hover') {\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(event => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n }\n\n SelectorEngine.find(SELECTOR_ITEM_IMG, this._element).forEach(itemImg => {\n EventHandler.on(itemImg, EVENT_DRAG_START, event => event.preventDefault())\n })\n\n if (this._pointerEvent) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => end(event))\n }\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(direction)\n }\n }\n\n _getItemIndex(element) {\n this._items = element && element.parentNode ?\n SelectorEngine.find(SELECTOR_ITEM, element.parentNode) :\n []\n\n return this._items.indexOf(element)\n }\n\n _getItemByOrder(order, activeElement) {\n const isNext = order === ORDER_NEXT\n return getNextActiveElement(this._items, activeElement, isNext, this._config.wrap)\n }\n\n _triggerSlideEvent(relatedTarget, eventDirectionName) {\n const targetIndex = this._getItemIndex(relatedTarget)\n const fromIndex = this._getItemIndex(SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element))\n\n return EventHandler.trigger(this._element, EVENT_SLIDE, {\n relatedTarget,\n direction: eventDirectionName,\n from: fromIndex,\n to: targetIndex\n })\n }\n\n _setActiveIndicatorElement(element) {\n if (this._indicatorsElement) {\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const indicators = SelectorEngine.find(SELECTOR_INDICATOR, this._indicatorsElement)\n\n for (let i = 0; i < indicators.length; i++) {\n if (Number.parseInt(indicators[i].getAttribute('data-bs-slide-to'), 10) === this._getItemIndex(element)) {\n indicators[i].classList.add(CLASS_NAME_ACTIVE)\n indicators[i].setAttribute('aria-current', 'true')\n break\n }\n }\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n if (elementInterval) {\n this._config.defaultInterval = this._config.defaultInterval || this._config.interval\n this._config.interval = elementInterval\n } else {\n this._config.interval = this._config.defaultInterval || this._config.interval\n }\n }\n\n _slide(directionOrOrder, element) {\n const order = this._directionToOrder(directionOrOrder)\n const activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n const activeElementIndex = this._getItemIndex(activeElement)\n const nextElement = element || this._getItemByOrder(order, activeElement)\n\n const nextElementIndex = this._getItemIndex(nextElement)\n const isCycling = Boolean(this._interval)\n\n const isNext = order === ORDER_NEXT\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n const eventDirectionName = this._orderToDirection(order)\n\n if (nextElement && nextElement.classList.contains(CLASS_NAME_ACTIVE)) {\n this._isSliding = false\n return\n }\n\n if (this._isSliding) {\n return\n }\n\n const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName)\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n return\n }\n\n this._isSliding = true\n\n if (isCycling) {\n this.pause()\n }\n\n this._setActiveIndicatorElement(nextElement)\n this._activeElement = nextElement\n\n const triggerSlidEvent = () => {\n EventHandler.trigger(this._element, EVENT_SLID, {\n relatedTarget: nextElement,\n direction: eventDirectionName,\n from: activeElementIndex,\n to: nextElementIndex\n })\n }\n\n if (this._element.classList.contains(CLASS_NAME_SLIDE)) {\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n setTimeout(triggerSlidEvent, 0)\n }\n\n this._queueCallback(completeCallBack, activeElement, true)\n } else {\n activeElement.classList.remove(CLASS_NAME_ACTIVE)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n this._isSliding = false\n triggerSlidEvent()\n }\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _directionToOrder(direction) {\n if (![DIRECTION_RIGHT, DIRECTION_LEFT].includes(direction)) {\n return direction\n }\n\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (![ORDER_NEXT, ORDER_PREV].includes(order)) {\n return order\n }\n\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n\n static carouselInterface(element, config) {\n const data = Carousel.getOrCreateInstance(element, config)\n\n let { _config } = data\n if (typeof config === 'object') {\n _config = {\n ..._config,\n ...config\n }\n }\n\n const action = typeof config === 'string' ? config : _config.slide\n\n if (typeof config === 'number') {\n data.to(config)\n } else if (typeof action === 'string') {\n if (typeof data[action] === 'undefined') {\n throw new TypeError(`No method named \"${action}\"`)\n }\n\n data[action]()\n } else if (_config.interval && _config.ride) {\n data.pause()\n data.cycle()\n }\n }\n\n static jQueryInterface(config) {\n return this.each(function () {\n Carousel.carouselInterface(this, config)\n })\n }\n\n static dataApiClickHandler(event) {\n const target = getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n const config = {\n ...Manipulator.getDataAttributes(target),\n ...Manipulator.getDataAttributes(this)\n }\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n config.interval = false\n }\n\n Carousel.carouselInterface(target, config)\n\n if (slideIndex) {\n Carousel.getInstance(target).to(slideIndex)\n }\n\n event.preventDefault()\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, Carousel.dataApiClickHandler)\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (let i = 0, len = carousels.length; i < len; i++) {\n Carousel.carouselInterface(carousels[i], Carousel.getInstance(carousels[i]))\n }\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Carousel to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElement,\n getSelectorFromElement,\n getElementFromSelector,\n reflow,\n typeCheckConfig\n} from './util/index'\nimport Data from './dom/data'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst Default = {\n toggle: true,\n parent: null\n}\n\nconst DefaultType = {\n toggle: 'boolean',\n parent: '(null|element)'\n}\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._isTransitioning = false\n this._config = this._getConfig(config)\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (let i = 0, len = toggleList.length; i < len; i++) {\n const elem = toggleList[i]\n const selector = getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElem => foundElem === this._element)\n\n if (selector !== null && filterElement.length) {\n this._selector = selector\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let actives = []\n let activesData\n\n if (this._config.parent) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n actives = SelectorEngine.find(SELECTOR_ACTIVES, this._config.parent).filter(elem => !children.includes(elem)) // remove children if greater depth\n }\n\n const container = SelectorEngine.findOne(this._selector)\n if (actives.length) {\n const tempActiveData = actives.find(elem => container !== elem)\n activesData = tempActiveData ? Collapse.getInstance(tempActiveData) : null\n\n if (activesData && activesData._isTransitioning) {\n return\n }\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n actives.forEach(elemActive => {\n if (container !== elemActive) {\n Collapse.getOrCreateInstance(elemActive, { toggle: false }).hide()\n }\n\n if (!activesData) {\n Data.set(elemActive, DATA_KEY, null)\n }\n })\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n const triggerArrayLength = this._triggerArray.length\n for (let i = 0; i < triggerArrayLength; i++) {\n const trigger = this._triggerArray[i]\n const elem = getElementFromSelector(trigger)\n\n if (elem && !this._isShown(elem)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...config\n }\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n SelectorEngine.find(SELECTOR_DATA_TOGGLE, this._config.parent).filter(elem => !children.includes(elem))\n .forEach(element => {\n const selected = getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n })\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n triggerArray.forEach(elem => {\n if (isOpen) {\n elem.classList.remove(CLASS_NAME_COLLAPSED)\n } else {\n elem.classList.add(CLASS_NAME_COLLAPSED)\n }\n\n elem.setAttribute('aria-expanded', isOpen)\n })\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n const selector = getSelectorFromElement(this)\n const selectorElements = SelectorEngine.find(selector)\n\n selectorElements.forEach(element => {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n })\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Collapse to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\n\nimport {\n defineJQueryPlugin,\n getElement,\n getElementFromSelector,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst SPACE_KEY = 'Space'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEY}|${ARROW_DOWN_KEY}|${ESCAPE_KEY}`)\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_NAVBAR = 'navbar'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]'\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\n\nconst Default = {\n offset: [0, 2],\n boundary: 'clippingParents',\n reference: 'toggle',\n display: 'dynamic',\n popperConfig: null,\n autoClose: true\n}\n\nconst DefaultType = {\n offset: '(array|string|function)',\n boundary: '(string|element)',\n reference: '(string|element|object)',\n display: 'string',\n popperConfig: '(null|object|function)',\n autoClose: '(boolean|string)'\n}\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._popper = null\n this._config = this._getConfig(config)\n this._menu = this._getMenuElement()\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown(this._menu)) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n const parent = Dropdown.getParentFromElement(this._element)\n // Totally disable Popper for Dropdowns in Navbar\n if (this._inNavbar) {\n Manipulator.setDataAttribute(this._menu, 'popper', 'none')\n } else {\n this._createPopper(parent)\n }\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement &&\n !parent.closest(SELECTOR_NAVBAR_NAV)) {\n [].concat(...document.body.children)\n .forEach(elem => EventHandler.on(elem, 'mouseover', noop))\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown(this._menu)) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n [].concat(...document.body.children)\n .forEach(elem => EventHandler.off(elem, 'mouseover', noop))\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = {\n ...this.constructor.Default,\n ...Manipulator.getDataAttributes(this._element),\n ...config\n }\n\n typeCheckConfig(NAME, config, this.constructor.DefaultType)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper(parent) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n const isDisplayStatic = popperConfig.modifiers.find(modifier => modifier.name === 'applyStyles' && modifier.enabled === false)\n\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n\n if (isDisplayStatic) {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static')\n }\n }\n\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getMenuElement() {\n return SelectorEngine.next(this._element, SELECTOR_MENU)[0]\n }\n\n _getPlacement() {\n const parentDropdown = this._element.parentNode\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(`.${CLASS_NAME_NAVBAR}`) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(val => Number.parseInt(val, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display\n if (this._config.display === 'static') {\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible)\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event && (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY))) {\n return\n }\n\n const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (let i = 0, len = toggles.length; i < len; i++) {\n const context = Dropdown.getInstance(toggles[i])\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n if (!context._isShown()) {\n continue\n }\n\n const relatedTarget = {\n relatedTarget: context._element\n }\n\n if (event) {\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static getParentFromElement(element) {\n return getElementFromSelector(element) || element.parentNode\n }\n\n static dataApiKeydownHandler(event) {\n // If not input/textarea:\n // - And not a key in REGEXP_KEYDOWN => not a dropdown command\n // If input/textarea:\n // - If space key => not a dropdown command\n // - If key is other than escape\n // - If key is not up or down => not a dropdown command\n // - If trigger inside the menu => not a dropdown command\n if (/input|textarea/i.test(event.target.tagName) ?\n event.key === SPACE_KEY || (event.key !== ESCAPE_KEY &&\n ((event.key !== ARROW_DOWN_KEY && event.key !== ARROW_UP_KEY) ||\n event.target.closest(SELECTOR_MENU))) :\n !REGEXP_KEYDOWN.test(event.key)) {\n return\n }\n\n const isActive = this.classList.contains(CLASS_NAME_SHOW)\n\n if (!isActive && event.key === ESCAPE_KEY) {\n return\n }\n\n event.preventDefault()\n event.stopPropagation()\n\n if (isDisabled(this)) {\n return\n }\n\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0]\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (event.key === ESCAPE_KEY) {\n instance.hide()\n return\n }\n\n if (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY) {\n if (!isActive) {\n instance.show()\n }\n\n instance._selectMenuItem(event)\n return\n }\n\n if (!isActive || event.key === SPACE_KEY) {\n Dropdown.clearMenus()\n }\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Dropdown to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine'\nimport Manipulator from '../dom/manipulator'\nimport { isElement } from './index'\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, 'paddingRight', calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width)\n }\n\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProp, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProp)\n const calculatedValue = window.getComputedStyle(element)[styleProp]\n element.style[styleProp] = `${callback(Number.parseFloat(calculatedValue))}px`\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, 'paddingRight')\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight')\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight')\n }\n\n _saveInitialAttribute(element, styleProp) {\n const actualValue = element.style[styleProp]\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProp, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProp) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProp)\n if (typeof value === 'undefined') {\n element.style.removeProperty(styleProp)\n } else {\n Manipulator.removeDataAttribute(element, styleProp)\n element.style[styleProp] = value\n }\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n } else {\n SelectorEngine.find(selector, this._element).forEach(callBack)\n }\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler'\nimport { execute, executeAfterTransition, getElement, reflow, typeCheckConfig } from './index'\n\nconst Default = {\n className: 'modal-backdrop',\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n isAnimated: false,\n rootElement: 'body', // give the choice to place backdrop under different elements\n clickCallback: null\n}\n\nconst DefaultType = {\n className: 'string',\n isVisible: 'boolean',\n isAnimated: 'boolean',\n rootElement: '(element|string)',\n clickCallback: '(function|null)'\n}\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nclass Backdrop {\n constructor(config) {\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n if (this._config.isAnimated) {\n reflow(this._getElement())\n }\n\n this._getElement().classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n // Private\n\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _getConfig(config) {\n config = {\n ...Default,\n ...(typeof config === 'object' ? config : {})\n }\n\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n this._config.rootElement.append(this._getElement())\n\n EventHandler.on(this._getElement(), EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler'\nimport SelectorEngine from '../dom/selector-engine'\nimport { typeCheckConfig } from './index'\n\nconst Default = {\n trapElement: null, // The element to trap focus inside of\n autofocus: true\n}\n\nconst DefaultType = {\n trapElement: 'element',\n autofocus: 'boolean'\n}\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nclass FocusTrap {\n constructor(config) {\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n activate() {\n const { trapElement, autofocus } = this._config\n\n if (this._isActive) {\n return\n }\n\n if (autofocus) {\n trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n\n _handleFocusin(event) {\n const { target } = event\n const { trapElement } = this._config\n\n if (target === document || target === trapElement || trapElement.contains(target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n\n _getConfig(config) {\n config = {\n ...Default,\n ...(typeof config === 'object' ? config : {})\n }\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElementFromSelector,\n isRTL,\n isVisible,\n reflow,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport ScrollBarHelper from './util/scrollbar'\nimport BaseComponent from './base-component'\nimport Backdrop from './util/backdrop'\nimport FocusTrap from './util/focustrap'\nimport { enableDismissTrigger } from './util/component-functions'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n focus: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n focus: 'boolean'\n}\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEUP_DISMISS = `mouseup.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._config = this._getConfig(config)\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._ignoreBackdropClick = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n\n if (this._isAnimated()) {\n this._isTransitioning = true\n }\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._setEscapeEvent()\n this._setResizeEvent()\n\n EventHandler.on(this._dialog, EVENT_MOUSEDOWN_DISMISS, () => {\n EventHandler.one(this._element, EVENT_MOUSEUP_DISMISS, event => {\n if (event.target === this._element) {\n this._ignoreBackdropClick = true\n }\n })\n })\n\n this._showBackdrop(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n const isAnimated = this._isAnimated()\n\n if (isAnimated) {\n this._isTransitioning = true\n }\n\n this._setEscapeEvent()\n this._setResizeEvent()\n\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n EventHandler.off(this._element, EVENT_CLICK_DISMISS)\n EventHandler.off(this._dialog, EVENT_MOUSEDOWN_DISMISS)\n\n this._queueCallback(() => this._hideModal(), this._element, isAnimated)\n }\n\n dispose() {\n [window, this._dialog]\n .forEach(htmlElement => EventHandler.off(htmlElement, EVENT_KEY))\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' ? config : {})\n }\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _showElement(relatedTarget) {\n const isAnimated = this._isAnimated()\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n\n if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {\n // Don't move modal's DOM position\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n if (isAnimated) {\n reflow(this._element)\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, isAnimated)\n }\n\n _setEscapeEvent() {\n if (this._isShown) {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (this._config.keyboard && event.key === ESCAPE_KEY) {\n event.preventDefault()\n this.hide()\n } else if (!this._config.keyboard && event.key === ESCAPE_KEY) {\n this._triggerBackdropTransition()\n }\n })\n } else {\n EventHandler.off(this._element, EVENT_KEYDOWN_DISMISS)\n }\n }\n\n _setResizeEvent() {\n if (this._isShown) {\n EventHandler.on(window, EVENT_RESIZE, () => this._adjustDialog())\n } else {\n EventHandler.off(window, EVENT_RESIZE)\n }\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _showBackdrop(callback) {\n EventHandler.on(this._element, EVENT_CLICK_DISMISS, event => {\n if (this._ignoreBackdropClick) {\n this._ignoreBackdropClick = false\n return\n }\n\n if (event.target !== event.currentTarget) {\n return\n }\n\n if (this._config.backdrop === true) {\n this.hide()\n } else if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n }\n })\n\n this._backdrop.show(callback)\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const { classList, scrollHeight, style } = this._element\n const isModalOverflowing = scrollHeight > document.documentElement.clientHeight\n\n // return if the following background transition hasn't yet completed\n if ((!isModalOverflowing && style.overflowY === 'hidden') || classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n style.overflowY = 'hidden'\n }\n\n classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n classList.remove(CLASS_NAME_STATIC)\n if (!isModalOverflowing) {\n this._queueCallback(() => {\n style.overflowY = ''\n }, this._dialog)\n }\n }, this._dialog)\n\n this._element.focus()\n }\n\n // ----------------------------------------------------------------------\n // the following methods are used to handle overflowing modals\n // ----------------------------------------------------------------------\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if ((!isBodyOverflowing && isModalOverflowing && !isRTL()) || (isBodyOverflowing && !isModalOverflowing && isRTL())) {\n this._element.style.paddingLeft = `${scrollbarWidth}px`\n }\n\n if ((isBodyOverflowing && !isModalOverflowing && !isRTL()) || (!isBodyOverflowing && isModalOverflowing && isRTL())) {\n this._element.style.paddingRight = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking moddal toggler while another one is open\n const allReadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (allReadyOpen) {\n Modal.getInstance(allReadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Modal to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElementFromSelector,\n isDisabled,\n isVisible,\n typeCheckConfig\n} from './util/index'\nimport ScrollBarHelper from './util/scrollbar'\nimport EventHandler from './dom/event-handler'\nimport BaseComponent from './base-component'\nimport SelectorEngine from './dom/selector-engine'\nimport Manipulator from './dom/manipulator'\nimport Backdrop from './util/backdrop'\nimport FocusTrap from './util/focustrap'\nimport { enableDismissTrigger } from './util/component-functions'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: 'boolean',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._config = this._getConfig(config)\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n\n static get NAME() {\n return NAME\n }\n\n static get Default() {\n return Default\n }\n\n // Public\n\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._element.style.visibility = 'visible'\n\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const completeCallBack = () => {\n if (!this._config.scroll) {\n this._focustrap.activate()\n }\n\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._element.style.visibility = 'hidden'\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' ? config : {})\n }\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _initializeBackDrop() {\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible: this._config.backdrop,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: () => this.hide()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (this._config.keyboard && event.key === ESCAPE_KEY) {\n this.hide()\n }\n })\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const allReadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (allReadyOpen && allReadyOpen !== target) {\n Offcanvas.getInstance(allReadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () =>\n SelectorEngine.find(OPEN_SELECTOR).forEach(el => Offcanvas.getOrCreateInstance(el).show())\n)\n\nenableDismissTrigger(Offcanvas)\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\n/**\n * A pattern that recognizes a commonly useful subset of URLs that are safe.\n *\n * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts\n */\nconst SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i\n\n/**\n * A pattern that matches safe data URLs. Only matches image, video and audio types.\n *\n * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts\n */\nconst DATA_URL_PATTERN = /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[\\d+/a-z]+=*$/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue) || DATA_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n const regExp = allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n\n // Check if a regular expression validates the attribute.\n for (let i = 0, len = regExp.length; i < len; i++) {\n if (regExp[i].test(attributeName)) {\n return true\n }\n }\n\n return false\n}\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n div: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFn && typeof sanitizeFn === 'function') {\n return sanitizeFn(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (let i = 0, len = elements.length; i < len; i++) {\n const element = elements[i]\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n attributeList.forEach(attribute => {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n })\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\n\nimport {\n defineJQueryPlugin,\n findShadowRoot,\n getElement,\n getUID,\n isElement,\n isRTL,\n noop,\n typeCheckConfig\n} from './util/index'\nimport { DefaultAllowlist, sanitizeHtml } from './util/sanitizer'\nimport Data from './dom/data'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'tooltip'\nconst DATA_KEY = 'bs.tooltip'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst CLASS_PREFIX = 'bs-tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst DefaultType = {\n animation: 'boolean',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string',\n delay: '(number|object)',\n html: 'boolean',\n selector: '(string|boolean)',\n placement: '(string|function)',\n offset: '(array|string|function)',\n container: '(string|element|boolean)',\n fallbackPlacements: 'array',\n boundary: '(string|element)',\n customClass: '(string|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n allowList: 'object',\n popperConfig: '(null|object|function)'\n}\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n animation: true,\n template: '<div class=\"tooltip\" role=\"tooltip\">' +\n '<div class=\"tooltip-arrow\"></div>' +\n '<div class=\"tooltip-inner\"></div>' +\n '</div>',\n trigger: 'hover focus',\n title: '',\n delay: 0,\n html: false,\n selector: false,\n placement: 'top',\n offset: [0, 0],\n container: false,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n boundary: 'clippingParents',\n customClass: '',\n sanitize: true,\n sanitizeFn: null,\n allowList: DefaultAllowlist,\n popperConfig: null\n}\n\nconst Event = {\n HIDE: `hide${EVENT_KEY}`,\n HIDDEN: `hidden${EVENT_KEY}`,\n SHOW: `show${EVENT_KEY}`,\n SHOWN: `shown${EVENT_KEY}`,\n INSERTED: `inserted${EVENT_KEY}`,\n CLICK: `click${EVENT_KEY}`,\n FOCUSIN: `focusin${EVENT_KEY}`,\n FOCUSOUT: `focusout${EVENT_KEY}`,\n MOUSEENTER: `mouseenter${EVENT_KEY}`,\n MOUSELEAVE: `mouseleave${EVENT_KEY}`\n}\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst HOVER_STATE_SHOW = 'show'\nconst HOVER_STATE_OUT = 'out'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org)')\n }\n\n super(element)\n\n // private\n this._isEnabled = true\n this._timeout = 0\n this._hoverState = ''\n this._activeTrigger = {}\n this._popper = null\n\n // Protected\n this._config = this._getConfig(config)\n this.tip = null\n\n this._setListeners()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n static get Event() {\n return Event\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n // Public\n\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle(event) {\n if (!this._isEnabled) {\n return\n }\n\n if (event) {\n const context = this._initializeOnDelegatedTarget(event)\n\n context._activeTrigger.click = !context._activeTrigger.click\n\n if (context._isWithActiveTrigger()) {\n context._enter(null, context)\n } else {\n context._leave(null, context)\n }\n } else {\n if (this.getTipElement().classList.contains(CLASS_NAME_SHOW)) {\n this._leave(null, this)\n return\n }\n\n this._enter(null, this)\n }\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this.tip) {\n this.tip.remove()\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this.isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.Event.SHOW)\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = shadowRoot === null ?\n this._element.ownerDocument.documentElement.contains(this._element) :\n shadowRoot.contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // A trick to recreate a tooltip in case a new title is given by using the NOT documented `data-bs-original-title`\n // This will be removed later in favor of a `setContent` method\n if (this.constructor.NAME === 'tooltip' && this.tip && this.getTitle() !== this.tip.querySelector(SELECTOR_TOOLTIP_INNER).innerHTML) {\n this._disposePopper()\n this.tip.remove()\n this.tip = null\n }\n\n const tip = this.getTipElement()\n const tipId = getUID(this.constructor.NAME)\n\n tip.setAttribute('id', tipId)\n this._element.setAttribute('aria-describedby', tipId)\n\n if (this._config.animation) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n const placement = typeof this._config.placement === 'function' ?\n this._config.placement.call(this, tip, this._element) :\n this._config.placement\n\n const attachment = this._getAttachment(placement)\n this._addAttachmentClass(attachment)\n\n const { container } = this._config\n Data.set(tip, this.constructor.DATA_KEY, this)\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.Event.INSERTED)\n }\n\n if (this._popper) {\n this._popper.update()\n } else {\n this._popper = Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n const customClass = this._resolvePossibleFunction(this._config.customClass)\n if (customClass) {\n tip.classList.add(...customClass.split(' '))\n }\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n [].concat(...document.body.children).forEach(element => {\n EventHandler.on(element, 'mouseover', noop)\n })\n }\n\n const complete = () => {\n const prevHoverState = this._hoverState\n\n this._hoverState = null\n EventHandler.trigger(this._element, this.constructor.Event.SHOWN)\n\n if (prevHoverState === HOVER_STATE_OUT) {\n this._leave(null, this)\n }\n }\n\n const isAnimated = this.tip.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(complete, this.tip, isAnimated)\n }\n\n hide() {\n if (!this._popper) {\n return\n }\n\n const tip = this.getTipElement()\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (this._hoverState !== HOVER_STATE_SHOW) {\n tip.remove()\n }\n\n this._cleanTipClass()\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.Event.HIDDEN)\n\n this._disposePopper()\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.Event.HIDE)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n [].concat(...document.body.children)\n .forEach(element => EventHandler.off(element, 'mouseover', noop))\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n\n const isAnimated = this.tip.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(complete, this.tip, isAnimated)\n this._hoverState = ''\n }\n\n update() {\n if (this._popper !== null) {\n this._popper.update()\n }\n }\n\n // Protected\n\n isWithContent() {\n return Boolean(this.getTitle())\n }\n\n getTipElement() {\n if (this.tip) {\n return this.tip\n }\n\n const element = document.createElement('div')\n element.innerHTML = this._config.template\n\n const tip = element.children[0]\n this.setContent(tip)\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n\n this.tip = tip\n return this.tip\n }\n\n setContent(tip) {\n this._sanitizeAndSetContent(tip, this.getTitle(), SELECTOR_TOOLTIP_INNER)\n }\n\n _sanitizeAndSetContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!content && templateElement) {\n templateElement.remove()\n return\n }\n\n // we use append for html objects to maintain js events\n this.setElementContent(templateElement, content)\n }\n\n setElementContent(element, content) {\n if (element === null) {\n return\n }\n\n if (isElement(content)) {\n content = getElement(content)\n\n // content is a DOM node or a jQuery\n if (this._config.html) {\n if (content.parentNode !== element) {\n element.innerHTML = ''\n element.append(content)\n }\n } else {\n element.textContent = content.textContent\n }\n\n return\n }\n\n if (this._config.html) {\n if (this._config.sanitize) {\n content = sanitizeHtml(content, this._config.allowList, this._config.sanitizeFn)\n }\n\n element.innerHTML = content\n } else {\n element.textContent = content\n }\n }\n\n getTitle() {\n const title = this._element.getAttribute('data-bs-original-title') || this._config.title\n\n return this._resolvePossibleFunction(title)\n }\n\n updateAttachment(attachment) {\n if (attachment === 'right') {\n return 'end'\n }\n\n if (attachment === 'left') {\n return 'start'\n }\n\n return attachment\n }\n\n // Private\n\n _initializeOnDelegatedTarget(event, context) {\n return context || this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(val => Number.parseInt(val, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(content) {\n return typeof content === 'function' ? content.call(this._element) : content\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'onChange',\n enabled: true,\n phase: 'afterWrite',\n fn: data => this._handlePopperPlacementChange(data)\n }\n ],\n onFirstUpdate: data => {\n if (data.options.placement !== data.placement) {\n this._handlePopperPlacementChange(data)\n }\n }\n }\n\n return {\n ...defaultBsPopperConfig,\n ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)\n }\n }\n\n _addAttachmentClass(attachment) {\n this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(attachment)}`)\n }\n\n _getAttachment(placement) {\n return AttachmentMap[placement.toUpperCase()]\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n triggers.forEach(trigger => {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.Event.CLICK, this._config.selector, event => this.toggle(event))\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.Event.MOUSEENTER :\n this.constructor.Event.FOCUSIN\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.Event.MOUSELEAVE :\n this.constructor.Event.FOCUSOUT\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => this._enter(event))\n EventHandler.on(this._element, eventOut, this._config.selector, event => this._leave(event))\n }\n })\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._config.selector) {\n this._config = {\n ...this._config,\n trigger: 'manual',\n selector: ''\n }\n } else {\n this._fixTitle()\n }\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n const originalTitleType = typeof this._element.getAttribute('data-bs-original-title')\n\n if (title || originalTitleType !== 'string') {\n this._element.setAttribute('data-bs-original-title', title || '')\n if (title && !this._element.getAttribute('aria-label') && !this._element.textContent) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('title', '')\n }\n }\n\n _enter(event, context) {\n context = this._initializeOnDelegatedTarget(event, context)\n\n if (event) {\n context._activeTrigger[\n event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER\n ] = true\n }\n\n if (context.getTipElement().classList.contains(CLASS_NAME_SHOW) || context._hoverState === HOVER_STATE_SHOW) {\n context._hoverState = HOVER_STATE_SHOW\n return\n }\n\n clearTimeout(context._timeout)\n\n context._hoverState = HOVER_STATE_SHOW\n\n if (!context._config.delay || !context._config.delay.show) {\n context.show()\n return\n }\n\n context._timeout = setTimeout(() => {\n if (context._hoverState === HOVER_STATE_SHOW) {\n context.show()\n }\n }, context._config.delay.show)\n }\n\n _leave(event, context) {\n context = this._initializeOnDelegatedTarget(event, context)\n\n if (event) {\n context._activeTrigger[\n event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER\n ] = context._element.contains(event.relatedTarget)\n }\n\n if (context._isWithActiveTrigger()) {\n return\n }\n\n clearTimeout(context._timeout)\n\n context._hoverState = HOVER_STATE_OUT\n\n if (!context._config.delay || !context._config.delay.hide) {\n context.hide()\n return\n }\n\n context._timeout = setTimeout(() => {\n if (context._hoverState === HOVER_STATE_OUT) {\n context.hide()\n }\n }, context._config.delay.hide)\n }\n\n _isWithActiveTrigger() {\n for (const trigger in this._activeTrigger) {\n if (this._activeTrigger[trigger]) {\n return true\n }\n }\n\n return false\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n Object.keys(dataAttributes).forEach(dataAttr => {\n if (DISALLOWED_ATTRIBUTES.has(dataAttr)) {\n delete dataAttributes[dataAttr]\n }\n })\n\n config = {\n ...this.constructor.Default,\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n typeCheckConfig(NAME, config, this.constructor.DefaultType)\n\n if (config.sanitize) {\n config.template = sanitizeHtml(config.template, config.allowList, config.sanitizeFn)\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const key in this._config) {\n if (this.constructor.Default[key] !== this._config[key]) {\n config[key] = this._config[key]\n }\n }\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _cleanTipClass() {\n const tip = this.getTipElement()\n const basicClassPrefixRegex = new RegExp(`(^|\\\\s)${this._getBasicClassPrefix()}\\\\S+`, 'g')\n const tabClass = tip.getAttribute('class').match(basicClassPrefixRegex)\n if (tabClass !== null && tabClass.length > 0) {\n tabClass.map(token => token.trim())\n .forEach(tClass => tip.classList.remove(tClass))\n }\n }\n\n _getBasicClassPrefix() {\n return CLASS_PREFIX\n }\n\n _handlePopperPlacementChange(popperData) {\n const { state } = popperData\n\n if (!state) {\n return\n }\n\n this.tip = state.elements.popper\n this._cleanTipClass()\n this._addAttachmentClass(this._getAttachment(state.placement))\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Tooltip to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { defineJQueryPlugin } from './util/index'\nimport Tooltip from './tooltip'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'popover'\nconst DATA_KEY = 'bs.popover'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst CLASS_PREFIX = 'bs-popover'\n\nconst Default = {\n ...Tooltip.Default,\n placement: 'right',\n offset: [0, 8],\n trigger: 'click',\n content: '',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(string|element|function)'\n}\n\nconst Event = {\n HIDE: `hide${EVENT_KEY}`,\n HIDDEN: `hidden${EVENT_KEY}`,\n SHOW: `show${EVENT_KEY}`,\n SHOWN: `shown${EVENT_KEY}`,\n INSERTED: `inserted${EVENT_KEY}`,\n CLICK: `click${EVENT_KEY}`,\n FOCUSIN: `focusin${EVENT_KEY}`,\n FOCUSOUT: `focusout${EVENT_KEY}`,\n MOUSEENTER: `mouseenter${EVENT_KEY}`,\n MOUSELEAVE: `mouseleave${EVENT_KEY}`\n}\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Popover extends Tooltip {\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n static get Event() {\n return Event\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n // Overrides\n\n isWithContent() {\n return this.getTitle() || this._getContent()\n }\n\n setContent(tip) {\n this._sanitizeAndSetContent(tip, this.getTitle(), SELECTOR_TITLE)\n this._sanitizeAndSetContent(tip, this._getContent(), SELECTOR_CONTENT)\n }\n\n // Private\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n _getBasicClassPrefix() {\n return CLASS_PREFIX\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Popover to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElement,\n getSelectorFromElement,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst Default = {\n offset: 10,\n method: 'auto',\n target: ''\n}\n\nconst DefaultType = {\n offset: 'number',\n method: 'string',\n target: '(string|element)'\n}\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_SCROLL = `scroll${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}, .${CLASS_NAME_DROPDOWN_ITEM}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst METHOD_OFFSET = 'offset'\nconst METHOD_POSITION = 'position'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element)\n this._scrollElement = this._element.tagName === 'BODY' ? window : this._element\n this._config = this._getConfig(config)\n this._offsets = []\n this._targets = []\n this._activeTarget = null\n this._scrollHeight = 0\n\n EventHandler.on(this._scrollElement, EVENT_SCROLL, () => this._process())\n\n this.refresh()\n this._process()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n refresh() {\n const autoMethod = this._scrollElement === this._scrollElement.window ?\n METHOD_OFFSET :\n METHOD_POSITION\n\n const offsetMethod = this._config.method === 'auto' ?\n autoMethod :\n this._config.method\n\n const offsetBase = offsetMethod === METHOD_POSITION ?\n this._getScrollTop() :\n 0\n\n this._offsets = []\n this._targets = []\n this._scrollHeight = this._getScrollHeight()\n\n const targets = SelectorEngine.find(SELECTOR_LINK_ITEMS, this._config.target)\n\n targets.map(element => {\n const targetSelector = getSelectorFromElement(element)\n const target = targetSelector ? SelectorEngine.findOne(targetSelector) : null\n\n if (target) {\n const targetBCR = target.getBoundingClientRect()\n if (targetBCR.width || targetBCR.height) {\n return [\n Manipulator[offsetMethod](target).top + offsetBase,\n targetSelector\n ]\n }\n }\n\n return null\n })\n .filter(item => item)\n .sort((a, b) => a[0] - b[0])\n .forEach(item => {\n this._offsets.push(item[0])\n this._targets.push(item[1])\n })\n }\n\n dispose() {\n EventHandler.off(this._scrollElement, EVENT_KEY)\n super.dispose()\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' && config ? config : {})\n }\n\n config.target = getElement(config.target) || document.documentElement\n\n typeCheckConfig(NAME, config, DefaultType)\n\n return config\n }\n\n _getScrollTop() {\n return this._scrollElement === window ?\n this._scrollElement.pageYOffset :\n this._scrollElement.scrollTop\n }\n\n _getScrollHeight() {\n return this._scrollElement.scrollHeight || Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight\n )\n }\n\n _getOffsetHeight() {\n return this._scrollElement === window ?\n window.innerHeight :\n this._scrollElement.getBoundingClientRect().height\n }\n\n _process() {\n const scrollTop = this._getScrollTop() + this._config.offset\n const scrollHeight = this._getScrollHeight()\n const maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight()\n\n if (this._scrollHeight !== scrollHeight) {\n this.refresh()\n }\n\n if (scrollTop >= maxScroll) {\n const target = this._targets[this._targets.length - 1]\n\n if (this._activeTarget !== target) {\n this._activate(target)\n }\n\n return\n }\n\n if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {\n this._activeTarget = null\n this._clear()\n return\n }\n\n for (let i = this._offsets.length; i--;) {\n const isActiveTarget = this._activeTarget !== this._targets[i] &&\n scrollTop >= this._offsets[i] &&\n (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1])\n\n if (isActiveTarget) {\n this._activate(this._targets[i])\n }\n }\n }\n\n _activate(target) {\n this._activeTarget = target\n\n this._clear()\n\n const queries = SELECTOR_LINK_ITEMS.split(',')\n .map(selector => `${selector}[data-bs-target=\"${target}\"],${selector}[href=\"${target}\"]`)\n\n const link = SelectorEngine.findOne(queries.join(','), this._config.target)\n\n link.classList.add(CLASS_NAME_ACTIVE)\n if (link.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, link.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n } else {\n SelectorEngine.parents(link, SELECTOR_NAV_LIST_GROUP)\n .forEach(listGroup => {\n // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n SelectorEngine.prev(listGroup, `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`)\n .forEach(item => item.classList.add(CLASS_NAME_ACTIVE))\n\n // Handle special case when .nav-link is inside .nav-item\n SelectorEngine.prev(listGroup, SELECTOR_NAV_ITEMS)\n .forEach(navItem => {\n SelectorEngine.children(navItem, SELECTOR_NAV_LINKS)\n .forEach(item => item.classList.add(CLASS_NAME_ACTIVE))\n })\n })\n }\n\n EventHandler.trigger(this._scrollElement, EVENT_ACTIVATE, {\n relatedTarget: target\n })\n }\n\n _clear() {\n SelectorEngine.find(SELECTOR_LINK_ITEMS, this._config.target)\n .filter(node => node.classList.contains(CLASS_NAME_ACTIVE))\n .forEach(node => node.classList.remove(CLASS_NAME_ACTIVE))\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = ScrollSpy.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n SelectorEngine.find(SELECTOR_DATA_SPY)\n .forEach(spy => new ScrollSpy(spy))\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .ScrollSpy to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(ScrollSpy)\n\nexport default ScrollSpy\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): tab.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElementFromSelector,\n isDisabled,\n reflow\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'tab'\nconst DATA_KEY = 'bs.tab'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ACTIVE_UL = ':scope > li > .active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\nconst SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Tab extends BaseComponent {\n // Getters\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n show() {\n if ((this._element.parentNode &&\n this._element.parentNode.nodeType === Node.ELEMENT_NODE &&\n this._element.classList.contains(CLASS_NAME_ACTIVE))) {\n return\n }\n\n let previous\n const target = getElementFromSelector(this._element)\n const listElement = this._element.closest(SELECTOR_NAV_LIST_GROUP)\n\n if (listElement) {\n const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? SELECTOR_ACTIVE_UL : SELECTOR_ACTIVE\n previous = SelectorEngine.find(itemSelector, listElement)\n previous = previous[previous.length - 1]\n }\n\n const hideEvent = previous ?\n EventHandler.trigger(previous, EVENT_HIDE, {\n relatedTarget: this._element\n }) :\n null\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget: previous\n })\n\n if (showEvent.defaultPrevented || (hideEvent !== null && hideEvent.defaultPrevented)) {\n return\n }\n\n this._activate(this._element, listElement)\n\n const complete = () => {\n EventHandler.trigger(previous, EVENT_HIDDEN, {\n relatedTarget: this._element\n })\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget: previous\n })\n }\n\n if (target) {\n this._activate(target, target.parentNode, complete)\n } else {\n complete()\n }\n }\n\n // Private\n\n _activate(element, container, callback) {\n const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ?\n SelectorEngine.find(SELECTOR_ACTIVE_UL, container) :\n SelectorEngine.children(container, SELECTOR_ACTIVE)\n\n const active = activeElements[0]\n const isTransitioning = callback && (active && active.classList.contains(CLASS_NAME_FADE))\n\n const complete = () => this._transitionComplete(element, active, callback)\n\n if (active && isTransitioning) {\n active.classList.remove(CLASS_NAME_SHOW)\n this._queueCallback(complete, element, true)\n } else {\n complete()\n }\n }\n\n _transitionComplete(element, active, callback) {\n if (active) {\n active.classList.remove(CLASS_NAME_ACTIVE)\n\n const dropdownChild = SelectorEngine.findOne(SELECTOR_DROPDOWN_ACTIVE_CHILD, active.parentNode)\n\n if (dropdownChild) {\n dropdownChild.classList.remove(CLASS_NAME_ACTIVE)\n }\n\n if (active.getAttribute('role') === 'tab') {\n active.setAttribute('aria-selected', false)\n }\n }\n\n element.classList.add(CLASS_NAME_ACTIVE)\n if (element.getAttribute('role') === 'tab') {\n element.setAttribute('aria-selected', true)\n }\n\n reflow(element)\n\n if (element.classList.contains(CLASS_NAME_FADE)) {\n element.classList.add(CLASS_NAME_SHOW)\n }\n\n let parent = element.parentNode\n if (parent && parent.nodeName === 'LI') {\n parent = parent.parentNode\n }\n\n if (parent && parent.classList.contains(CLASS_NAME_DROPDOWN_MENU)) {\n const dropdownElement = element.closest(SELECTOR_DROPDOWN)\n\n if (dropdownElement) {\n SelectorEngine.find(SELECTOR_DROPDOWN_TOGGLE, dropdownElement)\n .forEach(dropdown => dropdown.classList.add(CLASS_NAME_ACTIVE))\n }\n\n element.setAttribute('aria-expanded', true)\n }\n\n if (callback) {\n callback()\n }\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tab.getOrCreateInstance(this)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const data = Tab.getOrCreateInstance(this)\n data.show()\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Tab to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Tab)\n\nexport default Tab\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): toast.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n reflow,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport BaseComponent from './base-component'\nimport { enableDismissTrigger } from './util/component-functions'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'toast'\nconst DATA_KEY = 'bs.toast'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\n\nconst DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n}\n\nconst Default = {\n animation: true,\n autohide: true,\n delay: 5000\n}\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Toast extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._config = this._getConfig(config)\n this._timeout = null\n this._hasMouseInteraction = false\n this._hasKeyboardInteraction = false\n this._setListeners()\n }\n\n // Getters\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n show() {\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._clearTimeout()\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE)\n }\n\n const complete = () => {\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN)\n\n this._maybeScheduleHide()\n }\n\n this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\n reflow(this._element)\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n hide() {\n if (!this._element.classList.contains(CLASS_NAME_SHOW)) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const complete = () => {\n this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\n this._element.classList.remove(CLASS_NAME_SHOWING)\n this._element.classList.remove(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.classList.add(CLASS_NAME_SHOWING)\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n dispose() {\n this._clearTimeout()\n\n if (this._element.classList.contains(CLASS_NAME_SHOW)) {\n this._element.classList.remove(CLASS_NAME_SHOW)\n }\n\n super.dispose()\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' && config ? config : {})\n }\n\n typeCheckConfig(NAME, config, this.constructor.DefaultType)\n\n return config\n }\n\n _maybeScheduleHide() {\n if (!this._config.autohide) {\n return\n }\n\n if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\n return\n }\n\n this._timeout = setTimeout(() => {\n this.hide()\n }, this._config.delay)\n }\n\n _onInteraction(event, isInteracting) {\n switch (event.type) {\n case 'mouseover':\n case 'mouseout':\n this._hasMouseInteraction = isInteracting\n break\n case 'focusin':\n case 'focusout':\n this._hasKeyboardInteraction = isInteracting\n break\n default:\n break\n }\n\n if (isInteracting) {\n this._clearTimeout()\n return\n }\n\n const nextElement = event.relatedTarget\n if (this._element === nextElement || this._element.contains(nextElement)) {\n return\n }\n\n this._maybeScheduleHide()\n }\n\n _setListeners() {\n EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\n EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\n }\n\n _clearTimeout() {\n clearTimeout(this._timeout)\n this._timeout = null\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Toast.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n }\n })\n }\n}\n\nenableDismissTrigger(Toast)\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Toast to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Toast)\n\nexport default Toast\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): index.umd.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './src/alert'\nimport Button from './src/button'\nimport Carousel from './src/carousel'\nimport Collapse from './src/collapse'\nimport Dropdown from './src/dropdown'\nimport Modal from './src/modal'\nimport Offcanvas from './src/offcanvas'\nimport Popover from './src/popover'\nimport ScrollSpy from './src/scrollspy'\nimport Tab from './src/tab'\nimport Toast from './src/toast'\nimport Tooltip from './src/tooltip'\n\nexport default {\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Offcanvas,\n Popover,\n ScrollSpy,\n Tab,\n Toast,\n Tooltip\n}\n"]} \ No newline at end of file diff --git a/src/base/theme/bootsier/locales/en-US/bootsier.ftl b/src/base/theme/bootsier/locales/en-US/bootsier.ftl new file mode 100644 index 00000000..0e8969cd --- /dev/null +++ b/src/base/theme/bootsier/locales/en-US/bootsier.ftl @@ -0,0 +1,5 @@ +e404-description = Oops! Page Not Found +e404-message = The page you are looking for may have been removed, had its name changed, or is temporarily unavailable. +e500-description = Oops! Unexpected Error +e500-message = We're having an issue. Please report this error to an administrator. +back-homepage = Back to homepage diff --git a/src/base/theme/bootsier/locales/es-ES/bootsier.ftl b/src/base/theme/bootsier/locales/es-ES/bootsier.ftl new file mode 100644 index 00000000..998b54f2 --- /dev/null +++ b/src/base/theme/bootsier/locales/es-ES/bootsier.ftl @@ -0,0 +1,5 @@ +e404-description = ¡Vaya! Página No Encontrada +e404-message = La página que está buscando puede haber sido eliminada, cambiada de nombre o no está disponible temporalmente. +e500-description = ¡Vaya! Error Inesperado +e500-message = Está ocurriendo una incidencia. Por favor, informe de este error a un administrador. +back-homepage = Volver al inicio diff --git a/src/base/theme/bootsier/mod.rs b/src/base/theme/bootsier/mod.rs new file mode 100644 index 00000000..f0a0f61c --- /dev/null +++ b/src/base/theme/bootsier/mod.rs @@ -0,0 +1,82 @@ +use crate::prelude::*; + +include!(concat!(env!("OUT_DIR"), "/bootsier.rs")); + +localize!("en-US", "src/base/theme/bootsier/locales"); + +pub struct BootsierTheme; + +impl Theme for BootsierTheme { + fn name(&self) -> &str { + "Bootsier" + } + + fn configure_theme(&self, cfg: &mut server::web::ServiceConfig) { + cfg.service(actix_web_static_files::ResourceFiles::new( + "/bootsier", + generate() + )); + } + + fn before_render_page(&self, page: &mut Page) { + page.assets() + .with_favicon( + Favicon::new() + .with_icon("/bootsier/favicon.png") + ) + .add_stylesheet( + StyleSheet::source( + "/bootsier/css/bootstrap.min.css" + ) + .with_weight(-99) + ) + .add_javascript( + JavaScript::source( + "/bootsier/js/bootstrap.bundle.min.js" + ) + .with_weight(-98) + ) + .add_jquery(); + } + + fn render_error_page(&self, mut s: server::http::StatusCode) -> server::Result<Markup> { + let mut description = "e500-description"; + let mut message = "e500-description"; + match s { + server::http::StatusCode::NOT_FOUND => { + description = "e404-description"; + message = "e404-message"; + }, + _ => { + s = server::http::StatusCode::INTERNAL_SERVER_ERROR; + } + } + Page::prepare() + .with_title(format!("Error {}", s.as_str()).as_str()) + .add_to("content", Chunck::markup(html! { + div class="jumbotron" { + div class="media" { + img + src="/bootsier/images/caution.png" + class="mr-4" + style="width: 20%; max-width: 188px" + alt="Caution!"; + div class="media-body" { + h1 class="display-4" { (s) } + p class="lead" { (l(description)) } + hr class="my-4"; + p { (l(message)) } + a + class="btn btn-primary btn-lg" + href="/" + role="button" + { + (l("back-homepage")) + } + } + } + } + })) + .render() + } +} diff --git a/src/base/theme/mod.rs b/src/base/theme/mod.rs index b272be88..8794ed17 100644 --- a/src/base/theme/mod.rs +++ b/src/base/theme/mod.rs @@ -1 +1,3 @@ +pub mod aliner; pub mod minimal; +pub mod bootsier; diff --git a/src/config/settings.rs b/src/config/settings.rs index 4d791763..b2a758e7 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -109,7 +109,7 @@ Ajustes globales y valores predeterminados para las secciones *\[app\]*, "app.name" => "PageTop Application", "app.description" => "Developed with the amazing PageTop framework.", "app.language" => "en-US", - "app.theme" => "Minimal", + "app.theme" => "Bootsier", "app.startup_banner" => "Small", // [log] diff --git a/src/core/response/page/assets.rs b/src/core/response/page/assets.rs index d36c870e..2bffd73b 100644 --- a/src/core/response/page/assets.rs +++ b/src/core/response/page/assets.rs @@ -176,6 +176,7 @@ pub struct Assets { metadata : Vec<(String, String)>, stylesheets: Vec<StyleSheet>, javascripts: Vec<JavaScript>, + with_jquery: bool, seqid_count: u16, } @@ -186,6 +187,7 @@ impl Assets { metadata : Vec::new(), stylesheets: Vec::new(), javascripts: Vec::new(), + with_jquery: false, seqid_count: 0, } } @@ -222,6 +224,20 @@ impl Assets { self } + pub fn add_jquery(&mut self) -> &mut Self { + if !self.with_jquery { + self.add_javascript( + JavaScript::source( + "/assets/js/jquery.min.js?ver=3.6.0" + ) + .with_weight(i8::MIN) + .with_mode(JSMode::Normal) + ); + self.with_jquery = true; + } + self + } + pub fn render(&mut self) -> Markup { let ordered_css = &mut self.stylesheets; ordered_css.sort_by_key(|o| o.weight); diff --git a/src/core/server/mod.rs b/src/core/server/mod.rs index 713a7ae6..32e9ce92 100644 --- a/src/core/server/mod.rs +++ b/src/core/server/mod.rs @@ -1,5 +1,5 @@ pub use actix_web::{ - App, HttpRequest, HttpResponse, HttpServer, Responder, Result, web + App, HttpRequest, HttpResponse, HttpServer, Responder, Result, http, web }; mod main; diff --git a/src/core/state.rs b/src/core/state.rs index 88936bfd..307455a1 100644 --- a/src/core/state.rs +++ b/src/core/state.rs @@ -14,7 +14,9 @@ use std::collections::HashMap; pub static THEMES: Lazy<RwLock<Vec<&dyn Theme>>> = Lazy::new(|| { RwLock::new(vec![ + &base::theme::aliner::AlinerTheme, &base::theme::minimal::MinimalTheme, + &base::theme::bootsier::BootsierTheme, ]) }); @@ -24,7 +26,7 @@ pub static THEME: Lazy<&dyn Theme> = Lazy::new(|| { return *t; } } - &base::theme::minimal::MinimalTheme + &base::theme::bootsier::BootsierTheme }); pub fn register_theme(t: &'static (dyn Theme + 'static)) { diff --git a/src/core/theme/api.rs b/src/core/theme/api.rs index 26d71552..2f4a5682 100644 --- a/src/core/theme/api.rs +++ b/src/core/theme/api.rs @@ -1,6 +1,7 @@ use crate::core::server; use crate::core::theme::{Markup, html}; use crate::core::response::page::{Page, PageAssets, PageComponent}; +use crate::base::component::Chunck; /// Los temas deben implementar este "trait". pub trait Theme: Send + Sync { @@ -81,4 +82,15 @@ pub trait Theme: Send + Sync { } */ } + + fn render_error_page(&self, s: server::http::StatusCode) -> server::Result<Markup> { + Page::prepare() + .with_title(format!("Error {}", s.as_str()).as_str()) + .add_to("content", Chunck::markup(html! { + div { + h1 { (s) } + } + })) + .render() + } } From eddb397bc7cea6fa9480aab0f9873ff1de9ff18a Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 22 Feb 2022 20:45:18 +0100 Subject: [PATCH 013/244] =?UTF-8?q?Actualiza=20la=20estructura=20de=20los?= =?UTF-8?q?=20recursos=20est=C3=A1ticos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Se prepara PageTop para permitir en el futuro compilar los fuentes incluyendo los recursos estáticos dentro del ejecutable (tal y como está ahora), o usando una carpeta externa "static". --- CREDITS.md | 6 +- build.rs | 10 ++- src/base/theme/aliner/mod.rs | 6 +- .../theme/bootsier/assets/fonts/nunito.css | 70 ------------------ .../assets/fonts/nunito/cyrillic_400.woff2 | Bin 11248 -> 0 bytes .../assets/fonts/nunito/cyrillic_700.woff2 | Bin 11208 -> 0 bytes .../fonts/nunito/cyrillic_ext_400.woff2 | Bin 15308 -> 0 bytes .../fonts/nunito/cyrillic_ext_700.woff2 | Bin 15164 -> 0 bytes .../assets/fonts/nunito/latin_400.woff2 | Bin 18972 -> 0 bytes .../assets/fonts/nunito/latin_700.woff2 | Bin 19088 -> 0 bytes .../assets/fonts/nunito/latin_ext_400.woff2 | Bin 18380 -> 0 bytes .../assets/fonts/nunito/latin_ext_700.woff2 | Bin 18416 -> 0 bytes .../assets/fonts/nunito/vietnamese_400.woff2 | Bin 7568 -> 0 bytes .../assets/fonts/nunito/vietnamese_700.woff2 | Bin 7596 -> 0 bytes .../theme/bootsier/assets/js/bootstrap.min.js | 7 -- .../bootsier/assets/js/bootstrap.min.js.map | 1 - src/base/theme/bootsier/mod.rs | 12 +-- src/base/theme/minimal/mod.rs | 4 +- src/config/settings.rs | 30 +++----- src/core/all.rs | 7 ++ src/core/response/page/assets.rs | 2 +- .../core/server/figfonts}/slant.flf | 0 .../core/server/figfonts}/small.flf | 0 .../core/server/figfonts}/speed.flf | 0 .../core/server/figfonts}/starwars.flf | 0 src/core/server/main.rs | 10 +-- src/core/theme/api.rs | 8 +- .../assets => static/aliner}/css/styles.css | 0 .../bootsier}/css/bootstrap.min.css | 0 .../bootsier}/css/bootstrap.min.css.map | 0 .../bootsier}/images/caution.png | Bin .../bootsier}/js/bootstrap.bundle.min.js | 0 .../bootsier}/js/bootstrap.bundle.min.js.map | 0 .../assets => static/theme}/js/jquery.min.js | 0 .../assets => static/theme}/js/jquery.min.map | 0 35 files changed, 48 insertions(+), 125 deletions(-) delete mode 100644 src/base/theme/bootsier/assets/fonts/nunito.css delete mode 100644 src/base/theme/bootsier/assets/fonts/nunito/cyrillic_400.woff2 delete mode 100644 src/base/theme/bootsier/assets/fonts/nunito/cyrillic_700.woff2 delete mode 100644 src/base/theme/bootsier/assets/fonts/nunito/cyrillic_ext_400.woff2 delete mode 100644 src/base/theme/bootsier/assets/fonts/nunito/cyrillic_ext_700.woff2 delete mode 100644 src/base/theme/bootsier/assets/fonts/nunito/latin_400.woff2 delete mode 100644 src/base/theme/bootsier/assets/fonts/nunito/latin_700.woff2 delete mode 100644 src/base/theme/bootsier/assets/fonts/nunito/latin_ext_400.woff2 delete mode 100644 src/base/theme/bootsier/assets/fonts/nunito/latin_ext_700.woff2 delete mode 100644 src/base/theme/bootsier/assets/fonts/nunito/vietnamese_400.woff2 delete mode 100644 src/base/theme/bootsier/assets/fonts/nunito/vietnamese_700.woff2 delete mode 100644 src/base/theme/bootsier/assets/js/bootstrap.min.js delete mode 100644 src/base/theme/bootsier/assets/js/bootstrap.min.js.map rename {resources => src/core/server/figfonts}/slant.flf (100%) rename {resources => src/core/server/figfonts}/small.flf (100%) rename {resources => src/core/server/figfonts}/speed.flf (100%) rename {resources => src/core/server/figfonts}/starwars.flf (100%) rename {src/base/theme/aliner/assets => static/aliner}/css/styles.css (100%) rename {src/base/theme/bootsier/assets => static/bootsier}/css/bootstrap.min.css (100%) rename {src/base/theme/bootsier/assets => static/bootsier}/css/bootstrap.min.css.map (100%) rename {src/base/theme/bootsier/assets => static/bootsier}/images/caution.png (100%) rename {src/base/theme/bootsier/assets => static/bootsier}/js/bootstrap.bundle.min.js (100%) rename {src/base/theme/bootsier/assets => static/bootsier}/js/bootstrap.bundle.min.js.map (100%) rename {resources/assets => static/theme}/js/jquery.min.js (100%) rename {resources/assets => static/theme}/js/jquery.min.map (100%) diff --git a/CREDITS.md b/CREDITS.md index bd737e27..5b9979f4 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -1,9 +1,9 @@ # FIGfonts PageTop utiliza el paquete [figlet-rs](https://crates.io/crates/figlet-rs) de -*yuanbohan* para mostrar al inicio un rótulo con el nombre de la aplicación -usando [FIGlet](http://www.figlet.org/). Las fuentes incluidas en `resources` -son: +*yuanbohan*, que muestra al inicio de la ejecución un rótulo con el nombre de +la aplicación usando caracteres [FIGlet](http://www.figlet.org/). Las fuentes +incluidas en `resources` son: * [slant.flf](http://www.figlet.org/fontdb_example.cgi?font=slant.flf) por *Glenn Chappell*. diff --git a/build.rs b/build.rs index 75aee1d5..9b252213 100644 --- a/build.rs +++ b/build.rs @@ -4,28 +4,30 @@ use std::env; use std::path::Path; fn main() { - resource_dir("./resources/assets") + resource_dir("./static/theme") .with_generated_filename( Path::new(env::var("OUT_DIR").unwrap().as_str()) - .join("assets.rs") + .join("theme.rs") ) .with_generated_fn("assets") .build() .unwrap(); - resource_dir("./src/base/theme/aliner/assets") + resource_dir("./static/aliner") .with_generated_filename( Path::new(env::var("OUT_DIR").unwrap().as_str()) .join("aliner.rs") ) + .with_generated_fn("assets") .build() .unwrap(); - resource_dir("./src/base/theme/bootsier/assets") + resource_dir("./static/bootsier") .with_generated_filename( Path::new(env::var("OUT_DIR").unwrap().as_str()) .join("bootsier.rs") ) + .with_generated_fn("assets") .build() .unwrap(); } diff --git a/src/base/theme/aliner/mod.rs b/src/base/theme/aliner/mod.rs index 8ad4e291..68e7d509 100644 --- a/src/base/theme/aliner/mod.rs +++ b/src/base/theme/aliner/mod.rs @@ -5,14 +5,14 @@ include!(concat!(env!("OUT_DIR"), "/aliner.rs")); pub struct AlinerTheme; impl Theme for AlinerTheme { - fn name(&self) -> &str { - "Aliner" + fn name(&self) -> String { + "Aliner".to_string() } fn configure_theme(&self, cfg: &mut server::web::ServiceConfig) { cfg.service(actix_web_static_files::ResourceFiles::new( "/aliner", - generate() + assets() )); } diff --git a/src/base/theme/bootsier/assets/fonts/nunito.css b/src/base/theme/bootsier/assets/fonts/nunito.css deleted file mode 100644 index f444a08f..00000000 --- a/src/base/theme/bootsier/assets/fonts/nunito.css +++ /dev/null @@ -1,70 +0,0 @@ -@font-face { - font-family: 'Nunito'; - font-style: normal; - font-weight: 400; - src: url(/pagetop/fonts/nunito/cyrillic_ext_400.woff2) format('woff2'); - unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; -} -@font-face { - font-family: 'Nunito'; - font-style: normal; - font-weight: 400; - src: url(/pagetop/fonts/nunito/cyrillic_400.woff2) format('woff2'); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; -} -@font-face { - font-family: 'Nunito'; - font-style: normal; - font-weight: 400; - src: url(/pagetop/fonts/nunito/vietnamese_400.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} -@font-face { - font-family: 'Nunito'; - font-style: normal; - font-weight: 400; - src: url(/pagetop/fonts/nunito/latin_ext_400.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -@font-face { - font-family: 'Nunito'; - font-style: normal; - font-weight: 400; - src: url(/pagetop/fonts/nunito/latin_400.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -@font-face { - font-family: 'Nunito'; - font-style: normal; - font-weight: 700; - src: url(/pagetop/fonts/nunito/cyrillic_ext_700.woff2) format('woff2'); - unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; -} -@font-face { - font-family: 'Nunito'; - font-style: normal; - font-weight: 700; - src: url(/pagetop/fonts/nunito/cyrillic_700.woff2) format('woff2'); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; -} -@font-face { - font-family: 'Nunito'; - font-style: normal; - font-weight: 700; - src: url(/pagetop/fonts/nunito/vietnamese_700.woff2) format('woff2'); - unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; -} -@font-face { - font-family: 'Nunito'; - font-style: normal; - font-weight: 700; - src: url(/pagetop/fonts/nunito/latin_ext_700.woff2) format('woff2'); - unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; -} -@font-face { - font-family: 'Nunito'; - font-style: normal; - font-weight: 700; - src: url(/pagetop/fonts/nunito/latin_700.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} diff --git a/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_400.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_400.woff2 deleted file mode 100644 index cadafd359ff244c60bc4ad72a6f06d38e8e31eba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11248 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 ax^!^s)asj|cl@`}rFsASFY(Yp?G6B4bx>*m diff --git a/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_700.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_700.woff2 deleted file mode 100644 index 2b4950ff24895b57fc66398bad2f892916d8bb00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11208 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 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_ext_400.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_ext_400.woff2 deleted file mode 100644 index 5539f2e13a28cb3ebe3d732580615fc471225e02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15308 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 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_ext_700.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/cyrillic_ext_700.woff2 deleted file mode 100644 index 9f49fc13de796acbfb3b31845fc87ef947b18ec3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15164 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 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/latin_400.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/latin_400.woff2 deleted file mode 100644 index 2f9cc5964455b8f5ca989db989250dbebb1a5f66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18972 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 H?T~5}mj8_i diff --git a/src/base/theme/bootsier/assets/fonts/nunito/latin_700.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/latin_700.woff2 deleted file mode 100644 index 243810e4594c4c858d043e9dd3562bfd3b1adeff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19088 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 Tc<SUY`Kt13Q$5xzdK&-${v60d diff --git a/src/base/theme/bootsier/assets/fonts/nunito/latin_ext_400.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/latin_ext_400.woff2 deleted file mode 100644 index d859e4d3ceba36192ab6b0ac4e6e2e8ed21795d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18380 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 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/latin_ext_700.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/latin_ext_700.woff2 deleted file mode 100644 index 0f95acbcdd781cc2ffa1cb7ded7fe637b59a61d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18416 zcmV)TK(W7fPew8T0RR9107viu5dZ)H0JanW07r}f0RR9100000000000000000000 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 XMu&d5c*nl`nZ5LXaGxZcodEy<7R<vu diff --git a/src/base/theme/bootsier/assets/fonts/nunito/vietnamese_400.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/vietnamese_400.woff2 deleted file mode 100644 index 29df398069da61aee853e79efc918a5da50cfdf6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7568 zcmV;B9dF`yPew8T0RR9103DD35dZ)H07@hP039y?0RR9100000000000000000000 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 diff --git a/src/base/theme/bootsier/assets/fonts/nunito/vietnamese_700.woff2 b/src/base/theme/bootsier/assets/fonts/nunito/vietnamese_700.woff2 deleted file mode 100644 index efcc26dc5c69f23564e2cdbdf101e7fdf1e5ee79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7596 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 O#wJ^t_sl^H8{Ggk@tke| diff --git a/src/base/theme/bootsier/assets/js/bootstrap.min.js b/src/base/theme/bootsier/assets/js/bootstrap.min.js deleted file mode 100644 index d155068c..00000000 --- a/src/base/theme/bootsier/assets/js/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v5.1.3 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e(t.Popper)}(this,(function(t){"use strict";function e(t){if(t&&t.__esModule)return t;const e=Object.create(null);if(t)for(const i in t)if("default"!==i){const s=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,s.get?s:{enumerable:!0,get:()=>t[i]})}return e.default=t,Object.freeze(e)}const i=e(t),s="transitionend",n=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},o=t=>{const e=n(t);return e&&document.querySelector(e)?e:null},r=t=>{const e=n(t);return e?document.querySelector(e):null},a=t=>{t.dispatchEvent(new Event(s))},l=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),c=t=>l(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,h=(t,e,i)=>{Object.keys(i).forEach((s=>{const n=i[s],o=e[s],r=o&&l(o)?"element":null==(a=o)?`${a}`:{}.toString.call(a).match(/\s([a-z]+)/i)[1].toLowerCase();var a;if(!new RegExp(n).test(r))throw new TypeError(`${t.toUpperCase()}: Option "${s}" provided type "${r}" but expected type "${n}".`)}))},d=t=>!(!l(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),u=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),g=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?g(t.parentNode):null},_=()=>{},f=t=>{t.offsetHeight},p=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},m=[],b=()=>"rtl"===document.documentElement.dir,v=t=>{var e;e=()=>{const e=p();if(e){const i=t.NAME,s=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=s,t.jQueryInterface)}},"loading"===document.readyState?(m.length||document.addEventListener("DOMContentLoaded",(()=>{m.forEach((t=>t()))})),m.push(e)):e()},y=t=>{"function"==typeof t&&t()},E=(t,e,i=!0)=>{if(!i)return void y(t);const n=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const s=Number.parseFloat(e),n=Number.parseFloat(i);return s||n?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let o=!1;const r=({target:i})=>{i===e&&(o=!0,e.removeEventListener(s,r),y(t))};e.addEventListener(s,r),setTimeout((()=>{o||a(e)}),n)},w=(t,e,i,s)=>{let n=t.indexOf(e);if(-1===n)return t[!i&&s?t.length-1:0];const o=t.length;return n+=i?1:-1,s&&(n=(n+o)%o),t[Math.max(0,Math.min(n,o-1))]},A=/[^.]*(?=\..*)\.|.*/,T=/\..*/,C=/::\d+$/,k={};let L=1;const S={mouseenter:"mouseover",mouseleave:"mouseout"},O=/^(mouseenter|mouseleave)/i,N=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function D(t,e){return e&&`${e}::${L++}`||t.uidEvent||L++}function I(t){const e=D(t);return t.uidEvent=e,k[e]=k[e]||{},k[e]}function P(t,e,i=null){const s=Object.keys(t);for(let n=0,o=s.length;n<o;n++){const o=t[s[n]];if(o.originalHandler===e&&o.delegationSelector===i)return o}return null}function x(t,e,i){const s="string"==typeof e,n=s?i:e;let o=H(t);return N.has(o)||(o=t),[s,n,o]}function M(t,e,i,s,n){if("string"!=typeof e||!t)return;if(i||(i=s,s=null),O.test(e)){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};s?s=t(s):i=t(i)}const[o,r,a]=x(e,i,s),l=I(t),c=l[a]||(l[a]={}),h=P(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&n);const d=D(r,e.replace(A,"")),u=o?function(t,e,i){return function s(n){const o=t.querySelectorAll(e);for(let{target:r}=n;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return n.delegateTarget=r,s.oneOff&&$.off(t,n.type,e,i),i.apply(r,[n]);return null}}(t,i,s):function(t,e){return function i(s){return s.delegateTarget=t,i.oneOff&&$.off(t,s.type,e),e.apply(t,[s])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=n,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function j(t,e,i,s,n){const o=P(e[i],s,n);o&&(t.removeEventListener(i,o,Boolean(n)),delete e[i][o.uidEvent])}function H(t){return t=t.replace(T,""),S[t]||t}const $={on(t,e,i,s){M(t,e,i,s,!1)},one(t,e,i,s){M(t,e,i,s,!0)},off(t,e,i,s){if("string"!=typeof e||!t)return;const[n,o,r]=x(e,i,s),a=r!==e,l=I(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void j(t,l,r,o,n?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,s){const n=e[i]||{};Object.keys(n).forEach((o=>{if(o.includes(s)){const s=n[o];j(t,e,i,s.originalHandler,s.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const s=i.replace(C,"");if(!a||e.includes(s)){const e=h[i];j(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const s=p(),n=H(e),o=e!==n,r=N.has(n);let a,l=!0,c=!0,h=!1,d=null;return o&&s&&(a=s.Event(e,i),s(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(n,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},B=new Map,z={set(t,e,i){B.has(t)||B.set(t,new Map);const s=B.get(t);s.has(e)||0===s.size?s.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(t,e)=>B.has(t)&&B.get(t).get(e)||null,remove(t,e){if(!B.has(t))return;const i=B.get(t);i.delete(e),0===i.size&&B.delete(t)}};class R{constructor(t){(t=c(t))&&(this._element=t,z.set(this._element,this.constructor.DATA_KEY,this))}dispose(){z.remove(this._element,this.constructor.DATA_KEY),$.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){E(t,e,i)}static getInstance(t){return z.get(c(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const F=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;$.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),u(this))return;const n=r(this)||this.closest(`.${s}`);t.getOrCreateInstance(n)[e]()}))};class q extends R{static get NAME(){return"alert"}close(){if($.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),$.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}F(q,"close"),v(q);const W='[data-bs-toggle="button"]';class U extends R{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=U.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function K(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function V(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}$.on(document,"click.bs.button.data-api",W,(t=>{t.preventDefault();const e=t.target.closest(W);U.getOrCreateInstance(e).toggle()})),v(U);const X={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${V(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${V(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let s=i.replace(/^bs/,"");s=s.charAt(0).toLowerCase()+s.slice(1,s.length),e[s]=K(t.dataset[i])})),e},getDataAttribute:(t,e)=>K(t.getAttribute(`data-bs-${V(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},Y={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let s=t.parentNode;for(;s&&s.nodeType===Node.ELEMENT_NODE&&3!==s.nodeType;)s.matches(e)&&i.push(s),s=s.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(", ");return this.find(e,t).filter((t=>!u(t)&&d(t)))}},Q="carousel",G={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Z={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},J="next",tt="prev",et="left",it="right",st={ArrowLeft:it,ArrowRight:et},nt="slid.bs.carousel",ot="active",rt=".active.carousel-item";class at extends R{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=Y.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return G}static get NAME(){return Q}next(){this._slide(J)}nextWhenVisible(){!document.hidden&&d(this._element)&&this.next()}prev(){this._slide(tt)}pause(t){t||(this._isPaused=!0),Y.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(a(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=Y.findOne(rt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void $.one(this._element,nt,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?J:tt;this._slide(i,this._items[t])}_getConfig(t){return t={...G,...X.getDataAttributes(this._element),..."object"==typeof t?t:{}},h(Q,t,Z),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?it:et)}_addEventListeners(){this._config.keyboard&&$.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&($.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),$.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},s=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};Y.find(".carousel-item img",this._element).forEach((t=>{$.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?($.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),$.on(this._element,"pointerup.bs.carousel",(t=>s(t))),this._element.classList.add("pointer-event")):($.on(this._element,"touchstart.bs.carousel",(t=>e(t))),$.on(this._element,"touchmove.bs.carousel",(t=>i(t))),$.on(this._element,"touchend.bs.carousel",(t=>s(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=st[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?Y.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===J;return w(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),s=this._getItemIndex(Y.findOne(rt,this._element));return $.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:s,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=Y.findOne(".active",this._indicatorsElement);e.classList.remove(ot),e.removeAttribute("aria-current");const i=Y.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e<i.length;e++)if(Number.parseInt(i[e].getAttribute("data-bs-slide-to"),10)===this._getItemIndex(t)){i[e].classList.add(ot),i[e].setAttribute("aria-current","true");break}}}_updateInterval(){const t=this._activeElement||Y.findOne(rt,this._element);if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}_slide(t,e){const i=this._directionToOrder(t),s=Y.findOne(rt,this._element),n=this._getItemIndex(s),o=e||this._getItemByOrder(i,s),r=this._getItemIndex(o),a=Boolean(this._interval),l=i===J,c=l?"carousel-item-start":"carousel-item-end",h=l?"carousel-item-next":"carousel-item-prev",d=this._orderToDirection(i);if(o&&o.classList.contains(ot))return void(this._isSliding=!1);if(this._isSliding)return;if(this._triggerSlideEvent(o,d).defaultPrevented)return;if(!s||!o)return;this._isSliding=!0,a&&this.pause(),this._setActiveIndicatorElement(o),this._activeElement=o;const u=()=>{$.trigger(this._element,nt,{relatedTarget:o,direction:d,from:n,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),f(o),s.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(ot),s.classList.remove(ot,h,c),this._isSliding=!1,setTimeout(u,0)};this._queueCallback(t,s,!0)}else s.classList.remove(ot),o.classList.add(ot),this._isSliding=!1,u();a&&this.cycle()}_directionToOrder(t){return[it,et].includes(t)?b()?t===et?tt:J:t===et?J:tt:t}_orderToDirection(t){return[J,tt].includes(t)?b()?t===tt?et:it:t===tt?it:et:t}static carouselInterface(t,e){const i=at.getOrCreateInstance(t,e);let{_config:s}=i;"object"==typeof e&&(s={...s,...e});const n="string"==typeof e?e:s.slide;if("number"==typeof e)i.to(e);else if("string"==typeof n){if(void 0===i[n])throw new TypeError(`No method named "${n}"`);i[n]()}else s.interval&&s.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){at.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=r(this);if(!e||!e.classList.contains("carousel"))return;const i={...X.getDataAttributes(e),...X.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),at.carouselInterface(e,i),s&&at.getInstance(e).to(s),t.preventDefault()}}$.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",at.dataApiClickHandler),$.on(window,"load.bs.carousel.data-api",(()=>{const t=Y.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;e<i;e++)at.carouselInterface(t[e],at.getInstance(t[e]))})),v(at);const lt="collapse",ct={toggle:!0,parent:null},ht={toggle:"boolean",parent:"(null|element)"},dt="show",ut="collapse",gt="collapsing",_t="collapsed",ft=":scope .collapse .collapse",pt='[data-bs-toggle="collapse"]';class mt extends R{constructor(t,e){super(t),this._isTransitioning=!1,this._config=this._getConfig(e),this._triggerArray=[];const i=Y.find(pt);for(let t=0,e=i.length;t<e;t++){const e=i[t],s=o(e),n=Y.find(s).filter((t=>t===this._element));null!==s&&n.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return ct}static get NAME(){return lt}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=Y.find(ft,this._config.parent);e=Y.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=Y.findOne(this._selector);if(e.length){const s=e.find((t=>i!==t));if(t=s?mt.getInstance(s):null,t&&t._isTransitioning)return}if($.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&mt.getOrCreateInstance(e,{toggle:!1}).hide(),t||z.set(e,"bs.collapse",null)}));const s=this._getDimension();this._element.classList.remove(ut),this._element.classList.add(gt),this._element.style[s]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const n=`scroll${s[0].toUpperCase()+s.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(gt),this._element.classList.add(ut,dt),this._element.style[s]="",$.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[s]=`${this._element[n]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if($.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,f(this._element),this._element.classList.add(gt),this._element.classList.remove(ut,dt);const e=this._triggerArray.length;for(let t=0;t<e;t++){const e=this._triggerArray[t],i=r(e);i&&!this._isShown(i)&&this._addAriaAndCollapsedClass([e],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(gt),this._element.classList.add(ut),$.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(dt)}_getConfig(t){return(t={...ct,...X.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=c(t.parent),h(lt,t,ht),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=Y.find(ft,this._config.parent);Y.find(pt,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=r(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(_t):t.classList.add(_t),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=mt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}$.on(document,"click.bs.collapse.data-api",pt,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=o(this);Y.find(e).forEach((t=>{mt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),v(mt);const bt="dropdown",vt="Escape",yt="Space",Et="ArrowUp",wt="ArrowDown",At=new RegExp("ArrowUp|ArrowDown|Escape"),Tt="click.bs.dropdown.data-api",Ct="keydown.bs.dropdown.data-api",kt="show",Lt='[data-bs-toggle="dropdown"]',St=".dropdown-menu",Ot=b()?"top-end":"top-start",Nt=b()?"top-start":"top-end",Dt=b()?"bottom-end":"bottom-start",It=b()?"bottom-start":"bottom-end",Pt=b()?"left-start":"right-start",xt=b()?"right-start":"left-start",Mt={offset:[0,2],boundary:"clippingParents",reference:"toggle",display:"dynamic",popperConfig:null,autoClose:!0},jt={offset:"(array|string|function)",boundary:"(string|element)",reference:"(string|element|object)",display:"string",popperConfig:"(null|object|function)",autoClose:"(boolean|string)"};class Ht extends R{constructor(t,e){super(t),this._popper=null,this._config=this._getConfig(e),this._menu=this._getMenuElement(),this._inNavbar=this._detectNavbar()}static get Default(){return Mt}static get DefaultType(){return jt}static get NAME(){return bt}toggle(){return this._isShown()?this.hide():this.show()}show(){if(u(this._element)||this._isShown(this._menu))return;const t={relatedTarget:this._element};if($.trigger(this._element,"show.bs.dropdown",t).defaultPrevented)return;const e=Ht.getParentFromElement(this._element);this._inNavbar?X.setDataAttribute(this._menu,"popper","none"):this._createPopper(e),"ontouchstart"in document.documentElement&&!e.closest(".navbar-nav")&&[].concat(...document.body.children).forEach((t=>$.on(t,"mouseover",_))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(kt),this._element.classList.add(kt),$.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(u(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){$.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>$.off(t,"mouseover",_))),this._popper&&this._popper.destroy(),this._menu.classList.remove(kt),this._element.classList.remove(kt),this._element.setAttribute("aria-expanded","false"),X.removeDataAttribute(this._menu,"popper"),$.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...X.getDataAttributes(this._element),...t},h(bt,t,this.constructor.DefaultType),"object"==typeof t.reference&&!l(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${bt.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===i)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:l(this._config.reference)?e=c(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const s=this._getPopperConfig(),n=s.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=i.createPopper(e,this._menu,s),n&&X.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(kt)}_getMenuElement(){return Y.next(this._element,St)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return Pt;if(t.classList.contains("dropstart"))return xt;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?Nt:Ot:e?It:Dt}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=Y.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(d);i.length&&w(i,e,t===wt,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=Ht.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=Y.find(Lt);for(let i=0,s=e.length;i<s;i++){const s=Ht.getInstance(e[i]);if(!s||!1===s._config.autoClose)continue;if(!s._isShown())continue;const n={relatedTarget:s._element};if(t){const e=t.composedPath(),i=e.includes(s._menu);if(e.includes(s._element)||"inside"===s._config.autoClose&&!i||"outside"===s._config.autoClose&&i)continue;if(s._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;"click"===t.type&&(n.clickEvent=t)}s._completeHide(n)}}static getParentFromElement(t){return r(t)||t.parentNode}static dataApiKeydownHandler(t){if(/input|textarea/i.test(t.target.tagName)?t.key===yt||t.key!==vt&&(t.key!==wt&&t.key!==Et||t.target.closest(St)):!At.test(t.key))return;const e=this.classList.contains(kt);if(!e&&t.key===vt)return;if(t.preventDefault(),t.stopPropagation(),u(this))return;const i=this.matches(Lt)?this:Y.prev(this,Lt)[0],s=Ht.getOrCreateInstance(i);if(t.key!==vt)return t.key===Et||t.key===wt?(e||s.show(),void s._selectMenuItem(t)):void(e&&t.key!==yt||Ht.clearMenus());s.hide()}}$.on(document,Ct,Lt,Ht.dataApiKeydownHandler),$.on(document,Ct,St,Ht.dataApiKeydownHandler),$.on(document,Tt,Ht.clearMenus),$.on(document,"keyup.bs.dropdown.data-api",Ht.clearMenus),$.on(document,Tt,Lt,(function(t){t.preventDefault(),Ht.getOrCreateInstance(this).toggle()})),v(Ht);const $t=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",Bt=".sticky-top";class zt{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,"paddingRight",(e=>e+t)),this._setElementAttributes($t,"paddingRight",(e=>e+t)),this._setElementAttributes(Bt,"marginRight",(e=>e-t))}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const s=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+s)return;this._saveInitialAttribute(t,e);const n=window.getComputedStyle(t)[e];t.style[e]=`${i(Number.parseFloat(n))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes($t,"paddingRight"),this._resetElementAttributes(Bt,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&X.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=X.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(X.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){l(t)?e(t):Y.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const Rt={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},Ft={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},qt="show",Wt="mousedown.bs.backdrop";class Ut{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&f(this._getElement()),this._getElement().classList.add(qt),this._emulateAnimation((()=>{y(t)}))):y(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(qt),this._emulateAnimation((()=>{this.dispose(),y(t)}))):y(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...Rt,..."object"==typeof t?t:{}}).rootElement=c(t.rootElement),h("backdrop",t,Ft),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),$.on(this._getElement(),Wt,(()=>{y(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&($.off(this._element,Wt),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){E(t,this._getElement(),this._config.isAnimated)}}const Kt={trapElement:null,autofocus:!0},Vt={trapElement:"element",autofocus:"boolean"},Xt=".bs.focustrap",Yt="backward";class Qt{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),$.off(document,Xt),$.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),$.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,$.off(document,Xt))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const s=Y.focusableChildren(i);0===s.length?i.focus():this._lastTabNavDirection===Yt?s[s.length-1].focus():s[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Yt:"forward")}_getConfig(t){return t={...Kt,..."object"==typeof t?t:{}},h("focustrap",t,Vt),t}}const Gt="modal",Zt="Escape",Jt={backdrop:!0,keyboard:!0,focus:!0},te={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},ee="hidden.bs.modal",ie="show.bs.modal",se="resize.bs.modal",ne="click.dismiss.bs.modal",oe="keydown.dismiss.bs.modal",re="mousedown.dismiss.bs.modal",ae="modal-open",le="show",ce="modal-static";class he extends R{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=Y.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new zt}static get Default(){return Jt}static get NAME(){return Gt}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||$.trigger(this._element,ie,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(ae),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),$.on(this._dialog,re,(()=>{$.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if($.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(le),$.off(this._element,ne),$.off(this._dialog,re),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>$.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ut({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Qt({trapElement:this._element})}_getConfig(t){return t={...Jt,...X.getDataAttributes(this._element),..."object"==typeof t?t:{}},h(Gt,t,te),t}_showElement(t){const e=this._isAnimated(),i=Y.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&f(this._element),this._element.classList.add(le),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,$.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?$.on(this._element,oe,(t=>{this._config.keyboard&&t.key===Zt?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Zt||this._triggerBackdropTransition()})):$.off(this._element,oe)}_setResizeEvent(){this._isShown?$.on(window,se,(()=>this._adjustDialog())):$.off(window,se)}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(ae),this._resetAdjustments(),this._scrollBar.reset(),$.trigger(this._element,ee)}))}_showBackdrop(t){$.on(this._element,ne,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if($.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,s=e>document.documentElement.clientHeight;!s&&"hidden"===i.overflowY||t.contains(ce)||(s||(i.overflowY="hidden"),t.add(ce),this._queueCallback((()=>{t.remove(ce),s||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!b()||i&&!t&&b())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!b()||!i&&t&&b())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=he.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}$.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=r(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),$.one(e,ie,(t=>{t.defaultPrevented||$.one(e,ee,(()=>{d(this)&&this.focus()}))}));const i=Y.findOne(".modal.show");i&&he.getInstance(i).hide(),he.getOrCreateInstance(e).toggle(this)})),F(he),v(he);const de="offcanvas",ue={backdrop:!0,keyboard:!0,scroll:!1},ge={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},_e="show",fe=".offcanvas.show",pe="hidden.bs.offcanvas";class me extends R{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return de}static get Default(){return ue}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||$.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new zt).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(_e),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),$.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&($.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove(_e),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new zt).reset(),$.trigger(this._element,pe)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...ue,...X.getDataAttributes(this._element),..."object"==typeof t?t:{}},h(de,t,ge),t}_initializeBackDrop(){return new Ut({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Qt({trapElement:this._element})}_addEventListeners(){$.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=me.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}$.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=r(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),u(this))return;$.one(e,pe,(()=>{d(this)&&this.focus()}));const i=Y.findOne(fe);i&&i!==e&&me.getInstance(i).hide(),me.getOrCreateInstance(e).toggle(this)})),$.on(window,"load.bs.offcanvas.data-api",(()=>Y.find(fe).forEach((t=>me.getOrCreateInstance(t).show())))),F(me),v(me);const be=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),ve=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,ye=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Ee=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!be.has(i)||Boolean(ve.test(t.nodeValue)||ye.test(t.nodeValue));const s=e.filter((t=>t instanceof RegExp));for(let t=0,e=s.length;t<e;t++)if(s[t].test(i))return!0;return!1};function we(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const s=(new window.DOMParser).parseFromString(t,"text/html"),n=[].concat(...s.body.querySelectorAll("*"));for(let t=0,i=n.length;t<i;t++){const i=n[t],s=i.nodeName.toLowerCase();if(!Object.keys(e).includes(s)){i.remove();continue}const o=[].concat(...i.attributes),r=[].concat(e["*"]||[],e[s]||[]);o.forEach((t=>{Ee(t,r)||i.removeAttribute(t.nodeName)}))}return s.body.innerHTML}const Ae="tooltip",Te=new Set(["sanitize","allowList","sanitizeFn"]),Ce={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},ke={AUTO:"auto",TOP:"top",RIGHT:b()?"left":"right",BOTTOM:"bottom",LEFT:b()?"right":"left"},Le={animation:!0,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Se={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Oe="fade",Ne="show",De="show",Ie="out",Pe=".tooltip-inner",xe=".modal",Me="hide.bs.modal",je="hover",He="focus";class $e extends R{constructor(t,e){if(void 0===i)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return Le}static get NAME(){return Ae}static get Event(){return Se}static get DefaultType(){return Ce}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(Ne))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),$.off(this._element.closest(xe),Me,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=$.trigger(this._element,this.constructor.Event.SHOW),e=g(this._element),s=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!s)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(Pe).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),o=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",o),this._element.setAttribute("aria-describedby",o),this._config.animation&&n.classList.add(Oe);const r="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,a=this._getAttachment(r);this._addAttachmentClass(a);const{container:l}=this._config;z.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(l.append(n),$.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=i.createPopper(this._element,n,this._getPopperConfig(a)),n.classList.add(Ne);const c=this._resolvePossibleFunction(this._config.customClass);c&&n.classList.add(...c.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{$.on(t,"mouseover",_)}));const h=this.tip.classList.contains(Oe);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,$.trigger(this._element,this.constructor.Event.SHOWN),t===Ie&&this._leave(null,this)}),this.tip,h)}hide(){if(!this._popper)return;const t=this.getTipElement();if($.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(Ne),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>$.off(t,"mouseover",_))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(Oe);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==De&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),$.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(Oe,Ne),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),Pe)}_sanitizeAndSetContent(t,e,i){const s=Y.findOne(i,t);e||!s?this.setElementContent(s,e):s.remove()}setElementContent(t,e){if(null!==t)return l(e)?(e=c(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=we(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return ke[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)$.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===je?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===je?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;$.on(this._element,e,this._config.selector,(t=>this._enter(t))),$.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},$.on(this._element.closest(xe),Me,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?He:je]=!0),e.getTipElement().classList.contains(Ne)||e._hoverState===De?e._hoverState=De:(clearTimeout(e._timeout),e._hoverState=De,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===De&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?He:je]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=Ie,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===Ie&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=X.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Te.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:c(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),h(Ae,t,this.constructor.DefaultType),t.sanitize&&(t.template=we(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=$e.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}v($e);const Be={...$e.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'},ze={...$e.DefaultType,content:"(string|element|function)"},Re={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class Fe extends $e{static get Default(){return Be}static get NAME(){return"popover"}static get Event(){return Re}static get DefaultType(){return ze}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=Fe.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}v(Fe);const qe="scrollspy",We={offset:10,method:"auto",target:""},Ue={offset:"number",method:"string",target:"(string|element)"},Ke="active",Ve=".nav-link, .list-group-item, .dropdown-item",Xe="position";class Ye extends R{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,$.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return We}static get NAME(){return qe}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":Xe,e="auto"===this._config.method?t:this._config.method,i=e===Xe?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),Y.find(Ve,this._config.target).map((t=>{const s=o(t),n=s?Y.findOne(s):null;if(n){const t=n.getBoundingClientRect();if(t.width||t.height)return[X[e](n).top+i,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){$.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...We,...X.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=c(t.target)||document.documentElement,h(qe,t,Ue),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t<this._offsets[0]&&this._offsets[0]>0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t<this._offsets[e+1])&&this._activate(this._targets[e])}}_activate(t){this._activeTarget=t,this._clear();const e=Ve.split(",").map((e=>`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=Y.findOne(e.join(","),this._config.target);i.classList.add(Ke),i.classList.contains("dropdown-item")?Y.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(Ke):Y.parents(i,".nav, .list-group").forEach((t=>{Y.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(Ke))),Y.prev(t,".nav-item").forEach((t=>{Y.children(t,".nav-link").forEach((t=>t.classList.add(Ke)))}))})),$.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){Y.find(Ve,this._config.target).filter((t=>t.classList.contains(Ke))).forEach((t=>t.classList.remove(Ke)))}static jQueryInterface(t){return this.each((function(){const e=Ye.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}$.on(window,"load.bs.scrollspy.data-api",(()=>{Y.find('[data-bs-spy="scroll"]').forEach((t=>new Ye(t)))})),v(Ye);const Qe="active",Ge="fade",Ze="show",Je=".active",ti=":scope > li > .active";class ei extends R{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Qe))return;let t;const e=r(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?ti:Je;t=Y.find(e,i),t=t[t.length-1]}const s=t?$.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if($.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const n=()=>{$.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),$.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,n):n()}_activate(t,e,i){const s=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?Y.children(e,Je):Y.find(ti,e))[0],n=i&&s&&s.classList.contains(Ge),o=()=>this._transitionComplete(t,s,i);s&&n?(s.classList.remove(Ze),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Qe);const t=Y.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Qe),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Qe),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),f(t),t.classList.contains(Ge)&&t.classList.add(Ze);let s=t.parentNode;if(s&&"LI"===s.nodeName&&(s=s.parentNode),s&&s.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&Y.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Qe))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=ei.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}$.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),u(this)||ei.getOrCreateInstance(this).show()})),v(ei);const ii="toast",si="hide",ni="show",oi="showing",ri={animation:"boolean",autohide:"boolean",delay:"number"},ai={animation:!0,autohide:!0,delay:5e3};class li extends R{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return ri}static get Default(){return ai}static get NAME(){return ii}show(){$.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(si),f(this._element),this._element.classList.add(ni),this._element.classList.add(oi),this._queueCallback((()=>{this._element.classList.remove(oi),$.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(ni)&&($.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(oi),this._queueCallback((()=>{this._element.classList.add(si),this._element.classList.remove(oi),this._element.classList.remove(ni),$.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(ni)&&this._element.classList.remove(ni),super.dispose()}_getConfig(t){return t={...ai,...X.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},h(ii,t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){$.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),$.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),$.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),$.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=li.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return F(li),v(li),{Alert:q,Button:U,Carousel:at,Collapse:mt,Dropdown:Ht,Modal:he,Offcanvas:me,Popover:Fe,ScrollSpy:Ye,Tab:ei,Toast:li,Tooltip:$e}})); -//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/src/base/theme/bootsier/assets/js/bootstrap.min.js.map b/src/base/theme/bootsier/assets/js/bootstrap.min.js.map deleted file mode 100644 index 835a3d6b..00000000 --- a/src/base/theme/bootsier/assets/js/bootstrap.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/data.js","../../js/src/base-component.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/dom/manipulator.js","../../js/src/dom/selector-engine.js","../../js/src/carousel.js","../../js/src/collapse.js","../../js/src/dropdown.js","../../js/src/util/scrollbar.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"names":["TRANSITION_END","getSelector","element","selector","getAttribute","hrefAttr","includes","startsWith","split","trim","getSelectorFromElement","document","querySelector","getElementFromSelector","triggerTransitionEnd","dispatchEvent","Event","isElement","obj","jquery","nodeType","getElement","length","typeCheckConfig","componentName","config","configTypes","Object","keys","forEach","property","expectedTypes","value","valueType","toString","call","match","toLowerCase","RegExp","test","TypeError","toUpperCase","isVisible","getClientRects","getComputedStyle","getPropertyValue","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","parentNode","noop","reflow","offsetHeight","getjQuery","jQuery","window","body","DOMContentLoadedCallbacks","isRTL","dir","defineJQueryPlugin","plugin","callback","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","readyState","addEventListener","push","execute","executeAfterTransition","transitionElement","waitForTransition","emulatedDuration","transitionDuration","transitionDelay","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","getTransitionDurationFromElement","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","index","indexOf","listLength","Math","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","customEventsRegex","nativeEvents","Set","getUidEvent","uid","getEvent","findHandler","events","delegationSelector","uidEventList","i","len","event","originalHandler","normalizeParams","originalTypeEvent","delegationFn","delegation","typeEvent","getTypeEvent","has","addHandler","oneOff","wrapFn","relatedTarget","delegateTarget","this","handlers","previousFn","replace","domElements","querySelectorAll","EventHandler","off","type","apply","bootstrapDelegationHandler","bootstrapHandler","removeHandler","Boolean","on","one","inNamespace","isNamespace","elementEvent","namespace","storeElementEvent","handlerKey","removeNamespacedHandlers","slice","keyHandlers","trigger","args","isNative","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","evt","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","createEvent","initEvent","CustomEvent","cancelable","key","defineProperty","get","preventDefault","elementMap","Map","Data","set","instance","instanceMap","size","console","error","Array","from","remove","delete","BaseComponent","constructor","_element","DATA_KEY","dispose","EVENT_KEY","getOwnPropertyNames","propertyName","_queueCallback","isAnimated","static","getInstance","VERSION","Error","enableDismissTrigger","component","method","clickEvent","tagName","closest","getOrCreateInstance","Alert","close","_destroyElement","each","data","undefined","SELECTOR_DATA_TOGGLE","Button","toggle","setAttribute","normalizeData","val","normalizeDataKey","chr","button","Manipulator","setDataAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","dataset","filter","pureKey","charAt","getDataAttribute","offset","rect","getBoundingClientRect","top","pageYOffset","left","pageXOffset","position","offsetTop","offsetLeft","SelectorEngine","find","concat","Element","prototype","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","map","join","el","Default","interval","keyboard","slide","pause","wrap","touch","DefaultType","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","KEY_TO_DIRECTION","ArrowLeft","ArrowRight","EVENT_SLID","CLASS_NAME_ACTIVE","SELECTOR_ACTIVE_ITEM","Carousel","super","_items","_interval","_activeElement","_isPaused","_isSliding","touchTimeout","touchStartX","touchDeltaX","_config","_getConfig","_indicatorsElement","_touchSupported","navigator","maxTouchPoints","_pointerEvent","PointerEvent","_addEventListeners","_slide","nextWhenVisible","hidden","cycle","clearInterval","_updateInterval","setInterval","visibilityState","bind","to","activeIndex","_getItemIndex","order","_handleSwipe","absDeltax","abs","direction","_keydown","_addTouchEventListeners","hasPointerPenTouch","pointerType","start","clientX","touches","move","end","clearTimeout","itemImg","add","_getItemByOrder","isNext","_triggerSlideEvent","eventDirectionName","targetIndex","fromIndex","_setActiveIndicatorElement","activeIndicator","indicators","parseInt","elementInterval","defaultInterval","directionOrOrder","_directionToOrder","activeElementIndex","nextElement","nextElementIndex","isCycling","directionalClassName","orderClassName","_orderToDirection","triggerSlidEvent","completeCallBack","action","ride","carouselInterface","slideIndex","dataApiClickHandler","carousels","parent","CLASS_NAME_SHOW","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_COLLAPSED","CLASS_NAME_DEEPER_CHILDREN","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElem","_selector","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activesData","actives","container","tempActiveData","elemActive","dimension","_getDimension","style","scrollSize","triggerArrayLength","selected","triggerArray","isOpen","ESCAPE_KEY","SPACE_KEY","ARROW_UP_KEY","ARROW_DOWN_KEY","REGEXP_KEYDOWN","EVENT_CLICK_DATA_API","EVENT_KEYDOWN_DATA_API","SELECTOR_MENU","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","boundary","reference","display","popperConfig","autoClose","Dropdown","_popper","_menu","_getMenuElement","_inNavbar","_detectNavbar","getParentFromElement","_createPopper","focus","_completeHide","destroy","update","Popper","referenceElement","_getPopperConfig","isDisplayStatic","modifiers","modifier","enabled","createPopper","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","placement","options","_selectMenuItem","items","toggles","context","composedPath","isMenuTarget","isActive","stopPropagation","getToggleButton","clearMenus","dataApiKeydownHandler","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","ScrollBarHelper","getWidth","documentWidth","clientWidth","innerWidth","width","_disableOverFlow","_setElementAttributes","calculatedValue","_saveInitialAttribute","overflow","styleProp","scrollbarWidth","_applyManipulationCallback","reset","_resetElementAttributes","actualValue","removeProperty","callBack","isOverflowing","className","rootElement","clickCallback","EVENT_MOUSEDOWN","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","trapElement","autofocus","TAB_NAV_BACKWARD","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","elements","shiftKey","EVENT_HIDDEN","EVENT_SHOW","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_KEYDOWN_DISMISS","EVENT_MOUSEDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_ignoreBackdropClick","_scrollBar","_isAnimated","_adjustDialog","_setEscapeEvent","_setResizeEvent","_showBackdrop","_showElement","_hideModal","htmlElement","handleUpdate","modalBody","scrollTop","_triggerBackdropTransition","_resetAdjustments","currentTarget","scrollHeight","isModalOverflowing","clientHeight","overflowY","isBodyOverflowing","paddingLeft","paddingRight","showEvent","allReadyOpen","scroll","OPEN_SELECTOR","Offcanvas","visibility","blur","uriAttributes","SAFE_URL_PATTERN","DATA_URL_PATTERN","allowedAttribute","attribute","allowedAttributeList","attributeName","nodeName","nodeValue","regExp","attributeRegex","sanitizeHtml","unsafeHtml","allowList","sanitizeFn","createdDocument","DOMParser","parseFromString","elementName","attributeList","allowedAttributes","innerHTML","DISALLOWED_ATTRIBUTES","animation","template","title","delay","html","fallbackPlacements","customClass","sanitize","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","a","area","b","br","col","code","div","em","hr","h1","h2","h3","h4","h5","h6","img","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","HIDE","HIDDEN","SHOW","SHOWN","INSERTED","CLICK","FOCUSIN","FOCUSOUT","MOUSEENTER","MOUSELEAVE","CLASS_NAME_FADE","HOVER_STATE_SHOW","HOVER_STATE_OUT","SELECTOR_TOOLTIP_INNER","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","Tooltip","_isEnabled","_timeout","_hoverState","_activeTrigger","tip","_setListeners","enable","disable","toggleEnabled","_initializeOnDelegatedTarget","click","_isWithActiveTrigger","_enter","_leave","getTipElement","_hideModalHandler","_disposePopper","isWithContent","shadowRoot","isInTheDom","ownerDocument","getTitle","tipId","prefix","floor","random","getElementById","getUID","attachment","_getAttachment","_addAttachmentClass","_resolvePossibleFunction","prevHoverState","_cleanTipClass","setContent","_sanitizeAndSetContent","content","templateElement","setElementContent","textContent","updateAttachment","_getDelegateConfig","phase","_handlePopperPlacementChange","onFirstUpdate","_getBasicClassPrefix","eventIn","eventOut","_fixTitle","originalTitleType","dataAttributes","dataAttr","basicClassPrefixRegex","tabClass","token","tClass","state","popper","Popover","_getContent","SELECTOR_LINK_ITEMS","METHOD_POSITION","ScrollSpy","_scrollElement","_offsets","_targets","_activeTarget","_scrollHeight","_process","refresh","autoMethod","offsetMethod","offsetBase","_getScrollTop","_getScrollHeight","targetSelector","targetBCR","height","item","sort","_getOffsetHeight","innerHeight","maxScroll","_activate","_clear","queries","link","listGroup","navItem","node","spy","SELECTOR_ACTIVE","SELECTOR_ACTIVE_UL","Tab","listElement","itemSelector","hideEvent","complete","active","isTransitioning","_transitionComplete","dropdownChild","dropdownElement","dropdown","CLASS_NAME_HIDE","CLASS_NAME_SHOWING","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","_onInteraction","isInteracting"],"mappings":"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","sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1000000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n// Shoutout AngusCroll (https://goo.gl/pxwQGp)\nconst toType = obj => {\n if (obj === null || obj === undefined) {\n return `${obj}`\n }\n\n return {}.toString.call(obj).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * --------------------------------------------------------------------------\n * Public Util Api\n * --------------------------------------------------------------------------\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttr = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttr || (!hrefAttr.includes('#') && !hrefAttr.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {\n hrefAttr = `#${hrefAttr.split('#')[1]}`\n }\n\n selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null\n }\n\n return selector\n}\n\nconst getSelectorFromElement = element => {\n const selector = getSelector(element)\n\n if (selector) {\n return document.querySelector(selector) ? selector : null\n }\n\n return null\n}\n\nconst getElementFromSelector = element => {\n const selector = getSelector(element)\n\n return selector ? document.querySelector(selector) : null\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = obj => {\n if (!obj || typeof obj !== 'object') {\n return false\n }\n\n if (typeof obj.jquery !== 'undefined') {\n obj = obj[0]\n }\n\n return typeof obj.nodeType !== 'undefined'\n}\n\nconst getElement = obj => {\n if (isElement(obj)) { // it's a jQuery object or a node element\n return obj.jquery ? obj[0] : obj\n }\n\n if (typeof obj === 'string' && obj.length > 0) {\n return document.querySelector(obj)\n }\n\n return null\n}\n\nconst typeCheckConfig = (componentName, config, configTypes) => {\n Object.keys(configTypes).forEach(property => {\n const expectedTypes = configTypes[property]\n const value = config[property]\n const valueType = value && isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${componentName.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n })\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n return getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n // eslint-disable-next-line no-unused-expressions\n element.offsetHeight\n}\n\nconst getjQuery = () => {\n const { jQuery } = window\n\n if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n DOMContentLoadedCallbacks.forEach(callback => callback())\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = callback => {\n if (typeof callback === 'function') {\n callback()\n }\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element depending on the direction and if cycle is allowed\n if (index === -1) {\n return list[!shouldGetNext && isCycleAllowed ? list.length - 1 : 0]\n }\n\n const listLength = list.length\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n getElement,\n getUID,\n getSelectorFromElement,\n getElementFromSelector,\n getTransitionDurationFromElement,\n triggerTransitionEnd,\n isElement,\n typeCheckConfig,\n isVisible,\n isDisabled,\n findShadowRoot,\n noop,\n getNextActiveElement,\n reflow,\n getjQuery,\n onDOMContentLoaded,\n isRTL,\n defineJQueryPlugin,\n execute,\n executeAfterTransition\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\nconst customEventsRegex = /^(mouseenter|mouseleave)/i\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * ------------------------------------------------------------------------\n * Private methods\n * ------------------------------------------------------------------------\n */\n\nfunction getUidEvent(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getEvent(element) {\n const uid = getUidEvent(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n event.delegateTarget = element\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (let i = domElements.length; i--;) {\n if (domElements[i] === target) {\n event.delegateTarget = target\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n\n // To please ESLint\n return null\n }\n}\n\nfunction findHandler(events, handler, delegationSelector = null) {\n const uidEventList = Object.keys(events)\n\n for (let i = 0, len = uidEventList.length; i < len; i++) {\n const event = events[uidEventList[i]]\n\n if (event.originalHandler === handler && event.delegationSelector === delegationSelector) {\n return event\n }\n }\n\n return null\n}\n\nfunction normalizeParams(originalTypeEvent, handler, delegationFn) {\n const delegation = typeof handler === 'string'\n const originalHandler = delegation ? delegationFn : handler\n\n let typeEvent = getTypeEvent(originalTypeEvent)\n const isNative = nativeEvents.has(typeEvent)\n\n if (!isNative) {\n typeEvent = originalTypeEvent\n }\n\n return [delegation, originalHandler, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFn, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n if (!handler) {\n handler = delegationFn\n delegationFn = null\n }\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (customEventsRegex.test(originalTypeEvent)) {\n const wrapFn = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n if (delegationFn) {\n delegationFn = wrapFn(delegationFn)\n } else {\n handler = wrapFn(handler)\n }\n }\n\n const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn)\n const events = getEvent(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFn = findHandler(handlers, originalHandler, delegation ? handler : null)\n\n if (previousFn) {\n previousFn.oneOff = previousFn.oneOff && oneOff\n\n return\n }\n\n const uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = delegation ?\n bootstrapDelegationHandler(element, handler, delegationFn) :\n bootstrapHandler(element, handler)\n\n fn.delegationSelector = delegation ? handler : null\n fn.originalHandler = originalHandler\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, delegation)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n Object.keys(storeElementEvent).forEach(handlerKey => {\n if (handlerKey.includes(namespace)) {\n const event = storeElementEvent[handlerKey]\n\n removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector)\n }\n })\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFn) {\n addHandler(element, event, handler, delegationFn, false)\n },\n\n one(element, event, handler, delegationFn) {\n addHandler(element, event, handler, delegationFn, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFn) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getEvent(element)\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof originalHandler !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!events || !events[typeEvent]) {\n return\n }\n\n removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null)\n return\n }\n\n if (isNamespace) {\n Object.keys(events).forEach(elementEvent => {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n })\n }\n\n const storeElementEvent = events[typeEvent] || {}\n Object.keys(storeElementEvent).forEach(keyHandlers => {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n const event = storeElementEvent[keyHandlers]\n\n removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector)\n }\n })\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n const isNative = nativeEvents.has(typeEvent)\n\n let jQueryEvent\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n let evt = null\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n if (isNative) {\n evt = document.createEvent('HTMLEvents')\n evt.initEvent(typeEvent, bubbles, true)\n } else {\n evt = new CustomEvent(event, {\n bubbles,\n cancelable: true\n })\n }\n\n // merge custom information in our event\n if (typeof args !== 'undefined') {\n Object.keys(args).forEach(key => {\n Object.defineProperty(evt, key, {\n get() {\n return args[key]\n }\n })\n })\n }\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && typeof jQueryEvent !== 'undefined') {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data'\nimport {\n executeAfterTransition,\n getElement\n} from './util/index'\nimport EventHandler from './dom/event-handler'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst VERSION = '5.1.3'\n\nclass BaseComponent {\n constructor(element) {\n element = getElement(element)\n\n if (!element) {\n return\n }\n\n this._element = element\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n Object.getOwnPropertyNames(this).forEach(propertyName => {\n this[propertyName] = null\n })\n }\n\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n /** Static */\n\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler'\nimport { getElementFromSelector, isDisabled } from './index'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { defineJQueryPlugin } from './util/index'\nimport EventHandler from './dom/event-handler'\nimport BaseComponent from './base-component'\nimport { enableDismissTrigger } from './util/component-functions'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Alert extends BaseComponent {\n // Getters\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Alert to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { defineJQueryPlugin } from './util/index'\nimport EventHandler from './dom/event-handler'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\n\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Button extends BaseComponent {\n // Getters\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Button to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(val) {\n if (val === 'true') {\n return true\n }\n\n if (val === 'false') {\n return false\n }\n\n if (val === Number(val).toString()) {\n return Number(val)\n }\n\n if (val === '' || val === 'null') {\n return null\n }\n\n return val\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n\n Object.keys(element.dataset)\n .filter(key => key.startsWith('bs'))\n .forEach(key => {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)\n attributes[pureKey] = normalizeData(element.dataset[key])\n })\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n },\n\n offset(element) {\n const rect = element.getBoundingClientRect()\n\n return {\n top: rect.top + window.pageYOffset,\n left: rect.left + window.pageXOffset\n }\n },\n\n position(element) {\n return {\n top: element.offsetTop,\n left: element.offsetLeft\n }\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible } from '../util/index'\n\nconst NODE_TEXT = 3\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children)\n .filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n\n let ancestor = element.parentNode\n\n while (ancestor && ancestor.nodeType === Node.ELEMENT_NODE && ancestor.nodeType !== NODE_TEXT) {\n if (ancestor.matches(selector)) {\n parents.push(ancestor)\n }\n\n ancestor = ancestor.parentNode\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(', ')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElementFromSelector,\n isRTL,\n isVisible,\n getNextActiveElement,\n reflow,\n triggerTransitionEnd,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n slide: false,\n pause: 'hover',\n wrap: true,\n touch: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)',\n keyboard: 'boolean',\n slide: '(boolean|string)',\n pause: '(string|boolean)',\n wrap: 'boolean',\n touch: 'boolean'\n}\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ACTIVE_ITEM = '.active.carousel-item'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_INDICATOR = '[data-bs-target]'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._items = null\n this._interval = null\n this._activeElement = null\n this._isPaused = false\n this._isSliding = false\n this.touchTimeout = null\n this.touchStartX = 0\n this.touchDeltaX = 0\n\n this._config = this._getConfig(config)\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n this._pointerEvent = Boolean(window.PointerEvent)\n\n this._addEventListeners()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause(event) {\n if (!event) {\n this._isPaused = true\n }\n\n if (SelectorEngine.findOne(SELECTOR_NEXT_PREV, this._element)) {\n triggerTransitionEnd(this._element)\n this.cycle(true)\n }\n\n clearInterval(this._interval)\n this._interval = null\n }\n\n cycle(event) {\n if (!event) {\n this._isPaused = false\n }\n\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n\n if (this._config && this._config.interval && !this._isPaused) {\n this._updateInterval()\n\n this._interval = setInterval(\n (document.visibilityState ? this.nextWhenVisible : this.next).bind(this),\n this._config.interval\n )\n }\n }\n\n to(index) {\n this._activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n const activeIndex = this._getItemIndex(this._activeElement)\n\n if (index > this._items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n if (activeIndex === index) {\n this.pause()\n this.cycle()\n return\n }\n\n const order = index > activeIndex ?\n ORDER_NEXT :\n ORDER_PREV\n\n this._slide(order, this._items[index])\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' ? config : {})\n }\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _handleSwipe() {\n const absDeltax = Math.abs(this.touchDeltaX)\n\n if (absDeltax <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltax / this.touchDeltaX\n\n this.touchDeltaX = 0\n\n if (!direction) {\n return\n }\n\n this._slide(direction > 0 ? DIRECTION_RIGHT : DIRECTION_LEFT)\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, event => this.pause(event))\n EventHandler.on(this._element, EVENT_MOUSELEAVE, event => this.cycle(event))\n }\n\n if (this._config.touch && this._touchSupported) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n const hasPointerPenTouch = event => {\n return this._pointerEvent &&\n (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n const start = event => {\n if (hasPointerPenTouch(event)) {\n this.touchStartX = event.clientX\n } else if (!this._pointerEvent) {\n this.touchStartX = event.touches[0].clientX\n }\n }\n\n const move = event => {\n // ensure swiping with one touch and not pinching\n this.touchDeltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this.touchStartX\n }\n\n const end = event => {\n if (hasPointerPenTouch(event)) {\n this.touchDeltaX = event.clientX - this.touchStartX\n }\n\n this._handleSwipe()\n if (this._config.pause === 'hover') {\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(event => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n }\n\n SelectorEngine.find(SELECTOR_ITEM_IMG, this._element).forEach(itemImg => {\n EventHandler.on(itemImg, EVENT_DRAG_START, event => event.preventDefault())\n })\n\n if (this._pointerEvent) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => end(event))\n }\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(direction)\n }\n }\n\n _getItemIndex(element) {\n this._items = element && element.parentNode ?\n SelectorEngine.find(SELECTOR_ITEM, element.parentNode) :\n []\n\n return this._items.indexOf(element)\n }\n\n _getItemByOrder(order, activeElement) {\n const isNext = order === ORDER_NEXT\n return getNextActiveElement(this._items, activeElement, isNext, this._config.wrap)\n }\n\n _triggerSlideEvent(relatedTarget, eventDirectionName) {\n const targetIndex = this._getItemIndex(relatedTarget)\n const fromIndex = this._getItemIndex(SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element))\n\n return EventHandler.trigger(this._element, EVENT_SLIDE, {\n relatedTarget,\n direction: eventDirectionName,\n from: fromIndex,\n to: targetIndex\n })\n }\n\n _setActiveIndicatorElement(element) {\n if (this._indicatorsElement) {\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const indicators = SelectorEngine.find(SELECTOR_INDICATOR, this._indicatorsElement)\n\n for (let i = 0; i < indicators.length; i++) {\n if (Number.parseInt(indicators[i].getAttribute('data-bs-slide-to'), 10) === this._getItemIndex(element)) {\n indicators[i].classList.add(CLASS_NAME_ACTIVE)\n indicators[i].setAttribute('aria-current', 'true')\n break\n }\n }\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n if (elementInterval) {\n this._config.defaultInterval = this._config.defaultInterval || this._config.interval\n this._config.interval = elementInterval\n } else {\n this._config.interval = this._config.defaultInterval || this._config.interval\n }\n }\n\n _slide(directionOrOrder, element) {\n const order = this._directionToOrder(directionOrOrder)\n const activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n const activeElementIndex = this._getItemIndex(activeElement)\n const nextElement = element || this._getItemByOrder(order, activeElement)\n\n const nextElementIndex = this._getItemIndex(nextElement)\n const isCycling = Boolean(this._interval)\n\n const isNext = order === ORDER_NEXT\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n const eventDirectionName = this._orderToDirection(order)\n\n if (nextElement && nextElement.classList.contains(CLASS_NAME_ACTIVE)) {\n this._isSliding = false\n return\n }\n\n if (this._isSliding) {\n return\n }\n\n const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName)\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n return\n }\n\n this._isSliding = true\n\n if (isCycling) {\n this.pause()\n }\n\n this._setActiveIndicatorElement(nextElement)\n this._activeElement = nextElement\n\n const triggerSlidEvent = () => {\n EventHandler.trigger(this._element, EVENT_SLID, {\n relatedTarget: nextElement,\n direction: eventDirectionName,\n from: activeElementIndex,\n to: nextElementIndex\n })\n }\n\n if (this._element.classList.contains(CLASS_NAME_SLIDE)) {\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n setTimeout(triggerSlidEvent, 0)\n }\n\n this._queueCallback(completeCallBack, activeElement, true)\n } else {\n activeElement.classList.remove(CLASS_NAME_ACTIVE)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n this._isSliding = false\n triggerSlidEvent()\n }\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _directionToOrder(direction) {\n if (![DIRECTION_RIGHT, DIRECTION_LEFT].includes(direction)) {\n return direction\n }\n\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (![ORDER_NEXT, ORDER_PREV].includes(order)) {\n return order\n }\n\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n\n static carouselInterface(element, config) {\n const data = Carousel.getOrCreateInstance(element, config)\n\n let { _config } = data\n if (typeof config === 'object') {\n _config = {\n ..._config,\n ...config\n }\n }\n\n const action = typeof config === 'string' ? config : _config.slide\n\n if (typeof config === 'number') {\n data.to(config)\n } else if (typeof action === 'string') {\n if (typeof data[action] === 'undefined') {\n throw new TypeError(`No method named \"${action}\"`)\n }\n\n data[action]()\n } else if (_config.interval && _config.ride) {\n data.pause()\n data.cycle()\n }\n }\n\n static jQueryInterface(config) {\n return this.each(function () {\n Carousel.carouselInterface(this, config)\n })\n }\n\n static dataApiClickHandler(event) {\n const target = getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n const config = {\n ...Manipulator.getDataAttributes(target),\n ...Manipulator.getDataAttributes(this)\n }\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n config.interval = false\n }\n\n Carousel.carouselInterface(target, config)\n\n if (slideIndex) {\n Carousel.getInstance(target).to(slideIndex)\n }\n\n event.preventDefault()\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, Carousel.dataApiClickHandler)\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (let i = 0, len = carousels.length; i < len; i++) {\n Carousel.carouselInterface(carousels[i], Carousel.getInstance(carousels[i]))\n }\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Carousel to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElement,\n getSelectorFromElement,\n getElementFromSelector,\n reflow,\n typeCheckConfig\n} from './util/index'\nimport Data from './dom/data'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst Default = {\n toggle: true,\n parent: null\n}\n\nconst DefaultType = {\n toggle: 'boolean',\n parent: '(null|element)'\n}\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._isTransitioning = false\n this._config = this._getConfig(config)\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (let i = 0, len = toggleList.length; i < len; i++) {\n const elem = toggleList[i]\n const selector = getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElem => foundElem === this._element)\n\n if (selector !== null && filterElement.length) {\n this._selector = selector\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let actives = []\n let activesData\n\n if (this._config.parent) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n actives = SelectorEngine.find(SELECTOR_ACTIVES, this._config.parent).filter(elem => !children.includes(elem)) // remove children if greater depth\n }\n\n const container = SelectorEngine.findOne(this._selector)\n if (actives.length) {\n const tempActiveData = actives.find(elem => container !== elem)\n activesData = tempActiveData ? Collapse.getInstance(tempActiveData) : null\n\n if (activesData && activesData._isTransitioning) {\n return\n }\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n actives.forEach(elemActive => {\n if (container !== elemActive) {\n Collapse.getOrCreateInstance(elemActive, { toggle: false }).hide()\n }\n\n if (!activesData) {\n Data.set(elemActive, DATA_KEY, null)\n }\n })\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n const triggerArrayLength = this._triggerArray.length\n for (let i = 0; i < triggerArrayLength; i++) {\n const trigger = this._triggerArray[i]\n const elem = getElementFromSelector(trigger)\n\n if (elem && !this._isShown(elem)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...config\n }\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n SelectorEngine.find(SELECTOR_DATA_TOGGLE, this._config.parent).filter(elem => !children.includes(elem))\n .forEach(element => {\n const selected = getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n })\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n triggerArray.forEach(elem => {\n if (isOpen) {\n elem.classList.remove(CLASS_NAME_COLLAPSED)\n } else {\n elem.classList.add(CLASS_NAME_COLLAPSED)\n }\n\n elem.setAttribute('aria-expanded', isOpen)\n })\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n const selector = getSelectorFromElement(this)\n const selectorElements = SelectorEngine.find(selector)\n\n selectorElements.forEach(element => {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n })\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Collapse to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\n\nimport {\n defineJQueryPlugin,\n getElement,\n getElementFromSelector,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst SPACE_KEY = 'Space'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEY}|${ARROW_DOWN_KEY}|${ESCAPE_KEY}`)\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_NAVBAR = 'navbar'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]'\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\n\nconst Default = {\n offset: [0, 2],\n boundary: 'clippingParents',\n reference: 'toggle',\n display: 'dynamic',\n popperConfig: null,\n autoClose: true\n}\n\nconst DefaultType = {\n offset: '(array|string|function)',\n boundary: '(string|element)',\n reference: '(string|element|object)',\n display: 'string',\n popperConfig: '(null|object|function)',\n autoClose: '(boolean|string)'\n}\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._popper = null\n this._config = this._getConfig(config)\n this._menu = this._getMenuElement()\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown(this._menu)) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n const parent = Dropdown.getParentFromElement(this._element)\n // Totally disable Popper for Dropdowns in Navbar\n if (this._inNavbar) {\n Manipulator.setDataAttribute(this._menu, 'popper', 'none')\n } else {\n this._createPopper(parent)\n }\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement &&\n !parent.closest(SELECTOR_NAVBAR_NAV)) {\n [].concat(...document.body.children)\n .forEach(elem => EventHandler.on(elem, 'mouseover', noop))\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown(this._menu)) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n [].concat(...document.body.children)\n .forEach(elem => EventHandler.off(elem, 'mouseover', noop))\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = {\n ...this.constructor.Default,\n ...Manipulator.getDataAttributes(this._element),\n ...config\n }\n\n typeCheckConfig(NAME, config, this.constructor.DefaultType)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper(parent) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n const isDisplayStatic = popperConfig.modifiers.find(modifier => modifier.name === 'applyStyles' && modifier.enabled === false)\n\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n\n if (isDisplayStatic) {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static')\n }\n }\n\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getMenuElement() {\n return SelectorEngine.next(this._element, SELECTOR_MENU)[0]\n }\n\n _getPlacement() {\n const parentDropdown = this._element.parentNode\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(`.${CLASS_NAME_NAVBAR}`) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(val => Number.parseInt(val, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display\n if (this._config.display === 'static') {\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible)\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event && (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY))) {\n return\n }\n\n const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (let i = 0, len = toggles.length; i < len; i++) {\n const context = Dropdown.getInstance(toggles[i])\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n if (!context._isShown()) {\n continue\n }\n\n const relatedTarget = {\n relatedTarget: context._element\n }\n\n if (event) {\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static getParentFromElement(element) {\n return getElementFromSelector(element) || element.parentNode\n }\n\n static dataApiKeydownHandler(event) {\n // If not input/textarea:\n // - And not a key in REGEXP_KEYDOWN => not a dropdown command\n // If input/textarea:\n // - If space key => not a dropdown command\n // - If key is other than escape\n // - If key is not up or down => not a dropdown command\n // - If trigger inside the menu => not a dropdown command\n if (/input|textarea/i.test(event.target.tagName) ?\n event.key === SPACE_KEY || (event.key !== ESCAPE_KEY &&\n ((event.key !== ARROW_DOWN_KEY && event.key !== ARROW_UP_KEY) ||\n event.target.closest(SELECTOR_MENU))) :\n !REGEXP_KEYDOWN.test(event.key)) {\n return\n }\n\n const isActive = this.classList.contains(CLASS_NAME_SHOW)\n\n if (!isActive && event.key === ESCAPE_KEY) {\n return\n }\n\n event.preventDefault()\n event.stopPropagation()\n\n if (isDisabled(this)) {\n return\n }\n\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0]\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (event.key === ESCAPE_KEY) {\n instance.hide()\n return\n }\n\n if (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY) {\n if (!isActive) {\n instance.show()\n }\n\n instance._selectMenuItem(event)\n return\n }\n\n if (!isActive || event.key === SPACE_KEY) {\n Dropdown.clearMenus()\n }\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Dropdown to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine'\nimport Manipulator from '../dom/manipulator'\nimport { isElement } from './index'\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, 'paddingRight', calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width)\n }\n\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProp, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProp)\n const calculatedValue = window.getComputedStyle(element)[styleProp]\n element.style[styleProp] = `${callback(Number.parseFloat(calculatedValue))}px`\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, 'paddingRight')\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight')\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight')\n }\n\n _saveInitialAttribute(element, styleProp) {\n const actualValue = element.style[styleProp]\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProp, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProp) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProp)\n if (typeof value === 'undefined') {\n element.style.removeProperty(styleProp)\n } else {\n Manipulator.removeDataAttribute(element, styleProp)\n element.style[styleProp] = value\n }\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n } else {\n SelectorEngine.find(selector, this._element).forEach(callBack)\n }\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler'\nimport { execute, executeAfterTransition, getElement, reflow, typeCheckConfig } from './index'\n\nconst Default = {\n className: 'modal-backdrop',\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n isAnimated: false,\n rootElement: 'body', // give the choice to place backdrop under different elements\n clickCallback: null\n}\n\nconst DefaultType = {\n className: 'string',\n isVisible: 'boolean',\n isAnimated: 'boolean',\n rootElement: '(element|string)',\n clickCallback: '(function|null)'\n}\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nclass Backdrop {\n constructor(config) {\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n if (this._config.isAnimated) {\n reflow(this._getElement())\n }\n\n this._getElement().classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n // Private\n\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _getConfig(config) {\n config = {\n ...Default,\n ...(typeof config === 'object' ? config : {})\n }\n\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n this._config.rootElement.append(this._getElement())\n\n EventHandler.on(this._getElement(), EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler'\nimport SelectorEngine from '../dom/selector-engine'\nimport { typeCheckConfig } from './index'\n\nconst Default = {\n trapElement: null, // The element to trap focus inside of\n autofocus: true\n}\n\nconst DefaultType = {\n trapElement: 'element',\n autofocus: 'boolean'\n}\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nclass FocusTrap {\n constructor(config) {\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n activate() {\n const { trapElement, autofocus } = this._config\n\n if (this._isActive) {\n return\n }\n\n if (autofocus) {\n trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n\n _handleFocusin(event) {\n const { target } = event\n const { trapElement } = this._config\n\n if (target === document || target === trapElement || trapElement.contains(target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n\n _getConfig(config) {\n config = {\n ...Default,\n ...(typeof config === 'object' ? config : {})\n }\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElementFromSelector,\n isRTL,\n isVisible,\n reflow,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport ScrollBarHelper from './util/scrollbar'\nimport BaseComponent from './base-component'\nimport Backdrop from './util/backdrop'\nimport FocusTrap from './util/focustrap'\nimport { enableDismissTrigger } from './util/component-functions'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n focus: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n focus: 'boolean'\n}\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEUP_DISMISS = `mouseup.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._config = this._getConfig(config)\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._ignoreBackdropClick = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n\n if (this._isAnimated()) {\n this._isTransitioning = true\n }\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._setEscapeEvent()\n this._setResizeEvent()\n\n EventHandler.on(this._dialog, EVENT_MOUSEDOWN_DISMISS, () => {\n EventHandler.one(this._element, EVENT_MOUSEUP_DISMISS, event => {\n if (event.target === this._element) {\n this._ignoreBackdropClick = true\n }\n })\n })\n\n this._showBackdrop(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n const isAnimated = this._isAnimated()\n\n if (isAnimated) {\n this._isTransitioning = true\n }\n\n this._setEscapeEvent()\n this._setResizeEvent()\n\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n EventHandler.off(this._element, EVENT_CLICK_DISMISS)\n EventHandler.off(this._dialog, EVENT_MOUSEDOWN_DISMISS)\n\n this._queueCallback(() => this._hideModal(), this._element, isAnimated)\n }\n\n dispose() {\n [window, this._dialog]\n .forEach(htmlElement => EventHandler.off(htmlElement, EVENT_KEY))\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' ? config : {})\n }\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _showElement(relatedTarget) {\n const isAnimated = this._isAnimated()\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n\n if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {\n // Don't move modal's DOM position\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n if (isAnimated) {\n reflow(this._element)\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, isAnimated)\n }\n\n _setEscapeEvent() {\n if (this._isShown) {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (this._config.keyboard && event.key === ESCAPE_KEY) {\n event.preventDefault()\n this.hide()\n } else if (!this._config.keyboard && event.key === ESCAPE_KEY) {\n this._triggerBackdropTransition()\n }\n })\n } else {\n EventHandler.off(this._element, EVENT_KEYDOWN_DISMISS)\n }\n }\n\n _setResizeEvent() {\n if (this._isShown) {\n EventHandler.on(window, EVENT_RESIZE, () => this._adjustDialog())\n } else {\n EventHandler.off(window, EVENT_RESIZE)\n }\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _showBackdrop(callback) {\n EventHandler.on(this._element, EVENT_CLICK_DISMISS, event => {\n if (this._ignoreBackdropClick) {\n this._ignoreBackdropClick = false\n return\n }\n\n if (event.target !== event.currentTarget) {\n return\n }\n\n if (this._config.backdrop === true) {\n this.hide()\n } else if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n }\n })\n\n this._backdrop.show(callback)\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const { classList, scrollHeight, style } = this._element\n const isModalOverflowing = scrollHeight > document.documentElement.clientHeight\n\n // return if the following background transition hasn't yet completed\n if ((!isModalOverflowing && style.overflowY === 'hidden') || classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n style.overflowY = 'hidden'\n }\n\n classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n classList.remove(CLASS_NAME_STATIC)\n if (!isModalOverflowing) {\n this._queueCallback(() => {\n style.overflowY = ''\n }, this._dialog)\n }\n }, this._dialog)\n\n this._element.focus()\n }\n\n // ----------------------------------------------------------------------\n // the following methods are used to handle overflowing modals\n // ----------------------------------------------------------------------\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if ((!isBodyOverflowing && isModalOverflowing && !isRTL()) || (isBodyOverflowing && !isModalOverflowing && isRTL())) {\n this._element.style.paddingLeft = `${scrollbarWidth}px`\n }\n\n if ((isBodyOverflowing && !isModalOverflowing && !isRTL()) || (!isBodyOverflowing && isModalOverflowing && isRTL())) {\n this._element.style.paddingRight = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking moddal toggler while another one is open\n const allReadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (allReadyOpen) {\n Modal.getInstance(allReadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Modal to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElementFromSelector,\n isDisabled,\n isVisible,\n typeCheckConfig\n} from './util/index'\nimport ScrollBarHelper from './util/scrollbar'\nimport EventHandler from './dom/event-handler'\nimport BaseComponent from './base-component'\nimport SelectorEngine from './dom/selector-engine'\nimport Manipulator from './dom/manipulator'\nimport Backdrop from './util/backdrop'\nimport FocusTrap from './util/focustrap'\nimport { enableDismissTrigger } from './util/component-functions'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: 'boolean',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._config = this._getConfig(config)\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n\n static get NAME() {\n return NAME\n }\n\n static get Default() {\n return Default\n }\n\n // Public\n\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._element.style.visibility = 'visible'\n\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const completeCallBack = () => {\n if (!this._config.scroll) {\n this._focustrap.activate()\n }\n\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._element.style.visibility = 'hidden'\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' ? config : {})\n }\n typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _initializeBackDrop() {\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible: this._config.backdrop,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: () => this.hide()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (this._config.keyboard && event.key === ESCAPE_KEY) {\n this.hide()\n }\n })\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const allReadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (allReadyOpen && allReadyOpen !== target) {\n Offcanvas.getInstance(allReadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () =>\n SelectorEngine.find(OPEN_SELECTOR).forEach(el => Offcanvas.getOrCreateInstance(el).show())\n)\n\nenableDismissTrigger(Offcanvas)\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\n/**\n * A pattern that recognizes a commonly useful subset of URLs that are safe.\n *\n * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts\n */\nconst SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i\n\n/**\n * A pattern that matches safe data URLs. Only matches image, video and audio types.\n *\n * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts\n */\nconst DATA_URL_PATTERN = /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[\\d+/a-z]+=*$/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue) || DATA_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n const regExp = allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n\n // Check if a regular expression validates the attribute.\n for (let i = 0, len = regExp.length; i < len; i++) {\n if (regExp[i].test(attributeName)) {\n return true\n }\n }\n\n return false\n}\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n div: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFn && typeof sanitizeFn === 'function') {\n return sanitizeFn(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (let i = 0, len = elements.length; i < len; i++) {\n const element = elements[i]\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n attributeList.forEach(attribute => {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n })\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\n\nimport {\n defineJQueryPlugin,\n findShadowRoot,\n getElement,\n getUID,\n isElement,\n isRTL,\n noop,\n typeCheckConfig\n} from './util/index'\nimport { DefaultAllowlist, sanitizeHtml } from './util/sanitizer'\nimport Data from './dom/data'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'tooltip'\nconst DATA_KEY = 'bs.tooltip'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst CLASS_PREFIX = 'bs-tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst DefaultType = {\n animation: 'boolean',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string',\n delay: '(number|object)',\n html: 'boolean',\n selector: '(string|boolean)',\n placement: '(string|function)',\n offset: '(array|string|function)',\n container: '(string|element|boolean)',\n fallbackPlacements: 'array',\n boundary: '(string|element)',\n customClass: '(string|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n allowList: 'object',\n popperConfig: '(null|object|function)'\n}\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n animation: true,\n template: '<div class=\"tooltip\" role=\"tooltip\">' +\n '<div class=\"tooltip-arrow\"></div>' +\n '<div class=\"tooltip-inner\"></div>' +\n '</div>',\n trigger: 'hover focus',\n title: '',\n delay: 0,\n html: false,\n selector: false,\n placement: 'top',\n offset: [0, 0],\n container: false,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n boundary: 'clippingParents',\n customClass: '',\n sanitize: true,\n sanitizeFn: null,\n allowList: DefaultAllowlist,\n popperConfig: null\n}\n\nconst Event = {\n HIDE: `hide${EVENT_KEY}`,\n HIDDEN: `hidden${EVENT_KEY}`,\n SHOW: `show${EVENT_KEY}`,\n SHOWN: `shown${EVENT_KEY}`,\n INSERTED: `inserted${EVENT_KEY}`,\n CLICK: `click${EVENT_KEY}`,\n FOCUSIN: `focusin${EVENT_KEY}`,\n FOCUSOUT: `focusout${EVENT_KEY}`,\n MOUSEENTER: `mouseenter${EVENT_KEY}`,\n MOUSELEAVE: `mouseleave${EVENT_KEY}`\n}\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst HOVER_STATE_SHOW = 'show'\nconst HOVER_STATE_OUT = 'out'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org)')\n }\n\n super(element)\n\n // private\n this._isEnabled = true\n this._timeout = 0\n this._hoverState = ''\n this._activeTrigger = {}\n this._popper = null\n\n // Protected\n this._config = this._getConfig(config)\n this.tip = null\n\n this._setListeners()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n static get Event() {\n return Event\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n // Public\n\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle(event) {\n if (!this._isEnabled) {\n return\n }\n\n if (event) {\n const context = this._initializeOnDelegatedTarget(event)\n\n context._activeTrigger.click = !context._activeTrigger.click\n\n if (context._isWithActiveTrigger()) {\n context._enter(null, context)\n } else {\n context._leave(null, context)\n }\n } else {\n if (this.getTipElement().classList.contains(CLASS_NAME_SHOW)) {\n this._leave(null, this)\n return\n }\n\n this._enter(null, this)\n }\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this.tip) {\n this.tip.remove()\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this.isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.Event.SHOW)\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = shadowRoot === null ?\n this._element.ownerDocument.documentElement.contains(this._element) :\n shadowRoot.contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // A trick to recreate a tooltip in case a new title is given by using the NOT documented `data-bs-original-title`\n // This will be removed later in favor of a `setContent` method\n if (this.constructor.NAME === 'tooltip' && this.tip && this.getTitle() !== this.tip.querySelector(SELECTOR_TOOLTIP_INNER).innerHTML) {\n this._disposePopper()\n this.tip.remove()\n this.tip = null\n }\n\n const tip = this.getTipElement()\n const tipId = getUID(this.constructor.NAME)\n\n tip.setAttribute('id', tipId)\n this._element.setAttribute('aria-describedby', tipId)\n\n if (this._config.animation) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n const placement = typeof this._config.placement === 'function' ?\n this._config.placement.call(this, tip, this._element) :\n this._config.placement\n\n const attachment = this._getAttachment(placement)\n this._addAttachmentClass(attachment)\n\n const { container } = this._config\n Data.set(tip, this.constructor.DATA_KEY, this)\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.Event.INSERTED)\n }\n\n if (this._popper) {\n this._popper.update()\n } else {\n this._popper = Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n const customClass = this._resolvePossibleFunction(this._config.customClass)\n if (customClass) {\n tip.classList.add(...customClass.split(' '))\n }\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n [].concat(...document.body.children).forEach(element => {\n EventHandler.on(element, 'mouseover', noop)\n })\n }\n\n const complete = () => {\n const prevHoverState = this._hoverState\n\n this._hoverState = null\n EventHandler.trigger(this._element, this.constructor.Event.SHOWN)\n\n if (prevHoverState === HOVER_STATE_OUT) {\n this._leave(null, this)\n }\n }\n\n const isAnimated = this.tip.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(complete, this.tip, isAnimated)\n }\n\n hide() {\n if (!this._popper) {\n return\n }\n\n const tip = this.getTipElement()\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (this._hoverState !== HOVER_STATE_SHOW) {\n tip.remove()\n }\n\n this._cleanTipClass()\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.Event.HIDDEN)\n\n this._disposePopper()\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.Event.HIDE)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n [].concat(...document.body.children)\n .forEach(element => EventHandler.off(element, 'mouseover', noop))\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n\n const isAnimated = this.tip.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(complete, this.tip, isAnimated)\n this._hoverState = ''\n }\n\n update() {\n if (this._popper !== null) {\n this._popper.update()\n }\n }\n\n // Protected\n\n isWithContent() {\n return Boolean(this.getTitle())\n }\n\n getTipElement() {\n if (this.tip) {\n return this.tip\n }\n\n const element = document.createElement('div')\n element.innerHTML = this._config.template\n\n const tip = element.children[0]\n this.setContent(tip)\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n\n this.tip = tip\n return this.tip\n }\n\n setContent(tip) {\n this._sanitizeAndSetContent(tip, this.getTitle(), SELECTOR_TOOLTIP_INNER)\n }\n\n _sanitizeAndSetContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!content && templateElement) {\n templateElement.remove()\n return\n }\n\n // we use append for html objects to maintain js events\n this.setElementContent(templateElement, content)\n }\n\n setElementContent(element, content) {\n if (element === null) {\n return\n }\n\n if (isElement(content)) {\n content = getElement(content)\n\n // content is a DOM node or a jQuery\n if (this._config.html) {\n if (content.parentNode !== element) {\n element.innerHTML = ''\n element.append(content)\n }\n } else {\n element.textContent = content.textContent\n }\n\n return\n }\n\n if (this._config.html) {\n if (this._config.sanitize) {\n content = sanitizeHtml(content, this._config.allowList, this._config.sanitizeFn)\n }\n\n element.innerHTML = content\n } else {\n element.textContent = content\n }\n }\n\n getTitle() {\n const title = this._element.getAttribute('data-bs-original-title') || this._config.title\n\n return this._resolvePossibleFunction(title)\n }\n\n updateAttachment(attachment) {\n if (attachment === 'right') {\n return 'end'\n }\n\n if (attachment === 'left') {\n return 'start'\n }\n\n return attachment\n }\n\n // Private\n\n _initializeOnDelegatedTarget(event, context) {\n return context || this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(val => Number.parseInt(val, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(content) {\n return typeof content === 'function' ? content.call(this._element) : content\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'onChange',\n enabled: true,\n phase: 'afterWrite',\n fn: data => this._handlePopperPlacementChange(data)\n }\n ],\n onFirstUpdate: data => {\n if (data.options.placement !== data.placement) {\n this._handlePopperPlacementChange(data)\n }\n }\n }\n\n return {\n ...defaultBsPopperConfig,\n ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)\n }\n }\n\n _addAttachmentClass(attachment) {\n this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(attachment)}`)\n }\n\n _getAttachment(placement) {\n return AttachmentMap[placement.toUpperCase()]\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n triggers.forEach(trigger => {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.Event.CLICK, this._config.selector, event => this.toggle(event))\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.Event.MOUSEENTER :\n this.constructor.Event.FOCUSIN\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.Event.MOUSELEAVE :\n this.constructor.Event.FOCUSOUT\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => this._enter(event))\n EventHandler.on(this._element, eventOut, this._config.selector, event => this._leave(event))\n }\n })\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._config.selector) {\n this._config = {\n ...this._config,\n trigger: 'manual',\n selector: ''\n }\n } else {\n this._fixTitle()\n }\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n const originalTitleType = typeof this._element.getAttribute('data-bs-original-title')\n\n if (title || originalTitleType !== 'string') {\n this._element.setAttribute('data-bs-original-title', title || '')\n if (title && !this._element.getAttribute('aria-label') && !this._element.textContent) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('title', '')\n }\n }\n\n _enter(event, context) {\n context = this._initializeOnDelegatedTarget(event, context)\n\n if (event) {\n context._activeTrigger[\n event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER\n ] = true\n }\n\n if (context.getTipElement().classList.contains(CLASS_NAME_SHOW) || context._hoverState === HOVER_STATE_SHOW) {\n context._hoverState = HOVER_STATE_SHOW\n return\n }\n\n clearTimeout(context._timeout)\n\n context._hoverState = HOVER_STATE_SHOW\n\n if (!context._config.delay || !context._config.delay.show) {\n context.show()\n return\n }\n\n context._timeout = setTimeout(() => {\n if (context._hoverState === HOVER_STATE_SHOW) {\n context.show()\n }\n }, context._config.delay.show)\n }\n\n _leave(event, context) {\n context = this._initializeOnDelegatedTarget(event, context)\n\n if (event) {\n context._activeTrigger[\n event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER\n ] = context._element.contains(event.relatedTarget)\n }\n\n if (context._isWithActiveTrigger()) {\n return\n }\n\n clearTimeout(context._timeout)\n\n context._hoverState = HOVER_STATE_OUT\n\n if (!context._config.delay || !context._config.delay.hide) {\n context.hide()\n return\n }\n\n context._timeout = setTimeout(() => {\n if (context._hoverState === HOVER_STATE_OUT) {\n context.hide()\n }\n }, context._config.delay.hide)\n }\n\n _isWithActiveTrigger() {\n for (const trigger in this._activeTrigger) {\n if (this._activeTrigger[trigger]) {\n return true\n }\n }\n\n return false\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n Object.keys(dataAttributes).forEach(dataAttr => {\n if (DISALLOWED_ATTRIBUTES.has(dataAttr)) {\n delete dataAttributes[dataAttr]\n }\n })\n\n config = {\n ...this.constructor.Default,\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n typeCheckConfig(NAME, config, this.constructor.DefaultType)\n\n if (config.sanitize) {\n config.template = sanitizeHtml(config.template, config.allowList, config.sanitizeFn)\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const key in this._config) {\n if (this.constructor.Default[key] !== this._config[key]) {\n config[key] = this._config[key]\n }\n }\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _cleanTipClass() {\n const tip = this.getTipElement()\n const basicClassPrefixRegex = new RegExp(`(^|\\\\s)${this._getBasicClassPrefix()}\\\\S+`, 'g')\n const tabClass = tip.getAttribute('class').match(basicClassPrefixRegex)\n if (tabClass !== null && tabClass.length > 0) {\n tabClass.map(token => token.trim())\n .forEach(tClass => tip.classList.remove(tClass))\n }\n }\n\n _getBasicClassPrefix() {\n return CLASS_PREFIX\n }\n\n _handlePopperPlacementChange(popperData) {\n const { state } = popperData\n\n if (!state) {\n return\n }\n\n this.tip = state.elements.popper\n this._cleanTipClass()\n this._addAttachmentClass(this._getAttachment(state.placement))\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Tooltip to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { defineJQueryPlugin } from './util/index'\nimport Tooltip from './tooltip'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'popover'\nconst DATA_KEY = 'bs.popover'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst CLASS_PREFIX = 'bs-popover'\n\nconst Default = {\n ...Tooltip.Default,\n placement: 'right',\n offset: [0, 8],\n trigger: 'click',\n content: '',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(string|element|function)'\n}\n\nconst Event = {\n HIDE: `hide${EVENT_KEY}`,\n HIDDEN: `hidden${EVENT_KEY}`,\n SHOW: `show${EVENT_KEY}`,\n SHOWN: `shown${EVENT_KEY}`,\n INSERTED: `inserted${EVENT_KEY}`,\n CLICK: `click${EVENT_KEY}`,\n FOCUSIN: `focusin${EVENT_KEY}`,\n FOCUSOUT: `focusout${EVENT_KEY}`,\n MOUSEENTER: `mouseenter${EVENT_KEY}`,\n MOUSELEAVE: `mouseleave${EVENT_KEY}`\n}\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Popover extends Tooltip {\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n static get Event() {\n return Event\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n // Overrides\n\n isWithContent() {\n return this.getTitle() || this._getContent()\n }\n\n setContent(tip) {\n this._sanitizeAndSetContent(tip, this.getTitle(), SELECTOR_TITLE)\n this._sanitizeAndSetContent(tip, this._getContent(), SELECTOR_CONTENT)\n }\n\n // Private\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n _getBasicClassPrefix() {\n return CLASS_PREFIX\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Popover to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElement,\n getSelectorFromElement,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst Default = {\n offset: 10,\n method: 'auto',\n target: ''\n}\n\nconst DefaultType = {\n offset: 'number',\n method: 'string',\n target: '(string|element)'\n}\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_SCROLL = `scroll${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}, .${CLASS_NAME_DROPDOWN_ITEM}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst METHOD_OFFSET = 'offset'\nconst METHOD_POSITION = 'position'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element)\n this._scrollElement = this._element.tagName === 'BODY' ? window : this._element\n this._config = this._getConfig(config)\n this._offsets = []\n this._targets = []\n this._activeTarget = null\n this._scrollHeight = 0\n\n EventHandler.on(this._scrollElement, EVENT_SCROLL, () => this._process())\n\n this.refresh()\n this._process()\n }\n\n // Getters\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n refresh() {\n const autoMethod = this._scrollElement === this._scrollElement.window ?\n METHOD_OFFSET :\n METHOD_POSITION\n\n const offsetMethod = this._config.method === 'auto' ?\n autoMethod :\n this._config.method\n\n const offsetBase = offsetMethod === METHOD_POSITION ?\n this._getScrollTop() :\n 0\n\n this._offsets = []\n this._targets = []\n this._scrollHeight = this._getScrollHeight()\n\n const targets = SelectorEngine.find(SELECTOR_LINK_ITEMS, this._config.target)\n\n targets.map(element => {\n const targetSelector = getSelectorFromElement(element)\n const target = targetSelector ? SelectorEngine.findOne(targetSelector) : null\n\n if (target) {\n const targetBCR = target.getBoundingClientRect()\n if (targetBCR.width || targetBCR.height) {\n return [\n Manipulator[offsetMethod](target).top + offsetBase,\n targetSelector\n ]\n }\n }\n\n return null\n })\n .filter(item => item)\n .sort((a, b) => a[0] - b[0])\n .forEach(item => {\n this._offsets.push(item[0])\n this._targets.push(item[1])\n })\n }\n\n dispose() {\n EventHandler.off(this._scrollElement, EVENT_KEY)\n super.dispose()\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' && config ? config : {})\n }\n\n config.target = getElement(config.target) || document.documentElement\n\n typeCheckConfig(NAME, config, DefaultType)\n\n return config\n }\n\n _getScrollTop() {\n return this._scrollElement === window ?\n this._scrollElement.pageYOffset :\n this._scrollElement.scrollTop\n }\n\n _getScrollHeight() {\n return this._scrollElement.scrollHeight || Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight\n )\n }\n\n _getOffsetHeight() {\n return this._scrollElement === window ?\n window.innerHeight :\n this._scrollElement.getBoundingClientRect().height\n }\n\n _process() {\n const scrollTop = this._getScrollTop() + this._config.offset\n const scrollHeight = this._getScrollHeight()\n const maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight()\n\n if (this._scrollHeight !== scrollHeight) {\n this.refresh()\n }\n\n if (scrollTop >= maxScroll) {\n const target = this._targets[this._targets.length - 1]\n\n if (this._activeTarget !== target) {\n this._activate(target)\n }\n\n return\n }\n\n if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {\n this._activeTarget = null\n this._clear()\n return\n }\n\n for (let i = this._offsets.length; i--;) {\n const isActiveTarget = this._activeTarget !== this._targets[i] &&\n scrollTop >= this._offsets[i] &&\n (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1])\n\n if (isActiveTarget) {\n this._activate(this._targets[i])\n }\n }\n }\n\n _activate(target) {\n this._activeTarget = target\n\n this._clear()\n\n const queries = SELECTOR_LINK_ITEMS.split(',')\n .map(selector => `${selector}[data-bs-target=\"${target}\"],${selector}[href=\"${target}\"]`)\n\n const link = SelectorEngine.findOne(queries.join(','), this._config.target)\n\n link.classList.add(CLASS_NAME_ACTIVE)\n if (link.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, link.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n } else {\n SelectorEngine.parents(link, SELECTOR_NAV_LIST_GROUP)\n .forEach(listGroup => {\n // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n SelectorEngine.prev(listGroup, `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`)\n .forEach(item => item.classList.add(CLASS_NAME_ACTIVE))\n\n // Handle special case when .nav-link is inside .nav-item\n SelectorEngine.prev(listGroup, SELECTOR_NAV_ITEMS)\n .forEach(navItem => {\n SelectorEngine.children(navItem, SELECTOR_NAV_LINKS)\n .forEach(item => item.classList.add(CLASS_NAME_ACTIVE))\n })\n })\n }\n\n EventHandler.trigger(this._scrollElement, EVENT_ACTIVATE, {\n relatedTarget: target\n })\n }\n\n _clear() {\n SelectorEngine.find(SELECTOR_LINK_ITEMS, this._config.target)\n .filter(node => node.classList.contains(CLASS_NAME_ACTIVE))\n .forEach(node => node.classList.remove(CLASS_NAME_ACTIVE))\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = ScrollSpy.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n SelectorEngine.find(SELECTOR_DATA_SPY)\n .forEach(spy => new ScrollSpy(spy))\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .ScrollSpy to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(ScrollSpy)\n\nexport default ScrollSpy\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): tab.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n getElementFromSelector,\n isDisabled,\n reflow\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport SelectorEngine from './dom/selector-engine'\nimport BaseComponent from './base-component'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'tab'\nconst DATA_KEY = 'bs.tab'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ACTIVE_UL = ':scope > li > .active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\nconst SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Tab extends BaseComponent {\n // Getters\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n show() {\n if ((this._element.parentNode &&\n this._element.parentNode.nodeType === Node.ELEMENT_NODE &&\n this._element.classList.contains(CLASS_NAME_ACTIVE))) {\n return\n }\n\n let previous\n const target = getElementFromSelector(this._element)\n const listElement = this._element.closest(SELECTOR_NAV_LIST_GROUP)\n\n if (listElement) {\n const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? SELECTOR_ACTIVE_UL : SELECTOR_ACTIVE\n previous = SelectorEngine.find(itemSelector, listElement)\n previous = previous[previous.length - 1]\n }\n\n const hideEvent = previous ?\n EventHandler.trigger(previous, EVENT_HIDE, {\n relatedTarget: this._element\n }) :\n null\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget: previous\n })\n\n if (showEvent.defaultPrevented || (hideEvent !== null && hideEvent.defaultPrevented)) {\n return\n }\n\n this._activate(this._element, listElement)\n\n const complete = () => {\n EventHandler.trigger(previous, EVENT_HIDDEN, {\n relatedTarget: this._element\n })\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget: previous\n })\n }\n\n if (target) {\n this._activate(target, target.parentNode, complete)\n } else {\n complete()\n }\n }\n\n // Private\n\n _activate(element, container, callback) {\n const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ?\n SelectorEngine.find(SELECTOR_ACTIVE_UL, container) :\n SelectorEngine.children(container, SELECTOR_ACTIVE)\n\n const active = activeElements[0]\n const isTransitioning = callback && (active && active.classList.contains(CLASS_NAME_FADE))\n\n const complete = () => this._transitionComplete(element, active, callback)\n\n if (active && isTransitioning) {\n active.classList.remove(CLASS_NAME_SHOW)\n this._queueCallback(complete, element, true)\n } else {\n complete()\n }\n }\n\n _transitionComplete(element, active, callback) {\n if (active) {\n active.classList.remove(CLASS_NAME_ACTIVE)\n\n const dropdownChild = SelectorEngine.findOne(SELECTOR_DROPDOWN_ACTIVE_CHILD, active.parentNode)\n\n if (dropdownChild) {\n dropdownChild.classList.remove(CLASS_NAME_ACTIVE)\n }\n\n if (active.getAttribute('role') === 'tab') {\n active.setAttribute('aria-selected', false)\n }\n }\n\n element.classList.add(CLASS_NAME_ACTIVE)\n if (element.getAttribute('role') === 'tab') {\n element.setAttribute('aria-selected', true)\n }\n\n reflow(element)\n\n if (element.classList.contains(CLASS_NAME_FADE)) {\n element.classList.add(CLASS_NAME_SHOW)\n }\n\n let parent = element.parentNode\n if (parent && parent.nodeName === 'LI') {\n parent = parent.parentNode\n }\n\n if (parent && parent.classList.contains(CLASS_NAME_DROPDOWN_MENU)) {\n const dropdownElement = element.closest(SELECTOR_DROPDOWN)\n\n if (dropdownElement) {\n SelectorEngine.find(SELECTOR_DROPDOWN_TOGGLE, dropdownElement)\n .forEach(dropdown => dropdown.classList.add(CLASS_NAME_ACTIVE))\n }\n\n element.setAttribute('aria-expanded', true)\n }\n\n if (callback) {\n callback()\n }\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tab.getOrCreateInstance(this)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const data = Tab.getOrCreateInstance(this)\n data.show()\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Tab to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Tab)\n\nexport default Tab\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): toast.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n defineJQueryPlugin,\n reflow,\n typeCheckConfig\n} from './util/index'\nimport EventHandler from './dom/event-handler'\nimport Manipulator from './dom/manipulator'\nimport BaseComponent from './base-component'\nimport { enableDismissTrigger } from './util/component-functions'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'toast'\nconst DATA_KEY = 'bs.toast'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\n\nconst DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n}\n\nconst Default = {\n animation: true,\n autohide: true,\n delay: 5000\n}\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Toast extends BaseComponent {\n constructor(element, config) {\n super(element)\n\n this._config = this._getConfig(config)\n this._timeout = null\n this._hasMouseInteraction = false\n this._hasKeyboardInteraction = false\n this._setListeners()\n }\n\n // Getters\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n\n show() {\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._clearTimeout()\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE)\n }\n\n const complete = () => {\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN)\n\n this._maybeScheduleHide()\n }\n\n this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\n reflow(this._element)\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n hide() {\n if (!this._element.classList.contains(CLASS_NAME_SHOW)) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const complete = () => {\n this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\n this._element.classList.remove(CLASS_NAME_SHOWING)\n this._element.classList.remove(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.classList.add(CLASS_NAME_SHOWING)\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n dispose() {\n this._clearTimeout()\n\n if (this._element.classList.contains(CLASS_NAME_SHOW)) {\n this._element.classList.remove(CLASS_NAME_SHOW)\n }\n\n super.dispose()\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...Manipulator.getDataAttributes(this._element),\n ...(typeof config === 'object' && config ? config : {})\n }\n\n typeCheckConfig(NAME, config, this.constructor.DefaultType)\n\n return config\n }\n\n _maybeScheduleHide() {\n if (!this._config.autohide) {\n return\n }\n\n if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\n return\n }\n\n this._timeout = setTimeout(() => {\n this.hide()\n }, this._config.delay)\n }\n\n _onInteraction(event, isInteracting) {\n switch (event.type) {\n case 'mouseover':\n case 'mouseout':\n this._hasMouseInteraction = isInteracting\n break\n case 'focusin':\n case 'focusout':\n this._hasKeyboardInteraction = isInteracting\n break\n default:\n break\n }\n\n if (isInteracting) {\n this._clearTimeout()\n return\n }\n\n const nextElement = event.relatedTarget\n if (this._element === nextElement || this._element.contains(nextElement)) {\n return\n }\n\n this._maybeScheduleHide()\n }\n\n _setListeners() {\n EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\n EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\n }\n\n _clearTimeout() {\n clearTimeout(this._timeout)\n this._timeout = null\n }\n\n // Static\n\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Toast.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n }\n })\n }\n}\n\nenableDismissTrigger(Toast)\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n * add .Toast to jQuery only if jQuery is present\n */\n\ndefineJQueryPlugin(Toast)\n\nexport default Toast\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v5.1.3): index.umd.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './src/alert'\nimport Button from './src/button'\nimport Carousel from './src/carousel'\nimport Collapse from './src/collapse'\nimport Dropdown from './src/dropdown'\nimport Modal from './src/modal'\nimport Offcanvas from './src/offcanvas'\nimport Popover from './src/popover'\nimport ScrollSpy from './src/scrollspy'\nimport Tab from './src/tab'\nimport Toast from './src/toast'\nimport Tooltip from './src/tooltip'\n\nexport default {\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Offcanvas,\n Popover,\n ScrollSpy,\n Tab,\n Toast,\n Tooltip\n}\n"]} \ No newline at end of file diff --git a/src/base/theme/bootsier/mod.rs b/src/base/theme/bootsier/mod.rs index f0a0f61c..92e7437a 100644 --- a/src/base/theme/bootsier/mod.rs +++ b/src/base/theme/bootsier/mod.rs @@ -7,14 +7,14 @@ localize!("en-US", "src/base/theme/bootsier/locales"); pub struct BootsierTheme; impl Theme for BootsierTheme { - fn name(&self) -> &str { - "Bootsier" + fn name(&self) -> String { + "Bootsier".to_string() } fn configure_theme(&self, cfg: &mut server::web::ServiceConfig) { cfg.service(actix_web_static_files::ResourceFiles::new( "/bootsier", - generate() + assets() )); } @@ -26,15 +26,15 @@ impl Theme for BootsierTheme { ) .add_stylesheet( StyleSheet::source( - "/bootsier/css/bootstrap.min.css" + "/bootsier/css/bootstrap.min.css?v=5.1.3" ) .with_weight(-99) ) .add_javascript( JavaScript::source( - "/bootsier/js/bootstrap.bundle.min.js" + "/bootsier/js/bootstrap.bundle.min.js?v=5.1.3" ) - .with_weight(-98) + .with_weight(-99) ) .add_jquery(); } diff --git a/src/base/theme/minimal/mod.rs b/src/base/theme/minimal/mod.rs index ea1ea1f4..9ea6e87e 100644 --- a/src/base/theme/minimal/mod.rs +++ b/src/base/theme/minimal/mod.rs @@ -3,7 +3,7 @@ use crate::prelude::*; pub struct MinimalTheme; impl Theme for MinimalTheme { - fn name(&self) -> &str { - "Minimal" + fn name(&self) -> String { + "Minimal".to_string() } } diff --git a/src/config/settings.rs b/src/config/settings.rs index b2a758e7..94097c3a 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -6,7 +6,10 @@ use serde::Deserialize; use std::env; -/// Carga los ajustes globales "clave = valor" al arrancar la aplicación. +/// Al arrancar la aplicación, carga los valores originales "clave = valor" de +/// los archivos de configuración. Con [`config_map`] se asignarán los ajustes +/// globales ([`SETTINGS`]); y se podrán asignar los ajustes específicos de la +/// aplicación, o también de un tema, módulo o componente. pub static CONFIG: Lazy<Config> = Lazy::new(|| { // Establece el modo de ejecución según el valor de la variable de entorno // PAGETOP_RUN_MODE. Asume "default" por defecto. @@ -15,8 +18,7 @@ pub static CONFIG: Lazy<Config> = Lazy::new(|| { // Inicializa los ajustes. let mut settings = Config::default(); - // Lee los ajustes combinando los archivos de configuración disponibles y - // asigna el modo de ejecución. + // Combina los archivos de configuración y asigna el modo de ejecución. settings .merge( File::with_name( @@ -36,23 +38,13 @@ pub static CONFIG: Lazy<Config> = Lazy::new(|| { }); #[macro_export] -/// Usar esta macro para obtener el valor de cualquier ajuste global, donde -/// clave y valor son cadenas de caracteres. Devuelve la cadena vacía si no -/// encuentra un ajuste para la clave. -macro_rules! config_get { - ( $key:expr ) => { - $crate::config::CONFIG.get_str($key).unwrap_or("".to_string()) - }; -} - -#[macro_export] -/// Carga los ajustes específicos de tu módulo o aplicación en una estructura -/// similar a [`SETTINGS`] con tipos de variables seguros. Genera un *panic!* -/// en caso de asignaciones no válidas. +/// Asigna los ajustes específicos de la aplicación, o de un tema, módulo o +/// componente, en una estructura similar a [`SETTINGS`] con tipos de variables +/// seguros. Produce un *panic!* en caso de asignaciones no válidas. macro_rules! config_map { - ( $COMMENT:expr, $CONF:ident, $TYPE:tt $(, $key:expr => $value:expr)* ) => { + ( $COMM:expr, $CONF:ident, $TYPE:tt $(, $key:expr => $value:expr)* ) => { $crate::doc_comment! { - concat!($COMMENT), + concat!($COMM), pub static $CONF: $crate::Lazy<$TYPE> = $crate::Lazy::new(|| { let mut settings = $crate::config::CONFIG.clone(); @@ -101,7 +93,7 @@ pub struct Settings { config_map!(r#" Ajustes globales y valores predeterminados para las secciones *\[app\]*, -*\[log\]* y *\[webserver\]* específicas de PageTop. +*\[log\]* y *\[webserver\]* de PageTop. "#, SETTINGS, Settings, diff --git a/src/core/all.rs b/src/core/all.rs index 716dac9b..3fe712b6 100644 --- a/src/core/all.rs +++ b/src/core/all.rs @@ -1,6 +1,13 @@ use crate::core::{server, state}; +include!(concat!(env!("OUT_DIR"), "/theme.rs")); + pub fn themes(cfg: &mut server::web::ServiceConfig) { + cfg.service(actix_web_static_files::ResourceFiles::new( + "/theme", + assets() + )); + for t in state::THEMES.read().unwrap().iter() { t.configure_theme(cfg); } diff --git a/src/core/response/page/assets.rs b/src/core/response/page/assets.rs index 2bffd73b..c01855d9 100644 --- a/src/core/response/page/assets.rs +++ b/src/core/response/page/assets.rs @@ -228,7 +228,7 @@ impl Assets { if !self.with_jquery { self.add_javascript( JavaScript::source( - "/assets/js/jquery.min.js?ver=3.6.0" + "/theme/js/jquery.min.js?v=3.6.0" ) .with_weight(i8::MIN) .with_mode(JSMode::Normal) diff --git a/resources/slant.flf b/src/core/server/figfonts/slant.flf similarity index 100% rename from resources/slant.flf rename to src/core/server/figfonts/slant.flf diff --git a/resources/small.flf b/src/core/server/figfonts/small.flf similarity index 100% rename from resources/small.flf rename to src/core/server/figfonts/small.flf diff --git a/resources/speed.flf b/src/core/server/figfonts/speed.flf similarity index 100% rename from resources/speed.flf rename to src/core/server/figfonts/speed.flf diff --git a/resources/starwars.flf b/src/core/server/figfonts/starwars.flf similarity index 100% rename from resources/starwars.flf rename to src/core/server/figfonts/starwars.flf diff --git a/src/core/server/main.rs b/src/core/server/main.rs index b915743e..8616158e 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -57,16 +57,16 @@ pub fn run(bootstrap: Option<fn()>) -> Result<Server, std::io::Error> { if SETTINGS.app.startup_banner.to_lowercase() != "off" { let figfont = figlet_rs::FIGfont::from_content( match SETTINGS.app.startup_banner.to_lowercase().as_str() { - "slant" => include_str!("../../../resources/slant.flf"), - "small" => include_str!("../../../resources/small.flf"), - "speed" => include_str!("../../../resources/speed.flf"), - "starwars" => include_str!("../../../resources/starwars.flf"), + "slant" => include_str!("figfonts/slant.flf"), + "small" => include_str!("figfonts/small.flf"), + "speed" => include_str!("figfonts/speed.flf"), + "starwars" => include_str!("figfonts/starwars.flf"), _ => { trace::warn!( "FIGfont \"{}\" not found for banner. Using \"{}\"", SETTINGS.app.startup_banner, "Small" ); - include_str!("../../../resources/small.flf") + include_str!("figfonts/small.flf") } } ).unwrap(); diff --git a/src/core/theme/api.rs b/src/core/theme/api.rs index 2f4a5682..8c0caad1 100644 --- a/src/core/theme/api.rs +++ b/src/core/theme/api.rs @@ -5,10 +5,10 @@ use crate::base::component::Chunck; /// Los temas deben implementar este "trait". pub trait Theme: Send + Sync { - fn name(&self) -> &str; + fn name(&self) -> String; - fn description(&self) -> &str { - "" + fn description(&self) -> String { + "".to_string() } #[allow(unused_variables)] @@ -41,7 +41,7 @@ pub trait Theme: Send + Sync { fn render_page_body(&self, page: &mut Page) -> Markup { html! { - body id="body" class=(page.body_classes()) { + body class=(page.body_classes()) { @match page.template() { "admin" => { @for region in &["top-menu", "side-menu", "content"] { diff --git a/src/base/theme/aliner/assets/css/styles.css b/static/aliner/css/styles.css similarity index 100% rename from src/base/theme/aliner/assets/css/styles.css rename to static/aliner/css/styles.css diff --git a/src/base/theme/bootsier/assets/css/bootstrap.min.css b/static/bootsier/css/bootstrap.min.css similarity index 100% rename from src/base/theme/bootsier/assets/css/bootstrap.min.css rename to static/bootsier/css/bootstrap.min.css diff --git a/src/base/theme/bootsier/assets/css/bootstrap.min.css.map b/static/bootsier/css/bootstrap.min.css.map similarity index 100% rename from src/base/theme/bootsier/assets/css/bootstrap.min.css.map rename to static/bootsier/css/bootstrap.min.css.map diff --git a/src/base/theme/bootsier/assets/images/caution.png b/static/bootsier/images/caution.png similarity index 100% rename from src/base/theme/bootsier/assets/images/caution.png rename to static/bootsier/images/caution.png diff --git a/src/base/theme/bootsier/assets/js/bootstrap.bundle.min.js b/static/bootsier/js/bootstrap.bundle.min.js similarity index 100% rename from src/base/theme/bootsier/assets/js/bootstrap.bundle.min.js rename to static/bootsier/js/bootstrap.bundle.min.js diff --git a/src/base/theme/bootsier/assets/js/bootstrap.bundle.min.js.map b/static/bootsier/js/bootstrap.bundle.min.js.map similarity index 100% rename from src/base/theme/bootsier/assets/js/bootstrap.bundle.min.js.map rename to static/bootsier/js/bootstrap.bundle.min.js.map diff --git a/resources/assets/js/jquery.min.js b/static/theme/js/jquery.min.js similarity index 100% rename from resources/assets/js/jquery.min.js rename to static/theme/js/jquery.min.js diff --git a/resources/assets/js/jquery.min.map b/static/theme/js/jquery.min.map similarity index 100% rename from resources/assets/js/jquery.min.map rename to static/theme/js/jquery.min.map From edf5ddf81b2951192f62d3f55f682681cbfe62c8 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 25 Feb 2022 20:42:06 +0100 Subject: [PATCH 014/244] =?UTF-8?q?A=C3=B1ade=20componente=20para=20crear?= =?UTF-8?q?=20men=C3=BAs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit También introduce el nuevo módulo Admin para porporcionar un entorno común de administración para los demás módulos de PageTop. --- config/default.toml | 2 +- src/base/component/block.rs | 105 ++++++++ src/base/component/container.rs | 12 +- src/base/component/form/button.rs | 24 +- src/base/component/form/date.rs | 33 +-- src/base/component/form/form.rs | 33 +-- src/base/component/form/hidden.rs | 60 +---- src/base/component/form/input.rs | 33 +-- src/base/component/menu.rs | 252 +++++++++++++++++++ src/base/component/mod.rs | 4 + src/base/module/admin/configure.rs | 17 ++ src/base/module/admin/mod.rs | 4 + src/base/module/admin/summary.rs | 54 +++++ src/base/module/mod.rs | 1 + src/base/theme/bootsier/mod.rs | 4 +- src/core/response/page/assets.rs | 23 +- src/core/response/page/component.rs | 8 + src/core/state.rs | 1 + src/lib.rs | 2 +- src/macros/mod.rs | 19 -- src/prelude.rs | 2 + src/util.rs | 42 ++++ static/theme/menu/css/menu-blue.css | 333 ++++++++++++++++++++++++++ static/theme/menu/css/menu-clean.css | 327 +++++++++++++++++++++++++ static/theme/menu/css/menu-mint.css | 331 +++++++++++++++++++++++++ static/theme/menu/css/menu-simple.css | 249 +++++++++++++++++++ static/theme/menu/css/menu.css | 58 +++++ static/theme/menu/js/menu.min.js | 3 + 28 files changed, 1849 insertions(+), 187 deletions(-) create mode 100644 src/base/component/block.rs create mode 100644 src/base/component/menu.rs create mode 100644 src/base/module/admin/configure.rs create mode 100644 src/base/module/admin/mod.rs create mode 100644 src/base/module/admin/summary.rs delete mode 100644 src/macros/mod.rs create mode 100644 src/util.rs create mode 100644 static/theme/menu/css/menu-blue.css create mode 100644 static/theme/menu/css/menu-clean.css create mode 100644 static/theme/menu/css/menu-mint.css create mode 100644 static/theme/menu/css/menu-simple.css create mode 100644 static/theme/menu/css/menu.css create mode 100644 static/theme/menu/js/menu.min.js diff --git a/config/default.toml b/config/default.toml index f96d1a7d..5f8778a3 100644 --- a/config/default.toml +++ b/config/default.toml @@ -1,3 +1,3 @@ [app] name = "PageTop Essence" -language = "es-ES" +description = "A modern Content Management System for sharing the world." diff --git a/src/base/component/block.rs b/src/base/component/block.rs new file mode 100644 index 00000000..03e67e01 --- /dev/null +++ b/src/base/component/block.rs @@ -0,0 +1,105 @@ +use crate::prelude::*; + +pub struct Block { + renderable: fn() -> bool, + weight : i8, + id : Option<String>, + title : String, + markup : Vec<Markup>, + template : String, +} + +impl PageComponent for Block { + + fn prepare() -> Self { + Block { + renderable: always, + weight : 0, + id : None, + title : "".to_string(), + markup : Vec::new(), + template : "default".to_string(), + } + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> i8 { + self.weight + } + + fn default_render(&self, assets: &mut PageAssets) -> Markup { + let id = assets.required_id(self.name(), self.id()); + html! { + div id=(id) class="block" { + @if !self.title.is_empty() { + h2 class="block-title" { (self.title) } + } + div class="block-body" { + @for markup in self.markup.iter() { + (*markup) + } + } + } + } + } +} + +impl Block { + + pub fn markup(markup: Markup) -> Self { + Block::prepare().add_markup(markup) + } + + // Block BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_id(mut self, id: &str) -> Self { + self.id = util::valid_id(id); + self + } + + pub fn with_title(mut self, title: &str) -> Self { + self.title = title.to_string(); + self + } + + pub fn add_markup(mut self, markup: Markup) -> Self { + self.markup.push(markup); + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.template = template.to_string(); + self + } + + // Block GETTERS. + + pub fn id(&self) -> &str { + util::assigned_value(&self.id) + } + + pub fn title(&self) -> &str { + self.title.as_str() + } + + pub fn template(&self) -> &str { + self.template.as_str() + } +} + +fn always() -> bool { + true +} diff --git a/src/base/component/container.rs b/src/base/component/container.rs index d4315ddc..61c08336 100644 --- a/src/base/component/container.rs +++ b/src/base/component/container.rs @@ -5,7 +5,7 @@ enum ContainerType { Column, Row, Wrapper } pub struct Container { renderable: fn() -> bool, weight : i8, - id : String, + id : Option<String>, container : ContainerType, components: PageContainer, template : String, @@ -17,7 +17,7 @@ impl PageComponent for Container { Container { renderable: always, weight : 0, - id : "".to_string(), + id : None, container : ContainerType::Wrapper, components: PageContainer::new(), template : "default".to_string(), @@ -39,7 +39,7 @@ impl PageComponent for Container { ContainerType::Column => "col", }; html! { - div class=(classes) { + div id=[&self.id] class=(classes) { (self.components.render(assets)) } } @@ -73,7 +73,7 @@ impl Container { } pub fn with_id(mut self, id: &str) -> Self { - self.id = id.to_string(); + self.id = util::valid_id(id); self } @@ -87,10 +87,10 @@ impl Container { self } - // Grid GETTERS. + // Container GETTERS. pub fn id(&self) -> &str { - self.id.as_str() + util::assigned_value(&self.id) } pub fn template(&self) -> &str { diff --git a/src/base/component/form/button.rs b/src/base/component/form/button.rs index 440ccf93..c95eb3ec 100644 --- a/src/base/component/form/button.rs +++ b/src/base/component/form/button.rs @@ -23,7 +23,7 @@ impl PageComponent for Button { name : None, value : None, autofocus : None, - disabled : None, + disabled : None, template : "default".to_string(), } } @@ -96,20 +96,12 @@ impl Button { } pub fn with_name(mut self, name: &str) -> Self { - self.name = if name.is_empty() { - None - } else { - Some(name.replace(" ", "_")) - }; + self.name = util::valid_id(name); self } pub fn with_value(mut self, value: &str) -> Self { - self.value = if value.is_empty() { - None - } else { - Some(value.to_string()) - }; + self.value = util::optional_value(value); self } @@ -137,17 +129,11 @@ impl Button { // Button GETTERS. pub fn name(&self) -> &str { - match &self.name { - Some(name) => name.as_str(), - _ => "" - } + util::assigned_value(&self.name) } pub fn value(&self) -> &str { - match &self.value { - Some(value) => value.as_str(), - _ => "" - } + util::assigned_value(&self.value) } pub fn has_autofocus(&self) -> bool { diff --git a/src/base/component/form/date.rs b/src/base/component/form/date.rs index e1e33be0..b2839e8e 100644 --- a/src/base/component/form/date.rs +++ b/src/base/component/form/date.rs @@ -107,20 +107,12 @@ impl Date { } pub fn with_name(mut self, name: &str) -> Self { - self.name = if name.is_empty() { - None - } else { - Some(name.replace(" ", "_")) - }; + self.name = util::valid_id(name); self } pub fn with_value(mut self, value: &str) -> Self { - self.value = if value.is_empty() { - None - } else { - Some(value.to_string()) - }; + self.value = util::optional_value(value); self } @@ -130,11 +122,7 @@ impl Date { } pub fn with_placeholder(mut self, placeholder: &str) -> Self { - self.placeholder = if placeholder.is_empty() { - None - } else { - Some(placeholder.to_string()) - }; + self.placeholder = util::optional_value(placeholder); self } @@ -191,17 +179,11 @@ impl Date { // Date GETTERS. pub fn name(&self) -> &str { - match &self.name { - Some(name) => name.as_str(), - _ => "" - } + util::assigned_value(&self.name) } pub fn value(&self) -> &str { - match &self.value { - Some(value) => value.as_str(), - _ => "" - } + util::assigned_value(&self.value) } pub fn label(&self) -> &str { @@ -209,10 +191,7 @@ impl Date { } pub fn placeholder(&self) -> &str { - match &self.placeholder { - Some(placeholder) => placeholder.as_str(), - _ => "" - } + util::assigned_value(&self.placeholder) } pub fn has_autofocus(&self) -> bool { diff --git a/src/base/component/form/form.rs b/src/base/component/form/form.rs index 519587e0..6f73469d 100644 --- a/src/base/component/form/form.rs +++ b/src/base/component/form/form.rs @@ -71,20 +71,12 @@ impl Form { } pub fn with_id(mut self, id: &str) -> Self { - self.id = if id.is_empty() { - None - } else { - Some(id.replace(" ", "_")) - }; + self.id = util::valid_id(id); self } pub fn with_action(mut self, action: &str) -> Self { - self.action = if action.is_empty() { - None - } else { - Some(action.to_string()) - }; + self.action = util::optional_value(action); self } @@ -94,11 +86,7 @@ impl Form { } pub fn with_charset(mut self, charset: &str) -> Self { - self.charset = if charset.is_empty() { - None - } else { - Some(charset.to_string()) - }; + self.charset = util::optional_value(charset); self } @@ -115,17 +103,11 @@ impl Form { // Form GETTERS. pub fn id(&self) -> &str { - match &self.id { - Some(id) => id.as_str(), - _ => "" - } + util::assigned_value(&self.id) } pub fn action(&self) -> &str { - match &self.action { - Some(action) => action.as_str(), - _ => "" - } + util::assigned_value(&self.action) } pub fn method(&self) -> &str { @@ -136,10 +118,7 @@ impl Form { } pub fn charset(&self) -> &str { - match &self.charset { - Some(charset) => charset.as_str(), - _ => "" - } + util::assigned_value(&self.charset) } pub fn template(&self) -> &str { diff --git a/src/base/component/form/hidden.rs b/src/base/component/form/hidden.rs index a95cfc77..57b4b34f 100644 --- a/src/base/component/form/hidden.rs +++ b/src/base/component/form/hidden.rs @@ -1,29 +1,21 @@ use crate::prelude::*; pub struct Hidden { - renderable : fn() -> bool, - weight : i8, - name : Option<String>, - value : Option<String>, - template : String, + weight : i8, + name : Option<String>, + value : Option<String>, } impl PageComponent for Hidden { fn prepare() -> Self { Hidden { - renderable : always, - weight : 0, - name : None, - value : None, - template : "default".to_string(), + weight : 0, + name : None, + value : None, } } - fn is_renderable(&self) -> bool { - (self.renderable)() - } - fn weight(&self) -> i8 { self.weight } @@ -51,60 +43,28 @@ impl Hidden { // Hidden BUILDER. - pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { - self.renderable = renderable; - self - } - pub fn with_weight(mut self, weight: i8) -> Self { self.weight = weight; self } pub fn with_name(mut self, name: &str) -> Self { - self.name = if name.is_empty() { - None - } else { - Some(name.replace(" ", "_")) - }; + self.name = util::valid_id(name); self } pub fn with_value(mut self, value: &str) -> Self { - self.value = if value.is_empty() { - None - } else { - Some(value.to_string()) - }; - self - } - - pub fn using_template(mut self, template: &str) -> Self { - self.template = template.to_string(); + self.value = util::optional_value(value); self } // Hidden GETTERS. pub fn name(&self) -> &str { - match &self.name { - Some(name) => name.as_str(), - _ => "" - } + util::assigned_value(&self.name) } pub fn value(&self) -> &str { - match &self.value { - Some(value) => value.as_str(), - _ => "" - } - } - - pub fn template(&self) -> &str { - self.template.as_str() + util::assigned_value(&self.value) } } - -fn always() -> bool { - true -} diff --git a/src/base/component/form/input.rs b/src/base/component/form/input.rs index d4ec8930..82c0bda3 100644 --- a/src/base/component/form/input.rs +++ b/src/base/component/form/input.rs @@ -162,20 +162,12 @@ impl Input { } pub fn with_name(mut self, name: &str) -> Self { - self.name = if name.is_empty() { - None - } else { - Some(name.replace(" ", "_")) - }; + self.name = util::valid_id(name); self } pub fn with_value(mut self, value: &str) -> Self { - self.value = if value.is_empty() { - None - } else { - Some(value.to_string()) - }; + self.value = util::optional_value(value); self } @@ -200,11 +192,7 @@ impl Input { } pub fn with_placeholder(mut self, placeholder: &str) -> Self { - self.placeholder = if placeholder.is_empty() { - None - } else { - Some(placeholder.to_string()) - }; + self.placeholder = util::optional_value(placeholder); self } @@ -261,17 +249,11 @@ impl Input { // Input GETTERS. pub fn name(&self) -> &str { - match &self.name { - Some(name) => name.as_str(), - _ => "" - } + util::assigned_value(&self.name) } pub fn value(&self) -> &str { - match &self.value { - Some(value) => value.as_str(), - _ => "" - } + util::assigned_value(&self.value) } pub fn label(&self) -> &str { @@ -291,10 +273,7 @@ impl Input { } pub fn placeholder(&self) -> &str { - match &self.placeholder { - Some(placeholder) => placeholder.as_str(), - _ => "" - } + util::assigned_value(&self.placeholder) } pub fn has_autofocus(&self) -> bool { diff --git a/src/base/component/menu.rs b/src/base/component/menu.rs new file mode 100644 index 00000000..34be6e33 --- /dev/null +++ b/src/base/component/menu.rs @@ -0,0 +1,252 @@ +use crate::prelude::*; + +enum MenuItemType { + Label(String), + Link(String, String), + LinkBlank(String, String), + Markup(Markup), + Separator, + Submenu(String, Menu), +} + +// ----------------------------------------------------------------------------- +// MenuItem. +// ----------------------------------------------------------------------------- + +pub struct MenuItem { + renderable: fn() -> bool, + weight : i8, + item_type : Option<MenuItemType>, +} + +impl PageComponent for MenuItem { + + fn prepare() -> Self { + MenuItem { + renderable: always, + weight : 0, + item_type : None, + } + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> i8 { + self.weight + } + + fn default_render(&self, assets: &mut PageAssets) -> Markup { + match &self.item_type { + Some(MenuItemType::Label(label)) => html! { + li class="label" { a href="#" { (label) } } + }, + Some(MenuItemType::Link(label, path)) => html! { + li class="link" { a href=(path) { (label) } } + }, + Some(MenuItemType::LinkBlank(label, path)) => html! { + li class="link_blank" { + a href=(path) target="_blank" { (label) } + } + }, + Some(MenuItemType::Markup(markup)) => html! { + li class="markup" { (*markup) } + }, + Some(MenuItemType::Submenu(label, menu)) => html! { + li class="submenu" { + a href="#" { (label) } + ul { + (menu.render_items(assets)) + } + } + }, + Some(MenuItemType::Separator) => html! { + li class="separator" { } + }, + None => html! {} + } + } +} + +impl MenuItem { + + pub fn label(label: &str) -> Self { + MenuItem { + renderable: always, + weight : 0, + item_type : Some(MenuItemType::Label(label.to_string())), + } + } + + pub fn link(label: &str, path: &str) -> Self { + MenuItem { + renderable: always, + weight : 0, + item_type : Some(MenuItemType::Link( + label.to_string(), + path.to_string(), + )), + } + } + + pub fn link_blank(label: &str, path: &str) -> Self { + MenuItem { + renderable: always, + weight : 0, + item_type : Some(MenuItemType::LinkBlank( + label.to_string(), + path.to_string(), + )), + } + } + + pub fn markup(markup: Markup) -> Self { + MenuItem { + renderable: always, + weight : 0, + item_type : Some(MenuItemType::Markup(markup)), + } + } + + pub fn separator() -> Self { + MenuItem { + renderable: always, + weight : 0, + item_type : Some(MenuItemType::Separator), + } + } + + pub fn submenu(label: &str, menu: Menu) -> Self { + MenuItem { + renderable: always, + weight : 0, + item_type : Some(MenuItemType::Submenu( + label.to_string(), + menu + )), + } + } + + // MenuItem BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } +} + +// ----------------------------------------------------------------------------- +// Menu. +// ----------------------------------------------------------------------------- + +pub struct Menu { + renderable: fn() -> bool, + weight : i8, + id : Option<String>, + items : PageContainer, + template : String, +} + +impl PageComponent for Menu { + + fn prepare() -> Self { + Menu { + renderable: always, + weight : 0, + id : None, + items : PageContainer::new(), + template : "default".to_string(), + } + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> i8 { + self.weight + } + + fn default_render(&self, assets: &mut PageAssets) -> Markup { + assets + .add_stylesheet(StyleSheet::source( + "/theme/menu/css/menu.css?ver=1.1.1" + )) + .add_stylesheet(StyleSheet::source( + "/theme/menu/css/menu-clean.css?ver=1.1.1" + )) + .add_javascript(JavaScript::source( + "/theme/menu/js/menu.min.js?ver=1.1.1" + )) + .add_jquery(); + + let id = assets.required_id(self.name(), self.id()); + html! { + ul id=(id) class="sm sm-clean" { + (self.render_items(assets)) + } + script type="text/javascript" defer { + "jQuery(function(){jQuery('#" (id) "').smartmenus({" + "hideTimeout: 0," + "showTimeout: 80," + "});});" + } + } + } +} + +impl Menu { + + // Menu BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_id(mut self, id: &str) -> Self { + self.id = util::valid_id(id); + self + } + + pub fn add(mut self, item: MenuItem) -> Self { + self.items.add(item); + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.template = template.to_string(); + self + } + + // Menu GETTERS. + + pub fn id(&self) -> &str { + util::assigned_value(&self.id) + } + + pub fn template(&self) -> &str { + self.template.as_str() + } + + // Menu EXTRAS. + + pub fn render_items(&self, assets: &mut PageAssets) -> Markup { + html! { (self.items.render(assets)) } + } +} + +fn always() -> bool { + true +} diff --git a/src/base/component/mod.rs b/src/base/component/mod.rs index 07c16cf7..f9973108 100644 --- a/src/base/component/mod.rs +++ b/src/base/component/mod.rs @@ -2,6 +2,10 @@ mod container; pub use container::Container; mod chunck; pub use chunck::Chunck; +mod block; +pub use block::Block; +mod menu; +pub use menu::{Menu, MenuItem}; pub mod form; pub use form::{Form, FormMethod}; diff --git a/src/base/module/admin/configure.rs b/src/base/module/admin/configure.rs new file mode 100644 index 00000000..1859f016 --- /dev/null +++ b/src/base/module/admin/configure.rs @@ -0,0 +1,17 @@ +use crate::prelude::*; +use crate::base::module::admin::summary::summary; + +pub struct AdminModule; + +impl Module for AdminModule { + fn name(&self) -> String { + "PageTop Admin".to_string() + } + + fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { + cfg.service( + server::web::scope("/admin") + .route("", server::web::get().to(summary)) + ); + } +} diff --git a/src/base/module/admin/mod.rs b/src/base/module/admin/mod.rs new file mode 100644 index 00000000..1444391b --- /dev/null +++ b/src/base/module/admin/mod.rs @@ -0,0 +1,4 @@ +mod configure; +pub use configure::AdminModule; + +mod summary; diff --git a/src/base/module/admin/summary.rs b/src/base/module/admin/summary.rs new file mode 100644 index 00000000..6f620fd0 --- /dev/null +++ b/src/base/module/admin/summary.rs @@ -0,0 +1,54 @@ +use crate::prelude::*; + +pub async fn summary() -> server::Result<Markup> { + let top_menu = Menu::prepare() + .add(MenuItem::label("Opción 1")) + .add(MenuItem::link("Opción 2", "https://www.google.es")) + .add(MenuItem::link_blank("Opción 3", "https://www.google.es")) + .add(MenuItem::submenu("Submenú 1", Menu::prepare() + .add(MenuItem::label("Opción 1")) + .add(MenuItem::label("Opción 2")) + )) + .add(MenuItem::separator()) + .add(MenuItem::submenu("Submenú 2", Menu::prepare() + .add(MenuItem::label("Opción 1")) + .add(MenuItem::label("Opción 2")) + )) + .add(MenuItem::label("Opción 4")); + + let side_menu = Menu::prepare() + .add(MenuItem::label("Opción 1")) + .add(MenuItem::link("Opción 2", "https://www.google.es")) + .add(MenuItem::link_blank("Opción 3", "https://www.google.es")) + .add(MenuItem::submenu("Submenú 1", Menu::prepare() + .add(MenuItem::label("Opción 1")) + .add(MenuItem::label("Opción 2")) + )) + .add(MenuItem::separator()) + .add(MenuItem::submenu("Submenú 2", Menu::prepare() + .add(MenuItem::label("Opción 1")) + .add(MenuItem::label("Opción 2")) + )) + .add(MenuItem::label("Opción 4")); + + Page::prepare() + .with_title("Admin") + + .add_to("top-menu", top_menu) + + .add_to("content", Container::row() + .add(Container::column() + .add(side_menu) + ) + .add(Container::column() + .add(Chunck::markup(html! { + p { "Columna 2"} + })) + ) + ) + + + .using_template("admin") + + .render() +} diff --git a/src/base/module/mod.rs b/src/base/module/mod.rs index dd90a79f..3a4e2d51 100644 --- a/src/base/module/mod.rs +++ b/src/base/module/mod.rs @@ -1,2 +1,3 @@ +pub mod admin; pub mod homepage; pub mod user; diff --git a/src/base/theme/bootsier/mod.rs b/src/base/theme/bootsier/mod.rs index 92e7437a..2d37cb05 100644 --- a/src/base/theme/bootsier/mod.rs +++ b/src/base/theme/bootsier/mod.rs @@ -26,13 +26,13 @@ impl Theme for BootsierTheme { ) .add_stylesheet( StyleSheet::source( - "/bootsier/css/bootstrap.min.css?v=5.1.3" + "/bootsier/css/bootstrap.min.css?ver=5.1.3" ) .with_weight(-99) ) .add_javascript( JavaScript::source( - "/bootsier/js/bootstrap.bundle.min.js?v=5.1.3" + "/bootsier/js/bootstrap.bundle.min.js?ver=5.1.3" ) .with_weight(-99) ) diff --git a/src/core/response/page/assets.rs b/src/core/response/page/assets.rs index c01855d9..8d929f79 100644 --- a/src/core/response/page/assets.rs +++ b/src/core/response/page/assets.rs @@ -177,7 +177,7 @@ pub struct Assets { stylesheets: Vec<StyleSheet>, javascripts: Vec<JavaScript>, with_jquery: bool, - seqid_count: u16, + id_counter : u32, } impl Assets { @@ -188,7 +188,7 @@ impl Assets { stylesheets: Vec::new(), javascripts: Vec::new(), with_jquery: false, - seqid_count: 0, + id_counter : 0, } } @@ -228,7 +228,7 @@ impl Assets { if !self.with_jquery { self.add_javascript( JavaScript::source( - "/theme/js/jquery.min.js?v=3.6.0" + "/theme/js/jquery.min.js?ver=3.6.0" ) .with_weight(i8::MIN) .with_mode(JSMode::Normal) @@ -262,13 +262,20 @@ impl Assets { } } - // Assets GETTERS. + // Assets EXTRAS. - pub fn seqid(&mut self, id: &str) -> String { + pub fn required_id(&mut self, prefix: &str, id: &str) -> String { if id.is_empty() { - self.seqid_count += 1; - return format!("seqid-{}", self.seqid_count); + let prefix = prefix.trim().replace(" ", "_").to_lowercase(); + let prefix = if prefix.is_empty() { + "prefix".to_string() + } else { + prefix + }; + self.id_counter += 1; + [prefix, self.id_counter.to_string()].join("-") + } else { + id.to_string() } - id.to_string() } } diff --git a/src/core/response/page/component.rs b/src/core/response/page/component.rs index 097d960f..aebb1f43 100644 --- a/src/core/response/page/component.rs +++ b/src/core/response/page/component.rs @@ -9,6 +9,14 @@ pub trait Component: Downcast + Send + Sync { fn prepare() -> Self where Self: Sized; + fn name(&self) -> &str { + let name = type_name::<Self>(); + match name.rfind("::") { + Some(position) => &name[(position + 2)..], + None => name + } + } + fn qualified_name(&self) -> &str { type_name::<Self>() } diff --git a/src/core/state.rs b/src/core/state.rs index 307455a1..a53d8d80 100644 --- a/src/core/state.rs +++ b/src/core/state.rs @@ -39,6 +39,7 @@ pub fn register_theme(t: &'static (dyn Theme + 'static)) { pub static MODULES: Lazy<RwLock<Vec<&dyn Module>>> = Lazy::new(|| { RwLock::new(vec![ + &base::module::admin::AdminModule, &base::module::user::UserModule, ]) }); diff --git a/src/lib.rs b/src/lib.rs index 327379a9..42f51a3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,11 +7,11 @@ pub use once_cell::sync::Lazy; // APIs públicas. // ----------------------------------------------------------------------------- -pub mod macros; // Macros útiles. pub mod config; // Gestión de la configuración. pub mod trace; // Traza de ejecución. pub mod locale; // Localización. pub mod core; // Servidor web y sistemas para Temas, Módulos y Respuestas. pub mod base; // Temas, Módulos y Componentes base. +pub mod util; // Macros y funciones útiles. pub mod prelude; // Re-exporta recursos comunes. diff --git a/src/macros/mod.rs b/src/macros/mod.rs deleted file mode 100644 index 88ab3f90..00000000 --- a/src/macros/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -#[macro_export] -/// Macro para construir grupos de pares clave-valor. -/// -/// ``` -/// let args = args![ -/// "userName" => "Roberto", -/// "photoCount" => 3, -/// "userGender" => "male" -/// ]; -/// ``` -macro_rules! args { - ( $($key:expr => $value:expr),* ) => {{ - let mut a = std::collections::HashMap::new(); - $( - a.insert(String::from($key), $value.into()); - )* - a - }}; -} diff --git a/src/prelude.rs b/src/prelude.rs index b4b62b18..4a66e08b 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,6 +1,8 @@ //! Re-exporta recursos comunes. pub use crate::args; +pub use crate::util; + pub use crate::config::SETTINGS; pub use crate::trace; pub use crate::localize; diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 00000000..638e948f --- /dev/null +++ b/src/util.rs @@ -0,0 +1,42 @@ +#[macro_export] +/// Macro para construir grupos de pares clave-valor. +/// +/// ``` +/// let args = args![ +/// "userName" => "Roberto", +/// "photoCount" => 3, +/// "userGender" => "male" +/// ]; +/// ``` +macro_rules! args { + ( $($key:expr => $value:expr),* ) => {{ + let mut a = std::collections::HashMap::new(); + $( + a.insert(String::from($key), $value.into()); + )* + a + }}; +} + +pub fn valid_id(id: &str) -> Option<String> { + let id = id.trim().replace(" ", "_").to_lowercase(); + match id.is_empty() { + true => None, + false => Some(id), + } +} + +pub fn optional_value(value: &str) -> Option<String> { + let value = value.to_string(); + match value.is_empty() { + true => None, + false => Some(value), + } +} + +pub fn assigned_value(value: &Option<String>) -> &str { + match value { + Some(value) => value.as_str(), + _ => "", + } +} diff --git a/static/theme/menu/css/menu-blue.css b/static/theme/menu/css/menu-blue.css new file mode 100644 index 00000000..4cff3bb5 --- /dev/null +++ b/static/theme/menu/css/menu-blue.css @@ -0,0 +1,333 @@ +@import url(https://fonts.googleapis.com/css?family=PT+Sans+Narrow:400,700); +.sm-blue { + background: transparent; + border-radius: 8px; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); +} +.sm-blue a, .sm-blue a:hover, .sm-blue a:focus, .sm-blue a:active { + padding: 10px 20px; + /* make room for the toggle button (sub indicator) */ + padding-right: 58px; + background: #3092c0; + background-image: linear-gradient(to bottom, #3298c8, #2e8cb8); + color: #fff; + font-family: "PT Sans Narrow", "Arial Narrow", Arial, Helvetica, sans-serif; + font-size: 18px; + font-weight: bold; + line-height: 23px; + text-decoration: none; + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.2); +} +.sm-blue a.current { + background: #006892; + background-image: linear-gradient(to bottom, #006188, #006f9c); + color: #fff; +} +.sm-blue a.disabled { + color: #a1d1e8; +} +.sm-blue a .sub-arrow { + position: absolute; + top: 50%; + margin-top: -17px; + left: auto; + right: 4px; + width: 34px; + height: 34px; + overflow: hidden; + font: bold 16px/34px monospace !important; + text-align: center; + text-shadow: none; + background: rgba(0, 0, 0, 0.1); + border-radius: 4px; +} +.sm-blue a .sub-arrow::before { + content: '+'; +} +.sm-blue a.highlighted .sub-arrow::before { + content: '-'; +} +.sm-blue > li:first-child > a, .sm-blue > li:first-child > :not(ul) a { + border-radius: 8px 8px 0 0; +} +.sm-blue > li:last-child > a, .sm-blue > li:last-child > *:not(ul) a, .sm-blue > li:last-child > ul, .sm-blue > li:last-child > ul > li:last-child > a, .sm-blue > li:last-child > ul > li:last-child > *:not(ul) a, .sm-blue > li:last-child > ul > li:last-child > ul, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > a, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > *:not(ul) a, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > ul, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > a, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > *:not(ul) a, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > a, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > *:not(ul) a, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul { + border-radius: 0 0 8px 8px; +} +.sm-blue > li:last-child > a.highlighted, .sm-blue > li:last-child > *:not(ul) a.highlighted, .sm-blue > li:last-child > ul > li:last-child > a.highlighted, .sm-blue > li:last-child > ul > li:last-child > *:not(ul) a.highlighted, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > a.highlighted, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > *:not(ul) a.highlighted, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > a.highlighted, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > *:not(ul) a.highlighted, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > a.highlighted, .sm-blue > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > *:not(ul) a.highlighted { + border-radius: 0; +} +.sm-blue ul { + background: #fff; +} +.sm-blue ul ul { + background: rgba(102, 102, 102, 0.1); +} +.sm-blue ul a, .sm-blue ul a:hover, .sm-blue ul a:focus, .sm-blue ul a:active { + background: transparent; + color: #2b82ac; + font-size: 16px; + text-shadow: none; + border-left: 8px solid transparent; +} +.sm-blue ul a.current { + background: #006892; + background-image: linear-gradient(to bottom, #006188, #006f9c); + color: #fff; +} +.sm-blue ul a.disabled { + color: #b3b3b3; +} +.sm-blue ul ul a, +.sm-blue ul ul a:hover, +.sm-blue ul ul a:focus, +.sm-blue ul ul a:active { + border-left: 16px solid transparent; +} +.sm-blue ul ul ul a, +.sm-blue ul ul ul a:hover, +.sm-blue ul ul ul a:focus, +.sm-blue ul ul ul a:active { + border-left: 24px solid transparent; +} +.sm-blue ul ul ul ul a, +.sm-blue ul ul ul ul a:hover, +.sm-blue ul ul ul ul a:focus, +.sm-blue ul ul ul ul a:active { + border-left: 32px solid transparent; +} +.sm-blue ul ul ul ul ul a, +.sm-blue ul ul ul ul ul a:hover, +.sm-blue ul ul ul ul ul a:focus, +.sm-blue ul ul ul ul ul a:active { + border-left: 40px solid transparent; +} +.sm-blue ul li { + border-top: 1px solid rgba(0, 0, 0, 0.05); +} +.sm-blue ul li:first-child { + border-top: 0; +} + +@media (min-width: 768px) { + /* Switch to desktop layout + ----------------------------------------------- + These transform the menu tree from + collapsible to desktop (navbar + dropdowns) + -----------------------------------------------*/ + /* start... (it's not recommended editing these rules) */ + .sm-blue ul { + position: absolute; + width: 12em; + } + + .sm-blue li { + float: left; + } + + .sm-blue.sm-rtl li { + float: right; + } + + .sm-blue ul li, .sm-blue.sm-rtl ul li, .sm-blue.sm-vertical li { + float: none; + } + + .sm-blue a { + white-space: nowrap; + } + + .sm-blue ul a, .sm-blue.sm-vertical a { + white-space: normal; + } + + .sm-blue .sm-nowrap > li > a, .sm-blue .sm-nowrap > li > :not(ul) a { + white-space: nowrap; + } + + /* ...end */ + .sm-blue { + background: #3092c0; + background-image: linear-gradient(to bottom, #3298c8, #2e8cb8); + border-radius: 8px; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); + } + .sm-blue a, .sm-blue a:hover, .sm-blue a:focus, .sm-blue a:active, .sm-blue a.highlighted { + padding: 13px 24px; + background: #3092c0; + background-image: linear-gradient(to bottom, #3298c8, #2e8cb8); + color: #fff; + } + .sm-blue a:hover, .sm-blue a:focus, .sm-blue a:active, .sm-blue a.highlighted { + background: #2b82ac; + background-image: linear-gradient(to bottom, #2d89b4, #297ca3); + } + .sm-blue a.current { + background: #006892; + background-image: linear-gradient(to bottom, #006188, #006f9c); + color: #fff; + } + .sm-blue a.disabled { + background: #3092c0; + background-image: linear-gradient(to bottom, #3298c8, #2e8cb8); + color: #a1d1e8; + } + .sm-blue a .sub-arrow { + top: auto; + margin-top: 0; + bottom: 2px; + left: 50%; + margin-left: -5px; + right: auto; + width: 0; + height: 0; + border-width: 5px; + border-style: solid dashed dashed dashed; + border-color: #a1d1e8 transparent transparent transparent; + background: transparent; + border-radius: 0; + } + .sm-blue a .sub-arrow::before { + display: none; + } + .sm-blue > li:first-child > a, .sm-blue > li:first-child > :not(ul) a { + border-radius: 8px 0 0 8px; + } + .sm-blue > li:last-child > a, .sm-blue > li:last-child > :not(ul) a { + border-radius: 0 8px 8px 0 !important; + } + .sm-blue > li { + border-left: 1px solid #2b82ac; + } + .sm-blue > li:first-child { + border-left: 0; + } + .sm-blue ul { + border: 1px solid #a8a8a8; + padding: 7px 0; + background: #fff; + border-radius: 0 0 4px 4px !important; + box-shadow: 0 5px 12px rgba(0, 0, 0, 0.2); + } + .sm-blue ul ul { + border-radius: 4px !important; + background: #fff; + } + .sm-blue ul a, .sm-blue ul a:hover, .sm-blue ul a:focus, .sm-blue ul a:active, .sm-blue ul a.highlighted { + border: 0 !important; + padding: 9px 23px; + background: transparent; + color: #2b82ac; + border-radius: 0 !important; + } + .sm-blue ul a:hover, .sm-blue ul a:focus, .sm-blue ul a:active, .sm-blue ul a.highlighted { + background: #3092c0; + background-image: linear-gradient(to bottom, #3298c8, #2e8cb8); + color: #fff; + } + .sm-blue ul a.current { + background: #006892; + background-image: linear-gradient(to bottom, #006188, #006f9c); + color: #fff; + } + .sm-blue ul a.disabled { + background: #fff; + color: #b3b3b3; + } + .sm-blue ul a .sub-arrow { + top: 50%; + margin-top: -5px; + bottom: auto; + left: auto; + margin-left: 0; + right: 10px; + border-style: dashed dashed dashed solid; + border-color: transparent transparent transparent #a1d1e8; + } + .sm-blue ul li { + border: 0; + } + .sm-blue .scroll-up, + .sm-blue .scroll-down { + position: absolute; + display: none; + visibility: hidden; + overflow: hidden; + background: #fff; + height: 20px; + } + .sm-blue .scroll-up-arrow, + .sm-blue .scroll-down-arrow { + position: absolute; + top: -2px; + left: 50%; + margin-left: -8px; + width: 0; + height: 0; + overflow: hidden; + border-width: 8px; + border-style: dashed dashed solid dashed; + border-color: transparent transparent #2b82ac transparent; + } + .sm-blue .scroll-down-arrow { + top: 6px; + border-style: solid dashed dashed dashed; + border-color: #2b82ac transparent transparent transparent; + } + .sm-blue.sm-rtl.sm-vertical a .sub-arrow { + right: auto; + left: 10px; + border-style: dashed solid dashed dashed; + border-color: transparent #a1d1e8 transparent transparent; + } + .sm-blue.sm-rtl > li:first-child > a, .sm-blue.sm-rtl > li:first-child > :not(ul) a { + border-radius: 0 8px 8px 0; + } + .sm-blue.sm-rtl > li:last-child > a, .sm-blue.sm-rtl > li:last-child > :not(ul) a { + border-radius: 8px 0 0 8px !important; + } + .sm-blue.sm-rtl > li:first-child { + border-left: 1px solid #2b82ac; + } + .sm-blue.sm-rtl > li:last-child { + border-left: 0; + } + .sm-blue.sm-rtl ul a .sub-arrow { + right: auto; + left: 10px; + border-style: dashed solid dashed dashed; + border-color: transparent #a1d1e8 transparent transparent; + } + .sm-blue.sm-vertical { + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); + } + .sm-blue.sm-vertical a { + padding: 9px 23px; + } + .sm-blue.sm-vertical a .sub-arrow { + top: 50%; + margin-top: -5px; + bottom: auto; + left: auto; + margin-left: 0; + right: 10px; + border-style: dashed dashed dashed solid; + border-color: transparent transparent transparent #a1d1e8; + } + .sm-blue.sm-vertical > li:first-child > a, .sm-blue.sm-vertical > li:first-child > :not(ul) a { + border-radius: 8px 8px 0 0; + } + .sm-blue.sm-vertical > li:last-child > a, .sm-blue.sm-vertical > li:last-child > :not(ul) a { + border-radius: 0 0 8px 8px !important; + } + .sm-blue.sm-vertical > li { + border-left: 0 !important; + } + .sm-blue.sm-vertical ul { + border-radius: 4px !important; + } + .sm-blue.sm-vertical ul a { + padding: 9px 23px; + } +} + +/*# sourceMappingURL=sm-blue.css.map */ diff --git a/static/theme/menu/css/menu-clean.css b/static/theme/menu/css/menu-clean.css new file mode 100644 index 00000000..4fb39b72 --- /dev/null +++ b/static/theme/menu/css/menu-clean.css @@ -0,0 +1,327 @@ +.sm-clean { + background: #eeeeee; + border-radius: 5px; +} +.sm-clean a, .sm-clean a:hover, .sm-clean a:focus, .sm-clean a:active { + padding: 13px 20px; + /* make room for the toggle button (sub indicator) */ + padding-right: 58px; + color: #555555; + font-family: "Lucida Sans Unicode", "Lucida Sans", "Lucida Grande", Arial, sans-serif; + font-size: 18px; + font-weight: normal; + line-height: 17px; + text-decoration: none; +} +.sm-clean a.current { + color: #D23600; +} +.sm-clean a.disabled { + color: #bbbbbb; +} +.sm-clean a .sub-arrow { + position: absolute; + top: 50%; + margin-top: -17px; + left: auto; + right: 4px; + width: 34px; + height: 34px; + overflow: hidden; + font: bold 16px/34px monospace !important; + text-align: center; + text-shadow: none; + background: rgba(255, 255, 255, 0.5); + border-radius: 5px; +} +.sm-clean a .sub-arrow::before { + content: '+'; +} +.sm-clean a.highlighted .sub-arrow::before { + content: '-'; +} +.sm-clean > li:first-child > a, .sm-clean > li:first-child > :not(ul) a { + border-radius: 5px 5px 0 0; +} +.sm-clean > li:last-child > a, .sm-clean > li:last-child > *:not(ul) a, .sm-clean > li:last-child > ul, .sm-clean > li:last-child > ul > li:last-child > a, .sm-clean > li:last-child > ul > li:last-child > *:not(ul) a, .sm-clean > li:last-child > ul > li:last-child > ul, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > a, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > *:not(ul) a, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > ul, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > a, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > *:not(ul) a, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > a, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > *:not(ul) a, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul { + border-radius: 0 0 5px 5px; +} +.sm-clean > li:last-child > a.highlighted, .sm-clean > li:last-child > *:not(ul) a.highlighted, .sm-clean > li:last-child > ul > li:last-child > a.highlighted, .sm-clean > li:last-child > ul > li:last-child > *:not(ul) a.highlighted, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > a.highlighted, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > *:not(ul) a.highlighted, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > a.highlighted, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > *:not(ul) a.highlighted, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > a.highlighted, .sm-clean > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > ul > li:last-child > *:not(ul) a.highlighted { + border-radius: 0; +} +.sm-clean li { + border-top: 1px solid rgba(0, 0, 0, 0.05); +} +.sm-clean > li:first-child { + border-top: 0; +} +.sm-clean ul { + background: rgba(162, 162, 162, 0.1); +} +.sm-clean ul a, .sm-clean ul a:hover, .sm-clean ul a:focus, .sm-clean ul a:active { + font-size: 16px; + border-left: 8px solid transparent; +} +.sm-clean ul ul a, +.sm-clean ul ul a:hover, +.sm-clean ul ul a:focus, +.sm-clean ul ul a:active { + border-left: 16px solid transparent; +} +.sm-clean ul ul ul a, +.sm-clean ul ul ul a:hover, +.sm-clean ul ul ul a:focus, +.sm-clean ul ul ul a:active { + border-left: 24px solid transparent; +} +.sm-clean ul ul ul ul a, +.sm-clean ul ul ul ul a:hover, +.sm-clean ul ul ul ul a:focus, +.sm-clean ul ul ul ul a:active { + border-left: 32px solid transparent; +} +.sm-clean ul ul ul ul ul a, +.sm-clean ul ul ul ul ul a:hover, +.sm-clean ul ul ul ul ul a:focus, +.sm-clean ul ul ul ul ul a:active { + border-left: 40px solid transparent; +} + +@media (min-width: 768px) { + /* Switch to desktop layout + ----------------------------------------------- + These transform the menu tree from + collapsible to desktop (navbar + dropdowns) + -----------------------------------------------*/ + /* start... (it's not recommended editing these rules) */ + .sm-clean ul { + position: absolute; + width: 12em; + } + + .sm-clean li { + float: left; + } + + .sm-clean.sm-rtl li { + float: right; + } + + .sm-clean ul li, .sm-clean.sm-rtl ul li, .sm-clean.sm-vertical li { + float: none; + } + + .sm-clean a { + white-space: nowrap; + } + + .sm-clean ul a, .sm-clean.sm-vertical a { + white-space: normal; + } + + .sm-clean .sm-nowrap > li > a, .sm-clean .sm-nowrap > li > :not(ul) a { + white-space: nowrap; + } + + /* ...end */ + .sm-clean { + padding: 0 10px; + background: #eeeeee; + border-radius: 100px; + } + .sm-clean a, .sm-clean a:hover, .sm-clean a:focus, .sm-clean a:active, .sm-clean a.highlighted { + padding: 12px 12px; + color: #555555; + border-radius: 0 !important; + } + .sm-clean a:hover, .sm-clean a:focus, .sm-clean a:active, .sm-clean a.highlighted { + color: #D23600; + } + .sm-clean a.current { + color: #D23600; + } + .sm-clean a.disabled { + color: #bbbbbb; + } + .sm-clean a.has-submenu { + padding-right: 24px; + } + .sm-clean a .sub-arrow { + top: 50%; + margin-top: -2px; + right: 12px; + width: 0; + height: 0; + border-width: 4px; + border-style: solid dashed dashed dashed; + border-color: #555555 transparent transparent transparent; + background: transparent; + border-radius: 0; + } + .sm-clean a .sub-arrow::before { + display: none; + } + .sm-clean li { + border-top: 0; + } + .sm-clean > li > ul::before, + .sm-clean > li > ul::after { + content: ''; + position: absolute; + top: -18px; + left: 30px; + width: 0; + height: 0; + overflow: hidden; + border-width: 9px; + border-style: dashed dashed solid dashed; + border-color: transparent transparent #bbbbbb transparent; + } + .sm-clean > li > ul::after { + top: -16px; + left: 31px; + border-width: 8px; + border-color: transparent transparent #fff transparent; + } + .sm-clean ul { + border: 1px solid #bbbbbb; + padding: 5px 0; + background: #fff; + border-radius: 5px !important; + box-shadow: 0 5px 9px rgba(0, 0, 0, 0.2); + } + .sm-clean ul a, .sm-clean ul a:hover, .sm-clean ul a:focus, .sm-clean ul a:active, .sm-clean ul a.highlighted { + border: 0 !important; + padding: 10px 20px; + color: #555555; + } + .sm-clean ul a:hover, .sm-clean ul a:focus, .sm-clean ul a:active, .sm-clean ul a.highlighted { + background: #eeeeee; + color: #D23600; + } + .sm-clean ul a.current { + color: #D23600; + } + .sm-clean ul a.disabled { + background: #fff; + color: #cccccc; + } + .sm-clean ul a.has-submenu { + padding-right: 20px; + } + .sm-clean ul a .sub-arrow { + right: 8px; + top: 50%; + margin-top: -5px; + border-width: 5px; + border-style: dashed dashed dashed solid; + border-color: transparent transparent transparent #555555; + } + .sm-clean .scroll-up, + .sm-clean .scroll-down { + position: absolute; + display: none; + visibility: hidden; + overflow: hidden; + background: #fff; + height: 20px; + } + .sm-clean .scroll-up:hover, + .sm-clean .scroll-down:hover { + background: #eeeeee; + } + .sm-clean .scroll-up:hover .scroll-up-arrow { + border-color: transparent transparent #D23600 transparent; + } + .sm-clean .scroll-down:hover .scroll-down-arrow { + border-color: #D23600 transparent transparent transparent; + } + .sm-clean .scroll-up-arrow, + .sm-clean .scroll-down-arrow { + position: absolute; + top: 0; + left: 50%; + margin-left: -6px; + width: 0; + height: 0; + overflow: hidden; + border-width: 6px; + border-style: dashed dashed solid dashed; + border-color: transparent transparent #555555 transparent; + } + .sm-clean .scroll-down-arrow { + top: 8px; + border-style: solid dashed dashed dashed; + border-color: #555555 transparent transparent transparent; + } + .sm-clean.sm-rtl a.has-submenu { + padding-right: 12px; + padding-left: 24px; + } + .sm-clean.sm-rtl a .sub-arrow { + right: auto; + left: 12px; + } + .sm-clean.sm-rtl.sm-vertical a.has-submenu { + padding: 10px 20px; + } + .sm-clean.sm-rtl.sm-vertical a .sub-arrow { + right: auto; + left: 8px; + border-style: dashed solid dashed dashed; + border-color: transparent #555555 transparent transparent; + } + .sm-clean.sm-rtl > li > ul::before { + left: auto; + right: 30px; + } + .sm-clean.sm-rtl > li > ul::after { + left: auto; + right: 31px; + } + .sm-clean.sm-rtl ul a.has-submenu { + padding: 10px 20px !important; + } + .sm-clean.sm-rtl ul a .sub-arrow { + right: auto; + left: 8px; + border-style: dashed solid dashed dashed; + border-color: transparent #555555 transparent transparent; + } + .sm-clean.sm-vertical { + padding: 10px 0; + border-radius: 5px; + } + .sm-clean.sm-vertical a { + padding: 10px 20px; + } + .sm-clean.sm-vertical a:hover, .sm-clean.sm-vertical a:focus, .sm-clean.sm-vertical a:active, .sm-clean.sm-vertical a.highlighted { + background: #fff; + } + .sm-clean.sm-vertical a.disabled { + background: #eeeeee; + } + .sm-clean.sm-vertical a .sub-arrow { + right: 8px; + top: 50%; + margin-top: -5px; + border-width: 5px; + border-style: dashed dashed dashed solid; + border-color: transparent transparent transparent #555555; + } + .sm-clean.sm-vertical > li > ul::before, + .sm-clean.sm-vertical > li > ul::after { + display: none; + } + .sm-clean.sm-vertical ul a { + padding: 10px 20px; + } + .sm-clean.sm-vertical ul a:hover, .sm-clean.sm-vertical ul a:focus, .sm-clean.sm-vertical ul a:active, .sm-clean.sm-vertical ul a.highlighted { + background: #eeeeee; + } + .sm-clean.sm-vertical ul a.disabled { + background: #fff; + } +} + +/*# sourceMappingURL=sm-clean.css.map */ diff --git a/static/theme/menu/css/menu-mint.css b/static/theme/menu/css/menu-mint.css new file mode 100644 index 00000000..1ab65555 --- /dev/null +++ b/static/theme/menu/css/menu-mint.css @@ -0,0 +1,331 @@ +.sm-mint { + border-top: 2px solid #8db863; + border-bottom: 2px solid #8db863; + background: #fff; +} +.sm-mint a, .sm-mint a:hover, .sm-mint a:focus, .sm-mint a:active { + padding: 13px 20px; + /* make room for the toggle button (sub indicator) */ + padding-right: 58px; + color: #333; + font-family: Arial, sans-serif; + font-size: 16px; + font-weight: normal; + line-height: 17px; + text-decoration: none; +} +.sm-mint a.current { + font-weight: bold; +} +.sm-mint a.disabled { + color: #cccccc; +} +.sm-mint a .sub-arrow { + position: absolute; + top: 50%; + margin-top: -17px; + left: auto; + right: 4px; + width: 34px; + height: 34px; + overflow: hidden; + font: bold 14px/34px monospace !important; + text-align: center; + text-shadow: none; + background: rgba(141, 184, 99, 0.2); + border-radius: 4px; +} +.sm-mint a .sub-arrow::before { + content: '+'; +} +.sm-mint a.highlighted .sub-arrow::before { + content: '-'; +} +.sm-mint li { + border-top: 1px solid rgba(141, 184, 99, 0.2); +} +.sm-mint > li:first-child { + border-top: 0; +} +.sm-mint ul { + background: rgba(141, 184, 99, 0.2); +} +.sm-mint ul a, .sm-mint ul a:hover, .sm-mint ul a:focus, .sm-mint ul a:active { + font-size: 14px; + border-left: 8px solid transparent; +} +.sm-mint ul ul a, +.sm-mint ul ul a:hover, +.sm-mint ul ul a:focus, +.sm-mint ul ul a:active { + border-left: 16px solid transparent; +} +.sm-mint ul ul ul a, +.sm-mint ul ul ul a:hover, +.sm-mint ul ul ul a:focus, +.sm-mint ul ul ul a:active { + border-left: 24px solid transparent; +} +.sm-mint ul ul ul ul a, +.sm-mint ul ul ul ul a:hover, +.sm-mint ul ul ul ul a:focus, +.sm-mint ul ul ul ul a:active { + border-left: 32px solid transparent; +} +.sm-mint ul ul ul ul ul a, +.sm-mint ul ul ul ul ul a:hover, +.sm-mint ul ul ul ul ul a:focus, +.sm-mint ul ul ul ul ul a:active { + border-left: 40px solid transparent; +} + +@media (min-width: 768px) { + /* Switch to desktop layout + ----------------------------------------------- + These transform the menu tree from + collapsible to desktop (navbar + dropdowns) + -----------------------------------------------*/ + /* start... (it's not recommended editing these rules) */ + .sm-mint ul { + position: absolute; + width: 12em; + } + + .sm-mint li { + float: left; + } + + .sm-mint.sm-rtl li { + float: right; + } + + .sm-mint ul li, .sm-mint.sm-rtl ul li, .sm-mint.sm-vertical li { + float: none; + } + + .sm-mint a { + white-space: nowrap; + } + + .sm-mint ul a, .sm-mint.sm-vertical a { + white-space: normal; + } + + .sm-mint .sm-nowrap > li > a, .sm-mint .sm-nowrap > li > :not(ul) a { + white-space: nowrap; + } + + /* ...end */ + .sm-mint { + border-top: 0; + background: transparent; + } + .sm-mint a, .sm-mint a:hover, .sm-mint a:focus, .sm-mint a:active, .sm-mint a.highlighted { + padding: 11px 20px; + color: #333; + border-radius: 4px 4px 0 0; + } + .sm-mint a:hover, .sm-mint a:focus, .sm-mint a:active { + background: #8db863; + color: #fff; + } + .sm-mint a.highlighted { + background: #F6FFED; + color: #333; + box-shadow: 0 4px 3px rgba(0, 0, 0, 0.25); + } + .sm-mint a.disabled { + background: transparent; + color: #cccccc; + box-shadow: none; + } + .sm-mint a.has-submenu { + padding-right: 34px; + } + .sm-mint a .sub-arrow { + top: 50%; + margin-top: -3px; + right: 20px; + width: 0; + height: 0; + border-width: 6px 4.02px 0 4.02px; + border-style: solid dashed dashed dashed; + border-color: #8db863 transparent transparent transparent; + background: transparent; + border-radius: 0; + } + .sm-mint a:hover .sub-arrow, .sm-mint a:focus .sub-arrow, .sm-mint a:active .sub-arrow { + border-color: #fff transparent transparent transparent; + } + .sm-mint a.highlighted .sub-arrow { + border-color: #8db863 transparent transparent transparent; + } + .sm-mint a.disabled .sub-arrow { + border-color: #8db863 transparent transparent transparent; + } + .sm-mint a .sub-arrow::before { + display: none; + } + .sm-mint li { + border-top: 0; + } + .sm-mint ul { + border: 0; + padding: 8px 0; + background: #F6FFED; + border-radius: 0 4px 4px 4px; + box-shadow: 0 4px 3px rgba(0, 0, 0, 0.25); + } + .sm-mint ul ul { + border-radius: 4px; + } + .sm-mint ul a, .sm-mint ul a:hover, .sm-mint ul a:focus, .sm-mint ul a:active, .sm-mint ul a.highlighted { + border: 0 !important; + padding: 10px 20px; + color: #333; + border-radius: 0; + } + .sm-mint ul a:hover, .sm-mint ul a:focus, .sm-mint ul a:active, .sm-mint ul a.highlighted { + background: #8db863; + color: #fff; + box-shadow: none; + } + .sm-mint ul a.disabled { + background: transparent; + color: #b3b3b3; + } + .sm-mint ul a.has-submenu { + padding-right: 20px; + } + .sm-mint ul a .sub-arrow { + right: 10px; + margin-top: -4.02px; + border-width: 4.02px 0 4.02px 6px; + border-style: dashed dashed dashed solid; + border-color: transparent transparent transparent #8db863; + } + .sm-mint ul a:hover .sub-arrow, .sm-mint ul a:focus .sub-arrow, .sm-mint ul a:active .sub-arrow, .sm-mint ul a.highlighted .sub-arrow { + border-color: transparent transparent transparent #fff; + } + .sm-mint ul a.disabled .sub-arrow { + border-color: transparent transparent transparent #8db863; + } + .sm-mint .scroll-up, + .sm-mint .scroll-down { + position: absolute; + display: none; + visibility: hidden; + overflow: hidden; + background: #F6FFED; + height: 20px; + } + .sm-mint .scroll-up-arrow, + .sm-mint .scroll-down-arrow { + position: absolute; + top: 6px; + left: 50%; + margin-left: -8px; + width: 0; + height: 0; + overflow: hidden; + border-width: 0 6px 8px 6px; + border-style: dashed dashed solid dashed; + border-color: transparent transparent #8db863 transparent; + } + .sm-mint .scroll-down-arrow { + border-width: 8px 6px 0 6px; + border-style: solid dashed dashed dashed; + border-color: #8db863 transparent transparent transparent; + } + .sm-mint.sm-rtl a.has-submenu { + padding-right: 20px; + padding-left: 34px; + } + .sm-mint.sm-rtl a .sub-arrow { + right: auto; + left: 20px; + } + .sm-mint.sm-rtl.sm-vertical { + border-right: 0; + border-left: 2px solid #8db863; + } + .sm-mint.sm-rtl.sm-vertical a { + border-radius: 0 4px 4px 0; + } + .sm-mint.sm-rtl.sm-vertical a.has-submenu { + padding: 10px 20px; + } + .sm-mint.sm-rtl.sm-vertical a .sub-arrow { + right: auto; + left: 10px; + border-width: 4.02px 6px 4.02px 0; + border-style: dashed solid dashed dashed; + border-color: transparent #8db863 transparent transparent; + } + .sm-mint.sm-rtl.sm-vertical a:hover .sub-arrow, .sm-mint.sm-rtl.sm-vertical a:focus .sub-arrow, .sm-mint.sm-rtl.sm-vertical a:active .sub-arrow, .sm-mint.sm-rtl.sm-vertical a.highlighted .sub-arrow { + border-color: transparent #fff transparent transparent; + } + .sm-mint.sm-rtl.sm-vertical a.disabled .sub-arrow { + border-color: transparent #8db863 transparent transparent; + } + .sm-mint.sm-rtl ul { + border-radius: 4px 0 4px 4px; + } + .sm-mint.sm-rtl ul a { + border-radius: 0 !important; + } + .sm-mint.sm-rtl ul a.has-submenu { + padding: 10px 20px !important; + } + .sm-mint.sm-rtl ul a .sub-arrow { + right: auto; + left: 10px; + border-width: 4.02px 6px 4.02px 0; + border-style: dashed solid dashed dashed; + border-color: transparent #8db863 transparent transparent; + } + .sm-mint.sm-rtl ul a:hover .sub-arrow, .sm-mint.sm-rtl ul a:focus .sub-arrow, .sm-mint.sm-rtl ul a:active .sub-arrow, .sm-mint.sm-rtl ul a.highlighted .sub-arrow { + border-color: transparent #fff transparent transparent; + } + .sm-mint.sm-rtl ul a.disabled .sub-arrow { + border-color: transparent #8db863 transparent transparent; + } + .sm-mint.sm-vertical { + border-bottom: 0; + border-right: 2px solid #8db863; + } + .sm-mint.sm-vertical a { + padding: 10px 20px; + border-radius: 4px 0 0 4px; + } + .sm-mint.sm-vertical a:hover, .sm-mint.sm-vertical a:focus, .sm-mint.sm-vertical a:active, .sm-mint.sm-vertical a.highlighted { + background: #8db863; + color: #fff; + box-shadow: none; + } + .sm-mint.sm-vertical a.disabled { + background: transparent; + color: #cccccc; + } + .sm-mint.sm-vertical a .sub-arrow { + right: 10px; + margin-top: -4.02px; + border-width: 4.02px 0 4.02px 6px; + border-style: dashed dashed dashed solid; + border-color: transparent transparent transparent #8db863; + } + .sm-mint.sm-vertical a:hover .sub-arrow, .sm-mint.sm-vertical a:focus .sub-arrow, .sm-mint.sm-vertical a:active .sub-arrow, .sm-mint.sm-vertical a.highlighted .sub-arrow { + border-color: transparent transparent transparent #fff; + } + .sm-mint.sm-vertical a.disabled .sub-arrow { + border-color: transparent transparent transparent #8db863; + } + .sm-mint.sm-vertical ul { + border-radius: 4px !important; + } + .sm-mint.sm-vertical ul a { + padding: 10px 20px; + } +} + +/*# sourceMappingURL=sm-mint.css.map */ diff --git a/static/theme/menu/css/menu-simple.css b/static/theme/menu/css/menu-simple.css new file mode 100644 index 00000000..8fcf0c15 --- /dev/null +++ b/static/theme/menu/css/menu-simple.css @@ -0,0 +1,249 @@ +.sm-simple { + border: 1px solid #bbbbbb; + background: #fff; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); +} +.sm-simple a, .sm-simple a:hover, .sm-simple a:focus, .sm-simple a:active { + padding: 13px 20px; + /* make room for the toggle button (sub indicator) */ + padding-right: 58px; + color: #555555; + font-family: "Lucida Sans Unicode", "Lucida Sans", "Lucida Grande", Arial, sans-serif; + font-size: 16px; + font-weight: normal; + line-height: 17px; + text-decoration: none; +} +.sm-simple a.current { + background: #555555; + color: #fff; +} +.sm-simple a.disabled { + color: #cccccc; +} +.sm-simple a .sub-arrow { + position: absolute; + top: 50%; + margin-top: -17px; + left: auto; + right: 4px; + width: 34px; + height: 34px; + overflow: hidden; + font: bold 14px/34px monospace !important; + text-align: center; + text-shadow: none; + background: rgba(0, 0, 0, 0.08); +} +.sm-simple a .sub-arrow::before { + content: '+'; +} +.sm-simple a.highlighted .sub-arrow::before { + content: '-'; +} +.sm-simple li { + border-top: 1px solid rgba(0, 0, 0, 0.05); +} +.sm-simple > li:first-child { + border-top: 0; +} +.sm-simple ul { + background: rgba(179, 179, 179, 0.1); +} +.sm-simple ul a, .sm-simple ul a:hover, .sm-simple ul a:focus, .sm-simple ul a:active { + font-size: 14px; + border-left: 8px solid transparent; +} +.sm-simple ul ul a, +.sm-simple ul ul a:hover, +.sm-simple ul ul a:focus, +.sm-simple ul ul a:active { + border-left: 16px solid transparent; +} +.sm-simple ul ul ul a, +.sm-simple ul ul ul a:hover, +.sm-simple ul ul ul a:focus, +.sm-simple ul ul ul a:active { + border-left: 24px solid transparent; +} +.sm-simple ul ul ul ul a, +.sm-simple ul ul ul ul a:hover, +.sm-simple ul ul ul ul a:focus, +.sm-simple ul ul ul ul a:active { + border-left: 32px solid transparent; +} +.sm-simple ul ul ul ul ul a, +.sm-simple ul ul ul ul ul a:hover, +.sm-simple ul ul ul ul ul a:focus, +.sm-simple ul ul ul ul ul a:active { + border-left: 40px solid transparent; +} + +@media (min-width: 768px) { + /* Switch to desktop layout + ----------------------------------------------- + These transform the menu tree from + collapsible to desktop (navbar + dropdowns) + -----------------------------------------------*/ + /* start... (it's not recommended editing these rules) */ + .sm-simple ul { + position: absolute; + width: 12em; + } + + .sm-simple li { + float: left; + } + + .sm-simple.sm-rtl li { + float: right; + } + + .sm-simple ul li, .sm-simple.sm-rtl ul li, .sm-simple.sm-vertical li { + float: none; + } + + .sm-simple a { + white-space: nowrap; + } + + .sm-simple ul a, .sm-simple.sm-vertical a { + white-space: normal; + } + + .sm-simple .sm-nowrap > li > a, .sm-simple .sm-nowrap > li > :not(ul) a { + white-space: nowrap; + } + + /* ...end */ + .sm-simple { + background: #fff; + } + .sm-simple a, .sm-simple a:hover, .sm-simple a:focus, .sm-simple a:active, .sm-simple a.highlighted { + padding: 11px 20px; + color: #555555; + } + .sm-simple a:hover, .sm-simple a:focus, .sm-simple a:active, .sm-simple a.highlighted { + background: #eeeeee; + } + .sm-simple a.current { + background: #555555; + color: #fff; + } + .sm-simple a.disabled { + background: #fff; + color: #cccccc; + } + .sm-simple a.has-submenu { + padding-right: 32px; + } + .sm-simple a .sub-arrow { + top: 50%; + margin-top: -8px; + right: 20px; + width: 8px; + height: 16px; + font: 14px/16px monospace !important; + background: transparent; + } + .sm-simple a.highlighted .sub-arrow::before { + content: '+'; + } + .sm-simple > li { + border-top: 0; + border-left: 1px solid #eeeeee; + } + .sm-simple > li:first-child { + border-left: 0; + } + .sm-simple ul { + border: 1px solid #bbbbbb; + background: #fff; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); + } + .sm-simple ul a { + border: 0 !important; + } + .sm-simple ul a.has-submenu { + padding-right: 20px; + } + .sm-simple ul a .sub-arrow { + left: 8px; + right: auto; + } + .sm-simple ul > li { + border-left: 0; + border-top: 1px solid #eeeeee; + } + .sm-simple ul > li:first-child { + border-top: 0; + } + .sm-simple .scroll-up, + .sm-simple .scroll-down { + position: absolute; + display: none; + visibility: hidden; + overflow: hidden; + background: #fff; + height: 20px; + } + .sm-simple .scroll-up-arrow, + .sm-simple .scroll-down-arrow { + position: absolute; + top: -2px; + left: 50%; + margin-left: -8px; + width: 0; + height: 0; + overflow: hidden; + border-width: 8px; + border-style: dashed dashed solid dashed; + border-color: transparent transparent #555555 transparent; + } + .sm-simple .scroll-down-arrow { + top: 6px; + border-style: solid dashed dashed dashed; + border-color: #555555 transparent transparent transparent; + } + .sm-simple.sm-rtl a.has-submenu { + padding-right: 20px; + padding-left: 32px; + } + .sm-simple.sm-rtl a .sub-arrow { + left: 20px; + right: auto; + } + .sm-simple.sm-rtl.sm-vertical a.has-submenu { + padding: 11px 20px; + } + .sm-simple.sm-rtl.sm-vertical a .sub-arrow { + left: auto; + right: 8px; + } + .sm-simple.sm-rtl > li:first-child { + border-left: 1px solid #eeeeee; + } + .sm-simple.sm-rtl > li:last-child { + border-left: 0; + } + .sm-simple.sm-rtl ul a.has-submenu { + padding: 11px 20px; + } + .sm-simple.sm-rtl ul a .sub-arrow { + left: auto; + right: 8px; + } + .sm-simple.sm-vertical a .sub-arrow { + left: 8px; + right: auto; + } + .sm-simple.sm-vertical li { + border-left: 0; + border-top: 1px solid #eeeeee; + } + .sm-simple.sm-vertical > li:first-child { + border-top: 0; + } +} + +/*# sourceMappingURL=sm-simple.css.map */ diff --git a/static/theme/menu/css/menu.css b/static/theme/menu/css/menu.css new file mode 100644 index 00000000..95cdf757 --- /dev/null +++ b/static/theme/menu/css/menu.css @@ -0,0 +1,58 @@ +.sm { + box-sizing: border-box; + position: relative; + z-index: 9999; + -webkit-tap-highlight-color: rgba(0,0,0,0); +} +.sm, +.sm ul, +.sm li { + display: block; + list-style: none; + margin: 0; + padding: 0; + line-height: normal; + direction: ltr; + text-align: left; +} +.sm-rtl, +.sm-rtl ul, +.sm-rtl li { + direction: rtl; + text-align: right; +} +.sm > li > h1, +.sm > li > h2, +.sm > li > h3, +.sm > li > h4, +.sm > li > h5, +.sm > li > h6 { + margin: 0; + padding: 0; +} +.sm ul { + display: none; +} +.sm li, +.sm a { + position: relative; +} +.sm a { + display: block; +} +.sm a.disabled { + cursor: default; +} +.sm::after { + content: ""; + display: block; + height: 0; + font: 0px/0 serif; + clear: both; + overflow: hidden; +} +.sm *, +.sm *::before, +.sm *::after { + box-sizing: inherit; +} diff --git a/static/theme/menu/js/menu.min.js b/static/theme/menu/js/menu.min.js new file mode 100644 index 00000000..d60d33c5 --- /dev/null +++ b/static/theme/menu/js/menu.min.js @@ -0,0 +1,3 @@ +/*! SmartMenus jQuery Plugin - v1.1.1 - July 23, 2020 + * http://www.smartmenus.org/ + * Copyright Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com; Licensed MIT */(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&"object"==typeof module.exports?module.exports=t(require("jquery")):t(jQuery)})(function($){function initMouseDetection(t){var e=".smartmenus_mouse";if(mouseDetectionEnabled||t)mouseDetectionEnabled&&t&&($(document).off(e),mouseDetectionEnabled=!1);else{var i=!0,s=null,o={mousemove:function(t){var e={x:t.pageX,y:t.pageY,timeStamp:(new Date).getTime()};if(s){var o=Math.abs(s.x-e.x),a=Math.abs(s.y-e.y);if((o>0||a>0)&&4>=o&&4>=a&&300>=e.timeStamp-s.timeStamp&&(mouse=!0,i)){var n=$(t.target).closest("a");n.is("a")&&$.each(menuTrees,function(){return $.contains(this.$root[0],n[0])?(this.itemEnter({currentTarget:n[0]}),!1):void 0}),i=!1}}s=e}};o[touchEvents?"touchstart":"pointerover pointermove pointerout MSPointerOver MSPointerMove MSPointerOut"]=function(t){isTouchEvent(t.originalEvent)&&(mouse=!1)},$(document).on(getEventsNS(o,e)),mouseDetectionEnabled=!0}}function isTouchEvent(t){return!/^(4|mouse)$/.test(t.pointerType)}function getEventsNS(t,e){e||(e="");var i={};for(var s in t)i[s.split(" ").join(e+" ")+e]=t[s];return i}var menuTrees=[],mouse=!1,touchEvents="ontouchstart"in window,mouseDetectionEnabled=!1,requestAnimationFrame=window.requestAnimationFrame||function(t){return setTimeout(t,1e3/60)},cancelAnimationFrame=window.cancelAnimationFrame||function(t){clearTimeout(t)},canAnimate=!!$.fn.animate;return $.SmartMenus=function(t,e){this.$root=$(t),this.opts=e,this.rootId="",this.accessIdPrefix="",this.$subArrow=null,this.activatedItems=[],this.visibleSubMenus=[],this.showTimeout=0,this.hideTimeout=0,this.scrollTimeout=0,this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.idInc=0,this.$firstLink=null,this.$firstSub=null,this.disabled=!1,this.$disableOverlay=null,this.$touchScrollingSub=null,this.cssTransforms3d="perspective"in t.style||"webkitPerspective"in t.style,this.wasCollapsible=!1,this.init()},$.extend($.SmartMenus,{hideAll:function(){$.each(menuTrees,function(){this.menuHideAll()})},destroy:function(){for(;menuTrees.length;)menuTrees[0].destroy();initMouseDetection(!0)},prototype:{init:function(t){var e=this;if(!t){menuTrees.push(this),this.rootId=((new Date).getTime()+Math.random()+"").replace(/\D/g,""),this.accessIdPrefix="sm-"+this.rootId+"-",this.$root.hasClass("sm-rtl")&&(this.opts.rightToLeftSubMenus=!0);var i=".smartmenus";this.$root.data("smartmenus",this).attr("data-smartmenus-id",this.rootId).dataSM("level",1).on(getEventsNS({"mouseover focusin":$.proxy(this.rootOver,this),"mouseout focusout":$.proxy(this.rootOut,this),keydown:$.proxy(this.rootKeyDown,this)},i)).on(getEventsNS({mouseenter:$.proxy(this.itemEnter,this),mouseleave:$.proxy(this.itemLeave,this),mousedown:$.proxy(this.itemDown,this),focus:$.proxy(this.itemFocus,this),blur:$.proxy(this.itemBlur,this),click:$.proxy(this.itemClick,this)},i),"a"),i+=this.rootId,this.opts.hideOnClick&&$(document).on(getEventsNS({touchstart:$.proxy(this.docTouchStart,this),touchmove:$.proxy(this.docTouchMove,this),touchend:$.proxy(this.docTouchEnd,this),click:$.proxy(this.docClick,this)},i)),$(window).on(getEventsNS({"resize orientationchange":$.proxy(this.winResize,this)},i)),this.opts.subIndicators&&(this.$subArrow=$("<span/>").addClass("sub-arrow"),this.opts.subIndicatorsText&&this.$subArrow.html(this.opts.subIndicatorsText)),initMouseDetection()}if(this.$firstSub=this.$root.find("ul").each(function(){e.menuInit($(this))}).eq(0),this.$firstLink=this.$root.find("a").eq(0),this.opts.markCurrentItem){var s=/(index|default)\.[^#\?\/]*/i,o=/#.*/,a=window.location.href.replace(s,""),n=a.replace(o,"");this.$root.find("a:not(.mega-menu a)").each(function(){var t=this.href.replace(s,""),i=$(this);(t==a||t==n)&&(i.addClass("current"),e.opts.markCurrentTree&&i.parentsUntil("[data-smartmenus-id]","ul").each(function(){$(this).dataSM("parent-a").addClass("current")}))})}this.wasCollapsible=this.isCollapsible()},destroy:function(t){if(!t){var e=".smartmenus";this.$root.removeData("smartmenus").removeAttr("data-smartmenus-id").removeDataSM("level").off(e),e+=this.rootId,$(document).off(e),$(window).off(e),this.opts.subIndicators&&(this.$subArrow=null)}this.menuHideAll();var i=this;this.$root.find("ul").each(function(){var t=$(this);t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.dataSM("shown-before")&&((i.opts.subMenusMinWidth||i.opts.subMenusMaxWidth)&&t.css({width:"",minWidth:"",maxWidth:""}).removeClass("sm-nowrap"),t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.css({zIndex:"",top:"",left:"",marginLeft:"",marginTop:"",display:""})),0==(t.attr("id")||"").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeDataSM("in-mega").removeDataSM("shown-before").removeDataSM("scroll-arrows").removeDataSM("parent-a").removeDataSM("level").removeDataSM("beforefirstshowfired").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeAttr("aria-expanded"),this.$root.find("a.has-submenu").each(function(){var t=$(this);0==t.attr("id").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeClass("has-submenu").removeDataSM("sub").removeAttr("aria-haspopup").removeAttr("aria-controls").removeAttr("aria-expanded").closest("li").removeDataSM("sub"),this.opts.subIndicators&&this.$root.find("span.sub-arrow").remove(),this.opts.markCurrentItem&&this.$root.find("a.current").removeClass("current"),t||(this.$root=null,this.$firstLink=null,this.$firstSub=null,this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),menuTrees.splice($.inArray(this,menuTrees),1))},disable:function(t){if(!this.disabled){if(this.menuHideAll(),!t&&!this.opts.isPopup&&this.$root.is(":visible")){var e=this.$root.offset();this.$disableOverlay=$('<div class="sm-jquery-disable-overlay"/>').css({position:"absolute",top:e.top,left:e.left,width:this.$root.outerWidth(),height:this.$root.outerHeight(),zIndex:this.getStartZIndex(!0),opacity:0}).appendTo(document.body)}this.disabled=!0}},docClick:function(t){return this.$touchScrollingSub?(this.$touchScrollingSub=null,void 0):((this.visibleSubMenus.length&&!$.contains(this.$root[0],t.target)||$(t.target).closest("a").length)&&this.menuHideAll(),void 0)},docTouchEnd:function(){if(this.lastTouch){if(!(!this.visibleSubMenus.length||void 0!==this.lastTouch.x2&&this.lastTouch.x1!=this.lastTouch.x2||void 0!==this.lastTouch.y2&&this.lastTouch.y1!=this.lastTouch.y2||this.lastTouch.target&&$.contains(this.$root[0],this.lastTouch.target))){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var t=this;this.hideTimeout=setTimeout(function(){t.menuHideAll()},350)}this.lastTouch=null}},docTouchMove:function(t){if(this.lastTouch){var e=t.originalEvent.touches[0];this.lastTouch.x2=e.pageX,this.lastTouch.y2=e.pageY}},docTouchStart:function(t){var e=t.originalEvent.touches[0];this.lastTouch={x1:e.pageX,y1:e.pageY,target:e.target}},enable:function(){this.disabled&&(this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),this.disabled=!1)},getClosestMenu:function(t){for(var e=$(t).closest("ul");e.dataSM("in-mega");)e=e.parent().closest("ul");return e[0]||null},getHeight:function(t){return this.getOffset(t,!0)},getOffset:function(t,e){var i;"none"==t.css("display")&&(i={position:t[0].style.position,visibility:t[0].style.visibility},t.css({position:"absolute",visibility:"hidden"}).show());var s=t[0].getBoundingClientRect&&t[0].getBoundingClientRect(),o=s&&(e?s.height||s.bottom-s.top:s.width||s.right-s.left);return o||0===o||(o=e?t[0].offsetHeight:t[0].offsetWidth),i&&t.hide().css(i),o},getStartZIndex:function(t){var e=parseInt(this[t?"$root":"$firstSub"].css("z-index"));return!t&&isNaN(e)&&(e=parseInt(this.$root.css("z-index"))),isNaN(e)?1:e},getTouchPoint:function(t){return t.touches&&t.touches[0]||t.changedTouches&&t.changedTouches[0]||t},getViewport:function(t){var e=t?"Height":"Width",i=document.documentElement["client"+e],s=window["inner"+e];return s&&(i=Math.min(i,s)),i},getViewportHeight:function(){return this.getViewport(!0)},getViewportWidth:function(){return this.getViewport()},getWidth:function(t){return this.getOffset(t)},handleEvents:function(){return!this.disabled&&this.isCSSOn()},handleItemEvents:function(t){return this.handleEvents()&&!this.isLinkInMegaMenu(t)},isCollapsible:function(){return"static"==this.$firstSub.css("position")},isCSSOn:function(){return"inline"!=this.$firstLink.css("display")},isFixed:function(){var t="fixed"==this.$root.css("position");return t||this.$root.parentsUntil("body").each(function(){return"fixed"==$(this).css("position")?(t=!0,!1):void 0}),t},isLinkInMegaMenu:function(t){return $(this.getClosestMenu(t[0])).hasClass("mega-menu")},isTouchMode:function(){return!mouse||this.opts.noMouseOver||this.isCollapsible()},itemActivate:function(t,e){var i=t.closest("ul"),s=i.dataSM("level");if(s>1&&(!this.activatedItems[s-2]||this.activatedItems[s-2][0]!=i.dataSM("parent-a")[0])){var o=this;$(i.parentsUntil("[data-smartmenus-id]","ul").get().reverse()).add(i).each(function(){o.itemActivate($(this).dataSM("parent-a"))})}if((!this.isCollapsible()||e)&&this.menuHideSubMenus(this.activatedItems[s-1]&&this.activatedItems[s-1][0]==t[0]?s:s-1),this.activatedItems[s-1]=t,this.$root.triggerHandler("activate.smapi",t[0])!==!1){var a=t.dataSM("sub");a&&(this.isTouchMode()||!this.opts.showOnClick||this.clickActivated)&&this.menuShow(a)}},itemBlur:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&this.$root.triggerHandler("blur.smapi",e[0])},itemClick:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(this.$touchScrollingSub&&this.$touchScrollingSub[0]==e.closest("ul")[0])return this.$touchScrollingSub=null,t.stopPropagation(),!1;if(this.$root.triggerHandler("click.smapi",e[0])===!1)return!1;var i=e.dataSM("sub"),s=i?2==i.dataSM("level"):!1;if(i){var o=$(t.target).is(".sub-arrow"),a=this.isCollapsible(),n=/toggle$/.test(this.opts.collapsibleBehavior),r=/link$/.test(this.opts.collapsibleBehavior),h=/^accordion/.test(this.opts.collapsibleBehavior);if(i.is(":visible")){if(!a&&this.opts.showOnClick&&s)return this.menuHide(i),this.clickActivated=!1,this.focusActivated=!1,!1;if(a&&(n||o))return this.itemActivate(e,h),this.menuHide(i),!1}else if((!r||!a||o)&&(!a&&this.opts.showOnClick&&s&&(this.clickActivated=!0),this.itemActivate(e,h),i.is(":visible")))return this.focusActivated=!0,!1}return!a&&this.opts.showOnClick&&s||e.hasClass("disabled")||this.$root.triggerHandler("select.smapi",e[0])===!1?!1:void 0}},itemDown:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&e.dataSM("mousedown",!0)},itemEnter:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(!this.isTouchMode()){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);var i=this;this.showTimeout=setTimeout(function(){i.itemActivate(e)},this.opts.showOnClick&&1==e.closest("ul").dataSM("level")?1:this.opts.showTimeout)}this.$root.triggerHandler("mouseenter.smapi",e[0])}},itemFocus:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(!this.focusActivated||this.isTouchMode()&&e.dataSM("mousedown")||this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0]==e[0]||this.itemActivate(e,!0),this.$root.triggerHandler("focus.smapi",e[0]))},itemLeave:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(this.isTouchMode()||(e[0].blur(),this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0)),e.removeDataSM("mousedown"),this.$root.triggerHandler("mouseleave.smapi",e[0]))},menuHide:function(t){if(this.$root.triggerHandler("beforehide.smapi",t[0])!==!1&&(canAnimate&&t.stop(!0,!0),"none"!=t.css("display"))){var e=function(){t.css("z-index","")};this.isCollapsible()?canAnimate&&this.opts.collapsibleHideFunction?this.opts.collapsibleHideFunction.call(this,t,e):t.hide(this.opts.collapsibleHideDuration,e):canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,t,e):t.hide(this.opts.hideDuration,e),t.dataSM("scroll")&&(this.menuScrollStop(t),t.css({"touch-action":"","-ms-touch-action":"","-webkit-transform":"",transform:""}).off(".smartmenus_scroll").removeDataSM("scroll").dataSM("scroll-arrows").hide()),t.dataSM("parent-a").removeClass("highlighted").attr("aria-expanded","false"),t.attr({"aria-expanded":"false","aria-hidden":"true"});var i=t.dataSM("level");this.activatedItems.splice(i-1,1),this.visibleSubMenus.splice($.inArray(t,this.visibleSubMenus),1),this.$root.triggerHandler("hide.smapi",t[0])}},menuHideAll:function(){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);for(var t=this.opts.isPopup?1:0,e=this.visibleSubMenus.length-1;e>=t;e--)this.menuHide(this.visibleSubMenus[e]);this.opts.isPopup&&(canAnimate&&this.$root.stop(!0,!0),this.$root.is(":visible")&&(canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,this.$root):this.$root.hide(this.opts.hideDuration))),this.activatedItems=[],this.visibleSubMenus=[],this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.$root.triggerHandler("hideAll.smapi")},menuHideSubMenus:function(t){for(var e=this.activatedItems.length-1;e>=t;e--){var i=this.activatedItems[e].dataSM("sub");i&&this.menuHide(i)}},menuInit:function(t){if(!t.dataSM("in-mega")){t.hasClass("mega-menu")&&t.find("ul").dataSM("in-mega",!0);for(var e=2,i=t[0];(i=i.parentNode.parentNode)!=this.$root[0];)e++;var s=t.prevAll("a").eq(-1);s.length||(s=t.prevAll().find("a").eq(-1)),s.addClass("has-submenu").dataSM("sub",t),t.dataSM("parent-a",s).dataSM("level",e).parent().dataSM("sub",t);var o=s.attr("id")||this.accessIdPrefix+ ++this.idInc,a=t.attr("id")||this.accessIdPrefix+ ++this.idInc;s.attr({id:o,"aria-haspopup":"true","aria-controls":a,"aria-expanded":"false"}),t.attr({id:a,role:"group","aria-hidden":"true","aria-labelledby":o,"aria-expanded":"false"}),this.opts.subIndicators&&s[this.opts.subIndicatorsPos](this.$subArrow.clone())}},menuPosition:function(t){var e,i,s=t.dataSM("parent-a"),o=s.closest("li"),a=o.parent(),n=t.dataSM("level"),r=this.getWidth(t),h=this.getHeight(t),u=s.offset(),l=u.left,c=u.top,d=this.getWidth(s),m=this.getHeight(s),p=$(window),f=p.scrollLeft(),v=p.scrollTop(),b=this.getViewportWidth(),S=this.getViewportHeight(),g=a.parent().is("[data-sm-horizontal-sub]")||2==n&&!a.hasClass("sm-vertical"),w=this.opts.rightToLeftSubMenus&&!o.is("[data-sm-reverse]")||!this.opts.rightToLeftSubMenus&&o.is("[data-sm-reverse]"),M=2==n?this.opts.mainMenuSubOffsetX:this.opts.subMenusSubOffsetX,T=2==n?this.opts.mainMenuSubOffsetY:this.opts.subMenusSubOffsetY;if(g?(e=w?d-r-M:M,i=this.opts.bottomToTopSubMenus?-h-T:m+T):(e=w?M-r:d-M,i=this.opts.bottomToTopSubMenus?m-T-h:T),this.opts.keepInViewport){var y=l+e,I=c+i;if(w&&f>y?e=g?f-y+e:d-M:!w&&y+r>f+b&&(e=g?f+b-r-y+e:M-r),g||(S>h&&I+h>v+S?i+=v+S-h-I:(h>=S||v>I)&&(i+=v-I)),g&&(I+h>v+S+.49||v>I)||!g&&h>S+.49){var x=this;t.dataSM("scroll-arrows")||t.dataSM("scroll-arrows",$([$('<span class="scroll-up"><span class="scroll-up-arrow"></span></span>')[0],$('<span class="scroll-down"><span class="scroll-down-arrow"></span></span>')[0]]).on({mouseenter:function(){t.dataSM("scroll").up=$(this).hasClass("scroll-up"),x.menuScroll(t)},mouseleave:function(e){x.menuScrollStop(t),x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(t){t.preventDefault()}}).insertAfter(t));var A=".smartmenus_scroll";if(t.dataSM("scroll",{y:this.cssTransforms3d?0:i-m,step:1,itemH:m,subH:h,arrowDownH:this.getHeight(t.dataSM("scroll-arrows").eq(1))}).on(getEventsNS({mouseover:function(e){x.menuScrollOver(t,e)},mouseout:function(e){x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(e){x.menuScrollMousewheel(t,e)}},A)).dataSM("scroll-arrows").css({top:"auto",left:"0",marginLeft:e+(parseInt(t.css("border-left-width"))||0),width:r-(parseInt(t.css("border-left-width"))||0)-(parseInt(t.css("border-right-width"))||0),zIndex:t.css("z-index")}).eq(g&&this.opts.bottomToTopSubMenus?0:1).show(),this.isFixed()){var C={};C[touchEvents?"touchstart touchmove touchend":"pointerdown pointermove pointerup MSPointerDown MSPointerMove MSPointerUp"]=function(e){x.menuScrollTouch(t,e)},t.css({"touch-action":"none","-ms-touch-action":"none"}).on(getEventsNS(C,A))}}}t.css({top:"auto",left:"0",marginLeft:e,marginTop:i-m})},menuScroll:function(t,e,i){var s,o=t.dataSM("scroll"),a=t.dataSM("scroll-arrows"),n=o.up?o.upEnd:o.downEnd;if(!e&&o.momentum){if(o.momentum*=.92,s=o.momentum,.5>s)return this.menuScrollStop(t),void 0}else s=i||(e||!this.opts.scrollAccelerate?this.opts.scrollStep:Math.floor(o.step));var r=t.dataSM("level");if(this.activatedItems[r-1]&&this.activatedItems[r-1].dataSM("sub")&&this.activatedItems[r-1].dataSM("sub").is(":visible")&&this.menuHideSubMenus(r-1),o.y=o.up&&o.y>=n||!o.up&&n>=o.y?o.y:Math.abs(n-o.y)>s?o.y+(o.up?s:-s):n,t.css(this.cssTransforms3d?{"-webkit-transform":"translate3d(0, "+o.y+"px, 0)",transform:"translate3d(0, "+o.y+"px, 0)"}:{marginTop:o.y}),mouse&&(o.up&&o.y>o.downEnd||!o.up&&o.y<o.upEnd)&&a.eq(o.up?1:0).show(),o.y==n)mouse&&a.eq(o.up?0:1).hide(),this.menuScrollStop(t);else if(!e){this.opts.scrollAccelerate&&o.step<this.opts.scrollStep&&(o.step+=.2);var h=this;this.scrollTimeout=requestAnimationFrame(function(){h.menuScroll(t)})}},menuScrollMousewheel:function(t,e){if(this.getClosestMenu(e.target)==t[0]){e=e.originalEvent;var i=(e.wheelDelta||-e.detail)>0;t.dataSM("scroll-arrows").eq(i?0:1).is(":visible")&&(t.dataSM("scroll").up=i,this.menuScroll(t,!0))}e.preventDefault()},menuScrollOut:function(t,e){mouse&&(/^scroll-(up|down)/.test((e.relatedTarget||"").className)||(t[0]==e.relatedTarget||$.contains(t[0],e.relatedTarget))&&this.getClosestMenu(e.relatedTarget)==t[0]||t.dataSM("scroll-arrows").css("visibility","hidden"))},menuScrollOver:function(t,e){if(mouse&&!/^scroll-(up|down)/.test(e.target.className)&&this.getClosestMenu(e.target)==t[0]){this.menuScrollRefreshData(t);var i=t.dataSM("scroll"),s=$(window).scrollTop()-t.dataSM("parent-a").offset().top-i.itemH;t.dataSM("scroll-arrows").eq(0).css("margin-top",s).end().eq(1).css("margin-top",s+this.getViewportHeight()-i.arrowDownH).end().css("visibility","visible")}},menuScrollRefreshData:function(t){var e=t.dataSM("scroll"),i=$(window).scrollTop()-t.dataSM("parent-a").offset().top-e.itemH;this.cssTransforms3d&&(i=-(parseFloat(t.css("margin-top"))-i)),$.extend(e,{upEnd:i,downEnd:i+this.getViewportHeight()-e.subH})},menuScrollStop:function(t){return this.scrollTimeout?(cancelAnimationFrame(this.scrollTimeout),this.scrollTimeout=0,t.dataSM("scroll").step=1,!0):void 0},menuScrollTouch:function(t,e){if(e=e.originalEvent,isTouchEvent(e)){var i=this.getTouchPoint(e);if(this.getClosestMenu(i.target)==t[0]){var s=t.dataSM("scroll");if(/(start|down)$/i.test(e.type))this.menuScrollStop(t)?(e.preventDefault(),this.$touchScrollingSub=t):this.$touchScrollingSub=null,this.menuScrollRefreshData(t),$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp});else if(/move$/i.test(e.type)){var o=void 0!==s.touchY?s.touchY:s.touchStartY;if(void 0!==o&&o!=i.pageY){this.$touchScrollingSub=t;var a=i.pageY>o;void 0!==s.up&&s.up!=a&&$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp}),$.extend(s,{up:a,touchY:i.pageY}),this.menuScroll(t,!0,Math.abs(i.pageY-o))}e.preventDefault()}else void 0!==s.touchY&&((s.momentum=15*Math.pow(Math.abs(i.pageY-s.touchStartY)/(e.timeStamp-s.touchStartTime),2))&&(this.menuScrollStop(t),this.menuScroll(t),e.preventDefault()),delete s.touchY)}}},menuShow:function(t){if((t.dataSM("beforefirstshowfired")||(t.dataSM("beforefirstshowfired",!0),this.$root.triggerHandler("beforefirstshow.smapi",t[0])!==!1))&&this.$root.triggerHandler("beforeshow.smapi",t[0])!==!1&&(t.dataSM("shown-before",!0),canAnimate&&t.stop(!0,!0),!t.is(":visible"))){var e=t.dataSM("parent-a"),i=this.isCollapsible();if((this.opts.keepHighlighted||i)&&e.addClass("highlighted"),i)t.removeClass("sm-nowrap").css({zIndex:"",width:"auto",minWidth:"",maxWidth:"",top:"",left:"",marginLeft:"",marginTop:""});else{if(t.css("z-index",this.zIndexInc=(this.zIndexInc||this.getStartZIndex())+1),(this.opts.subMenusMinWidth||this.opts.subMenusMaxWidth)&&(t.css({width:"auto",minWidth:"",maxWidth:""}).addClass("sm-nowrap"),this.opts.subMenusMinWidth&&t.css("min-width",this.opts.subMenusMinWidth),this.opts.subMenusMaxWidth)){var s=this.getWidth(t);t.css("max-width",this.opts.subMenusMaxWidth),s>this.getWidth(t)&&t.removeClass("sm-nowrap").css("width",this.opts.subMenusMaxWidth)}this.menuPosition(t)}var o=function(){t.css("overflow","")};i?canAnimate&&this.opts.collapsibleShowFunction?this.opts.collapsibleShowFunction.call(this,t,o):t.show(this.opts.collapsibleShowDuration,o):canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,t,o):t.show(this.opts.showDuration,o),e.attr("aria-expanded","true"),t.attr({"aria-expanded":"true","aria-hidden":"false"}),this.visibleSubMenus.push(t),this.$root.triggerHandler("show.smapi",t[0])}},popupHide:function(t){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},t?1:this.opts.hideTimeout)},popupShow:function(t,e){if(!this.opts.isPopup)return alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'),void 0;if(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),this.$root.dataSM("shown-before",!0),canAnimate&&this.$root.stop(!0,!0),!this.$root.is(":visible")){this.$root.css({left:t,top:e});var i=this,s=function(){i.$root.css("overflow","")};canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,this.$root,s):this.$root.show(this.opts.showDuration,s),this.visibleSubMenus[0]=this.$root}},refresh:function(){this.destroy(!0),this.init(!0)},rootKeyDown:function(t){if(this.handleEvents())switch(t.keyCode){case 27:var e=this.activatedItems[0];if(e){this.menuHideAll(),e[0].focus();var i=e.dataSM("sub");i&&this.menuHide(i)}break;case 32:var s=$(t.target);if(s.is("a")&&this.handleItemEvents(s)){var i=s.dataSM("sub");i&&!i.is(":visible")&&(this.itemClick({currentTarget:t.target}),t.preventDefault())}}},rootOut:function(t){if(this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),!this.opts.showOnClick||!this.opts.hideOnClick)){var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},this.opts.hideTimeout)}},rootOver:function(t){this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0)},winResize:function(t){if(this.handleEvents()){if(!("onorientationchange"in window)||"orientationchange"==t.type){var e=this.isCollapsible();this.wasCollapsible&&e||(this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0].blur(),this.menuHideAll()),this.wasCollapsible=e}}else if(this.$disableOverlay){var i=this.$root.offset();this.$disableOverlay.css({top:i.top,left:i.left,width:this.$root.outerWidth(),height:this.$root.outerHeight()})}}}}),$.fn.dataSM=function(t,e){return e?this.data(t+"_smartmenus",e):this.data(t+"_smartmenus")},$.fn.removeDataSM=function(t){return this.removeData(t+"_smartmenus")},$.fn.smartmenus=function(options){if("string"==typeof options){var args=arguments,method=options;return Array.prototype.shift.call(args),this.each(function(){var t=$(this).data("smartmenus");t&&t[method]&&t[method].apply(t,args)})}return this.each(function(){var dataOpts=$(this).data("sm-options")||null;if(dataOpts&&"object"!=typeof dataOpts)try{dataOpts=eval("("+dataOpts+")")}catch(e){dataOpts=null,alert('ERROR\n\nSmartMenus jQuery init:\nInvalid "data-sm-options" attribute value syntax.')}new $.SmartMenus(this,$.extend({},$.fn.smartmenus.defaults,options,dataOpts))})},$.fn.smartmenus.defaults={isPopup:!1,mainMenuSubOffsetX:0,mainMenuSubOffsetY:0,subMenusSubOffsetX:0,subMenusSubOffsetY:0,subMenusMinWidth:"10em",subMenusMaxWidth:"20em",subIndicators:!0,subIndicatorsPos:"append",subIndicatorsText:"",scrollStep:30,scrollAccelerate:!0,showTimeout:250,hideTimeout:500,showDuration:0,showFunction:null,hideDuration:0,hideFunction:function(t,e){t.fadeOut(200,e)},collapsibleShowDuration:0,collapsibleShowFunction:function(t,e){t.slideDown(200,e)},collapsibleHideDuration:0,collapsibleHideFunction:function(t,e){t.slideUp(200,e)},showOnClick:!1,hideOnClick:!0,noMouseOver:!1,keepInViewport:!0,keepHighlighted:!0,markCurrentItem:!1,markCurrentTree:!0,rightToLeftSubMenus:!1,bottomToTopSubMenus:!1,collapsibleBehavior:"default"},$}); \ No newline at end of file From 3764f707daa61b0c84325206ac8bf04425fcc9c2 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 26 Feb 2022 21:15:00 +0100 Subject: [PATCH 015/244] =?UTF-8?q?A=C3=B1ade=20elecci=C3=B3n=20de=20tema?= =?UTF-8?q?=20espec=C3=ADfico=20por=20p=C3=A1gina?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Característica útil para facilitar que el módulo Admin pueda renderizar sus páginas siempre con el mismo tema, indepedientemente del tema por defecto. También podrá ser decisivo para permitir a los usuarios usar un tema diferente. --- src/base/module/admin/summary.rs | 3 ++ src/core/all.rs | 55 ++++++++++++++++++++++++-- src/core/mod.rs | 5 --- src/core/module/mod.rs | 14 +++++++ src/core/response/page/assets.rs | 18 ++++++++- src/core/response/page/mod.rs | 11 ++++++ src/core/response/page/page.rs | 19 ++++++--- src/core/server/main.rs | 3 +- src/core/state.rs | 67 -------------------------------- src/core/theme/mod.rs | 14 +++++++ src/prelude.rs | 4 +- 11 files changed, 127 insertions(+), 86 deletions(-) delete mode 100644 src/core/state.rs diff --git a/src/base/module/admin/summary.rs b/src/base/module/admin/summary.rs index 6f620fd0..a6fe5e5d 100644 --- a/src/base/module/admin/summary.rs +++ b/src/base/module/admin/summary.rs @@ -32,6 +32,9 @@ pub async fn summary() -> server::Result<Markup> { .add(MenuItem::label("Opción 4")); Page::prepare() + + .using_theme(&bootsier::BootsierTheme) + .with_title("Admin") .add_to("top-menu", top_menu) diff --git a/src/core/all.rs b/src/core/all.rs index 3fe712b6..3174fc5f 100644 --- a/src/core/all.rs +++ b/src/core/all.rs @@ -1,20 +1,69 @@ -use crate::core::{server, state}; +use crate::Lazy; +use crate::config::SETTINGS; +use crate::core::theme::Theme; +use crate::core::module::Module; +use crate::core::response::page::PageContainer; +use crate::core::server; +use crate::base; + +use std::sync::RwLock; +use std::collections::HashMap; include!(concat!(env!("OUT_DIR"), "/theme.rs")); +// ----------------------------------------------------------------------------- +// Temas registrados y tema por defecto. +// ----------------------------------------------------------------------------- + +pub static THEMES: Lazy<RwLock<Vec<&dyn Theme>>> = Lazy::new(|| { + RwLock::new(vec![ + &base::theme::aliner::AlinerTheme, + &base::theme::minimal::MinimalTheme, + &base::theme::bootsier::BootsierTheme, + ]) +}); + +pub static DEFAULT_THEME: Lazy<&dyn Theme> = Lazy::new(|| { + for t in THEMES.read().unwrap().iter() { + if t.name().to_lowercase() == SETTINGS.app.theme.to_lowercase() { + return *t; + } + } + &base::theme::bootsier::BootsierTheme +}); + pub fn themes(cfg: &mut server::web::ServiceConfig) { cfg.service(actix_web_static_files::ResourceFiles::new( "/theme", assets() )); - for t in state::THEMES.read().unwrap().iter() { + for t in THEMES.read().unwrap().iter() { t.configure_theme(cfg); } } +// ----------------------------------------------------------------------------- +// Módulos registrados. +// ----------------------------------------------------------------------------- + +pub static MODULES: Lazy<RwLock<Vec<&dyn Module>>> = Lazy::new(|| { + RwLock::new(vec![ + &base::module::admin::AdminModule, + &base::module::user::UserModule, + ]) +}); + pub fn modules(cfg: &mut server::web::ServiceConfig) { - for m in state::MODULES.read().unwrap().iter() { + for m in MODULES.read().unwrap().iter() { m.configure_module(cfg); } } + +// ----------------------------------------------------------------------------- +// Componentes globales. +// ----------------------------------------------------------------------------- + +pub static COMPONENTS: Lazy<RwLock<HashMap<&str, PageContainer>>> = Lazy::new( + || { RwLock::new(HashMap::new()) } +); diff --git a/src/core/mod.rs b/src/core/mod.rs index de375c10..40530f15 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,10 +1,5 @@ pub use actix_web::dev::Server; -mod state; -pub use state::register_theme; -pub use state::register_module; -pub use state::add_component_to; - mod all; pub mod theme; diff --git a/src/core/module/mod.rs b/src/core/module/mod.rs index a8f85139..c77e530e 100644 --- a/src/core/module/mod.rs +++ b/src/core/module/mod.rs @@ -1,2 +1,16 @@ +use crate::core::all::MODULES; + mod api; pub use api::Module; + +pub fn register_module(m: &'static (dyn Module + 'static)) { + MODULES.write().unwrap().push(m); +} + +pub fn find_module(name: &str) -> Option<&'static (dyn Module + 'static)> { + let modules = MODULES.write().unwrap(); + match modules.iter().find(|t| t.name() == name) { + Some(module) => Some(*module), + _ => None, + } +} diff --git a/src/core/response/page/assets.rs b/src/core/response/page/assets.rs index 8d929f79..c515bb04 100644 --- a/src/core/response/page/assets.rs +++ b/src/core/response/page/assets.rs @@ -1,4 +1,5 @@ -use crate::core::theme::{Markup, PreEscaped, html}; +use crate::core::all::DEFAULT_THEME; +use crate::core::theme::{Markup, PreEscaped, Theme, html}; // ----------------------------------------------------------------------------- // Favicon. @@ -172,6 +173,7 @@ impl JavaScript { // ----------------------------------------------------------------------------- pub struct Assets { + theme : &'static dyn Theme, favicon : Option<Favicon>, metadata : Vec<(String, String)>, stylesheets: Vec<StyleSheet>, @@ -183,6 +185,7 @@ pub struct Assets { impl Assets { pub fn new() -> Self { Assets { + theme : *DEFAULT_THEME, favicon : None, metadata : Vec::new(), stylesheets: Vec::new(), @@ -192,6 +195,11 @@ impl Assets { } } + pub fn using_theme(&mut self, theme: &'static dyn Theme) -> &mut Self { + self.theme = theme; + self + } + pub fn with_favicon(&mut self, favicon: Favicon) -> &mut Self { self.favicon = Some(favicon); self @@ -238,6 +246,14 @@ impl Assets { self } + /// Assets GETTERS. + + pub fn theme(&mut self) -> &'static dyn Theme { + self.theme + } + + /// Assets RENDER. + pub fn render(&mut self) -> Markup { let ordered_css = &mut self.stylesheets; ordered_css.sort_by_key(|o| o.weight); diff --git a/src/core/response/page/mod.rs b/src/core/response/page/mod.rs index 881e0df3..83f0e0e9 100644 --- a/src/core/response/page/mod.rs +++ b/src/core/response/page/mod.rs @@ -1,3 +1,5 @@ +use crate::core::all::COMPONENTS; + pub mod assets; pub use assets::Assets as PageAssets; @@ -10,3 +12,12 @@ pub use container::Container as PageContainer; mod page; pub use page::Page; pub use page::render_component; + +pub fn add_component_to(region: &'static str, component: impl PageComponent) { + let mut hmap = COMPONENTS.write().unwrap(); + if let Some(regions) = hmap.get_mut(region) { + regions.add(component); + } else { + hmap.insert(region, PageContainer::new_with(component)); + } +} diff --git a/src/core/response/page/page.rs b/src/core/response/page/page.rs index add4c64d..dea08591 100644 --- a/src/core/response/page/page.rs +++ b/src/core/response/page/page.rs @@ -1,7 +1,7 @@ use crate::config::SETTINGS; use crate::core::server; -use crate::core::state::{COMPONENTS, THEME}; -use crate::core::theme::{DOCTYPE, Markup, html}; +use crate::core::all::COMPONENTS; +use crate::core::theme::{DOCTYPE, Markup, Theme, html}; use crate::core::response::page::{PageAssets, PageComponent, PageContainer}; use std::borrow::Cow; @@ -132,13 +132,13 @@ impl<'a> Page<'a> { pub fn render(&mut self) -> server::Result<Markup> { // Acciones del tema antes de renderizar la página. - THEME.before_render_page(self); + self.assets.theme().before_render_page(self); // Primero, renderizar el cuerpo. - let body = THEME.render_page_body(self); + let body = self.assets.theme().render_page_body(self); // Luego, renderizar la cabecera. - let head = THEME.render_page_head(self); + let head = self.assets.theme().render_page_head(self); // Finalmente, renderizar la página. return Ok(html! { @@ -156,6 +156,13 @@ impl<'a> Page<'a> { None => html! {} } } + + // Page EXTRAS. + + pub fn using_theme(&mut self, theme: &'static dyn Theme) -> &mut Self { + self.assets.using_theme(theme); + self + } } pub fn render_component( @@ -163,7 +170,7 @@ pub fn render_component( assets: &mut PageAssets ) -> Markup { match component.is_renderable() { - true => match THEME.render_component(component, assets) { + true => match assets.theme().render_component(component, assets) { Some(markup) => markup, None => component.default_render(assets) }, diff --git a/src/core/server/main.rs b/src/core/server/main.rs index 8616158e..2c8e2d37 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -1,6 +1,7 @@ use crate::{base, trace}; use crate::config::SETTINGS; -use crate::core::{Server, all, register_module, server}; +use crate::core::{Server, all, server}; +use crate::core::module::register_module; use tracing_log::LogTracer; use tracing_subscriber::{EnvFilter, Registry}; diff --git a/src/core/state.rs b/src/core/state.rs deleted file mode 100644 index a53d8d80..00000000 --- a/src/core/state.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::Lazy; -use crate::config::SETTINGS; -use crate::core::theme::Theme; -use crate::core::module::Module; -use crate::core::response::page::{PageComponent, PageContainer}; -use crate::base; - -use std::sync::RwLock; -use std::collections::HashMap; - -// ----------------------------------------------------------------------------- -// Temas registrados. -// ----------------------------------------------------------------------------- - -pub static THEMES: Lazy<RwLock<Vec<&dyn Theme>>> = Lazy::new(|| { - RwLock::new(vec![ - &base::theme::aliner::AlinerTheme, - &base::theme::minimal::MinimalTheme, - &base::theme::bootsier::BootsierTheme, - ]) -}); - -pub static THEME: Lazy<&dyn Theme> = Lazy::new(|| { - for t in THEMES.read().unwrap().iter() { - if t.name().to_lowercase() == SETTINGS.app.theme.to_lowercase() { - return *t; - } - } - &base::theme::bootsier::BootsierTheme -}); - -pub fn register_theme(t: &'static (dyn Theme + 'static)) { - THEMES.write().unwrap().push(t); -} - -// ----------------------------------------------------------------------------- -// Módulos registrados. -// ----------------------------------------------------------------------------- - -pub static MODULES: Lazy<RwLock<Vec<&dyn Module>>> = Lazy::new(|| { - RwLock::new(vec![ - &base::module::admin::AdminModule, - &base::module::user::UserModule, - ]) -}); - -pub fn register_module(m: &'static (dyn Module + 'static)) { - MODULES.write().unwrap().push(m); -} - -// ----------------------------------------------------------------------------- -// Componentes globales. -// ----------------------------------------------------------------------------- - -pub static COMPONENTS: Lazy<RwLock<HashMap<&str, PageContainer>>> = Lazy::new( - || { RwLock::new(HashMap::new()) } -); - -#[allow(dead_code)] -pub fn add_component_to(region: &'static str, component: impl PageComponent) { - let mut hmap = COMPONENTS.write().unwrap(); - if let Some(regions) = hmap.get_mut(region) { - regions.add(component); - } else { - hmap.insert(region, PageContainer::new_with(component)); - } -} diff --git a/src/core/theme/mod.rs b/src/core/theme/mod.rs index 9b908257..b3376d49 100644 --- a/src/core/theme/mod.rs +++ b/src/core/theme/mod.rs @@ -1,4 +1,18 @@ +use crate::core::all::THEMES; + pub use maud::{DOCTYPE, Markup, PreEscaped, html}; mod api; pub use api::Theme; + +pub fn register_theme(t: &'static (dyn Theme + 'static)) { + THEMES.write().unwrap().push(t); +} + +pub fn find_theme(name: &str) -> Option<&'static (dyn Theme + 'static)> { + let themes = THEMES.write().unwrap(); + match themes.iter().find(|t| t.name() == name) { + Some(theme) => Some(*theme), + _ => None, + } +} diff --git a/src/prelude.rs b/src/prelude.rs index 4a66e08b..1792da41 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -15,8 +15,6 @@ pub use crate::core::response::page::*; pub use crate::core::response::page::assets::*; pub use crate::core::server; -pub use crate::core::register_theme; -pub use crate::core::register_module; -pub use crate::core::add_component_to; +pub use crate::base::theme::*; pub use crate::base::component::*; From 83fd12b5cc774aa24c381b78f99a33b92cf12447 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 26 Feb 2022 21:48:39 +0100 Subject: [PATCH 016/244] =?UTF-8?q?Modifica=20la=20forma=20de=20identifica?= =?UTF-8?q?r=20temas=20y=20m=C3=B3dulos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cada módulo y cada tema requerirá a partir de ahora un identificador que debería ser único y con alguna sintaxis particular aún por definir (por ejemplo, admitiendo sólo minúsculas y sin espacios). --- src/base/module/admin/configure.rs | 17 ----------- src/base/module/admin/locales/en-US/admin.ftl | 2 ++ src/base/module/admin/locales/es-ES/admin.ftl | 2 ++ src/base/module/admin/mod.rs | 28 +++++++++++++++++-- src/base/module/admin/summary.rs | 2 +- src/base/module/homepage/mod.rs | 4 +++ src/base/module/user/mod.rs | 4 +++ src/base/theme/aliner/mod.rs | 4 +++ src/base/theme/bootsier/mod.rs | 4 +++ src/base/theme/minimal/mod.rs | 4 +++ src/core/module/api.rs | 2 ++ src/core/module/mod.rs | 4 +-- src/core/response/page/assets.rs | 6 ++-- src/core/response/page/page.rs | 6 ++-- src/core/theme/api.rs | 2 ++ src/core/theme/mod.rs | 4 +-- 16 files changed, 65 insertions(+), 30 deletions(-) delete mode 100644 src/base/module/admin/configure.rs create mode 100644 src/base/module/admin/locales/en-US/admin.ftl create mode 100644 src/base/module/admin/locales/es-ES/admin.ftl diff --git a/src/base/module/admin/configure.rs b/src/base/module/admin/configure.rs deleted file mode 100644 index 1859f016..00000000 --- a/src/base/module/admin/configure.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::prelude::*; -use crate::base::module::admin::summary::summary; - -pub struct AdminModule; - -impl Module for AdminModule { - fn name(&self) -> String { - "PageTop Admin".to_string() - } - - fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { - cfg.service( - server::web::scope("/admin") - .route("", server::web::get().to(summary)) - ); - } -} diff --git a/src/base/module/admin/locales/en-US/admin.ftl b/src/base/module/admin/locales/en-US/admin.ftl new file mode 100644 index 00000000..7f37e03b --- /dev/null +++ b/src/base/module/admin/locales/en-US/admin.ftl @@ -0,0 +1,2 @@ +module_name = Admin module +module_desc = Administration module. diff --git a/src/base/module/admin/locales/es-ES/admin.ftl b/src/base/module/admin/locales/es-ES/admin.ftl new file mode 100644 index 00000000..d9211301 --- /dev/null +++ b/src/base/module/admin/locales/es-ES/admin.ftl @@ -0,0 +1,2 @@ +module_name = Admin module +module_desc = Módulo de administración. diff --git a/src/base/module/admin/mod.rs b/src/base/module/admin/mod.rs index 1444391b..7550c381 100644 --- a/src/base/module/admin/mod.rs +++ b/src/base/module/admin/mod.rs @@ -1,4 +1,28 @@ -mod configure; -pub use configure::AdminModule; +use crate::prelude::*; + +localize!("en-US", "src/base/module/admin/locales"); mod summary; + +pub struct AdminModule; + +impl Module for AdminModule { + fn id(&self) -> &'static str { + "admin" + } + + fn name(&self) -> String { + l("module_name") + } + + fn description(&self) -> String { + l("module_desc") + } + + fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { + cfg.service( + server::web::scope("/admin") + .route("", server::web::get().to(summary::summary)) + ); + } +} diff --git a/src/base/module/admin/summary.rs b/src/base/module/admin/summary.rs index a6fe5e5d..2f889e9e 100644 --- a/src/base/module/admin/summary.rs +++ b/src/base/module/admin/summary.rs @@ -33,7 +33,7 @@ pub async fn summary() -> server::Result<Markup> { Page::prepare() - .using_theme(&bootsier::BootsierTheme) + .using_theme("bootsier") .with_title("Admin") diff --git a/src/base/module/homepage/mod.rs b/src/base/module/homepage/mod.rs index 2e4164d0..a8ed27b7 100644 --- a/src/base/module/homepage/mod.rs +++ b/src/base/module/homepage/mod.rs @@ -5,6 +5,10 @@ localize!("en-US", "src/base/module/homepage/locales"); pub struct HomepageModule; impl Module for HomepageModule { + fn id(&self) -> &'static str { + "homepage" + } + fn name(&self) -> String { l("module_name") } diff --git a/src/base/module/user/mod.rs b/src/base/module/user/mod.rs index eea6528c..98ff27fa 100644 --- a/src/base/module/user/mod.rs +++ b/src/base/module/user/mod.rs @@ -5,6 +5,10 @@ localize!("en-US", "src/base/module/user/locales"); pub struct UserModule; impl Module for UserModule { + fn id(&self) -> &'static str { + "user" + } + fn name(&self) -> String { l("module_name") } diff --git a/src/base/theme/aliner/mod.rs b/src/base/theme/aliner/mod.rs index 68e7d509..6df2fb93 100644 --- a/src/base/theme/aliner/mod.rs +++ b/src/base/theme/aliner/mod.rs @@ -5,6 +5,10 @@ include!(concat!(env!("OUT_DIR"), "/aliner.rs")); pub struct AlinerTheme; impl Theme for AlinerTheme { + fn id(&self) -> &'static str { + "aliner" + } + fn name(&self) -> String { "Aliner".to_string() } diff --git a/src/base/theme/bootsier/mod.rs b/src/base/theme/bootsier/mod.rs index 2d37cb05..58975335 100644 --- a/src/base/theme/bootsier/mod.rs +++ b/src/base/theme/bootsier/mod.rs @@ -7,6 +7,10 @@ localize!("en-US", "src/base/theme/bootsier/locales"); pub struct BootsierTheme; impl Theme for BootsierTheme { + fn id(&self) -> &'static str { + "bootsier" + } + fn name(&self) -> String { "Bootsier".to_string() } diff --git a/src/base/theme/minimal/mod.rs b/src/base/theme/minimal/mod.rs index 9ea6e87e..970181b7 100644 --- a/src/base/theme/minimal/mod.rs +++ b/src/base/theme/minimal/mod.rs @@ -3,6 +3,10 @@ use crate::prelude::*; pub struct MinimalTheme; impl Theme for MinimalTheme { + fn id(&self) -> &'static str { + "minimal" + } + fn name(&self) -> String { "Minimal".to_string() } diff --git a/src/core/module/api.rs b/src/core/module/api.rs index bbbdb5eb..68488b84 100644 --- a/src/core/module/api.rs +++ b/src/core/module/api.rs @@ -2,6 +2,8 @@ use crate::core::server; /// Los módulos deben implementar este *trait*. pub trait Module: Send + Sync { + fn id(&self) -> &'static str; + fn name(&self) -> String; fn description(&self) -> String { diff --git a/src/core/module/mod.rs b/src/core/module/mod.rs index c77e530e..c480df38 100644 --- a/src/core/module/mod.rs +++ b/src/core/module/mod.rs @@ -7,9 +7,9 @@ pub fn register_module(m: &'static (dyn Module + 'static)) { MODULES.write().unwrap().push(m); } -pub fn find_module(name: &str) -> Option<&'static (dyn Module + 'static)> { +pub fn find_module(id: &str) -> Option<&'static (dyn Module + 'static)> { let modules = MODULES.write().unwrap(); - match modules.iter().find(|t| t.name() == name) { + match modules.iter().find(|t| t.id() == id) { Some(module) => Some(*module), _ => None, } diff --git a/src/core/response/page/assets.rs b/src/core/response/page/assets.rs index c515bb04..7e1205eb 100644 --- a/src/core/response/page/assets.rs +++ b/src/core/response/page/assets.rs @@ -1,5 +1,5 @@ use crate::core::all::DEFAULT_THEME; -use crate::core::theme::{Markup, PreEscaped, Theme, html}; +use crate::core::theme::{Markup, PreEscaped, Theme, find_theme, html}; // ----------------------------------------------------------------------------- // Favicon. @@ -195,8 +195,8 @@ impl Assets { } } - pub fn using_theme(&mut self, theme: &'static dyn Theme) -> &mut Self { - self.theme = theme; + pub fn using_theme(&mut self, theme_id: &str) -> &mut Self { + self.theme = find_theme(theme_id).unwrap_or(*DEFAULT_THEME); self } diff --git a/src/core/response/page/page.rs b/src/core/response/page/page.rs index dea08591..99041edd 100644 --- a/src/core/response/page/page.rs +++ b/src/core/response/page/page.rs @@ -1,7 +1,7 @@ use crate::config::SETTINGS; use crate::core::server; use crate::core::all::COMPONENTS; -use crate::core::theme::{DOCTYPE, Markup, Theme, html}; +use crate::core::theme::{DOCTYPE, Markup, html}; use crate::core::response::page::{PageAssets, PageComponent, PageContainer}; use std::borrow::Cow; @@ -159,8 +159,8 @@ impl<'a> Page<'a> { // Page EXTRAS. - pub fn using_theme(&mut self, theme: &'static dyn Theme) -> &mut Self { - self.assets.using_theme(theme); + pub fn using_theme(&mut self, theme_id: &str) -> &mut Self { + self.assets.using_theme(theme_id); self } } diff --git a/src/core/theme/api.rs b/src/core/theme/api.rs index 8c0caad1..45f3e6a8 100644 --- a/src/core/theme/api.rs +++ b/src/core/theme/api.rs @@ -5,6 +5,8 @@ use crate::base::component::Chunck; /// Los temas deben implementar este "trait". pub trait Theme: Send + Sync { + fn id(&self) -> &'static str; + fn name(&self) -> String; fn description(&self) -> String { diff --git a/src/core/theme/mod.rs b/src/core/theme/mod.rs index b3376d49..973af092 100644 --- a/src/core/theme/mod.rs +++ b/src/core/theme/mod.rs @@ -9,9 +9,9 @@ pub fn register_theme(t: &'static (dyn Theme + 'static)) { THEMES.write().unwrap().push(t); } -pub fn find_theme(name: &str) -> Option<&'static (dyn Theme + 'static)> { +pub fn find_theme(id: &str) -> Option<&'static (dyn Theme + 'static)> { let themes = THEMES.write().unwrap(); - match themes.iter().find(|t| t.name() == name) { + match themes.iter().find(|t| t.id() == id) { Some(theme) => Some(*theme), _ => None, } From 0f185887a69aaca5025da615929ab4094fce7aba Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 28 Feb 2022 22:20:28 +0100 Subject: [PATCH 017/244] =?UTF-8?q?Mejora=20la=20gesti=C3=B3n=20de=20la=20?= =?UTF-8?q?traza=20de=20seguimiento?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aprovecha la potencia de los crates propios del ecosistema tracing para proporcionar las funcionalidades más importantes vía ajustes de configuración. --- Cargo.toml | 4 +-- config/settings.default.toml | 8 +++-- src/config/settings.rs | 15 ++++++-- src/core/server/main.rs | 66 +++++++----------------------------- src/locale/locale.rs | 23 +++++++++++++ src/locale/mod.rs | 15 ++------ src/trace/mod.rs | 4 +++ src/trace/trace.rs | 57 +++++++++++++++++++++++++++++++ 8 files changed, 119 insertions(+), 73 deletions(-) create mode 100644 src/locale/locale.rs create mode 100644 src/trace/trace.rs diff --git a/Cargo.toml b/Cargo.toml index 7b4ac161..6d9fa877 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,10 +31,8 @@ figlet-rs = "0.1.3" config_rs = { package = "config", version = "0.11.0", features = ["toml"] } tracing = "0.1" -tracing-log = "0.1" tracing-appender = "0.2" -tracing-subscriber = { version = "0.3", features = ["registry", "env-filter"] } -tracing-bunyan-formatter = "0.3" +tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] } tracing-actix-web = "0.2" fluent-templates = "0.6.1" diff --git a/config/settings.default.toml b/config/settings.default.toml index aea77e5e..3a4fb0ff 100644 --- a/config/settings.default.toml +++ b/config/settings.default.toml @@ -1,10 +1,12 @@ [app] name = "PageTop Application" description = "Developed with the amazing PageTop framework." -# Idioma (localización) predeterminado. -language = "en-US" # Tema predeterminado. theme = "Bootsier" +# Idioma (localización) predeterminado. +language = "en-US" +# Dirección predeterminada para el texto: "ltr", "rtl" o "auto". +direction = "ltr" # Rótulo al inicio: "Off", "Slant", "Small", "Speed" o "Starwars". startup_banner = "Small" @@ -18,6 +20,8 @@ rolling = "Daily" path = "log" # Prefijo para los archivos de traza (si rolling != "Stdout"). prefix = "tracing.log" +# Presentación de las trazas: "Json", "Full", "Compact" o "Pretty". +format = "Json" [webserver] # Configuración del servidor web. diff --git a/src/config/settings.rs b/src/config/settings.rs index 94097c3a..66ddbe42 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -42,7 +42,12 @@ pub static CONFIG: Lazy<Config> = Lazy::new(|| { /// componente, en una estructura similar a [`SETTINGS`] con tipos de variables /// seguros. Produce un *panic!* en caso de asignaciones no válidas. macro_rules! config_map { - ( $COMM:expr, $CONF:ident, $TYPE:tt $(, $key:expr => $value:expr)* ) => { + ( + $COMM:expr, + $CONF:ident, + $TYPE:tt + $(, $key:expr => $value:expr)* + ) => { $crate::doc_comment! { concat!($COMM), @@ -64,8 +69,9 @@ macro_rules! config_map { pub struct App { pub name : String, pub description : String, - pub language : String, pub theme : String, + pub language : String, + pub direction : String, pub startup_banner: String, pub run_mode : String, } @@ -76,6 +82,7 @@ pub struct Log { pub rolling : String, pub path : String, pub prefix : String, + pub format : String, } #[derive(Debug, Deserialize)] @@ -100,8 +107,9 @@ Ajustes globales y valores predeterminados para las secciones *\[app\]*, // [app] "app.name" => "PageTop Application", "app.description" => "Developed with the amazing PageTop framework.", - "app.language" => "en-US", "app.theme" => "Bootsier", + "app.language" => "en-US", + "app.direction" => "ltr", "app.startup_banner" => "Small", // [log] @@ -109,6 +117,7 @@ Ajustes globales y valores predeterminados para las secciones *\[app\]*, "log.rolling" => "Daily", "log.path" => "log", "log.prefix" => "tracing.log", + "log.format" => "json", // [webserver] "webserver.bind_address" => "localhost", diff --git a/src/core/server/main.rs b/src/core/server/main.rs index 2c8e2d37..fb9663b1 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -1,59 +1,11 @@ -use crate::{base, trace}; +use crate::{Lazy, base, locale, trace}; use crate::config::SETTINGS; use crate::core::{Server, all, server}; use crate::core::module::register_module; -use tracing_log::LogTracer; -use tracing_subscriber::{EnvFilter, Registry}; -use tracing_subscriber::layer::SubscriberExt; -use tracing::subscriber::set_global_default; -use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; -use tracing_actix_web::TracingLogger; - use actix_web::middleware::normalize; pub fn run(bootstrap: Option<fn()>) -> Result<Server, std::io::Error> { - // Inicia la traza de ejecución de la aplicación. - let env_filter = EnvFilter::try_new(&SETTINGS.log.tracing) - .unwrap_or(EnvFilter::new("Info")); - - let rolling = SETTINGS.log.rolling.to_lowercase(); - let (non_blocking, _guard) = match rolling.as_str() { - "stdout" => tracing_appender::non_blocking( - std::io::stdout() - ), - _ => tracing_appender::non_blocking({ - let path = &SETTINGS.log.path; - let prefix = &SETTINGS.log.prefix; - match rolling.as_str() { - "daily" => tracing_appender::rolling::daily(path, prefix), - "hourly" => tracing_appender::rolling::hourly(path, prefix), - "minutely" => tracing_appender::rolling::minutely(path, prefix), - "endless" => tracing_appender::rolling::never(path, prefix), - _ => { - println!( - "Rolling value \"{}\" not valid. Using \"daily\"", - rolling - ); - tracing_appender::rolling::daily(path, prefix) - } - } - }) - }; - let formatting_layer = BunyanFormattingLayer::new( - String::from(&SETTINGS.app.name), - non_blocking - ); - - let subscriber = Registry::default() - .with(env_filter) - .with(JsonStorageLayer) - .with(formatting_layer); - - set_global_default(subscriber).expect("Unable to setup subscriber!"); - - LogTracer::init().expect("Unable to setup log tracer!"); - // Imprime el rótulo (opcional) de bienvenida. if SETTINGS.app.startup_banner.to_lowercase() != "off" { let figfont = figlet_rs::FIGfont::from_content( @@ -63,9 +15,11 @@ pub fn run(bootstrap: Option<fn()>) -> Result<Server, std::io::Error> { "speed" => include_str!("figfonts/speed.flf"), "starwars" => include_str!("figfonts/starwars.flf"), _ => { - trace::warn!( - "FIGfont \"{}\" not found for banner. Using \"{}\"", - SETTINGS.app.startup_banner, "Small" + println!( + "FIGfont \"{}\" not found for banner. {}. {}.", + SETTINGS.app.startup_banner, + "Using \"Small\"", + "Check the settings file", ); include_str!("figfonts/small.flf") } @@ -78,6 +32,12 @@ pub fn run(bootstrap: Option<fn()>) -> Result<Server, std::io::Error> { ); } + // Traza de seguimiento. + Lazy::force(&trace::TRACING); + + // Identificador de idioma. + Lazy::force(&locale::LANGID); + // Ejecuta la función de inicio de la aplicación. if bootstrap != None { trace::debug!("Calling application bootstrap"); @@ -92,7 +52,7 @@ pub fn run(bootstrap: Option<fn()>) -> Result<Server, std::io::Error> { // Inicializa el servidor web. let server = server::HttpServer::new(|| { server::App::new() - .wrap(TracingLogger) + .wrap(tracing_actix_web::TracingLogger) .wrap(normalize::NormalizePath::new(normalize::TrailingSlash::Trim)) .configure(&all::themes) .configure(&all::modules) diff --git a/src/locale/locale.rs b/src/locale/locale.rs new file mode 100644 index 00000000..3638a6a4 --- /dev/null +++ b/src/locale/locale.rs @@ -0,0 +1,23 @@ +use crate::{Lazy, trace}; +use crate::config::SETTINGS; + +use unic_langid::LanguageIdentifier; + +/// Almacena el Identificador de Idioma Unicode ([Unicode Language Identifier] +/// (https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier)) de +/// la aplicación, obtenido de `SETTINGS.app.language`. +pub static LANGID: Lazy<LanguageIdentifier> = Lazy::new(|| { + match SETTINGS.app.language.parse() { + Ok(language) => language, + Err(_) => { + trace::warn!( + "Failed to parse language \"{}\". {}. {}. {}.", + SETTINGS.app.language, + "Unicode Language Identifier not recognized", + "Using \"en-US\"", + "Check the settings file", + ); + "en-US".parse().unwrap() + } + } +}); diff --git a/src/locale/mod.rs b/src/locale/mod.rs index 6e64cc8f..e13d9f21 100644 --- a/src/locale/mod.rs +++ b/src/locale/mod.rs @@ -1,21 +1,12 @@ -use crate::Lazy; -use crate::config::SETTINGS; - -use unic_langid::LanguageIdentifier; - pub use fluent_templates::{static_loader as static_locale, Loader as Locale}; pub use fluent_templates; pub use fluent_templates::fluent_bundle::FluentValue; -/// Almacena el Identificador de Idioma Unicode ([Unicode Language Identifier] -/// (https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier)) de -/// la aplicación, obtenido de `SETTINGS.app.language`. -pub static LANGID: Lazy<LanguageIdentifier> = Lazy::new(|| { - SETTINGS.app.language.parse().expect("Failed to parse.") -}); +mod locale; +pub use locale::LANGID; #[macro_export] -/// Permite integrar fácilmente localización en tus temas y módulos. +/// Permite integrar fácilmente localización en temas, módulos y componentes. macro_rules! localize { ( $DEF_LANGID:literal, $locales:literal $(, $core_locales:literal)? ) => { use $crate::locale::*; diff --git a/src/trace/mod.rs b/src/trace/mod.rs index f4af4116..8ffa8bcd 100644 --- a/src/trace/mod.rs +++ b/src/trace/mod.rs @@ -1 +1,5 @@ +pub use tracing::{Level, event, span}; pub use tracing::{debug, error, info, trace, warn}; + +mod trace; +pub use trace::TRACING; diff --git a/src/trace/trace.rs b/src/trace/trace.rs new file mode 100644 index 00000000..fd907461 --- /dev/null +++ b/src/trace/trace.rs @@ -0,0 +1,57 @@ +use crate::Lazy; +use crate::config::SETTINGS; + +use tracing_appender::non_blocking::WorkerGuard; +use tracing_subscriber::EnvFilter; + +pub static TRACING: Lazy<WorkerGuard> = Lazy::new(|| { + let env_filter = EnvFilter::try_new(&SETTINGS.log.tracing) + .unwrap_or(EnvFilter::new("Info")); + + let rolling = SETTINGS.log.rolling.to_lowercase(); + let (non_blocking, guard) = match rolling.as_str() { + "stdout" => tracing_appender::non_blocking( + std::io::stdout() + ), + _ => tracing_appender::non_blocking({ + let path = &SETTINGS.log.path; + let prefix = &SETTINGS.log.prefix; + match rolling.as_str() { + "daily" => tracing_appender::rolling::daily(path, prefix), + "hourly" => tracing_appender::rolling::hourly(path, prefix), + "minutely" => tracing_appender::rolling::minutely(path, prefix), + "endless" => tracing_appender::rolling::never(path, prefix), + _ => { + println!( + "Rolling value \"{}\" not valid. {}. {}.", + SETTINGS.log.rolling, + "Using \"daily\"", + "Check the settings file", + ); + tracing_appender::rolling::daily(path, prefix) + } + } + }) + }; + let subscriber = tracing_subscriber::fmt() + .with_env_filter(env_filter) + .with_writer(non_blocking) + .with_ansi(rolling.as_str() == "stdout"); + match SETTINGS.log.format.to_lowercase().as_str() { + "json" => subscriber.json().init(), + "full" => subscriber.init(), + "compact" => subscriber.compact().init(), + "pretty" => subscriber.pretty().init(), + _ => { + println!( + "Tracing format \"{}\" not valid. {}. {}.", + SETTINGS.log.format, + "Using \"Full\"", + "Check the settings file", + ); + subscriber.init(); + } + } + + guard +}); From 9e65f89d2df69178716fd186f9f5454e4fc457a7 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 1 Mar 2022 17:50:36 +0100 Subject: [PATCH 018/244] =?UTF-8?q?Modifica=20la=20identificaci=C3=B3n=20d?= =?UTF-8?q?e=20m=C3=B3dulos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/module/admin/locales/en-US/admin.ftl | 4 ++-- src/base/module/admin/locales/es-ES/admin.ftl | 4 ++-- src/base/module/admin/mod.rs | 8 ++++---- .../module/homepage/locales/en-US/homepage.ftl | 4 ++-- .../module/homepage/locales/es-ES/homepage.ftl | 4 ++-- src/base/module/homepage/mod.rs | 8 ++++---- .../module/user/locales/en-US/homepage.ftl | 4 ++-- .../module/user/locales/es-ES/homepage.ftl | 4 ++-- src/base/module/user/mod.rs | 8 ++++---- src/base/theme/aliner/mod.rs | 4 ++-- src/base/theme/bootsier/mod.rs | 4 ++-- src/base/theme/minimal/mod.rs | 4 ++-- src/core/module/api.rs | 18 +++++++++++++++--- src/core/module/mod.rs | 16 +--------------- 14 files changed, 46 insertions(+), 48 deletions(-) diff --git a/src/base/module/admin/locales/en-US/admin.ftl b/src/base/module/admin/locales/en-US/admin.ftl index 7f37e03b..88da2fe6 100644 --- a/src/base/module/admin/locales/en-US/admin.ftl +++ b/src/base/module/admin/locales/en-US/admin.ftl @@ -1,2 +1,2 @@ -module_name = Admin module -module_desc = Administration module. +module_fullname = Admin module +module_description = Administration module. diff --git a/src/base/module/admin/locales/es-ES/admin.ftl b/src/base/module/admin/locales/es-ES/admin.ftl index d9211301..c9105a6a 100644 --- a/src/base/module/admin/locales/es-ES/admin.ftl +++ b/src/base/module/admin/locales/es-ES/admin.ftl @@ -1,2 +1,2 @@ -module_name = Admin module -module_desc = Módulo de administración. +module_fullname = Admin module +module_description = Módulo de administración. diff --git a/src/base/module/admin/mod.rs b/src/base/module/admin/mod.rs index 7550c381..5991d4f0 100644 --- a/src/base/module/admin/mod.rs +++ b/src/base/module/admin/mod.rs @@ -7,16 +7,16 @@ mod summary; pub struct AdminModule; impl Module for AdminModule { - fn id(&self) -> &'static str { + fn name(&self) -> &'static str { "admin" } - fn name(&self) -> String { - l("module_name") + fn fullname(&self) -> String { + l("module_fullname") } fn description(&self) -> String { - l("module_desc") + l("module_description") } fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { diff --git a/src/base/module/homepage/locales/en-US/homepage.ftl b/src/base/module/homepage/locales/en-US/homepage.ftl index ec401e64..39a5e426 100644 --- a/src/base/module/homepage/locales/en-US/homepage.ftl +++ b/src/base/module/homepage/locales/en-US/homepage.ftl @@ -1,5 +1,5 @@ -module_name = Default homepage -module_desc = Displays a default homepage when none is configured. +module_fullname = Default homepage +module_description = Displays a default homepage when none is configured. page_title = Hello world! diff --git a/src/base/module/homepage/locales/es-ES/homepage.ftl b/src/base/module/homepage/locales/es-ES/homepage.ftl index dee1df47..f1d85b2e 100644 --- a/src/base/module/homepage/locales/es-ES/homepage.ftl +++ b/src/base/module/homepage/locales/es-ES/homepage.ftl @@ -1,5 +1,5 @@ -module_name = Página de inicio predeterminada -module_desc = Muestra una página de inicio predeterminada cuando no hay ninguna configurada. +module_fullname = Página de inicio predeterminada +module_description = Muestra una página de inicio predeterminada cuando no hay ninguna configurada. page_title = ¡Hola mundo! diff --git a/src/base/module/homepage/mod.rs b/src/base/module/homepage/mod.rs index a8ed27b7..386b6716 100644 --- a/src/base/module/homepage/mod.rs +++ b/src/base/module/homepage/mod.rs @@ -5,16 +5,16 @@ localize!("en-US", "src/base/module/homepage/locales"); pub struct HomepageModule; impl Module for HomepageModule { - fn id(&self) -> &'static str { + fn name(&self) -> &'static str { "homepage" } - fn name(&self) -> String { - l("module_name") + fn fullname(&self) -> String { + l("module_fullname") } fn description(&self) -> String { - l("module_desc") + l("module_description") } fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { diff --git a/src/base/module/user/locales/en-US/homepage.ftl b/src/base/module/user/locales/en-US/homepage.ftl index e6ad0e91..0493672e 100644 --- a/src/base/module/user/locales/en-US/homepage.ftl +++ b/src/base/module/user/locales/en-US/homepage.ftl @@ -1,5 +1,5 @@ -module_name = User -module_desc = Manages the user registration and login system. +module_fullname = User +module_description = Manages the user registration and login system. username = User name password = Password diff --git a/src/base/module/user/locales/es-ES/homepage.ftl b/src/base/module/user/locales/es-ES/homepage.ftl index 68f1c889..ae9a70e0 100644 --- a/src/base/module/user/locales/es-ES/homepage.ftl +++ b/src/base/module/user/locales/es-ES/homepage.ftl @@ -1,5 +1,5 @@ -module_name = Usuario -module_desc = Gestion el registro de usuarios y el sistema de accesos. +module_fullname = Usuario +module_description = Gestion el registro de usuarios y el sistema de accesos. username = Nombre de usuario password = Contraseña diff --git a/src/base/module/user/mod.rs b/src/base/module/user/mod.rs index 98ff27fa..bbb3ee93 100644 --- a/src/base/module/user/mod.rs +++ b/src/base/module/user/mod.rs @@ -5,16 +5,16 @@ localize!("en-US", "src/base/module/user/locales"); pub struct UserModule; impl Module for UserModule { - fn id(&self) -> &'static str { + fn name(&self) -> &'static str { "user" } - fn name(&self) -> String { - l("module_name") + fn fullname(&self) -> String { + l("module_fullname") } fn description(&self) -> String { - l("module_desc") + l("module_description") } fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { diff --git a/src/base/theme/aliner/mod.rs b/src/base/theme/aliner/mod.rs index 6df2fb93..d27e2f91 100644 --- a/src/base/theme/aliner/mod.rs +++ b/src/base/theme/aliner/mod.rs @@ -5,11 +5,11 @@ include!(concat!(env!("OUT_DIR"), "/aliner.rs")); pub struct AlinerTheme; impl Theme for AlinerTheme { - fn id(&self) -> &'static str { + fn name(&self) -> &'static str { "aliner" } - fn name(&self) -> String { + fn fullname(&self) -> String { "Aliner".to_string() } diff --git a/src/base/theme/bootsier/mod.rs b/src/base/theme/bootsier/mod.rs index 58975335..97b7fa46 100644 --- a/src/base/theme/bootsier/mod.rs +++ b/src/base/theme/bootsier/mod.rs @@ -7,11 +7,11 @@ localize!("en-US", "src/base/theme/bootsier/locales"); pub struct BootsierTheme; impl Theme for BootsierTheme { - fn id(&self) -> &'static str { + fn name(&self) -> &'static str { "bootsier" } - fn name(&self) -> String { + fn fullname(&self) -> String { "Bootsier".to_string() } diff --git a/src/base/theme/minimal/mod.rs b/src/base/theme/minimal/mod.rs index 970181b7..17611468 100644 --- a/src/base/theme/minimal/mod.rs +++ b/src/base/theme/minimal/mod.rs @@ -3,11 +3,11 @@ use crate::prelude::*; pub struct MinimalTheme; impl Theme for MinimalTheme { - fn id(&self) -> &'static str { + fn name(&self) -> &'static str { "minimal" } - fn name(&self) -> String { + fn fullname(&self) -> String { "Minimal".to_string() } } diff --git a/src/core/module/api.rs b/src/core/module/api.rs index 68488b84..83be71c3 100644 --- a/src/core/module/api.rs +++ b/src/core/module/api.rs @@ -1,10 +1,10 @@ -use crate::core::server; +use crate::core::{all, server}; /// Los módulos deben implementar este *trait*. pub trait Module: Send + Sync { - fn id(&self) -> &'static str; + fn name(&self) -> &'static str; - fn name(&self) -> String; + fn fullname(&self) -> String; fn description(&self) -> String { "".to_string() @@ -14,3 +14,15 @@ pub trait Module: Send + Sync { fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { } } + +pub fn register_module(m: &'static (dyn Module + 'static)) { + all::MODULES.write().unwrap().push(m); +} + +pub fn find_module(name: &str) -> Option<&'static (dyn Module + 'static)> { + let modules = all::MODULES.write().unwrap(); + match modules.iter().find(|t| t.name() == name) { + Some(module) => Some(*module), + _ => None, + } +} diff --git a/src/core/module/mod.rs b/src/core/module/mod.rs index c480df38..08686bcd 100644 --- a/src/core/module/mod.rs +++ b/src/core/module/mod.rs @@ -1,16 +1,2 @@ -use crate::core::all::MODULES; - mod api; -pub use api::Module; - -pub fn register_module(m: &'static (dyn Module + 'static)) { - MODULES.write().unwrap().push(m); -} - -pub fn find_module(id: &str) -> Option<&'static (dyn Module + 'static)> { - let modules = MODULES.write().unwrap(); - match modules.iter().find(|t| t.id() == id) { - Some(module) => Some(*module), - _ => None, - } -} +pub use api::{Module, find_module, register_module}; From db3efa9ef92b09c189fcda21a5f5f460b91f0f1f Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 1 Mar 2022 19:35:02 +0100 Subject: [PATCH 019/244] =?UTF-8?q?Modifica=20gesti=C3=B3n=20de=20p=C3=A1g?= =?UTF-8?q?inas=20para=20normalizar=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/all.rs | 10 --- src/core/response/page/assets.rs | 13 ++- src/core/response/page/component.rs | 10 +-- src/core/response/page/mod.rs | 11 +-- src/core/response/page/page.rs | 122 ++++++++++++++++++---------- src/core/theme/api.rs | 38 +++++++-- src/core/theme/mod.rs | 16 +--- 7 files changed, 128 insertions(+), 92 deletions(-) diff --git a/src/core/all.rs b/src/core/all.rs index 3174fc5f..eb7bed10 100644 --- a/src/core/all.rs +++ b/src/core/all.rs @@ -1,5 +1,4 @@ use crate::Lazy; -use crate::config::SETTINGS; use crate::core::theme::Theme; use crate::core::module::Module; use crate::core::response::page::PageContainer; @@ -23,15 +22,6 @@ pub static THEMES: Lazy<RwLock<Vec<&dyn Theme>>> = Lazy::new(|| { ]) }); -pub static DEFAULT_THEME: Lazy<&dyn Theme> = Lazy::new(|| { - for t in THEMES.read().unwrap().iter() { - if t.name().to_lowercase() == SETTINGS.app.theme.to_lowercase() { - return *t; - } - } - &base::theme::bootsier::BootsierTheme -}); - pub fn themes(cfg: &mut server::web::ServiceConfig) { cfg.service(actix_web_static_files::ResourceFiles::new( "/theme", diff --git a/src/core/response/page/assets.rs b/src/core/response/page/assets.rs index 7e1205eb..71c3f668 100644 --- a/src/core/response/page/assets.rs +++ b/src/core/response/page/assets.rs @@ -1,6 +1,17 @@ -use crate::core::all::DEFAULT_THEME; +use crate::{Lazy, base}; +use crate::config::SETTINGS; +use crate::core::all; use crate::core::theme::{Markup, PreEscaped, Theme, find_theme, html}; +pub static DEFAULT_THEME: Lazy<&dyn Theme> = Lazy::new(|| { + for t in all::THEMES.read().unwrap().iter() { + if t.name().to_lowercase() == SETTINGS.app.theme.to_lowercase() { + return *t; + } + } + &base::theme::bootsier::BootsierTheme +}); + // ----------------------------------------------------------------------------- // Favicon. // ----------------------------------------------------------------------------- diff --git a/src/core/response/page/component.rs b/src/core/response/page/component.rs index aebb1f43..a7e0ffd7 100644 --- a/src/core/response/page/component.rs +++ b/src/core/response/page/component.rs @@ -9,7 +9,7 @@ pub trait Component: Downcast + Send + Sync { fn prepare() -> Self where Self: Sized; - fn name(&self) -> &str { + fn name(&self) -> &'static str { let name = type_name::<Self>(); match name.rfind("::") { Some(position) => &name[(position + 2)..], @@ -17,12 +17,12 @@ pub trait Component: Downcast + Send + Sync { } } - fn qualified_name(&self) -> &str { - type_name::<Self>() + fn fullname(&self) -> String { + type_name::<Self>().to_string() } - fn description(&self) -> &str { - "" + fn description(&self) -> String { + "".to_string() } fn is_renderable(&self) -> bool { diff --git a/src/core/response/page/mod.rs b/src/core/response/page/mod.rs index 83f0e0e9..d10c5fcc 100644 --- a/src/core/response/page/mod.rs +++ b/src/core/response/page/mod.rs @@ -1,5 +1,3 @@ -use crate::core::all::COMPONENTS; - pub mod assets; pub use assets::Assets as PageAssets; @@ -12,12 +10,5 @@ pub use container::Container as PageContainer; mod page; pub use page::Page; pub use page::render_component; +pub use page::add_component_to; -pub fn add_component_to(region: &'static str, component: impl PageComponent) { - let mut hmap = COMPONENTS.write().unwrap(); - if let Some(regions) = hmap.get_mut(region) { - regions.add(component); - } else { - hmap.insert(region, PageContainer::new_with(component)); - } -} diff --git a/src/core/response/page/page.rs b/src/core/response/page/page.rs index 99041edd..48ea5094 100644 --- a/src/core/response/page/page.rs +++ b/src/core/response/page/page.rs @@ -1,63 +1,96 @@ +use crate::{Lazy, trace, util}; use crate::config::SETTINGS; -use crate::core::server; -use crate::core::all::COMPONENTS; +use crate::core::{all, server}; use crate::core::theme::{DOCTYPE, Markup, html}; use crate::core::response::page::{PageAssets, PageComponent, PageContainer}; use std::borrow::Cow; use std::collections::HashMap; -pub enum TextDirection { LeftToRight, RightToLeft, Auto } +pub static DEFAULT_LANGUAGE: Lazy<Option<String>> = Lazy::new(|| { + let language = SETTINGS.app.language[..2].to_lowercase(); + if !language.is_empty() { + Some(language) + } else { + None + } +}); + +pub static DEFAULT_DIRECTION: Lazy<Option<String>> = Lazy::new(|| { + let direction = SETTINGS.app.direction.to_lowercase(); + match direction.as_str() { + "auto" => Some("auto".to_string()), + "ltr" => Some("ltr".to_string()), + "rtl" => Some("rtl".to_string()), + "" => None, + _ => { + trace::warn!( + "Text direction \"{}\" not valid. {}.", + SETTINGS.app.direction, + "Check the settings file" + ); + None + } + } +}); + +pub enum TextDirection { Auto, LeftToRight, RightToLeft } pub struct Page<'a> { - language : &'a str, - title : &'a str, - direction : &'a str, - description : &'a str, - body_classes: Cow<'a, str>, + language : Option<String>, + direction : Option<String>, + title : Option<String>, + description : Option<String>, assets : PageAssets, + body_classes: Cow<'a, str>, regions : HashMap<&'a str, PageContainer>, - template : &'a str, + template : Option<String>, } impl<'a> Page<'a> { pub fn prepare() -> Self { Page { - language : &SETTINGS.app.language[..2], - title : &SETTINGS.app.name, - direction : "ltr", - description : "", + language : match &*DEFAULT_LANGUAGE { + Some(language) => Some(language.to_string()), + _ => None, + }, + direction : match &*DEFAULT_DIRECTION { + Some(direction) => Some(direction.to_string()), + _ => None, + }, + title : None, + description : None, body_classes: "body".into(), assets : PageAssets::new(), - regions : COMPONENTS.read().unwrap().clone(), - template : "default", + regions : all::COMPONENTS.read().unwrap().clone(), + template : Some("default".to_string()), } } // Page BUILDER. - pub fn with_language(&mut self, language: &'a str) -> &mut Self { - self.language = language; - self - } - - pub fn with_title(&mut self, title: &'a str) -> &mut Self { - self.title = title; + pub fn with_language(&mut self, language: &str) -> &mut Self { + self.language = util::optional_value(language); self } pub fn with_direction(&mut self, dir: TextDirection) -> &mut Self { self.direction = match dir { - TextDirection::LeftToRight => "ltr", - TextDirection::RightToLeft => "rtl", - _ => "auto" + TextDirection::Auto => Some("auto".to_string()), + TextDirection::LeftToRight => Some("ltr".to_string()), + TextDirection::RightToLeft => Some("rtl".to_string()), }; self } - pub fn with_description(&mut self, description: &'a str) -> &mut Self { - self.description = description; + pub fn with_title(&mut self, title: &str) -> &mut Self { + self.title = util::optional_value(title); + self + } + + pub fn with_description(&mut self, description: &str) -> &mut Self { + self.description = util::optional_value(description); self } @@ -86,31 +119,27 @@ impl<'a> Page<'a> { self } - pub fn using_template(&mut self, template: &'a str) -> &mut Self { - self.template = template; + pub fn using_template(&mut self, template: &str) -> &mut Self { + self.template = util::optional_value(template); self } // Page GETTERS. pub fn language(&self) -> &str { - self.language + util::assigned_value(&self.language) + } + + pub fn direction(&self) -> &str { + util::assigned_value(&self.direction) } pub fn title(&self) -> &str { - self.title - } - - pub fn direction(&self) -> TextDirection { - match self.direction { - "ltr" => TextDirection::LeftToRight, - "rtl" => TextDirection::RightToLeft, - _ => TextDirection::Auto - } + util::assigned_value(&self.title) } pub fn description(&self) -> &str { - self.description + util::assigned_value(&self.description) } pub fn body_classes(&self) -> &str { @@ -125,7 +154,7 @@ impl<'a> Page<'a> { } pub fn template(&self) -> &str { - self.template + util::assigned_value(&self.template) } // Page RENDER. @@ -143,7 +172,7 @@ impl<'a> Page<'a> { // Finalmente, renderizar la página. return Ok(html! { (DOCTYPE) - html lang=(self.language) dir=(self.direction) { + html lang=[&self.language] dir=[&self.direction] { (head) (body) } @@ -177,3 +206,12 @@ pub fn render_component( false => html! {} } } + +pub fn add_component_to(region: &'static str, component: impl PageComponent) { + let mut hmap = all::COMPONENTS.write().unwrap(); + if let Some(regions) = hmap.get_mut(region) { + regions.add(component); + } else { + hmap.insert(region, PageContainer::new_with(component)); + } +} diff --git a/src/core/theme/api.rs b/src/core/theme/api.rs index 45f3e6a8..36350110 100644 --- a/src/core/theme/api.rs +++ b/src/core/theme/api.rs @@ -1,13 +1,14 @@ -use crate::core::server; +use crate::config::SETTINGS; +use crate::core::{all, server}; use crate::core::theme::{Markup, html}; use crate::core::response::page::{Page, PageAssets, PageComponent}; use crate::base::component::Chunck; /// Los temas deben implementar este "trait". pub trait Theme: Send + Sync { - fn id(&self) -> &'static str; + fn name(&self) -> &'static str; - fn name(&self) -> String; + fn fullname(&self) -> String; fn description(&self) -> String { "".to_string() @@ -22,19 +23,26 @@ pub trait Theme: Send + Sync { } fn render_page_head(&self, page: &mut Page) -> Markup { - let viewport = "width=device-width, initial-scale=1, shrink-to-fit=no"; + let title = page.title(); + let title = if title.is_empty() { + SETTINGS.app.name.to_string() + } else { + [SETTINGS.app.name.to_string(), title.to_string()].join(" | ") + }; let description = page.description(); + let viewport = "width=device-width, initial-scale=1, shrink-to-fit=no"; html! { head { meta charset="utf-8"; - meta http-equiv="X-UA-Compatible" content="IE=edge"; - meta name="viewport" content=(viewport); + title { (title) } + @if !description.is_empty() { meta name="description" content=(description); } - title { (page.title()) } + meta http-equiv="X-UA-Compatible" content="IE=edge"; + meta name="viewport" content=(viewport); (page.assets().render()) } @@ -72,8 +80,8 @@ pub trait Theme: Send + Sync { /* Cómo usarlo: - match component.type_name() { - "Block" => { + match component.handle() { + "block" => { let block = component.downcast_mut::<Block>().unwrap(); match block.template() { "default" => Some(block_default(block)), @@ -96,3 +104,15 @@ pub trait Theme: Send + Sync { .render() } } + +pub fn register_theme(t: &'static (dyn Theme + 'static)) { + all::THEMES.write().unwrap().push(t); +} + +pub fn find_theme(name: &str) -> Option<&'static (dyn Theme + 'static)> { + let themes = all::THEMES.write().unwrap(); + match themes.iter().find(|t| t.name() == name) { + Some(theme) => Some(*theme), + _ => None, + } +} diff --git a/src/core/theme/mod.rs b/src/core/theme/mod.rs index 973af092..9f708803 100644 --- a/src/core/theme/mod.rs +++ b/src/core/theme/mod.rs @@ -1,18 +1,4 @@ -use crate::core::all::THEMES; - pub use maud::{DOCTYPE, Markup, PreEscaped, html}; mod api; -pub use api::Theme; - -pub fn register_theme(t: &'static (dyn Theme + 'static)) { - THEMES.write().unwrap().push(t); -} - -pub fn find_theme(id: &str) -> Option<&'static (dyn Theme + 'static)> { - let themes = THEMES.write().unwrap(); - match themes.iter().find(|t| t.id() == id) { - Some(theme) => Some(*theme), - _ => None, - } -} +pub use api::{Theme, find_theme, register_theme}; From cac4c2f102137cbde35eb223948b668b1696b4be Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 1 Mar 2022 22:15:41 +0100 Subject: [PATCH 020/244] =?UTF-8?q?Actualiza=20y=20sanea=20piezas=20de=20c?= =?UTF-8?q?=C3=B3digo=20sensible?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component/block.rs | 2 +- src/base/component/menu.rs | 2 +- src/core/response/page/assets.rs | 14 +++++++------- src/core/response/page/component.rs | 4 ++-- src/core/response/page/container.rs | 8 ++++---- src/core/response/page/mod.rs | 13 +++++++++---- src/core/response/page/page.rs | 8 ++++---- src/core/theme/api.rs | 2 +- src/prelude.rs | 5 ----- 9 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/base/component/block.rs b/src/base/component/block.rs index 03e67e01..9ffe986d 100644 --- a/src/base/component/block.rs +++ b/src/base/component/block.rs @@ -31,7 +31,7 @@ impl PageComponent for Block { } fn default_render(&self, assets: &mut PageAssets) -> Markup { - let id = assets.required_id(self.name(), self.id()); + let id = assets.serial_id(self.name(), self.id()); html! { div id=(id) class="block" { @if !self.title.is_empty() { diff --git a/src/base/component/menu.rs b/src/base/component/menu.rs index 34be6e33..0f44fad5 100644 --- a/src/base/component/menu.rs +++ b/src/base/component/menu.rs @@ -186,7 +186,7 @@ impl PageComponent for Menu { )) .add_jquery(); - let id = assets.required_id(self.name(), self.id()); + let id = assets.serial_id(self.name(), self.id()); html! { ul id=(id) class="sm sm-clean" { (self.render_items(assets)) diff --git a/src/core/response/page/assets.rs b/src/core/response/page/assets.rs index 71c3f668..77174e58 100644 --- a/src/core/response/page/assets.rs +++ b/src/core/response/page/assets.rs @@ -3,7 +3,7 @@ use crate::config::SETTINGS; use crate::core::all; use crate::core::theme::{Markup, PreEscaped, Theme, find_theme, html}; -pub static DEFAULT_THEME: Lazy<&dyn Theme> = Lazy::new(|| { +static DEFAULT_THEME: Lazy<&dyn Theme> = Lazy::new(|| { for t in all::THEMES.read().unwrap().iter() { if t.name().to_lowercase() == SETTINGS.app.theme.to_lowercase() { return *t; @@ -183,7 +183,7 @@ impl JavaScript { // Page assets. // ----------------------------------------------------------------------------- -pub struct Assets { +pub struct PageAssets { theme : &'static dyn Theme, favicon : Option<Favicon>, metadata : Vec<(String, String)>, @@ -193,9 +193,9 @@ pub struct Assets { id_counter : u32, } -impl Assets { +impl PageAssets { pub fn new() -> Self { - Assets { + PageAssets { theme : *DEFAULT_THEME, favicon : None, metadata : Vec::new(), @@ -206,8 +206,8 @@ impl Assets { } } - pub fn using_theme(&mut self, theme_id: &str) -> &mut Self { - self.theme = find_theme(theme_id).unwrap_or(*DEFAULT_THEME); + pub fn using_theme(&mut self, theme_name: &str) -> &mut Self { + self.theme = find_theme(theme_name).unwrap_or(*DEFAULT_THEME); self } @@ -291,7 +291,7 @@ impl Assets { // Assets EXTRAS. - pub fn required_id(&mut self, prefix: &str, id: &str) -> String { + pub fn serial_id(&mut self, prefix: &str, id: &str) -> String { if id.is_empty() { let prefix = prefix.trim().replace(" ", "_").to_lowercase(); let prefix = if prefix.is_empty() { diff --git a/src/core/response/page/component.rs b/src/core/response/page/component.rs index a7e0ffd7..ccc0facb 100644 --- a/src/core/response/page/component.rs +++ b/src/core/response/page/component.rs @@ -5,7 +5,7 @@ use downcast_rs::{Downcast, impl_downcast}; use std::any::type_name; -pub trait Component: Downcast + Send + Sync { +pub trait PageComponent: Downcast + Send + Sync { fn prepare() -> Self where Self: Sized; @@ -39,4 +39,4 @@ pub trait Component: Downcast + Send + Sync { } } -impl_downcast!(Component); +impl_downcast!(PageComponent); diff --git a/src/core/response/page/container.rs b/src/core/response/page/container.rs index c9d2e13b..6bf5e56a 100644 --- a/src/core/response/page/container.rs +++ b/src/core/response/page/container.rs @@ -4,15 +4,15 @@ use crate::core::response::page::{PageAssets, PageComponent, render_component}; use std::sync::Arc; #[derive(Clone)] -pub struct Container(Vec<Arc<dyn PageComponent>>); +pub struct PageContainer(Vec<Arc<dyn PageComponent>>); -impl Container { +impl PageContainer { pub fn new() -> Self { - Container(Vec::new()) + PageContainer(Vec::new()) } pub fn new_with(component: impl PageComponent) -> Self { - let mut container = Container::new(); + let mut container = PageContainer::new(); container.add(component); container } diff --git a/src/core/response/page/mod.rs b/src/core/response/page/mod.rs index d10c5fcc..f34070e2 100644 --- a/src/core/response/page/mod.rs +++ b/src/core/response/page/mod.rs @@ -1,11 +1,16 @@ -pub mod assets; -pub use assets::Assets as PageAssets; +mod assets; +pub use assets::{ + Favicon, + StyleSheet, + JavaScript, JSMode, + PageAssets, +}; mod component; -pub use component::Component as PageComponent; +pub use component::PageComponent; mod container; -pub use container::Container as PageContainer; +pub use container::PageContainer; mod page; pub use page::Page; diff --git a/src/core/response/page/page.rs b/src/core/response/page/page.rs index 48ea5094..18e8c917 100644 --- a/src/core/response/page/page.rs +++ b/src/core/response/page/page.rs @@ -7,7 +7,7 @@ use crate::core::response::page::{PageAssets, PageComponent, PageContainer}; use std::borrow::Cow; use std::collections::HashMap; -pub static DEFAULT_LANGUAGE: Lazy<Option<String>> = Lazy::new(|| { +static DEFAULT_LANGUAGE: Lazy<Option<String>> = Lazy::new(|| { let language = SETTINGS.app.language[..2].to_lowercase(); if !language.is_empty() { Some(language) @@ -16,7 +16,7 @@ pub static DEFAULT_LANGUAGE: Lazy<Option<String>> = Lazy::new(|| { } }); -pub static DEFAULT_DIRECTION: Lazy<Option<String>> = Lazy::new(|| { +static DEFAULT_DIRECTION: Lazy<Option<String>> = Lazy::new(|| { let direction = SETTINGS.app.direction.to_lowercase(); match direction.as_str() { "auto" => Some("auto".to_string()), @@ -188,8 +188,8 @@ impl<'a> Page<'a> { // Page EXTRAS. - pub fn using_theme(&mut self, theme_id: &str) -> &mut Self { - self.assets.using_theme(theme_id); + pub fn using_theme(&mut self, theme_name: &str) -> &mut Self { + self.assets.using_theme(theme_name); self } } diff --git a/src/core/theme/api.rs b/src/core/theme/api.rs index 36350110..efbc9cef 100644 --- a/src/core/theme/api.rs +++ b/src/core/theme/api.rs @@ -80,7 +80,7 @@ pub trait Theme: Send + Sync { /* Cómo usarlo: - match component.handle() { + match component.name() { "block" => { let block = component.downcast_mut::<Block>().unwrap(); match block.template() { diff --git a/src/prelude.rs b/src/prelude.rs index 1792da41..94630400 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -8,13 +8,8 @@ pub use crate::trace; pub use crate::localize; pub use crate::core::theme::*; - pub use crate::core::module::*; - pub use crate::core::response::page::*; -pub use crate::core::response::page::assets::*; - pub use crate::core::server; -pub use crate::base::theme::*; pub use crate::base::component::*; From 67952f68401d81879b8d86c93fd7a49c80644dd1 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 1 Mar 2022 23:42:37 +0100 Subject: [PATCH 021/244] =?UTF-8?q?Actualiza=20la=20inicializaci=C3=B3n=20?= =?UTF-8?q?de=20traza+localizaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/mod.rs | 2 +- src/{locale/locale.rs => core/server/langid.rs} | 0 src/core/server/main.rs | 10 +++++----- src/core/server/mod.rs | 5 +++++ src/{trace/trace.rs => core/server/tracing.rs} | 0 src/{locale/mod.rs => locale.rs} | 4 +--- src/{trace/mod.rs => trace.rs} | 3 --- 7 files changed, 12 insertions(+), 12 deletions(-) rename src/{locale/locale.rs => core/server/langid.rs} (100%) rename src/{trace/trace.rs => core/server/tracing.rs} (100%) rename src/{locale/mod.rs => locale.rs} (97%) rename src/{trace/mod.rs => trace.rs} (71%) diff --git a/src/config/mod.rs b/src/config/mod.rs index afefaf4f..aba410ee 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -2,4 +2,4 @@ pub const CONFIG_DIR: &'static str = "config"; mod settings; -pub use crate::config::settings::{CONFIG, SETTINGS}; +pub use settings::{CONFIG, SETTINGS}; diff --git a/src/locale/locale.rs b/src/core/server/langid.rs similarity index 100% rename from src/locale/locale.rs rename to src/core/server/langid.rs diff --git a/src/core/server/main.rs b/src/core/server/main.rs index fb9663b1..c39c9f83 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -1,4 +1,4 @@ -use crate::{Lazy, base, locale, trace}; +use crate::{Lazy, base, trace}; use crate::config::SETTINGS; use crate::core::{Server, all, server}; use crate::core::module::register_module; @@ -32,11 +32,11 @@ pub fn run(bootstrap: Option<fn()>) -> Result<Server, std::io::Error> { ); } - // Traza de seguimiento. - Lazy::force(&trace::TRACING); + // Inicia la traza de la aplicación. + Lazy::force(&server::tracing::TRACING); - // Identificador de idioma. - Lazy::force(&locale::LANGID); + // Asigna identificador de idioma. + Lazy::force(&server::langid::LANGID); // Ejecuta la función de inicio de la aplicación. if bootstrap != None { diff --git a/src/core/server/mod.rs b/src/core/server/mod.rs index 32e9ce92..6bb25129 100644 --- a/src/core/server/mod.rs +++ b/src/core/server/mod.rs @@ -2,5 +2,10 @@ pub use actix_web::{ App, HttpRequest, HttpResponse, HttpServer, Responder, Result, http, web }; +mod tracing; + +mod langid; +pub use langid::LANGID; + mod main; pub use main::run; diff --git a/src/trace/trace.rs b/src/core/server/tracing.rs similarity index 100% rename from src/trace/trace.rs rename to src/core/server/tracing.rs diff --git a/src/locale/mod.rs b/src/locale.rs similarity index 97% rename from src/locale/mod.rs rename to src/locale.rs index e13d9f21..b43d9fd6 100644 --- a/src/locale/mod.rs +++ b/src/locale.rs @@ -2,14 +2,12 @@ pub use fluent_templates::{static_loader as static_locale, Loader as Locale}; pub use fluent_templates; pub use fluent_templates::fluent_bundle::FluentValue; -mod locale; -pub use locale::LANGID; - #[macro_export] /// Permite integrar fácilmente localización en temas, módulos y componentes. macro_rules! localize { ( $DEF_LANGID:literal, $locales:literal $(, $core_locales:literal)? ) => { use $crate::locale::*; + use $crate::core::server::LANGID; static_locale! { static LOCALES = { diff --git a/src/trace/mod.rs b/src/trace.rs similarity index 71% rename from src/trace/mod.rs rename to src/trace.rs index 8ffa8bcd..d8943c68 100644 --- a/src/trace/mod.rs +++ b/src/trace.rs @@ -1,5 +1,2 @@ pub use tracing::{Level, event, span}; pub use tracing::{debug, error, info, trace, warn}; - -mod trace; -pub use trace::TRACING; From b6dd473578a7df9a0cb7bbc03095c7c1080d8012 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 2 Mar 2022 23:19:16 +0100 Subject: [PATCH 022/244] =?UTF-8?q?Actualiza=20y=20simplifica=20la=20estru?= =?UTF-8?q?ctura=20del=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revisión general del código fuente para asegurar los elementos que deben ser públicos y estandarizar el uso de funciones globales. --- src/base/component/block.rs | 18 ++++----- src/base/component/chunck.rs | 4 +- src/base/component/container.rs | 6 +-- src/base/component/form/button.rs | 14 +++---- src/base/component/form/date.rs | 50 ++++++++++++------------ src/base/component/form/form.rs | 18 ++++----- src/base/component/form/hidden.rs | 6 +-- src/base/component/form/input.rs | 48 +++++++++++------------ src/base/component/menu.rs | 18 ++++----- src/base/module/admin/mod.rs | 4 +- src/base/module/homepage/mod.rs | 4 +- src/base/module/user/mod.rs | 6 +-- src/base/theme/aliner/mod.rs | 2 +- src/base/theme/bootsier/mod.rs | 2 +- src/base/theme/minimal/mod.rs | 2 +- src/{config/settings.rs => config.rs} | 4 +- src/config/mod.rs | 5 --- src/core/{all.rs => global.rs} | 12 +----- src/core/mod.rs | 2 +- src/core/module/api.rs | 28 ------------- src/core/module/definition.rs | 16 ++++++++ src/core/module/mod.rs | 18 ++++++++- src/core/response/page/assets.rs | 10 ++--- src/core/response/page/component.rs | 6 +-- src/core/response/page/page.rs | 44 ++++++++++----------- src/core/server/langid.rs | 23 ----------- src/core/server/main.rs | 22 ++++++++--- src/core/server/mod.rs | 3 -- src/core/server/tracing.rs | 13 ++++++ src/core/theme/{api.rs => definition.rs} | 20 ++-------- src/core/theme/mod.rs | 18 ++++++++- src/lib.rs | 2 +- src/locale.rs | 25 +++++++++++- src/util.rs | 14 +++---- 34 files changed, 250 insertions(+), 237 deletions(-) rename src/{config/settings.rs => config.rs} (97%) delete mode 100644 src/config/mod.rs rename src/core/{all.rs => global.rs} (83%) delete mode 100644 src/core/module/api.rs create mode 100644 src/core/module/definition.rs delete mode 100644 src/core/server/langid.rs rename src/core/theme/{api.rs => definition.rs} (85%) diff --git a/src/base/component/block.rs b/src/base/component/block.rs index 9ffe986d..4f658c9e 100644 --- a/src/base/component/block.rs +++ b/src/base/component/block.rs @@ -4,7 +4,7 @@ pub struct Block { renderable: fn() -> bool, weight : i8, id : Option<String>, - title : String, + title : Option<String>, markup : Vec<Markup>, template : String, } @@ -16,9 +16,9 @@ impl PageComponent for Block { renderable: always, weight : 0, id : None, - title : "".to_string(), + title : None, markup : Vec::new(), - template : "default".to_string(), + template : "default".to_owned(), } } @@ -34,8 +34,8 @@ impl PageComponent for Block { let id = assets.serial_id(self.name(), self.id()); html! { div id=(id) class="block" { - @if !self.title.is_empty() { - h2 class="block-title" { (self.title) } + @if self.title != None { + h2 class="block-title" { (self.title()) } } div class="block-body" { @for markup in self.markup.iter() { @@ -71,7 +71,7 @@ impl Block { } pub fn with_title(mut self, title: &str) -> Self { - self.title = title.to_string(); + self.title = util::optional_str(title); self } @@ -81,18 +81,18 @@ impl Block { } pub fn using_template(mut self, template: &str) -> Self { - self.template = template.to_string(); + self.template = template.to_owned(); self } // Block GETTERS. pub fn id(&self) -> &str { - util::assigned_value(&self.id) + util::assigned_str(&self.id) } pub fn title(&self) -> &str { - self.title.as_str() + util::assigned_str(&self.title) } pub fn template(&self) -> &str { diff --git a/src/base/component/chunck.rs b/src/base/component/chunck.rs index 8d4e956f..63cc20f7 100644 --- a/src/base/component/chunck.rs +++ b/src/base/component/chunck.rs @@ -14,7 +14,7 @@ impl PageComponent for Chunck { renderable: always, weight : 0, markup : Vec::new(), - template : "default".to_string(), + template : "default".to_owned(), } } @@ -59,7 +59,7 @@ impl Chunck { } pub fn using_template(mut self, template: &str) -> Self { - self.template = template.to_string(); + self.template = template.to_owned(); self } diff --git a/src/base/component/container.rs b/src/base/component/container.rs index 61c08336..161bea78 100644 --- a/src/base/component/container.rs +++ b/src/base/component/container.rs @@ -20,7 +20,7 @@ impl PageComponent for Container { id : None, container : ContainerType::Wrapper, components: PageContainer::new(), - template : "default".to_string(), + template : "default".to_owned(), } } @@ -83,14 +83,14 @@ impl Container { } pub fn using_template(mut self, template: &str) -> Self { - self.template = template.to_string(); + self.template = template.to_owned(); self } // Container GETTERS. pub fn id(&self) -> &str { - util::assigned_value(&self.id) + util::assigned_str(&self.id) } pub fn template(&self) -> &str { diff --git a/src/base/component/form/button.rs b/src/base/component/form/button.rs index c95eb3ec..c76c49dd 100644 --- a/src/base/component/form/button.rs +++ b/src/base/component/form/button.rs @@ -24,7 +24,7 @@ impl PageComponent for Button { value : None, autofocus : None, disabled : None, - template : "default".to_string(), + template : "default".to_owned(), } } @@ -101,13 +101,13 @@ impl Button { } pub fn with_value(mut self, value: &str) -> Self { - self.value = util::optional_value(value); + self.value = util::optional_str(value); self } pub fn autofocus(mut self, toggle: bool) -> Self { self.autofocus = match toggle { - true => Some("autofocus".to_string()), + true => Some("autofocus".to_owned()), false => None }; self @@ -115,25 +115,25 @@ impl Button { pub fn disabled(mut self, toggle: bool) -> Self { self.disabled = match toggle { - true => Some("disabled".to_string()), + true => Some("disabled".to_owned()), false => None }; self } pub fn using_template(mut self, template: &str) -> Self { - self.template = template.to_string(); + self.template = template.to_owned(); self } // Button GETTERS. pub fn name(&self) -> &str { - util::assigned_value(&self.name) + util::assigned_str(&self.name) } pub fn value(&self) -> &str { - util::assigned_value(&self.value) + util::assigned_str(&self.value) } pub fn has_autofocus(&self) -> bool { diff --git a/src/base/component/form/date.rs b/src/base/component/form/date.rs index b2839e8e..ccc6ab31 100644 --- a/src/base/component/form/date.rs +++ b/src/base/component/form/date.rs @@ -5,14 +5,14 @@ pub struct Date { weight : i8, name : Option<String>, value : Option<String>, - label : String, + label : Option<String>, placeholder : Option<String>, autofocus : Option<String>, autocomplete: Option<String>, disabled : Option<String>, readonly : Option<String>, required : Option<String>, - help_text : String, + help_text : Option<String>, template : String, } @@ -24,15 +24,15 @@ impl PageComponent for Date { weight : 0, name : None, value : None, - label : "".to_string(), + label : None, placeholder : None, autofocus : None, autocomplete: None, disabled : None, readonly : None, required : None, - help_text : "".to_string(), - template : "default".to_string(), + help_text : None, + template : "default".to_owned(), } } @@ -51,15 +51,15 @@ impl PageComponent for Date { Some(format!("edit-{}", name)) ), None => ( - "form-item form-type-date".to_string(), + "form-item form-type-date".to_owned(), None ) }; html! { div class=(class_item) { - @if !self.label.is_empty() { + @if self.label != None { label class="form-label" for=[&id_item] { - (self.label) " " + (self.label()) " " @if self.required != None { span class="form-required" @@ -82,9 +82,9 @@ impl PageComponent for Date { readonly=[&self.readonly] required=[&self.required] disabled=[&self.disabled]; - @if !self.help_text.is_empty() { + @if self.help_text != None { div class="form-text" { - (self.help_text) + (self.help_text()) } } } @@ -112,23 +112,23 @@ impl Date { } pub fn with_value(mut self, value: &str) -> Self { - self.value = util::optional_value(value); + self.value = util::optional_str(value); self } pub fn with_label(mut self, label: &str) -> Self { - self.label = label.to_string(); + self.label = util::optional_str(label); self } pub fn with_placeholder(mut self, placeholder: &str) -> Self { - self.placeholder = util::optional_value(placeholder); + self.placeholder = util::optional_str(placeholder); self } pub fn autofocus(mut self, toggle: bool) -> Self { self.autofocus = match toggle { - true => Some("autofocus".to_string()), + true => Some("autofocus".to_owned()), false => None }; self @@ -137,14 +137,14 @@ impl Date { pub fn autocomplete(mut self, toggle: bool) -> Self { self.autocomplete = match toggle { true => None, - false => Some("off".to_string()) + false => Some("off".to_owned()) }; self } pub fn disabled(mut self, toggle: bool) -> Self { self.disabled = match toggle { - true => Some("disabled".to_string()), + true => Some("disabled".to_owned()), false => None }; self @@ -152,7 +152,7 @@ impl Date { pub fn readonly(mut self, toggle: bool) -> Self { self.readonly = match toggle { - true => Some("readonly".to_string()), + true => Some("readonly".to_owned()), false => None }; self @@ -160,38 +160,38 @@ impl Date { pub fn required(mut self, toggle: bool) -> Self { self.required = match toggle { - true => Some("required".to_string()), + true => Some("required".to_owned()), false => None }; self } pub fn with_help_text(mut self, help_text: &str) -> Self { - self.help_text = help_text.to_string(); + self.help_text = util::optional_str(help_text); self } pub fn using_template(mut self, template: &str) -> Self { - self.template = template.to_string(); + self.template = template.to_owned(); self } // Date GETTERS. pub fn name(&self) -> &str { - util::assigned_value(&self.name) + util::assigned_str(&self.name) } pub fn value(&self) -> &str { - util::assigned_value(&self.value) + util::assigned_str(&self.value) } pub fn label(&self) -> &str { - self.label.as_str() + util::assigned_str(&self.label) } pub fn placeholder(&self) -> &str { - util::assigned_value(&self.placeholder) + util::assigned_str(&self.placeholder) } pub fn has_autofocus(&self) -> bool { @@ -230,7 +230,7 @@ impl Date { } pub fn help_text(&self) -> &str { - self.help_text.as_str() + util::assigned_str(&self.help_text) } pub fn template(&self) -> &str { diff --git a/src/base/component/form/form.rs b/src/base/component/form/form.rs index 6f73469d..63eace0c 100644 --- a/src/base/component/form/form.rs +++ b/src/base/component/form/form.rs @@ -22,9 +22,9 @@ impl PageComponent for Form { id : None, action : None, method : FormMethod::Post, - charset : Some("UTF-8".to_string()), + charset : Some("UTF-8".to_owned()), elements : PageContainer::new(), - template : "default".to_string(), + template : "default".to_owned(), } } @@ -39,7 +39,7 @@ impl PageComponent for Form { fn default_render(&self, assets: &mut PageAssets) -> Markup { let method = match self.method { FormMethod::Get => None, - FormMethod::Post => Some("post".to_string()) + FormMethod::Post => Some("post".to_owned()) }; html! { form @@ -76,7 +76,7 @@ impl Form { } pub fn with_action(mut self, action: &str) -> Self { - self.action = util::optional_value(action); + self.action = util::optional_str(action); self } @@ -86,7 +86,7 @@ impl Form { } pub fn with_charset(mut self, charset: &str) -> Self { - self.charset = util::optional_value(charset); + self.charset = util::optional_str(charset); self } @@ -96,18 +96,18 @@ impl Form { } pub fn using_template(mut self, template: &str) -> Self { - self.template = template.to_string(); + self.template = template.to_owned(); self } // Form GETTERS. pub fn id(&self) -> &str { - util::assigned_value(&self.id) + util::assigned_str(&self.id) } pub fn action(&self) -> &str { - util::assigned_value(&self.action) + util::assigned_str(&self.action) } pub fn method(&self) -> &str { @@ -118,7 +118,7 @@ impl Form { } pub fn charset(&self) -> &str { - util::assigned_value(&self.charset) + util::assigned_str(&self.charset) } pub fn template(&self) -> &str { diff --git a/src/base/component/form/hidden.rs b/src/base/component/form/hidden.rs index 57b4b34f..9ac0a4f9 100644 --- a/src/base/component/form/hidden.rs +++ b/src/base/component/form/hidden.rs @@ -54,17 +54,17 @@ impl Hidden { } pub fn with_value(mut self, value: &str) -> Self { - self.value = util::optional_value(value); + self.value = util::optional_str(value); self } // Hidden GETTERS. pub fn name(&self) -> &str { - util::assigned_value(&self.name) + util::assigned_str(&self.name) } pub fn value(&self) -> &str { - util::assigned_value(&self.value) + util::assigned_str(&self.value) } } diff --git a/src/base/component/form/input.rs b/src/base/component/form/input.rs index 82c0bda3..884d2232 100644 --- a/src/base/component/form/input.rs +++ b/src/base/component/form/input.rs @@ -8,7 +8,7 @@ pub struct Input { input_type : InputType, name : Option<String>, value : Option<String>, - label : String, + label : Option<String>, size : Option<u16>, minlength : Option<u16>, maxlength : Option<u16>, @@ -18,7 +18,7 @@ pub struct Input { disabled : Option<String>, readonly : Option<String>, required : Option<String>, - help_text : String, + help_text : Option<String>, template : String, } @@ -31,7 +31,7 @@ impl PageComponent for Input { input_type : InputType::Textfield, name : None, value : None, - label : "".to_string(), + label : None, size : Some(60), minlength : None, maxlength : Some(128), @@ -41,8 +41,8 @@ impl PageComponent for Input { disabled : None, readonly : None, required : None, - help_text : "".to_string(), - template : "default".to_string(), + help_text : None, + template : "default".to_owned(), } } @@ -75,9 +75,9 @@ impl PageComponent for Input { }; html! { div class=(class_item) { - @if !self.label.is_empty() { + @if self.label != None { label class="form-label" for=[&id_item] { - (self.label) " " + (self.label()) " " @if self.required != None { span class="form-required" @@ -103,9 +103,9 @@ impl PageComponent for Input { readonly=[&self.readonly] required=[&self.required] disabled=[&self.disabled]; - @if !self.help_text.is_empty() { + @if self.help_text != None { div class="form-text" { - (self.help_text) + (self.help_text()) } } } @@ -167,12 +167,12 @@ impl Input { } pub fn with_value(mut self, value: &str) -> Self { - self.value = util::optional_value(value); + self.value = util::optional_str(value); self } pub fn with_label(mut self, label: &str) -> Self { - self.label = label.to_string(); + self.label = util::optional_str(label); self } @@ -192,13 +192,13 @@ impl Input { } pub fn with_placeholder(mut self, placeholder: &str) -> Self { - self.placeholder = util::optional_value(placeholder); + self.placeholder = util::optional_str(placeholder); self } pub fn autofocus(mut self, toggle: bool) -> Self { self.autofocus = match toggle { - true => Some("autofocus".to_string()), + true => Some("autofocus".to_owned()), false => None }; self @@ -207,14 +207,14 @@ impl Input { pub fn autocomplete(mut self, toggle: bool) -> Self { self.autocomplete = match toggle { true => None, - false => Some("off".to_string()) + false => Some("off".to_owned()) }; self } pub fn disabled(mut self, toggle: bool) -> Self { self.disabled = match toggle { - true => Some("disabled".to_string()), + true => Some("disabled".to_owned()), false => None }; self @@ -222,7 +222,7 @@ impl Input { pub fn readonly(mut self, toggle: bool) -> Self { self.readonly = match toggle { - true => Some("readonly".to_string()), + true => Some("readonly".to_owned()), false => None }; self @@ -230,34 +230,34 @@ impl Input { pub fn required(mut self, toggle: bool) -> Self { self.required = match toggle { - true => Some("required".to_string()), + true => Some("required".to_owned()), false => None }; self } pub fn with_help_text(mut self, help_text: &str) -> Self { - self.help_text = help_text.to_string(); + self.help_text = util::optional_str(help_text); self } pub fn using_template(mut self, template: &str) -> Self { - self.template = template.to_string(); + self.template = template.to_owned(); self } // Input GETTERS. pub fn name(&self) -> &str { - util::assigned_value(&self.name) + util::assigned_str(&self.name) } pub fn value(&self) -> &str { - util::assigned_value(&self.value) + util::assigned_str(&self.value) } pub fn label(&self) -> &str { - self.label.as_str() + util::assigned_str(&self.label) } pub fn size(&self) -> Option<u16> { @@ -273,7 +273,7 @@ impl Input { } pub fn placeholder(&self) -> &str { - util::assigned_value(&self.placeholder) + util::assigned_str(&self.placeholder) } pub fn has_autofocus(&self) -> bool { @@ -312,7 +312,7 @@ impl Input { } pub fn help_text(&self) -> &str { - self.help_text.as_str() + util::assigned_str(&self.help_text) } pub fn template(&self) -> &str { diff --git a/src/base/component/menu.rs b/src/base/component/menu.rs index 0f44fad5..d3cdb6b8 100644 --- a/src/base/component/menu.rs +++ b/src/base/component/menu.rs @@ -75,7 +75,7 @@ impl MenuItem { MenuItem { renderable: always, weight : 0, - item_type : Some(MenuItemType::Label(label.to_string())), + item_type : Some(MenuItemType::Label(label.to_owned())), } } @@ -84,8 +84,8 @@ impl MenuItem { renderable: always, weight : 0, item_type : Some(MenuItemType::Link( - label.to_string(), - path.to_string(), + label.to_owned(), + path.to_owned(), )), } } @@ -95,8 +95,8 @@ impl MenuItem { renderable: always, weight : 0, item_type : Some(MenuItemType::LinkBlank( - label.to_string(), - path.to_string(), + label.to_owned(), + path.to_owned(), )), } } @@ -122,7 +122,7 @@ impl MenuItem { renderable: always, weight : 0, item_type : Some(MenuItemType::Submenu( - label.to_string(), + label.to_owned(), menu )), } @@ -161,7 +161,7 @@ impl PageComponent for Menu { weight : 0, id : None, items : PageContainer::new(), - template : "default".to_string(), + template : "default".to_owned(), } } @@ -226,14 +226,14 @@ impl Menu { } pub fn using_template(mut self, template: &str) -> Self { - self.template = template.to_string(); + self.template = template.to_owned(); self } // Menu GETTERS. pub fn id(&self) -> &str { - util::assigned_value(&self.id) + util::assigned_str(&self.id) } pub fn template(&self) -> &str { diff --git a/src/base/module/admin/mod.rs b/src/base/module/admin/mod.rs index 5991d4f0..0bb1202d 100644 --- a/src/base/module/admin/mod.rs +++ b/src/base/module/admin/mod.rs @@ -15,8 +15,8 @@ impl Module for AdminModule { l("module_fullname") } - fn description(&self) -> String { - l("module_description") + fn description(&self) -> Option<String> { + Some(l("module_description")) } fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { diff --git a/src/base/module/homepage/mod.rs b/src/base/module/homepage/mod.rs index 386b6716..de4b98ce 100644 --- a/src/base/module/homepage/mod.rs +++ b/src/base/module/homepage/mod.rs @@ -13,8 +13,8 @@ impl Module for HomepageModule { l("module_fullname") } - fn description(&self) -> String { - l("module_description") + fn description(&self) -> Option<String> { + Some(l("module_description")) } fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { diff --git a/src/base/module/user/mod.rs b/src/base/module/user/mod.rs index bbb3ee93..73ab7d16 100644 --- a/src/base/module/user/mod.rs +++ b/src/base/module/user/mod.rs @@ -13,8 +13,8 @@ impl Module for UserModule { l("module_fullname") } - fn description(&self) -> String { - l("module_description") + fn description(&self) -> Option<String> { + Some(l("module_description")) } fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { @@ -29,7 +29,7 @@ fn form_login() -> impl PageComponent { .with_name("name") .with_label(l("username").as_str()) .with_help_text(t("username_help", &args![ - "app" => SETTINGS.app.name.to_string() + "app" => SETTINGS.app.name.to_owned() ]).as_str()) .autofocus(true) ) diff --git a/src/base/theme/aliner/mod.rs b/src/base/theme/aliner/mod.rs index d27e2f91..b678d4b7 100644 --- a/src/base/theme/aliner/mod.rs +++ b/src/base/theme/aliner/mod.rs @@ -10,7 +10,7 @@ impl Theme for AlinerTheme { } fn fullname(&self) -> String { - "Aliner".to_string() + "Aliner".to_owned() } fn configure_theme(&self, cfg: &mut server::web::ServiceConfig) { diff --git a/src/base/theme/bootsier/mod.rs b/src/base/theme/bootsier/mod.rs index 97b7fa46..3a340a84 100644 --- a/src/base/theme/bootsier/mod.rs +++ b/src/base/theme/bootsier/mod.rs @@ -12,7 +12,7 @@ impl Theme for BootsierTheme { } fn fullname(&self) -> String { - "Bootsier".to_string() + "Bootsier".to_owned() } fn configure_theme(&self, cfg: &mut server::web::ServiceConfig) { diff --git a/src/base/theme/minimal/mod.rs b/src/base/theme/minimal/mod.rs index 17611468..c6780005 100644 --- a/src/base/theme/minimal/mod.rs +++ b/src/base/theme/minimal/mod.rs @@ -8,6 +8,6 @@ impl Theme for MinimalTheme { } fn fullname(&self) -> String { - "Minimal".to_string() + "Minimal".to_owned() } } diff --git a/src/config/settings.rs b/src/config.rs similarity index 97% rename from src/config/settings.rs rename to src/config.rs index 66ddbe42..bd80bd76 100644 --- a/src/config/settings.rs +++ b/src/config.rs @@ -1,11 +1,13 @@ use crate::Lazy; -use crate::config::CONFIG_DIR; use config_rs::{Config, File}; use serde::Deserialize; use std::env; +/// Nombre del directorio donde se encuentra la configuración. +const CONFIG_DIR: &'static str = "config"; + /// Al arrancar la aplicación, carga los valores originales "clave = valor" de /// los archivos de configuración. Con [`config_map`] se asignarán los ajustes /// globales ([`SETTINGS`]); y se podrán asignar los ajustes específicos de la diff --git a/src/config/mod.rs b/src/config/mod.rs deleted file mode 100644 index aba410ee..00000000 --- a/src/config/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -/// Nombre del directorio donde se encuentra la configuración. -pub const CONFIG_DIR: &'static str = "config"; - -mod settings; -pub use settings::{CONFIG, SETTINGS}; diff --git a/src/core/all.rs b/src/core/global.rs similarity index 83% rename from src/core/all.rs rename to src/core/global.rs index eb7bed10..1d64d44f 100644 --- a/src/core/all.rs +++ b/src/core/global.rs @@ -3,7 +3,6 @@ use crate::core::theme::Theme; use crate::core::module::Module; use crate::core::response::page::PageContainer; use crate::core::server; -use crate::base; use std::sync::RwLock; use std::collections::HashMap; @@ -15,11 +14,7 @@ include!(concat!(env!("OUT_DIR"), "/theme.rs")); // ----------------------------------------------------------------------------- pub static THEMES: Lazy<RwLock<Vec<&dyn Theme>>> = Lazy::new(|| { - RwLock::new(vec![ - &base::theme::aliner::AlinerTheme, - &base::theme::minimal::MinimalTheme, - &base::theme::bootsier::BootsierTheme, - ]) + RwLock::new(Vec::new()) }); pub fn themes(cfg: &mut server::web::ServiceConfig) { @@ -38,10 +33,7 @@ pub fn themes(cfg: &mut server::web::ServiceConfig) { // ----------------------------------------------------------------------------- pub static MODULES: Lazy<RwLock<Vec<&dyn Module>>> = Lazy::new(|| { - RwLock::new(vec![ - &base::module::admin::AdminModule, - &base::module::user::UserModule, - ]) + RwLock::new(Vec::new()) }); pub fn modules(cfg: &mut server::web::ServiceConfig) { diff --git a/src/core/mod.rs b/src/core/mod.rs index 40530f15..26618959 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,6 +1,6 @@ pub use actix_web::dev::Server; -mod all; +mod global; pub mod theme; pub mod module; diff --git a/src/core/module/api.rs b/src/core/module/api.rs deleted file mode 100644 index 83be71c3..00000000 --- a/src/core/module/api.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::core::{all, server}; - -/// Los módulos deben implementar este *trait*. -pub trait Module: Send + Sync { - fn name(&self) -> &'static str; - - fn fullname(&self) -> String; - - fn description(&self) -> String { - "".to_string() - } - - #[allow(unused_variables)] - fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { - } -} - -pub fn register_module(m: &'static (dyn Module + 'static)) { - all::MODULES.write().unwrap().push(m); -} - -pub fn find_module(name: &str) -> Option<&'static (dyn Module + 'static)> { - let modules = all::MODULES.write().unwrap(); - match modules.iter().find(|t| t.name() == name) { - Some(module) => Some(*module), - _ => None, - } -} diff --git a/src/core/module/definition.rs b/src/core/module/definition.rs new file mode 100644 index 00000000..40e9cee8 --- /dev/null +++ b/src/core/module/definition.rs @@ -0,0 +1,16 @@ +use crate::core::server; + +/// Los módulos deben implementar este *trait*. +pub trait Module: Send + Sync { + fn name(&self) -> &'static str; + + fn fullname(&self) -> String; + + fn description(&self) -> Option<String> { + None + } + + #[allow(unused_variables)] + fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { + } +} diff --git a/src/core/module/mod.rs b/src/core/module/mod.rs index 08686bcd..439cff79 100644 --- a/src/core/module/mod.rs +++ b/src/core/module/mod.rs @@ -1,2 +1,16 @@ -mod api; -pub use api::{Module, find_module, register_module}; +use crate::core::global; + +mod definition; +pub use definition::Module; + +pub fn register_module(m: &'static (dyn Module + 'static)) { + global::MODULES.write().unwrap().push(m); +} + +pub fn find_module(name: &str) -> Option<&'static (dyn Module + 'static)> { + let modules = global::MODULES.write().unwrap(); + match modules.iter().find(|t| t.name() == name) { + Some(module) => Some(*module), + _ => None, + } +} diff --git a/src/core/response/page/assets.rs b/src/core/response/page/assets.rs index 77174e58..11cdd35c 100644 --- a/src/core/response/page/assets.rs +++ b/src/core/response/page/assets.rs @@ -1,10 +1,10 @@ use crate::{Lazy, base}; use crate::config::SETTINGS; -use crate::core::all; +use crate::core::global; use crate::core::theme::{Markup, PreEscaped, Theme, find_theme, html}; static DEFAULT_THEME: Lazy<&dyn Theme> = Lazy::new(|| { - for t in all::THEMES.read().unwrap().iter() { + for t in global::THEMES.read().unwrap().iter() { if t.name().to_lowercase() == SETTINGS.app.theme.to_lowercase() { return *t; } @@ -73,7 +73,7 @@ impl Favicon { ) -> Self { let mut link: String = format!("<link rel=\"{}\"", rel); if let Some(i) = source.rfind('.') { - link = match source[i..].to_string().to_lowercase().as_str() { + link = match source[i..].to_owned().to_lowercase().as_str() { ".gif" => format!("{} type=\"image/gif\"", link), ".ico" => format!("{} type=\"image/x-icon\"", link), ".jpg" => format!("{} type=\"image/jpg\"", link), @@ -295,14 +295,14 @@ impl PageAssets { if id.is_empty() { let prefix = prefix.trim().replace(" ", "_").to_lowercase(); let prefix = if prefix.is_empty() { - "prefix".to_string() + "prefix".to_owned() } else { prefix }; self.id_counter += 1; [prefix, self.id_counter.to_string()].join("-") } else { - id.to_string() + id.to_owned() } } } diff --git a/src/core/response/page/component.rs b/src/core/response/page/component.rs index ccc0facb..1472ffe2 100644 --- a/src/core/response/page/component.rs +++ b/src/core/response/page/component.rs @@ -18,11 +18,11 @@ pub trait PageComponent: Downcast + Send + Sync { } fn fullname(&self) -> String { - type_name::<Self>().to_string() + type_name::<Self>().to_owned() } - fn description(&self) -> String { - "".to_string() + fn description(&self) -> Option<String> { + None } fn is_renderable(&self) -> bool { diff --git a/src/core/response/page/page.rs b/src/core/response/page/page.rs index 18e8c917..8052683d 100644 --- a/src/core/response/page/page.rs +++ b/src/core/response/page/page.rs @@ -1,6 +1,6 @@ use crate::{Lazy, trace, util}; use crate::config::SETTINGS; -use crate::core::{all, server}; +use crate::core::{global, server}; use crate::core::theme::{DOCTYPE, Markup, html}; use crate::core::response::page::{PageAssets, PageComponent, PageContainer}; @@ -19,9 +19,9 @@ static DEFAULT_LANGUAGE: Lazy<Option<String>> = Lazy::new(|| { static DEFAULT_DIRECTION: Lazy<Option<String>> = Lazy::new(|| { let direction = SETTINGS.app.direction.to_lowercase(); match direction.as_str() { - "auto" => Some("auto".to_string()), - "ltr" => Some("ltr".to_string()), - "rtl" => Some("rtl".to_string()), + "auto" => Some("auto".to_owned()), + "ltr" => Some("ltr".to_owned()), + "rtl" => Some("rtl".to_owned()), "" => None, _ => { trace::warn!( @@ -44,7 +44,7 @@ pub struct Page<'a> { assets : PageAssets, body_classes: Cow<'a, str>, regions : HashMap<&'a str, PageContainer>, - template : Option<String>, + template : String, } impl<'a> Page<'a> { @@ -52,45 +52,45 @@ impl<'a> Page<'a> { pub fn prepare() -> Self { Page { language : match &*DEFAULT_LANGUAGE { - Some(language) => Some(language.to_string()), + Some(language) => Some(language.to_owned()), _ => None, }, direction : match &*DEFAULT_DIRECTION { - Some(direction) => Some(direction.to_string()), + Some(direction) => Some(direction.to_owned()), _ => None, }, title : None, description : None, body_classes: "body".into(), assets : PageAssets::new(), - regions : all::COMPONENTS.read().unwrap().clone(), - template : Some("default".to_string()), + regions : global::COMPONENTS.read().unwrap().clone(), + template : "default".to_owned(), } } // Page BUILDER. pub fn with_language(&mut self, language: &str) -> &mut Self { - self.language = util::optional_value(language); + self.language = util::optional_str(language); self } pub fn with_direction(&mut self, dir: TextDirection) -> &mut Self { self.direction = match dir { - TextDirection::Auto => Some("auto".to_string()), - TextDirection::LeftToRight => Some("ltr".to_string()), - TextDirection::RightToLeft => Some("rtl".to_string()), + TextDirection::Auto => Some("auto".to_owned()), + TextDirection::LeftToRight => Some("ltr".to_owned()), + TextDirection::RightToLeft => Some("rtl".to_owned()), }; self } pub fn with_title(&mut self, title: &str) -> &mut Self { - self.title = util::optional_value(title); + self.title = util::optional_str(title); self } pub fn with_description(&mut self, description: &str) -> &mut Self { - self.description = util::optional_value(description); + self.description = util::optional_str(description); self } @@ -120,26 +120,26 @@ impl<'a> Page<'a> { } pub fn using_template(&mut self, template: &str) -> &mut Self { - self.template = util::optional_value(template); + self.template = template.to_owned(); self } // Page GETTERS. pub fn language(&self) -> &str { - util::assigned_value(&self.language) + util::assigned_str(&self.language) } pub fn direction(&self) -> &str { - util::assigned_value(&self.direction) + util::assigned_str(&self.direction) } pub fn title(&self) -> &str { - util::assigned_value(&self.title) + util::assigned_str(&self.title) } pub fn description(&self) -> &str { - util::assigned_value(&self.description) + util::assigned_str(&self.description) } pub fn body_classes(&self) -> &str { @@ -154,7 +154,7 @@ impl<'a> Page<'a> { } pub fn template(&self) -> &str { - util::assigned_value(&self.template) + self.template.as_str() } // Page RENDER. @@ -208,7 +208,7 @@ pub fn render_component( } pub fn add_component_to(region: &'static str, component: impl PageComponent) { - let mut hmap = all::COMPONENTS.write().unwrap(); + let mut hmap = global::COMPONENTS.write().unwrap(); if let Some(regions) = hmap.get_mut(region) { regions.add(component); } else { diff --git a/src/core/server/langid.rs b/src/core/server/langid.rs deleted file mode 100644 index 3638a6a4..00000000 --- a/src/core/server/langid.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::{Lazy, trace}; -use crate::config::SETTINGS; - -use unic_langid::LanguageIdentifier; - -/// Almacena el Identificador de Idioma Unicode ([Unicode Language Identifier] -/// (https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier)) de -/// la aplicación, obtenido de `SETTINGS.app.language`. -pub static LANGID: Lazy<LanguageIdentifier> = Lazy::new(|| { - match SETTINGS.app.language.parse() { - Ok(language) => language, - Err(_) => { - trace::warn!( - "Failed to parse language \"{}\". {}. {}. {}.", - SETTINGS.app.language, - "Unicode Language Identifier not recognized", - "Using \"en-US\"", - "Check the settings file", - ); - "en-US".parse().unwrap() - } - } -}); diff --git a/src/core/server/main.rs b/src/core/server/main.rs index c39c9f83..b6800142 100644 --- a/src/core/server/main.rs +++ b/src/core/server/main.rs @@ -1,6 +1,7 @@ -use crate::{Lazy, base, trace}; +use crate::{Lazy, base, locale, trace}; use crate::config::SETTINGS; -use crate::core::{Server, all, server}; +use crate::core::{Server, global, server}; +use crate::core::theme::register_theme; use crate::core::module::register_module; use actix_web::middleware::normalize; @@ -32,11 +33,20 @@ pub fn run(bootstrap: Option<fn()>) -> Result<Server, std::io::Error> { ); } - // Inicia la traza de la aplicación. + // Inicia registro de trazas y eventos. Lazy::force(&server::tracing::TRACING); // Asigna identificador de idioma. - Lazy::force(&server::langid::LANGID); + Lazy::force(&locale::LANGID); + + // Registra los temas predefinidos. + register_theme(&base::theme::aliner::AlinerTheme); + register_theme(&base::theme::minimal::MinimalTheme); + register_theme(&base::theme::bootsier::BootsierTheme); + + // Registra los módulos predeterminados. + register_module(&base::module::admin::AdminModule); + register_module(&base::module::user::UserModule); // Ejecuta la función de inicio de la aplicación. if bootstrap != None { @@ -54,8 +64,8 @@ pub fn run(bootstrap: Option<fn()>) -> Result<Server, std::io::Error> { server::App::new() .wrap(tracing_actix_web::TracingLogger) .wrap(normalize::NormalizePath::new(normalize::TrailingSlash::Trim)) - .configure(&all::themes) - .configure(&all::modules) + .configure(&global::themes) + .configure(&global::modules) }) .bind(format!("{}:{}", &SETTINGS.webserver.bind_address, diff --git a/src/core/server/mod.rs b/src/core/server/mod.rs index 6bb25129..7db53759 100644 --- a/src/core/server/mod.rs +++ b/src/core/server/mod.rs @@ -4,8 +4,5 @@ pub use actix_web::{ mod tracing; -mod langid; -pub use langid::LANGID; - mod main; pub use main::run; diff --git a/src/core/server/tracing.rs b/src/core/server/tracing.rs index fd907461..a9804213 100644 --- a/src/core/server/tracing.rs +++ b/src/core/server/tracing.rs @@ -4,6 +4,19 @@ use crate::config::SETTINGS; use tracing_appender::non_blocking::WorkerGuard; use tracing_subscriber::EnvFilter; +/// Registro de trazas y eventos de la aplicación. +/// +/// Para aumentar el rendimiento, un subproceso dedicado utiliza un sistema de +/// escritura sin bloqueo (*non-blocking writer*) que actúa periódicamente en +/// vez de enviar cada traza o evento al instante. Si el programa termina +/// abruptamente (por ejemplo, por un `panic!` o un `std::process::exit`), es +/// posible que algunas trazas o eventos no se envíen. +/// +/// Puesto que las trazas o eventos registrados poco antes de la caída de una +/// aplicación suelen ser importantes para diagnosticar la causa del fallo, con +/// `Lazy<WorkerGuard>` se garantiza que todos los registros almacenados se +/// enviarán antes de terminar la ejecución. + pub static TRACING: Lazy<WorkerGuard> = Lazy::new(|| { let env_filter = EnvFilter::try_new(&SETTINGS.log.tracing) .unwrap_or(EnvFilter::new("Info")); diff --git a/src/core/theme/api.rs b/src/core/theme/definition.rs similarity index 85% rename from src/core/theme/api.rs rename to src/core/theme/definition.rs index efbc9cef..12d9e05f 100644 --- a/src/core/theme/api.rs +++ b/src/core/theme/definition.rs @@ -1,5 +1,5 @@ use crate::config::SETTINGS; -use crate::core::{all, server}; +use crate::core::server; use crate::core::theme::{Markup, html}; use crate::core::response::page::{Page, PageAssets, PageComponent}; use crate::base::component::Chunck; @@ -10,8 +10,8 @@ pub trait Theme: Send + Sync { fn fullname(&self) -> String; - fn description(&self) -> String { - "".to_string() + fn description(&self) -> Option<String> { + None } #[allow(unused_variables)] @@ -25,7 +25,7 @@ pub trait Theme: Send + Sync { fn render_page_head(&self, page: &mut Page) -> Markup { let title = page.title(); let title = if title.is_empty() { - SETTINGS.app.name.to_string() + SETTINGS.app.name.to_owned() } else { [SETTINGS.app.name.to_string(), title.to_string()].join(" | ") }; @@ -104,15 +104,3 @@ pub trait Theme: Send + Sync { .render() } } - -pub fn register_theme(t: &'static (dyn Theme + 'static)) { - all::THEMES.write().unwrap().push(t); -} - -pub fn find_theme(name: &str) -> Option<&'static (dyn Theme + 'static)> { - let themes = all::THEMES.write().unwrap(); - match themes.iter().find(|t| t.name() == name) { - Some(theme) => Some(*theme), - _ => None, - } -} diff --git a/src/core/theme/mod.rs b/src/core/theme/mod.rs index 9f708803..8292ade6 100644 --- a/src/core/theme/mod.rs +++ b/src/core/theme/mod.rs @@ -1,4 +1,18 @@ +use crate::core::global; + pub use maud::{DOCTYPE, Markup, PreEscaped, html}; -mod api; -pub use api::{Theme, find_theme, register_theme}; +mod definition; +pub use definition::Theme; + +pub fn register_theme(t: &'static (dyn Theme + 'static)) { + global::THEMES.write().unwrap().push(t); +} + +pub fn find_theme(name: &str) -> Option<&'static (dyn Theme + 'static)> { + let themes = global::THEMES.write().unwrap(); + match themes.iter().find(|t| t.name() == name) { + Some(theme) => Some(*theme), + _ => None, + } +} diff --git a/src/lib.rs b/src/lib.rs index 42f51a3a..7d17db44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ pub use once_cell::sync::Lazy; // ----------------------------------------------------------------------------- pub mod config; // Gestión de la configuración. -pub mod trace; // Traza de ejecución. +pub mod trace; // Registro de trazas y eventos de la aplicación. pub mod locale; // Localización. pub mod core; // Servidor web y sistemas para Temas, Módulos y Respuestas. pub mod base; // Temas, Módulos y Componentes base. diff --git a/src/locale.rs b/src/locale.rs index b43d9fd6..e3639858 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -2,12 +2,35 @@ pub use fluent_templates::{static_loader as static_locale, Loader as Locale}; pub use fluent_templates; pub use fluent_templates::fluent_bundle::FluentValue; +use crate::{Lazy, trace}; +use crate::config::SETTINGS; + +use unic_langid::LanguageIdentifier; + +/// Almacena el Identificador de Idioma Unicode ([Unicode Language Identifier] +/// (https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier)) de +/// la aplicación, obtenido de `SETTINGS.app.language`. +pub static LANGID: Lazy<LanguageIdentifier> = Lazy::new(|| { + match SETTINGS.app.language.parse() { + Ok(language) => language, + Err(_) => { + trace::warn!( + "Failed to parse language \"{}\". {}. {}. {}.", + SETTINGS.app.language, + "Unicode Language Identifier not recognized", + "Using \"en-US\"", + "Check the settings file", + ); + "en-US".parse().unwrap() + } + } +}); + #[macro_export] /// Permite integrar fácilmente localización en temas, módulos y componentes. macro_rules! localize { ( $DEF_LANGID:literal, $locales:literal $(, $core_locales:literal)? ) => { use $crate::locale::*; - use $crate::core::server::LANGID; static_locale! { static LOCALES = { diff --git a/src/util.rs b/src/util.rs index 638e948f..3fff0a23 100644 --- a/src/util.rs +++ b/src/util.rs @@ -26,17 +26,17 @@ pub fn valid_id(id: &str) -> Option<String> { } } -pub fn optional_value(value: &str) -> Option<String> { - let value = value.to_string(); - match value.is_empty() { +pub fn optional_str(s: &str) -> Option<String> { + let s = s.to_owned(); + match s.is_empty() { true => None, - false => Some(value), + false => Some(s), } } -pub fn assigned_value(value: &Option<String>) -> &str { - match value { - Some(value) => value.as_str(), +pub fn assigned_str(optional: &Option<String>) -> &str { + match optional { + Some(o) => o.as_str(), _ => "", } } From 76785af4dc801e587cba904d013977acbd854c9b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 10 Mar 2022 00:10:48 +0100 Subject: [PATCH 023/244] =?UTF-8?q?A=C3=B1ade=20configuraci=C3=B3n=20y=20c?= =?UTF-8?q?onexi=C3=B3n=20a=20la=20base=20de=20datos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 12 +++ config/settings.default.toml | 14 ++++ src/base/module/admin/summary.rs | 3 +- src/config.rs | 19 +++++ src/core/server/app.rs | 138 +++++++++++++++++++++++++++++++ src/core/server/dbconn.rs | 8 ++ src/core/server/main.rs | 76 ----------------- src/core/server/mod.rs | 6 +- src/database.rs | 1 + src/lib.rs | 3 + src/locale.rs | 6 +- src/main.rs | 6 +- src/prelude.rs | 1 + 13 files changed, 210 insertions(+), 83 deletions(-) create mode 100644 src/core/server/app.rs create mode 100644 src/core/server/dbconn.rs delete mode 100644 src/core/server/main.rs create mode 100644 src/database.rs diff --git a/Cargo.toml b/Cargo.toml index 6d9fa877..d28a0e33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ once_cell = "1.9.0" figlet-rs = "0.1.3" config_rs = { package = "config", version = "0.11.0", features = ["toml"] } +url = "2.2.2" tracing = "0.1" tracing-appender = "0.2" @@ -47,9 +48,20 @@ downcast-rs = "1.2.0" serde = { version = "1.0", features = ["derive"] } +[dependencies.sea-orm] +version = "0.6" +features = ["macros", "debug-print", "runtime-async-std-native-tls"] +default-features = false + [build-dependencies] actix-web-static-files = "3.0.5" +[features] +default = ["sea-orm/sqlx-mysql"] +mysql = ["sea-orm/sqlx-mysql"] +postgres = ["sea-orm/sqlx-postgres"] +sqlite = ["sea-orm/sqlx-sqlite"] + [lib] name = "pagetop" diff --git a/config/settings.default.toml b/config/settings.default.toml index 3a4fb0ff..f22868d2 100644 --- a/config/settings.default.toml +++ b/config/settings.default.toml @@ -23,6 +23,20 @@ prefix = "tracing.log" # Presentación de las trazas: "Json", "Full", "Compact" o "Pretty". format = "Json" +[database] +# Ajustes para conectar con la base de datos. +# El tipo de base de datos es una característica de compilación. +# Nombre (mysql/postgres) o referencia (sqlite) de la base de datos. +db_name = "dbname" +# Usuario y contraseña (mysql/postgres). +db_user = "dbuser" +db_pass = "dbpass" +# Servidor (mysql/postgres) y puerto predeterminado (0 para 3306 ó 5432). +db_host = "localhost" +db_port = 0 +# Número máximo de conexiones habilitadas. +max_pool_size = 5 + [webserver] # Configuración del servidor web. bind_address = "localhost" diff --git a/src/base/module/admin/summary.rs b/src/base/module/admin/summary.rs index 2f889e9e..cee26c22 100644 --- a/src/base/module/admin/summary.rs +++ b/src/base/module/admin/summary.rs @@ -1,8 +1,9 @@ use crate::prelude::*; +use super::l; pub async fn summary() -> server::Result<Markup> { let top_menu = Menu::prepare() - .add(MenuItem::label("Opción 1")) + .add(MenuItem::label(l("module_fullname").as_str())) .add(MenuItem::link("Opción 2", "https://www.google.es")) .add(MenuItem::link_blank("Opción 3", "https://www.google.es")) .add(MenuItem::submenu("Submenú 1", Menu::prepare() diff --git a/src/config.rs b/src/config.rs index bd80bd76..c6232c7a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -87,6 +87,16 @@ pub struct Log { pub format : String, } +#[derive(Debug, Deserialize)] +pub struct Database { + pub db_name : String, + pub db_user : String, + pub db_pass : String, + pub db_host : String, + pub db_port : u16, + pub max_pool_size : u32, +} + #[derive(Debug, Deserialize)] pub struct Webserver { pub bind_address : String, @@ -97,6 +107,7 @@ pub struct Webserver { pub struct Settings { pub app : App, pub log : Log, + pub database : Database, pub webserver : Webserver, } @@ -121,6 +132,14 @@ Ajustes globales y valores predeterminados para las secciones *\[app\]*, "log.prefix" => "tracing.log", "log.format" => "json", + // [database] + "database.db_name" => "dbname", + "database.db_user" => "dbuser", + "database.db_pass" => "dbpass", + "database.db_host" => "localhost", + "database.db_port" => 0, + "database.max_pool_size" => 5, + // [webserver] "webserver.bind_address" => "localhost", "webserver.bind_port" => 8088 diff --git a/src/core/server/app.rs b/src/core/server/app.rs new file mode 100644 index 00000000..3861c412 --- /dev/null +++ b/src/core/server/app.rs @@ -0,0 +1,138 @@ +use crate::{Lazy, base, locale, trace}; +use crate::config::SETTINGS; +use crate::core::{Server, global, server}; +use crate::core::theme::register_theme; +use crate::core::module::register_module; + +use std::io::Error; +use actix_web::middleware::normalize::{NormalizePath, TrailingSlash}; + +pub struct Application { + server: Server, +} + +impl Application { + pub async fn build(bootstrap: Option<fn()>) -> Result<Self, Error> { + // Imprime rótulo (opcional) de bienvenida. + if SETTINGS.app.startup_banner.to_lowercase() != "off" { + let figfont = figlet_rs::FIGfont::from_content( + match SETTINGS.app.startup_banner.to_lowercase().as_str() { + "slant" => include_str!("figfonts/slant.flf"), + "small" => include_str!("figfonts/small.flf"), + "speed" => include_str!("figfonts/speed.flf"), + "starwars" => include_str!("figfonts/starwars.flf"), + _ => { + println!( + "FIGfont \"{}\" not found for banner. {}. {}.", + SETTINGS.app.startup_banner, + "Using \"Small\"", + "Check the settings file", + ); + include_str!("figfonts/small.flf") + } + } + ).unwrap(); + println!("\n{} {}\n\n Powered by PageTop {}\n", + figfont.convert(&SETTINGS.app.name).unwrap(), + &SETTINGS.app.description, + env!("CARGO_PKG_VERSION") + ); + } + + // Inicia registro de trazas y eventos. + Lazy::force(&server::tracing::TRACING); + + // Valida el identificador de idioma. + Lazy::force(&locale::LANGID); + + // Inicializa la conexión con la base de datos. + trace::info!( + "Connecting to database \"{}\" with a pool of {} connections.", + &SETTINGS.database.db_name, + &SETTINGS.database.max_pool_size + ); + + #[cfg(any(feature = "default", feature = "mysql"))] + let db_uri = format!( + "mysql://{}/{}", + &SETTINGS.database.db_host, + &SETTINGS.database.db_name + ); + + #[cfg(feature = "postgres")] + let db_uri = format!( + "postgres://{}/{}", + &SETTINGS.database.db_host, + &SETTINGS.database.db_name + ); + + #[cfg(feature = "sqlite")] + let db_uri = format!("sqlite://{}", &SETTINGS.database.db_name); + + let mut uri = url::Url::parse(&db_uri).unwrap(); + + // https://github.com/launchbadge/sqlx/issues/1624 + + #[cfg(not(feature = "sqlite"))] + uri.set_username(&SETTINGS.database.db_user.as_str()).unwrap(); + + #[cfg(not(feature = "sqlite"))] + uri.set_password(Some(&SETTINGS.database.db_pass.as_str())).unwrap(); + + #[cfg(not(feature = "sqlite"))] + if SETTINGS.database.db_port != 0 { + uri.set_port(Some(SETTINGS.database.db_port)).unwrap(); + } + + let mut db_options = sea_orm::ConnectOptions::new(uri.to_string()); + db_options.max_connections(SETTINGS.database.max_pool_size); + + let mut db_conn = server::dbconn::DBCONN.write().unwrap(); + *db_conn = Some( + sea_orm::Database::connect::<sea_orm::ConnectOptions>( + db_options.into() + ) + .await + .expect("Failed to connect to database") + ); + + // Registra los temas predefinidos. + register_theme(&base::theme::aliner::AlinerTheme); + register_theme(&base::theme::minimal::MinimalTheme); + register_theme(&base::theme::bootsier::BootsierTheme); + + // Registra los módulos predeterminados. + register_module(&base::module::admin::AdminModule); + register_module(&base::module::user::UserModule); + + // Ejecuta la función de inicio de la aplicación. + if bootstrap != None { + trace::debug!("Calling application bootstrap"); + let _ = &(bootstrap.unwrap())(); + } + + // Registra el módulo para la página de inicio de PageTop. + // Al ser el último, puede sobrecargarse con la función de inicio. + register_module(&base::module::homepage::HomepageModule); + + // Prepara el servidor web. + let server = server::HttpServer::new(|| { + server::App::new() + .wrap(tracing_actix_web::TracingLogger) + .wrap(NormalizePath::new(TrailingSlash::Trim)) + .configure(&global::themes) + .configure(&global::modules) + }) + .bind(format!("{}:{}", + &SETTINGS.webserver.bind_address, + &SETTINGS.webserver.bind_port + ))? + .run(); + + Ok(Self { server }) + } + + pub fn run(self) -> Result<Server, Error> { + Ok(self.server) + } +} diff --git a/src/core/server/dbconn.rs b/src/core/server/dbconn.rs new file mode 100644 index 00000000..e80629fc --- /dev/null +++ b/src/core/server/dbconn.rs @@ -0,0 +1,8 @@ +use crate::Lazy; +use crate::database::DatabaseConnection; + +use std::sync::RwLock; + +pub static DBCONN: Lazy<RwLock<Option<DatabaseConnection>>> = Lazy::new(|| { + RwLock::new(None) +}); diff --git a/src/core/server/main.rs b/src/core/server/main.rs deleted file mode 100644 index b6800142..00000000 --- a/src/core/server/main.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::{Lazy, base, locale, trace}; -use crate::config::SETTINGS; -use crate::core::{Server, global, server}; -use crate::core::theme::register_theme; -use crate::core::module::register_module; - -use actix_web::middleware::normalize; - -pub fn run(bootstrap: Option<fn()>) -> Result<Server, std::io::Error> { - // Imprime el rótulo (opcional) de bienvenida. - if SETTINGS.app.startup_banner.to_lowercase() != "off" { - let figfont = figlet_rs::FIGfont::from_content( - match SETTINGS.app.startup_banner.to_lowercase().as_str() { - "slant" => include_str!("figfonts/slant.flf"), - "small" => include_str!("figfonts/small.flf"), - "speed" => include_str!("figfonts/speed.flf"), - "starwars" => include_str!("figfonts/starwars.flf"), - _ => { - println!( - "FIGfont \"{}\" not found for banner. {}. {}.", - SETTINGS.app.startup_banner, - "Using \"Small\"", - "Check the settings file", - ); - include_str!("figfonts/small.flf") - } - } - ).unwrap(); - println!("\n{} {}\n\n Powered by PageTop {}\n", - figfont.convert(&SETTINGS.app.name).unwrap(), - &SETTINGS.app.description, - env!("CARGO_PKG_VERSION") - ); - } - - // Inicia registro de trazas y eventos. - Lazy::force(&server::tracing::TRACING); - - // Asigna identificador de idioma. - Lazy::force(&locale::LANGID); - - // Registra los temas predefinidos. - register_theme(&base::theme::aliner::AlinerTheme); - register_theme(&base::theme::minimal::MinimalTheme); - register_theme(&base::theme::bootsier::BootsierTheme); - - // Registra los módulos predeterminados. - register_module(&base::module::admin::AdminModule); - register_module(&base::module::user::UserModule); - - // Ejecuta la función de inicio de la aplicación. - if bootstrap != None { - trace::debug!("Calling application bootstrap"); - let _ = &(bootstrap.unwrap())(); - } - - // Registra el módulo para la página de inicio de PageTop. - // Al ser el último, puede sobrecargarse en la función de arranque. - register_module(&base::module::homepage::HomepageModule); - - - // Inicializa el servidor web. - let server = server::HttpServer::new(|| { - server::App::new() - .wrap(tracing_actix_web::TracingLogger) - .wrap(normalize::NormalizePath::new(normalize::TrailingSlash::Trim)) - .configure(&global::themes) - .configure(&global::modules) - }) - .bind(format!("{}:{}", - &SETTINGS.webserver.bind_address, - &SETTINGS.webserver.bind_port - ))? - .run(); - Ok(server) -} diff --git a/src/core/server/mod.rs b/src/core/server/mod.rs index 7db53759..8699b8d1 100644 --- a/src/core/server/mod.rs +++ b/src/core/server/mod.rs @@ -4,5 +4,7 @@ pub use actix_web::{ mod tracing; -mod main; -pub use main::run; +mod dbconn; + +mod app; +pub use app::Application; diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 00000000..cd70e401 --- /dev/null +++ b/src/database.rs @@ -0,0 +1 @@ +pub use sea_orm::DatabaseConnection; diff --git a/src/lib.rs b/src/lib.rs index 7d17db44..a01548ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,8 +10,11 @@ pub use once_cell::sync::Lazy; pub mod config; // Gestión de la configuración. pub mod trace; // Registro de trazas y eventos de la aplicación. pub mod locale; // Localización. +pub mod database; // Acceso a la base de datos. pub mod core; // Servidor web y sistemas para Temas, Módulos y Respuestas. pub mod base; // Temas, Módulos y Componentes base. pub mod util; // Macros y funciones útiles. pub mod prelude; // Re-exporta recursos comunes. + +pub use crate::core::server::Application; diff --git a/src/locale.rs b/src/locale.rs index e3639858..07cb0d8e 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -44,12 +44,12 @@ macro_rules! localize { } #[allow(dead_code)] - pub fn l(key: &str) -> String { + fn l(key: &str) -> String { LOCALES.lookup(&LANGID, key) } #[allow(dead_code)] - pub fn t( + fn t( key: &str, args: &std::collections::HashMap<String, FluentValue> ) -> String { @@ -57,7 +57,7 @@ macro_rules! localize { } #[allow(dead_code)] - pub fn e( + fn e( key: &str, args: &std::collections::HashMap<String, FluentValue> ) -> crate::core::theme::PreEscaped<String> { diff --git a/src/main.rs b/src/main.rs index 8559a909..30df2f36 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,8 @@ #[actix_web::main] async fn main() -> std::io::Result<()> { - pagetop::core::server::run(None)?.await + // ``` + // let app = pagetop::Application::build(None).await?; + // app.run()?.await + // ``` + pagetop::Application::build(None).await?.run()?.await } diff --git a/src/prelude.rs b/src/prelude.rs index 94630400..6ca17039 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -6,6 +6,7 @@ pub use crate::util; pub use crate::config::SETTINGS; pub use crate::trace; pub use crate::localize; +pub use crate::database; pub use crate::core::theme::*; pub use crate::core::module::*; From 619b7b73c6564260be2182f9e5e0adf0a7c89017 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 12 Mar 2022 01:39:08 +0100 Subject: [PATCH 024/244] =?UTF-8?q?A=C3=B1ade=20migraci=C3=B3n=20de=20BD?= =?UTF-8?q?=20usando=20Refinery=20y=20Barrel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Realmente esta funcionalidad se va a sustituir por alguna otra librería ya que Refinery usa un único número de versión que dificulta su uso en un contexto de módulos independientes con migraciones propias. --- Cargo.toml | 26 ++++--- STARTER.Cargo.toml | 1 + .../migrations/V1__create_table_system.rs | 13 ++++ src/base/module/admin/mod.rs | 5 ++ .../user/migrations/V1__create_table_user.rs | 13 ++++ src/base/module/user/mod.rs | 5 ++ src/core/global.rs | 14 +++- src/core/module/definition.rs | 5 ++ src/core/server/app.rs | 73 +++++++++---------- src/core/server/dbconn.rs | 8 -- src/core/server/mod.rs | 2 - src/database.rs | 1 - src/db.rs | 17 +++++ src/lib.rs | 4 +- src/prelude.rs | 4 +- 15 files changed, 129 insertions(+), 62 deletions(-) create mode 100644 src/base/module/admin/migrations/V1__create_table_system.rs create mode 100644 src/base/module/user/migrations/V1__create_table_user.rs delete mode 100644 src/core/server/dbconn.rs delete mode 100644 src/database.rs create mode 100644 src/db.rs diff --git a/Cargo.toml b/Cargo.toml index d28a0e33..7aa29cae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,6 @@ once_cell = "1.9.0" figlet-rs = "0.1.3" config_rs = { package = "config", version = "0.11.0", features = ["toml"] } -url = "2.2.2" tracing = "0.1" tracing-appender = "0.2" @@ -44,24 +43,31 @@ actix-web-static-files = "3.0.5" maud = { version = "0.23.0", features = ["actix-web"] } sycamore = { version = "0.7.1", features = ["ssr"] } + downcast-rs = "1.2.0" +url = "2.2.2" serde = { version = "1.0", features = ["derive"] } -[dependencies.sea-orm] -version = "0.6" -features = ["macros", "debug-print", "runtime-async-std-native-tls"] +[dependencies.sqlx] +version = "0.5.11" +features = ["migrate", "runtime-async-std-native-tls"] default-features = false +[dependencies.refinery] +version = "0.8.4" + +[dependencies.barrel] +version = "0.7.0" + +[features] +default = ["mysql"] +mysql = ["sqlx/mysql", "refinery/mysql", "barrel/mysql"] +postgres = ["sqlx/postgres", "refinery/postgres", "barrel/pg"] + [build-dependencies] actix-web-static-files = "3.0.5" -[features] -default = ["sea-orm/sqlx-mysql"] -mysql = ["sea-orm/sqlx-mysql"] -postgres = ["sea-orm/sqlx-postgres"] -sqlite = ["sea-orm/sqlx-sqlite"] - [lib] name = "pagetop" diff --git a/STARTER.Cargo.toml b/STARTER.Cargo.toml index 1db51f3d..08b251e7 100644 --- a/STARTER.Cargo.toml +++ b/STARTER.Cargo.toml @@ -10,3 +10,4 @@ edition = "2021" pagetop = { path = "pagetop" } actix-web = "3.3.3" maud = { version = "0.23.0" } +serde = { version = "1.0", features = ["derive"] } diff --git a/src/base/module/admin/migrations/V1__create_table_system.rs b/src/base/module/admin/migrations/V1__create_table_system.rs new file mode 100644 index 00000000..2cd6196a --- /dev/null +++ b/src/base/module/admin/migrations/V1__create_table_system.rs @@ -0,0 +1,13 @@ +use crate::prelude::*; + +pub fn migration() -> String { + let mut m = db::Migration::new(); + + m.create_table("system", |t| { + t.add_column("id", db::types::primary()); + t.add_column("title", db::types::varchar(255)); + t.add_column("is_completed", db::types::boolean().default(false)); + }); + + m.make::<db::Database>() +} diff --git a/src/base/module/admin/mod.rs b/src/base/module/admin/mod.rs index 0bb1202d..52079841 100644 --- a/src/base/module/admin/mod.rs +++ b/src/base/module/admin/mod.rs @@ -1,6 +1,7 @@ use crate::prelude::*; localize!("en-US", "src/base/module/admin/locales"); +embed_migrations!("src/base/module/admin/migrations"); mod summary; @@ -25,4 +26,8 @@ impl Module for AdminModule { .route("", server::web::get().to(summary::summary)) ); } + + fn configure_migrations(&self) -> Option<db::Migrations> { + Some(migrations::runner()) + } } diff --git a/src/base/module/user/migrations/V1__create_table_user.rs b/src/base/module/user/migrations/V1__create_table_user.rs new file mode 100644 index 00000000..9bc4e823 --- /dev/null +++ b/src/base/module/user/migrations/V1__create_table_user.rs @@ -0,0 +1,13 @@ +use crate::prelude::*; + +pub fn migration() -> String { + let mut m = db::Migration::new(); + + m.create_table("user", |t| { + t.add_column("id", db::types::primary()); + t.add_column("title", db::types::varchar(255)); + t.add_column("is_completed", db::types::boolean().default(false)); + }); + + m.make::<db::Database>() +} diff --git a/src/base/module/user/mod.rs b/src/base/module/user/mod.rs index 73ab7d16..48c69820 100644 --- a/src/base/module/user/mod.rs +++ b/src/base/module/user/mod.rs @@ -1,6 +1,7 @@ use crate::prelude::*; localize!("en-US", "src/base/module/user/locales"); +embed_migrations!("src/base/module/user/migrations"); pub struct UserModule; @@ -20,6 +21,10 @@ impl Module for UserModule { fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { cfg.route("/user/login", server::web::get().to(login)); } + + fn configure_migrations(&self) -> Option<db::Migrations> { + Some(migrations::runner()) + } } fn form_login() -> impl PageComponent { diff --git a/src/core/global.rs b/src/core/global.rs index 1d64d44f..7798d06d 100644 --- a/src/core/global.rs +++ b/src/core/global.rs @@ -1,4 +1,4 @@ -use crate::Lazy; +use crate::{Lazy, db}; use crate::core::theme::Theme; use crate::core::module::Module; use crate::core::response::page::PageContainer; @@ -42,6 +42,18 @@ pub fn modules(cfg: &mut server::web::ServiceConfig) { } } +pub fn migrations(db_uri: db::Uri) { + let mut conn = refinery::config::Config::try_from(db_uri).unwrap(); + for m in MODULES.read().unwrap().iter() { + match m.configure_migrations() { + Some(migrations) => { + migrations.run(&mut conn).expect("Failed to run migrations"); + }, + _ => {} + }; + } +} + // ----------------------------------------------------------------------------- // Componentes globales. // ----------------------------------------------------------------------------- diff --git a/src/core/module/definition.rs b/src/core/module/definition.rs index 40e9cee8..3f1e1e3d 100644 --- a/src/core/module/definition.rs +++ b/src/core/module/definition.rs @@ -1,3 +1,4 @@ +use crate::db; use crate::core::server; /// Los módulos deben implementar este *trait*. @@ -13,4 +14,8 @@ pub trait Module: Send + Sync { #[allow(unused_variables)] fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { } + + fn configure_migrations(&self) -> Option<db::Migrations> { + None + } } diff --git a/src/core/server/app.rs b/src/core/server/app.rs index 3861c412..d758d850 100644 --- a/src/core/server/app.rs +++ b/src/core/server/app.rs @@ -1,12 +1,23 @@ -use crate::{Lazy, base, locale, trace}; +use crate::{Lazy, base, db, locale, trace}; use crate::config::SETTINGS; use crate::core::{Server, global, server}; use crate::core::theme::register_theme; use crate::core::module::register_module; use std::io::Error; +use std::sync::RwLock; use actix_web::middleware::normalize::{NormalizePath, TrailingSlash}; +#[cfg(feature = "mysql")] +use sqlx::mysql::MySqlPoolOptions as DbPoolOptions; + +#[cfg(feature = "postgres")] +use sqlx::postgres::PgPoolOptions as DbPoolOptions; + +static DBCONN: Lazy<RwLock<Option<db::Conn>>> = Lazy::new(|| { + RwLock::new(None) +}); + pub struct Application { server: Server, } @@ -52,49 +63,33 @@ impl Application { &SETTINGS.database.max_pool_size ); - #[cfg(any(feature = "default", feature = "mysql"))] - let db_uri = format!( - "mysql://{}/{}", - &SETTINGS.database.db_host, - &SETTINGS.database.db_name - ); + #[cfg(feature = "mysql")] + let db_type = "mysql"; #[cfg(feature = "postgres")] - let db_uri = format!( - "postgres://{}/{}", - &SETTINGS.database.db_host, - &SETTINGS.database.db_name - ); - - #[cfg(feature = "sqlite")] - let db_uri = format!("sqlite://{}", &SETTINGS.database.db_name); - - let mut uri = url::Url::parse(&db_uri).unwrap(); + let db_type = "postgres"; // https://github.com/launchbadge/sqlx/issues/1624 - - #[cfg(not(feature = "sqlite"))] - uri.set_username(&SETTINGS.database.db_user.as_str()).unwrap(); - - #[cfg(not(feature = "sqlite"))] - uri.set_password(Some(&SETTINGS.database.db_pass.as_str())).unwrap(); - - #[cfg(not(feature = "sqlite"))] + let mut db_uri = db::Uri::parse(format!( + "{}://{}/{}", + db_type, + &SETTINGS.database.db_host, + &SETTINGS.database.db_name + ).as_str()).unwrap(); + db_uri.set_username(&SETTINGS.database.db_user.as_str()).unwrap(); + db_uri.set_password(Some(&SETTINGS.database.db_pass.as_str())).unwrap(); if SETTINGS.database.db_port != 0 { - uri.set_port(Some(SETTINGS.database.db_port)).unwrap(); + db_uri.set_port(Some(SETTINGS.database.db_port)).unwrap(); } - let mut db_options = sea_orm::ConnectOptions::new(uri.to_string()); - db_options.max_connections(SETTINGS.database.max_pool_size); - - let mut db_conn = server::dbconn::DBCONN.write().unwrap(); - *db_conn = Some( - sea_orm::Database::connect::<sea_orm::ConnectOptions>( - db_options.into() - ) + let db_pool = DbPoolOptions::new() + .max_connections(SETTINGS.database.max_pool_size) + .connect(db_uri.as_str()) .await - .expect("Failed to connect to database") - ); + .expect("Failed to connect to database"); + + let mut dbconn = DBCONN.write().unwrap(); + *dbconn = Some(db_pool); // Registra los temas predefinidos. register_theme(&base::theme::aliner::AlinerTheme); @@ -107,7 +102,7 @@ impl Application { // Ejecuta la función de inicio de la aplicación. if bootstrap != None { - trace::debug!("Calling application bootstrap"); + trace::info!("Calling application bootstrap."); let _ = &(bootstrap.unwrap())(); } @@ -115,6 +110,10 @@ impl Application { // Al ser el último, puede sobrecargarse con la función de inicio. register_module(&base::module::homepage::HomepageModule); + // Run migrations. + trace::info!("Running migrations."); + global::migrations(db_uri); + // Prepara el servidor web. let server = server::HttpServer::new(|| { server::App::new() diff --git a/src/core/server/dbconn.rs b/src/core/server/dbconn.rs deleted file mode 100644 index e80629fc..00000000 --- a/src/core/server/dbconn.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::Lazy; -use crate::database::DatabaseConnection; - -use std::sync::RwLock; - -pub static DBCONN: Lazy<RwLock<Option<DatabaseConnection>>> = Lazy::new(|| { - RwLock::new(None) -}); diff --git a/src/core/server/mod.rs b/src/core/server/mod.rs index 8699b8d1..ef85b53c 100644 --- a/src/core/server/mod.rs +++ b/src/core/server/mod.rs @@ -4,7 +4,5 @@ pub use actix_web::{ mod tracing; -mod dbconn; - mod app; pub use app::Application; diff --git a/src/database.rs b/src/database.rs deleted file mode 100644 index cd70e401..00000000 --- a/src/database.rs +++ /dev/null @@ -1 +0,0 @@ -pub use sea_orm::DatabaseConnection; diff --git a/src/db.rs b/src/db.rs new file mode 100644 index 00000000..c754be9c --- /dev/null +++ b/src/db.rs @@ -0,0 +1,17 @@ +pub use url::Url as Uri; + +#[cfg(feature = "mysql")] +pub use { + barrel::backend::MySql as Database, + sqlx::MySqlPool as Conn, +}; + +#[cfg(feature = "postgres")] +pub use { + barrel::backend::Pg as Database, + sqlx::PgPool as Conn, +}; + +pub use barrel::{Migration, types}; +pub use refinery::embed_migrations; +pub use refinery::Runner as Migrations; diff --git a/src/lib.rs b/src/lib.rs index a01548ba..a3906783 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,8 +10,8 @@ pub use once_cell::sync::Lazy; pub mod config; // Gestión de la configuración. pub mod trace; // Registro de trazas y eventos de la aplicación. pub mod locale; // Localización. -pub mod database; // Acceso a la base de datos. -pub mod core; // Servidor web y sistemas para Temas, Módulos y Respuestas. +pub mod db; // Acceso a la base de datos. +pub mod core; // Servidor web y APIs para Temas, Módulos y Respuestas web. pub mod base; // Temas, Módulos y Componentes base. pub mod util; // Macros y funciones útiles. diff --git a/src/prelude.rs b/src/prelude.rs index 6ca17039..f168e92f 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -6,7 +6,9 @@ pub use crate::util; pub use crate::config::SETTINGS; pub use crate::trace; pub use crate::localize; -pub use crate::database; + +pub use crate::db; +pub use crate::db::embed_migrations; pub use crate::core::theme::*; pub use crate::core::module::*; From 4b5d8ce38ac9932c7df9b8b54aad1326a0de50e8 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 13 Mar 2022 00:19:05 +0100 Subject: [PATCH 025/244] Elimina Refinery y Barrel en favor de SeaORM Se integran las funcionalidades de SeaORM en el funcionamiento de PageTop para abstraer el uso y acceso a la base de datos. --- Cargo.toml | 29 +++++----- .../migrations/V1__create_table_system.rs | 13 ----- src/base/module/admin/mod.rs | 5 -- src/base/module/user/entity/mod.rs | 1 + src/base/module/user/entity/user.rs | 18 +++++++ .../m20220312_000001_create_table_user.rs | 54 +++++++++++++++++++ src/base/module/user/migration/mod.rs | 12 +++++ .../user/migrations/V1__create_table_user.rs | 13 ----- src/base/module/user/mod.rs | 8 +-- src/core/global.rs | 10 +--- src/core/module/definition.rs | 5 +- src/core/server/app.rs | 32 ++++------- src/db.rs | 23 ++++---- src/lib.rs | 1 + src/prelude.rs | 9 ++-- src/util.rs | 15 +++++- 16 files changed, 150 insertions(+), 98 deletions(-) delete mode 100644 src/base/module/admin/migrations/V1__create_table_system.rs create mode 100644 src/base/module/user/entity/mod.rs create mode 100644 src/base/module/user/entity/user.rs create mode 100644 src/base/module/user/migration/m20220312_000001_create_table_user.rs create mode 100644 src/base/module/user/migration/mod.rs delete mode 100644 src/base/module/user/migrations/V1__create_table_user.rs diff --git a/Cargo.toml b/Cargo.toml index 7aa29cae..0c3a0a43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,8 +25,11 @@ categories = [ [dependencies] doc-comment = "0.3.3" -once_cell = "1.9.0" -figlet-rs = "0.1.3" +downcast-rs = "1.2.0" +figlet-rs = "0.1.3" +futures = "0.3" +once_cell = "1.9.0" +url = "2.2.2" config_rs = { package = "config", version = "0.11.0", features = ["toml"] } @@ -44,26 +47,22 @@ actix-web-static-files = "3.0.5" maud = { version = "0.23.0", features = ["actix-web"] } sycamore = { version = "0.7.1", features = ["ssr"] } -downcast-rs = "1.2.0" -url = "2.2.2" - serde = { version = "1.0", features = ["derive"] } -[dependencies.sqlx] -version = "0.5.11" -features = ["migrate", "runtime-async-std-native-tls"] +[dependencies.sea-orm] +version = "0.6" +features = ["debug-print", "macros", "runtime-async-std-native-tls"] default-features = false -[dependencies.refinery] -version = "0.8.4" - -[dependencies.barrel] -version = "0.7.0" +[dependencies.sea-schema] +version = "0.5" +features = ["debug-print", "migration"] +default-features = false [features] default = ["mysql"] -mysql = ["sqlx/mysql", "refinery/mysql", "barrel/mysql"] -postgres = ["sqlx/postgres", "refinery/postgres", "barrel/pg"] +mysql = ["sea-orm/sqlx-mysql"] +postgres = ["sea-orm/sqlx-postgres"] [build-dependencies] actix-web-static-files = "3.0.5" diff --git a/src/base/module/admin/migrations/V1__create_table_system.rs b/src/base/module/admin/migrations/V1__create_table_system.rs deleted file mode 100644 index 2cd6196a..00000000 --- a/src/base/module/admin/migrations/V1__create_table_system.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::prelude::*; - -pub fn migration() -> String { - let mut m = db::Migration::new(); - - m.create_table("system", |t| { - t.add_column("id", db::types::primary()); - t.add_column("title", db::types::varchar(255)); - t.add_column("is_completed", db::types::boolean().default(false)); - }); - - m.make::<db::Database>() -} diff --git a/src/base/module/admin/mod.rs b/src/base/module/admin/mod.rs index 52079841..0bb1202d 100644 --- a/src/base/module/admin/mod.rs +++ b/src/base/module/admin/mod.rs @@ -1,7 +1,6 @@ use crate::prelude::*; localize!("en-US", "src/base/module/admin/locales"); -embed_migrations!("src/base/module/admin/migrations"); mod summary; @@ -26,8 +25,4 @@ impl Module for AdminModule { .route("", server::web::get().to(summary::summary)) ); } - - fn configure_migrations(&self) -> Option<db::Migrations> { - Some(migrations::runner()) - } } diff --git a/src/base/module/user/entity/mod.rs b/src/base/module/user/entity/mod.rs new file mode 100644 index 00000000..22d12a38 --- /dev/null +++ b/src/base/module/user/entity/mod.rs @@ -0,0 +1 @@ +pub mod user; diff --git a/src/base/module/user/entity/user.rs b/src/base/module/user/entity/user.rs new file mode 100644 index 00000000..d0db4a98 --- /dev/null +++ b/src/base/module/user/entity/user.rs @@ -0,0 +1,18 @@ +use crate::db::entity::*; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize)] +#[sea_orm(table_name = "user")] +pub struct Model { + #[sea_orm(primary_key)] + #[serde(skip_deserializing)] + pub id: i32, + pub title: String, + #[sea_orm(column_type = "Text")] + pub text: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/base/module/user/migration/m20220312_000001_create_table_user.rs b/src/base/module/user/migration/m20220312_000001_create_table_user.rs new file mode 100644 index 00000000..729b72e0 --- /dev/null +++ b/src/base/module/user/migration/m20220312_000001_create_table_user.rs @@ -0,0 +1,54 @@ +use crate::db::migration::*; + +#[derive(Iden)] +enum User { + Table, + Id, + Title, + Text, +} + +pub struct Migration; + +impl MigrationName for Migration { + fn name(&self) -> &str { + "m20220312_000001_create_table_user" + } +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(User::Table) + .if_not_exists() + .col(ColumnDef::new(User::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(User::Title) + .string() + .not_null() + ) + .col(ColumnDef::new(User::Text) + .string() + .not_null() + ) + .to_owned() + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop() + .table(User::Table) + .to_owned() + ) + .await + } +} diff --git a/src/base/module/user/migration/mod.rs b/src/base/module/user/migration/mod.rs new file mode 100644 index 00000000..8b9167a6 --- /dev/null +++ b/src/base/module/user/migration/mod.rs @@ -0,0 +1,12 @@ +use crate::db::migration::*; + +pub mod m20220312_000001_create_table_user; + +pub struct Migrator; + +#[async_trait::async_trait] +impl MigratorTrait for Migrator { + fn migrations() -> Vec<Box<dyn MigrationTrait>> { + vec![Box::new(m20220312_000001_create_table_user::Migration)] + } +} diff --git a/src/base/module/user/migrations/V1__create_table_user.rs b/src/base/module/user/migrations/V1__create_table_user.rs deleted file mode 100644 index 9bc4e823..00000000 --- a/src/base/module/user/migrations/V1__create_table_user.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::prelude::*; - -pub fn migration() -> String { - let mut m = db::Migration::new(); - - m.create_table("user", |t| { - t.add_column("id", db::types::primary()); - t.add_column("title", db::types::varchar(255)); - t.add_column("is_completed", db::types::boolean().default(false)); - }); - - m.make::<db::Database>() -} diff --git a/src/base/module/user/mod.rs b/src/base/module/user/mod.rs index 48c69820..7dc3c043 100644 --- a/src/base/module/user/mod.rs +++ b/src/base/module/user/mod.rs @@ -1,7 +1,9 @@ use crate::prelude::*; localize!("en-US", "src/base/module/user/locales"); -embed_migrations!("src/base/module/user/migrations"); + +mod entity; +mod migration; pub struct UserModule; @@ -22,8 +24,8 @@ impl Module for UserModule { cfg.route("/user/login", server::web::get().to(login)); } - fn configure_migrations(&self) -> Option<db::Migrations> { - Some(migrations::runner()) + fn migrations(&self, dbconn: &db::DbConn) -> Result<(), db::DbErr> { + db_migrations!(dbconn) } } diff --git a/src/core/global.rs b/src/core/global.rs index 7798d06d..0879fe4c 100644 --- a/src/core/global.rs +++ b/src/core/global.rs @@ -42,15 +42,9 @@ pub fn modules(cfg: &mut server::web::ServiceConfig) { } } -pub fn migrations(db_uri: db::Uri) { - let mut conn = refinery::config::Config::try_from(db_uri).unwrap(); +pub fn migrations(dbconn: &db::DbConn) { for m in MODULES.read().unwrap().iter() { - match m.configure_migrations() { - Some(migrations) => { - migrations.run(&mut conn).expect("Failed to run migrations"); - }, - _ => {} - }; + m.migrations(dbconn).expect("Failed to run migrations"); } } diff --git a/src/core/module/definition.rs b/src/core/module/definition.rs index 3f1e1e3d..e11efd2e 100644 --- a/src/core/module/definition.rs +++ b/src/core/module/definition.rs @@ -15,7 +15,8 @@ pub trait Module: Send + Sync { fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { } - fn configure_migrations(&self) -> Option<db::Migrations> { - None + #[allow(unused_variables)] + fn migrations(&self, dbconn: &db::DbConn) -> Result<(), db::DbErr> { + Ok(()) } } diff --git a/src/core/server/app.rs b/src/core/server/app.rs index d758d850..1f2ec7f3 100644 --- a/src/core/server/app.rs +++ b/src/core/server/app.rs @@ -5,19 +5,8 @@ use crate::core::theme::register_theme; use crate::core::module::register_module; use std::io::Error; -use std::sync::RwLock; use actix_web::middleware::normalize::{NormalizePath, TrailingSlash}; -#[cfg(feature = "mysql")] -use sqlx::mysql::MySqlPoolOptions as DbPoolOptions; - -#[cfg(feature = "postgres")] -use sqlx::postgres::PgPoolOptions as DbPoolOptions; - -static DBCONN: Lazy<RwLock<Option<db::Conn>>> = Lazy::new(|| { - RwLock::new(None) -}); - pub struct Application { server: Server, } @@ -70,7 +59,7 @@ impl Application { let db_type = "postgres"; // https://github.com/launchbadge/sqlx/issues/1624 - let mut db_uri = db::Uri::parse(format!( + let mut db_uri = db::DbUri::parse(format!( "{}://{}/{}", db_type, &SETTINGS.database.db_host, @@ -82,14 +71,14 @@ impl Application { db_uri.set_port(Some(SETTINGS.database.db_port)).unwrap(); } - let db_pool = DbPoolOptions::new() - .max_connections(SETTINGS.database.max_pool_size) - .connect(db_uri.as_str()) - .await - .expect("Failed to connect to database"); + let mut db_options = sea_orm::ConnectOptions::new(db_uri.to_string()); + db_options.max_connections(SETTINGS.database.max_pool_size); - let mut dbconn = DBCONN.write().unwrap(); - *dbconn = Some(db_pool); + let dbconn = sea_orm::Database::connect::<sea_orm::ConnectOptions>( + db_options.into() + ) + .await + .expect("Failed to connect to database"); // Registra los temas predefinidos. register_theme(&base::theme::aliner::AlinerTheme); @@ -112,13 +101,14 @@ impl Application { // Run migrations. trace::info!("Running migrations."); - global::migrations(db_uri); + global::migrations(&dbconn); // Prepara el servidor web. - let server = server::HttpServer::new(|| { + let server = server::HttpServer::new(move || { server::App::new() .wrap(tracing_actix_web::TracingLogger) .wrap(NormalizePath::new(TrailingSlash::Trim)) + .data(dbconn.clone()) .configure(&global::themes) .configure(&global::modules) }) diff --git a/src/db.rs b/src/db.rs index c754be9c..fb3f789e 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,17 +1,14 @@ -pub use url::Url as Uri; +pub use url::Url as DbUri; -#[cfg(feature = "mysql")] -pub use { - barrel::backend::MySql as Database, - sqlx::MySqlPool as Conn, +pub use sea_orm::{ + DbErr, + DatabaseConnection as DbConn, }; -#[cfg(feature = "postgres")] -pub use { - barrel::backend::Pg as Database, - sqlx::PgPool as Conn, -}; +pub mod entity { + pub use sea_orm::entity::prelude::*; +} -pub use barrel::{Migration, types}; -pub use refinery::embed_migrations; -pub use refinery::Runner as Migrations; +pub mod migration { + pub use sea_schema::migration::prelude::*; +} diff --git a/src/lib.rs b/src/lib.rs index a3906783..8d75fb08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ pub use doc_comment::doc_comment; pub use once_cell::sync::Lazy; +pub use futures::executor::block_on as run_now; // ----------------------------------------------------------------------------- // APIs públicas. diff --git a/src/prelude.rs b/src/prelude.rs index f168e92f..bcff745b 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,14 +1,15 @@ //! Re-exporta recursos comunes. -pub use crate::args; -pub use crate::util; +pub use crate::{ + args, + db_migrations, +}; pub use crate::config::SETTINGS; pub use crate::trace; pub use crate::localize; pub use crate::db; -pub use crate::db::embed_migrations; pub use crate::core::theme::*; pub use crate::core::module::*; @@ -16,3 +17,5 @@ pub use crate::core::response::page::*; pub use crate::core::server; pub use crate::base::component::*; + +pub use crate::util; diff --git a/src/util.rs b/src/util.rs index 3fff0a23..5150d517 100644 --- a/src/util.rs +++ b/src/util.rs @@ -9,15 +9,26 @@ /// ]; /// ``` macro_rules! args { - ( $($key:expr => $value:expr),* ) => {{ + ( $($KEY:expr => $VALUE:expr),* ) => {{ let mut a = std::collections::HashMap::new(); $( - a.insert(String::from($key), $value.into()); + a.insert(String::from($KEY), $VALUE.into()); )* a }}; } +#[macro_export] +macro_rules! db_migrations { + ( $DBCONN:ident ) => {{ + $crate::run_now({ + use $crate::db::migration::MigratorTrait; + + migration::Migrator::up($DBCONN, None) + }) + }}; +} + pub fn valid_id(id: &str) -> Option<String> { let id = id.trim().replace(" ", "_").to_lowercase(); match id.is_empty() { From ab0ac11f65fe50fc65a9190094643ec50ae05949 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 13 Mar 2022 11:14:33 +0100 Subject: [PATCH 026/244] =?UTF-8?q?Modifica=20la=20estructura=20general=20?= =?UTF-8?q?del=20c=C3=B3digo=20fuente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Importante actualización que reorganiza el código fuente de PageTop. Usa Cargo para crear un espacio de trabajo con los diferentes proyectos que estructuran las funcionalidades de PageTop en módulos interdependientes que se integran en Drust para construir una solución web para la gestión de contenidos. --- Cargo.toml | 79 ++---------------- config/default.toml | 21 ++++- drust/Cargo.toml | 19 +++++ {src => drust/src}/main.rs | 4 - pagetop/Cargo.toml | 71 ++++++++++++++++ .../STARTER.Cargo.toml | 0 build.rs => pagetop/build.rs | 0 .../config}/settings.default.toml | 0 {src => pagetop/src}/base/component/block.rs | 0 {src => pagetop/src}/base/component/chunck.rs | 0 .../src}/base/component/container.rs | 0 .../src}/base/component/form/button.rs | 0 .../src}/base/component/form/date.rs | 0 .../src}/base/component/form/form.rs | 0 .../src}/base/component/form/hidden.rs | 0 .../src}/base/component/form/input.rs | 0 .../src}/base/component/form/mod.rs | 0 {src => pagetop/src}/base/component/menu.rs | 0 {src => pagetop/src}/base/component/mod.rs | 0 {src => pagetop/src}/base/mod.rs | 0 .../base/module/admin/locales/en-US/admin.ftl | 0 .../base/module/admin/locales/es-ES/admin.ftl | 0 {src => pagetop/src}/base/module/admin/mod.rs | 0 .../src}/base/module/admin/summary.rs | 0 .../homepage/locales/en-US/homepage.ftl | 0 .../homepage/locales/es-ES/homepage.ftl | 0 .../src}/base/module/homepage/mod.rs | 0 {src => pagetop/src}/base/module/mod.rs | 0 .../src}/base/module/user/entity/mod.rs | 0 .../src}/base/module/user/entity/user.rs | 0 .../module/user/locales/en-US/homepage.ftl | 0 .../module/user/locales/es-ES/homepage.ftl | 0 .../m20220312_000001_create_table_user.rs | 0 .../src}/base/module/user/migration/mod.rs | 0 {src => pagetop/src}/base/module/user/mod.rs | 0 {src => pagetop/src}/base/theme/aliner/mod.rs | 0 .../theme/bootsier/locales/en-US/bootsier.ftl | 0 .../theme/bootsier/locales/es-ES/bootsier.ftl | 0 .../src}/base/theme/bootsier/mod.rs | 0 .../src}/base/theme/minimal/mod.rs | 0 {src => pagetop/src}/base/theme/mod.rs | 0 {src => pagetop/src}/config.rs | 0 {src => pagetop/src}/core/global.rs | 0 {src => pagetop/src}/core/mod.rs | 0 .../src}/core/module/definition.rs | 0 {src => pagetop/src}/core/module/mod.rs | 0 {src => pagetop/src}/core/response/mod.rs | 0 .../src}/core/response/page/assets.rs | 0 .../src}/core/response/page/component.rs | 0 .../src}/core/response/page/container.rs | 0 .../src}/core/response/page/mod.rs | 0 .../src}/core/response/page/page.rs | 0 {src => pagetop/src}/core/server/app.rs | 2 +- .../src}/core/server/figfonts/slant.flf | 0 .../src}/core/server/figfonts/small.flf | 0 .../src}/core/server/figfonts/speed.flf | 0 .../src}/core/server/figfonts/starwars.flf | 0 {src => pagetop/src}/core/server/mod.rs | 0 {src => pagetop/src}/core/server/tracing.rs | 0 {src => pagetop/src}/core/theme/definition.rs | 0 {src => pagetop/src}/core/theme/mod.rs | 0 {src => pagetop/src}/db.rs | 0 {src => pagetop/src}/lib.rs | 0 {src => pagetop/src}/locale.rs | 0 {src => pagetop/src}/prelude.rs | 0 {src => pagetop/src}/trace.rs | 0 {src => pagetop/src}/util.rs | 0 .../static}/aliner/css/styles.css | 0 .../static}/bootsier/css/bootstrap.min.css | 0 .../bootsier/css/bootstrap.min.css.map | 0 .../static}/bootsier/images/caution.png | Bin .../bootsier/js/bootstrap.bundle.min.js | 0 .../bootsier/js/bootstrap.bundle.min.js.map | 0 .../static}/theme/js/jquery.min.js | 0 .../static}/theme/js/jquery.min.map | 0 .../static}/theme/menu/css/menu-blue.css | 0 .../static}/theme/menu/css/menu-clean.css | 0 .../static}/theme/menu/css/menu-mint.css | 0 .../static}/theme/menu/css/menu-simple.css | 0 .../static}/theme/menu/css/menu.css | 0 .../static}/theme/menu/js/menu.min.js | 0 {tests => pagetop/tests}/health_check.rs | 0 {tests => pagetop/tests}/main.rs | 0 83 files changed, 115 insertions(+), 81 deletions(-) create mode 100644 drust/Cargo.toml rename {src => drust/src}/main.rs (53%) create mode 100644 pagetop/Cargo.toml rename STARTER.Cargo.toml => pagetop/STARTER.Cargo.toml (100%) rename build.rs => pagetop/build.rs (100%) rename {config => pagetop/config}/settings.default.toml (100%) rename {src => pagetop/src}/base/component/block.rs (100%) rename {src => pagetop/src}/base/component/chunck.rs (100%) rename {src => pagetop/src}/base/component/container.rs (100%) rename {src => pagetop/src}/base/component/form/button.rs (100%) rename {src => pagetop/src}/base/component/form/date.rs (100%) rename {src => pagetop/src}/base/component/form/form.rs (100%) rename {src => pagetop/src}/base/component/form/hidden.rs (100%) rename {src => pagetop/src}/base/component/form/input.rs (100%) rename {src => pagetop/src}/base/component/form/mod.rs (100%) rename {src => pagetop/src}/base/component/menu.rs (100%) rename {src => pagetop/src}/base/component/mod.rs (100%) rename {src => pagetop/src}/base/mod.rs (100%) rename {src => pagetop/src}/base/module/admin/locales/en-US/admin.ftl (100%) rename {src => pagetop/src}/base/module/admin/locales/es-ES/admin.ftl (100%) rename {src => pagetop/src}/base/module/admin/mod.rs (100%) rename {src => pagetop/src}/base/module/admin/summary.rs (100%) rename {src => pagetop/src}/base/module/homepage/locales/en-US/homepage.ftl (100%) rename {src => pagetop/src}/base/module/homepage/locales/es-ES/homepage.ftl (100%) rename {src => pagetop/src}/base/module/homepage/mod.rs (100%) rename {src => pagetop/src}/base/module/mod.rs (100%) rename {src => pagetop/src}/base/module/user/entity/mod.rs (100%) rename {src => pagetop/src}/base/module/user/entity/user.rs (100%) rename {src => pagetop/src}/base/module/user/locales/en-US/homepage.ftl (100%) rename {src => pagetop/src}/base/module/user/locales/es-ES/homepage.ftl (100%) rename {src => pagetop/src}/base/module/user/migration/m20220312_000001_create_table_user.rs (100%) rename {src => pagetop/src}/base/module/user/migration/mod.rs (100%) rename {src => pagetop/src}/base/module/user/mod.rs (100%) rename {src => pagetop/src}/base/theme/aliner/mod.rs (100%) rename {src => pagetop/src}/base/theme/bootsier/locales/en-US/bootsier.ftl (100%) rename {src => pagetop/src}/base/theme/bootsier/locales/es-ES/bootsier.ftl (100%) rename {src => pagetop/src}/base/theme/bootsier/mod.rs (100%) rename {src => pagetop/src}/base/theme/minimal/mod.rs (100%) rename {src => pagetop/src}/base/theme/mod.rs (100%) rename {src => pagetop/src}/config.rs (100%) rename {src => pagetop/src}/core/global.rs (100%) rename {src => pagetop/src}/core/mod.rs (100%) rename {src => pagetop/src}/core/module/definition.rs (100%) rename {src => pagetop/src}/core/module/mod.rs (100%) rename {src => pagetop/src}/core/response/mod.rs (100%) rename {src => pagetop/src}/core/response/page/assets.rs (100%) rename {src => pagetop/src}/core/response/page/component.rs (100%) rename {src => pagetop/src}/core/response/page/container.rs (100%) rename {src => pagetop/src}/core/response/page/mod.rs (100%) rename {src => pagetop/src}/core/response/page/page.rs (100%) rename {src => pagetop/src}/core/server/app.rs (98%) rename {src => pagetop/src}/core/server/figfonts/slant.flf (100%) rename {src => pagetop/src}/core/server/figfonts/small.flf (100%) rename {src => pagetop/src}/core/server/figfonts/speed.flf (100%) rename {src => pagetop/src}/core/server/figfonts/starwars.flf (100%) rename {src => pagetop/src}/core/server/mod.rs (100%) rename {src => pagetop/src}/core/server/tracing.rs (100%) rename {src => pagetop/src}/core/theme/definition.rs (100%) rename {src => pagetop/src}/core/theme/mod.rs (100%) rename {src => pagetop/src}/db.rs (100%) rename {src => pagetop/src}/lib.rs (100%) rename {src => pagetop/src}/locale.rs (100%) rename {src => pagetop/src}/prelude.rs (100%) rename {src => pagetop/src}/trace.rs (100%) rename {src => pagetop/src}/util.rs (100%) rename {static => pagetop/static}/aliner/css/styles.css (100%) rename {static => pagetop/static}/bootsier/css/bootstrap.min.css (100%) rename {static => pagetop/static}/bootsier/css/bootstrap.min.css.map (100%) rename {static => pagetop/static}/bootsier/images/caution.png (100%) rename {static => pagetop/static}/bootsier/js/bootstrap.bundle.min.js (100%) rename {static => pagetop/static}/bootsier/js/bootstrap.bundle.min.js.map (100%) rename {static => pagetop/static}/theme/js/jquery.min.js (100%) rename {static => pagetop/static}/theme/js/jquery.min.map (100%) rename {static => pagetop/static}/theme/menu/css/menu-blue.css (100%) rename {static => pagetop/static}/theme/menu/css/menu-clean.css (100%) rename {static => pagetop/static}/theme/menu/css/menu-mint.css (100%) rename {static => pagetop/static}/theme/menu/css/menu-simple.css (100%) rename {static => pagetop/static}/theme/menu/css/menu.css (100%) rename {static => pagetop/static}/theme/menu/js/menu.min.js (100%) rename {tests => pagetop/tests}/health_check.rs (100%) rename {tests => pagetop/tests}/main.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 0c3a0a43..2369a8da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,74 +1,5 @@ -[package] -name = "pagetop" -version = "0.1.0" -edition = "2021" - -authors = [ - "Manuel Cillero <manuel@cillero.es>" -] -description = """\ - PageTop es un proyecto personal para aprender Rust. Incluye algunos de los \ - crates más estables y populares para desarrollar soluciones web modulares, \ - extensibles y configurables. También es un sistema para la gestión de \ - contenidos web.\ -""" -homepage = "https://suitepro.cillero.es/projects/pagetop" -repository = "https://gitlab.com/manuelcillero/pagetop" -license = "MIT" - -keywords = [ - "web", "cms", "framework", "frontend", "ssr" -] -categories = [ - "web-programming", "development-tools", "gui" -] - -[dependencies] -doc-comment = "0.3.3" -downcast-rs = "1.2.0" -figlet-rs = "0.1.3" -futures = "0.3" -once_cell = "1.9.0" -url = "2.2.2" - -config_rs = { package = "config", version = "0.11.0", features = ["toml"] } - -tracing = "0.1" -tracing-appender = "0.2" -tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] } -tracing-actix-web = "0.2" - -fluent-templates = "0.6.1" -unic-langid = "0.9.0" - -actix-web = "3.3.3" -actix-web-static-files = "3.0.5" - -maud = { version = "0.23.0", features = ["actix-web"] } -sycamore = { version = "0.7.1", features = ["ssr"] } - -serde = { version = "1.0", features = ["derive"] } - -[dependencies.sea-orm] -version = "0.6" -features = ["debug-print", "macros", "runtime-async-std-native-tls"] -default-features = false - -[dependencies.sea-schema] -version = "0.5" -features = ["debug-print", "migration"] -default-features = false - -[features] -default = ["mysql"] -mysql = ["sea-orm/sqlx-mysql"] -postgres = ["sea-orm/sqlx-postgres"] - -[build-dependencies] -actix-web-static-files = "3.0.5" - -[lib] -name = "pagetop" - -[[bin]] -name = "pagetop" +[workspace] +members = [ + "drust", + "pagetop", +] \ No newline at end of file diff --git a/config/default.toml b/config/default.toml index 5f8778a3..26676acb 100644 --- a/config/default.toml +++ b/config/default.toml @@ -1,3 +1,20 @@ [app] -name = "PageTop Essence" -description = "A modern Content Management System for sharing the world." +name = "Drust" +description = """\ + A modern Content Management System for sharing the world.\ +""" +language = "es-ES" +#theme = "Aliner" +#theme = "Minimal" +theme = "Bootsier" + +[database] +db_name = "drust" +db_user = "drust" +db_pass = "DrU__#3T" + +[log] +tracing = "Info" +#Info,actix_server::builder=Error,tracing_actix_web=Warn" +rolling = "Stdout" +format = "Compact" diff --git a/drust/Cargo.toml b/drust/Cargo.toml new file mode 100644 index 00000000..0a579e5f --- /dev/null +++ b/drust/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "drust" +version = "0.1.0" +edition = "2021" + +authors = [ + "Manuel Cillero <manuel@cillero.es>" +] +description = """\ + A modern Content Management System for sharing the world.\ +""" +homepage = "https://suitepro.cillero.es/projects/drust" +repository = "https://gitlab.com/manuelcillero/drust" + +[dependencies] +pagetop = { path = "../pagetop" } +actix-web = "3.3.3" +maud = { version = "0.23.0" } +serde = { version = "1.0", features = ["derive"] } diff --git a/src/main.rs b/drust/src/main.rs similarity index 53% rename from src/main.rs rename to drust/src/main.rs index 30df2f36..6916d3b1 100644 --- a/src/main.rs +++ b/drust/src/main.rs @@ -1,8 +1,4 @@ #[actix_web::main] async fn main() -> std::io::Result<()> { - // ``` - // let app = pagetop::Application::build(None).await?; - // app.run()?.await - // ``` pagetop::Application::build(None).await?.run()?.await } diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml new file mode 100644 index 00000000..278b6ba0 --- /dev/null +++ b/pagetop/Cargo.toml @@ -0,0 +1,71 @@ +[package] +name = "pagetop" +version = "0.1.0" +edition = "2021" + +authors = [ + "Manuel Cillero <manuel@cillero.es>" +] +description = """\ + PageTop es un proyecto personal para aprender Rust. Incluye algunos de los \ + crates más estables y populares para desarrollar soluciones web modulares, \ + extensibles y configurables. También es un sistema para la gestión de \ + contenidos web.\ +""" +homepage = "https://suitepro.cillero.es/projects/pagetop" +repository = "https://gitlab.com/manuelcillero/pagetop" +license = "MIT" + +keywords = [ + "web", "cms", "framework", "frontend", "ssr" +] +categories = [ + "web-programming", "development-tools", "gui" +] + +[dependencies] +doc-comment = "0.3.3" +downcast-rs = "1.2.0" +figlet-rs = "0.1.3" +futures = "0.3" +once_cell = "1.9.0" +url = "2.2.2" + +config_rs = { package = "config", version = "0.11.0", features = ["toml"] } + +tracing = "0.1" +tracing-appender = "0.2" +tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] } +tracing-actix-web = "0.2" + +fluent-templates = "0.6.1" +unic-langid = "0.9.0" + +actix-web = "3.3.3" +actix-web-static-files = "3.0.5" + +maud = { version = "0.23.0", features = ["actix-web"] } +sycamore = { version = "0.7.1", features = ["ssr"] } + +serde = { version = "1.0", features = ["derive"] } + +[dependencies.sea-orm] +version = "0.6" +features = ["debug-print", "macros", "runtime-async-std-native-tls"] +default-features = false + +[dependencies.sea-schema] +version = "0.5" +features = ["debug-print", "migration"] +default-features = false + +[features] +default = ["mysql"] +mysql = ["sea-orm/sqlx-mysql"] +postgres = ["sea-orm/sqlx-postgres"] + +[build-dependencies] +actix-web-static-files = "3.0.5" + +[lib] +name = "pagetop" diff --git a/STARTER.Cargo.toml b/pagetop/STARTER.Cargo.toml similarity index 100% rename from STARTER.Cargo.toml rename to pagetop/STARTER.Cargo.toml diff --git a/build.rs b/pagetop/build.rs similarity index 100% rename from build.rs rename to pagetop/build.rs diff --git a/config/settings.default.toml b/pagetop/config/settings.default.toml similarity index 100% rename from config/settings.default.toml rename to pagetop/config/settings.default.toml diff --git a/src/base/component/block.rs b/pagetop/src/base/component/block.rs similarity index 100% rename from src/base/component/block.rs rename to pagetop/src/base/component/block.rs diff --git a/src/base/component/chunck.rs b/pagetop/src/base/component/chunck.rs similarity index 100% rename from src/base/component/chunck.rs rename to pagetop/src/base/component/chunck.rs diff --git a/src/base/component/container.rs b/pagetop/src/base/component/container.rs similarity index 100% rename from src/base/component/container.rs rename to pagetop/src/base/component/container.rs diff --git a/src/base/component/form/button.rs b/pagetop/src/base/component/form/button.rs similarity index 100% rename from src/base/component/form/button.rs rename to pagetop/src/base/component/form/button.rs diff --git a/src/base/component/form/date.rs b/pagetop/src/base/component/form/date.rs similarity index 100% rename from src/base/component/form/date.rs rename to pagetop/src/base/component/form/date.rs diff --git a/src/base/component/form/form.rs b/pagetop/src/base/component/form/form.rs similarity index 100% rename from src/base/component/form/form.rs rename to pagetop/src/base/component/form/form.rs diff --git a/src/base/component/form/hidden.rs b/pagetop/src/base/component/form/hidden.rs similarity index 100% rename from src/base/component/form/hidden.rs rename to pagetop/src/base/component/form/hidden.rs diff --git a/src/base/component/form/input.rs b/pagetop/src/base/component/form/input.rs similarity index 100% rename from src/base/component/form/input.rs rename to pagetop/src/base/component/form/input.rs diff --git a/src/base/component/form/mod.rs b/pagetop/src/base/component/form/mod.rs similarity index 100% rename from src/base/component/form/mod.rs rename to pagetop/src/base/component/form/mod.rs diff --git a/src/base/component/menu.rs b/pagetop/src/base/component/menu.rs similarity index 100% rename from src/base/component/menu.rs rename to pagetop/src/base/component/menu.rs diff --git a/src/base/component/mod.rs b/pagetop/src/base/component/mod.rs similarity index 100% rename from src/base/component/mod.rs rename to pagetop/src/base/component/mod.rs diff --git a/src/base/mod.rs b/pagetop/src/base/mod.rs similarity index 100% rename from src/base/mod.rs rename to pagetop/src/base/mod.rs diff --git a/src/base/module/admin/locales/en-US/admin.ftl b/pagetop/src/base/module/admin/locales/en-US/admin.ftl similarity index 100% rename from src/base/module/admin/locales/en-US/admin.ftl rename to pagetop/src/base/module/admin/locales/en-US/admin.ftl diff --git a/src/base/module/admin/locales/es-ES/admin.ftl b/pagetop/src/base/module/admin/locales/es-ES/admin.ftl similarity index 100% rename from src/base/module/admin/locales/es-ES/admin.ftl rename to pagetop/src/base/module/admin/locales/es-ES/admin.ftl diff --git a/src/base/module/admin/mod.rs b/pagetop/src/base/module/admin/mod.rs similarity index 100% rename from src/base/module/admin/mod.rs rename to pagetop/src/base/module/admin/mod.rs diff --git a/src/base/module/admin/summary.rs b/pagetop/src/base/module/admin/summary.rs similarity index 100% rename from src/base/module/admin/summary.rs rename to pagetop/src/base/module/admin/summary.rs diff --git a/src/base/module/homepage/locales/en-US/homepage.ftl b/pagetop/src/base/module/homepage/locales/en-US/homepage.ftl similarity index 100% rename from src/base/module/homepage/locales/en-US/homepage.ftl rename to pagetop/src/base/module/homepage/locales/en-US/homepage.ftl diff --git a/src/base/module/homepage/locales/es-ES/homepage.ftl b/pagetop/src/base/module/homepage/locales/es-ES/homepage.ftl similarity index 100% rename from src/base/module/homepage/locales/es-ES/homepage.ftl rename to pagetop/src/base/module/homepage/locales/es-ES/homepage.ftl diff --git a/src/base/module/homepage/mod.rs b/pagetop/src/base/module/homepage/mod.rs similarity index 100% rename from src/base/module/homepage/mod.rs rename to pagetop/src/base/module/homepage/mod.rs diff --git a/src/base/module/mod.rs b/pagetop/src/base/module/mod.rs similarity index 100% rename from src/base/module/mod.rs rename to pagetop/src/base/module/mod.rs diff --git a/src/base/module/user/entity/mod.rs b/pagetop/src/base/module/user/entity/mod.rs similarity index 100% rename from src/base/module/user/entity/mod.rs rename to pagetop/src/base/module/user/entity/mod.rs diff --git a/src/base/module/user/entity/user.rs b/pagetop/src/base/module/user/entity/user.rs similarity index 100% rename from src/base/module/user/entity/user.rs rename to pagetop/src/base/module/user/entity/user.rs diff --git a/src/base/module/user/locales/en-US/homepage.ftl b/pagetop/src/base/module/user/locales/en-US/homepage.ftl similarity index 100% rename from src/base/module/user/locales/en-US/homepage.ftl rename to pagetop/src/base/module/user/locales/en-US/homepage.ftl diff --git a/src/base/module/user/locales/es-ES/homepage.ftl b/pagetop/src/base/module/user/locales/es-ES/homepage.ftl similarity index 100% rename from src/base/module/user/locales/es-ES/homepage.ftl rename to pagetop/src/base/module/user/locales/es-ES/homepage.ftl diff --git a/src/base/module/user/migration/m20220312_000001_create_table_user.rs b/pagetop/src/base/module/user/migration/m20220312_000001_create_table_user.rs similarity index 100% rename from src/base/module/user/migration/m20220312_000001_create_table_user.rs rename to pagetop/src/base/module/user/migration/m20220312_000001_create_table_user.rs diff --git a/src/base/module/user/migration/mod.rs b/pagetop/src/base/module/user/migration/mod.rs similarity index 100% rename from src/base/module/user/migration/mod.rs rename to pagetop/src/base/module/user/migration/mod.rs diff --git a/src/base/module/user/mod.rs b/pagetop/src/base/module/user/mod.rs similarity index 100% rename from src/base/module/user/mod.rs rename to pagetop/src/base/module/user/mod.rs diff --git a/src/base/theme/aliner/mod.rs b/pagetop/src/base/theme/aliner/mod.rs similarity index 100% rename from src/base/theme/aliner/mod.rs rename to pagetop/src/base/theme/aliner/mod.rs diff --git a/src/base/theme/bootsier/locales/en-US/bootsier.ftl b/pagetop/src/base/theme/bootsier/locales/en-US/bootsier.ftl similarity index 100% rename from src/base/theme/bootsier/locales/en-US/bootsier.ftl rename to pagetop/src/base/theme/bootsier/locales/en-US/bootsier.ftl diff --git a/src/base/theme/bootsier/locales/es-ES/bootsier.ftl b/pagetop/src/base/theme/bootsier/locales/es-ES/bootsier.ftl similarity index 100% rename from src/base/theme/bootsier/locales/es-ES/bootsier.ftl rename to pagetop/src/base/theme/bootsier/locales/es-ES/bootsier.ftl diff --git a/src/base/theme/bootsier/mod.rs b/pagetop/src/base/theme/bootsier/mod.rs similarity index 100% rename from src/base/theme/bootsier/mod.rs rename to pagetop/src/base/theme/bootsier/mod.rs diff --git a/src/base/theme/minimal/mod.rs b/pagetop/src/base/theme/minimal/mod.rs similarity index 100% rename from src/base/theme/minimal/mod.rs rename to pagetop/src/base/theme/minimal/mod.rs diff --git a/src/base/theme/mod.rs b/pagetop/src/base/theme/mod.rs similarity index 100% rename from src/base/theme/mod.rs rename to pagetop/src/base/theme/mod.rs diff --git a/src/config.rs b/pagetop/src/config.rs similarity index 100% rename from src/config.rs rename to pagetop/src/config.rs diff --git a/src/core/global.rs b/pagetop/src/core/global.rs similarity index 100% rename from src/core/global.rs rename to pagetop/src/core/global.rs diff --git a/src/core/mod.rs b/pagetop/src/core/mod.rs similarity index 100% rename from src/core/mod.rs rename to pagetop/src/core/mod.rs diff --git a/src/core/module/definition.rs b/pagetop/src/core/module/definition.rs similarity index 100% rename from src/core/module/definition.rs rename to pagetop/src/core/module/definition.rs diff --git a/src/core/module/mod.rs b/pagetop/src/core/module/mod.rs similarity index 100% rename from src/core/module/mod.rs rename to pagetop/src/core/module/mod.rs diff --git a/src/core/response/mod.rs b/pagetop/src/core/response/mod.rs similarity index 100% rename from src/core/response/mod.rs rename to pagetop/src/core/response/mod.rs diff --git a/src/core/response/page/assets.rs b/pagetop/src/core/response/page/assets.rs similarity index 100% rename from src/core/response/page/assets.rs rename to pagetop/src/core/response/page/assets.rs diff --git a/src/core/response/page/component.rs b/pagetop/src/core/response/page/component.rs similarity index 100% rename from src/core/response/page/component.rs rename to pagetop/src/core/response/page/component.rs diff --git a/src/core/response/page/container.rs b/pagetop/src/core/response/page/container.rs similarity index 100% rename from src/core/response/page/container.rs rename to pagetop/src/core/response/page/container.rs diff --git a/src/core/response/page/mod.rs b/pagetop/src/core/response/page/mod.rs similarity index 100% rename from src/core/response/page/mod.rs rename to pagetop/src/core/response/page/mod.rs diff --git a/src/core/response/page/page.rs b/pagetop/src/core/response/page/page.rs similarity index 100% rename from src/core/response/page/page.rs rename to pagetop/src/core/response/page/page.rs diff --git a/src/core/server/app.rs b/pagetop/src/core/server/app.rs similarity index 98% rename from src/core/server/app.rs rename to pagetop/src/core/server/app.rs index 1f2ec7f3..b23b38f2 100644 --- a/src/core/server/app.rs +++ b/pagetop/src/core/server/app.rs @@ -47,7 +47,7 @@ impl Application { // Inicializa la conexión con la base de datos. trace::info!( - "Connecting to database \"{}\" with a pool of {} connections.", + "Connecting to database \"{}\" using a pool of {} connections.", &SETTINGS.database.db_name, &SETTINGS.database.max_pool_size ); diff --git a/src/core/server/figfonts/slant.flf b/pagetop/src/core/server/figfonts/slant.flf similarity index 100% rename from src/core/server/figfonts/slant.flf rename to pagetop/src/core/server/figfonts/slant.flf diff --git a/src/core/server/figfonts/small.flf b/pagetop/src/core/server/figfonts/small.flf similarity index 100% rename from src/core/server/figfonts/small.flf rename to pagetop/src/core/server/figfonts/small.flf diff --git a/src/core/server/figfonts/speed.flf b/pagetop/src/core/server/figfonts/speed.flf similarity index 100% rename from src/core/server/figfonts/speed.flf rename to pagetop/src/core/server/figfonts/speed.flf diff --git a/src/core/server/figfonts/starwars.flf b/pagetop/src/core/server/figfonts/starwars.flf similarity index 100% rename from src/core/server/figfonts/starwars.flf rename to pagetop/src/core/server/figfonts/starwars.flf diff --git a/src/core/server/mod.rs b/pagetop/src/core/server/mod.rs similarity index 100% rename from src/core/server/mod.rs rename to pagetop/src/core/server/mod.rs diff --git a/src/core/server/tracing.rs b/pagetop/src/core/server/tracing.rs similarity index 100% rename from src/core/server/tracing.rs rename to pagetop/src/core/server/tracing.rs diff --git a/src/core/theme/definition.rs b/pagetop/src/core/theme/definition.rs similarity index 100% rename from src/core/theme/definition.rs rename to pagetop/src/core/theme/definition.rs diff --git a/src/core/theme/mod.rs b/pagetop/src/core/theme/mod.rs similarity index 100% rename from src/core/theme/mod.rs rename to pagetop/src/core/theme/mod.rs diff --git a/src/db.rs b/pagetop/src/db.rs similarity index 100% rename from src/db.rs rename to pagetop/src/db.rs diff --git a/src/lib.rs b/pagetop/src/lib.rs similarity index 100% rename from src/lib.rs rename to pagetop/src/lib.rs diff --git a/src/locale.rs b/pagetop/src/locale.rs similarity index 100% rename from src/locale.rs rename to pagetop/src/locale.rs diff --git a/src/prelude.rs b/pagetop/src/prelude.rs similarity index 100% rename from src/prelude.rs rename to pagetop/src/prelude.rs diff --git a/src/trace.rs b/pagetop/src/trace.rs similarity index 100% rename from src/trace.rs rename to pagetop/src/trace.rs diff --git a/src/util.rs b/pagetop/src/util.rs similarity index 100% rename from src/util.rs rename to pagetop/src/util.rs diff --git a/static/aliner/css/styles.css b/pagetop/static/aliner/css/styles.css similarity index 100% rename from static/aliner/css/styles.css rename to pagetop/static/aliner/css/styles.css diff --git a/static/bootsier/css/bootstrap.min.css b/pagetop/static/bootsier/css/bootstrap.min.css similarity index 100% rename from static/bootsier/css/bootstrap.min.css rename to pagetop/static/bootsier/css/bootstrap.min.css diff --git a/static/bootsier/css/bootstrap.min.css.map b/pagetop/static/bootsier/css/bootstrap.min.css.map similarity index 100% rename from static/bootsier/css/bootstrap.min.css.map rename to pagetop/static/bootsier/css/bootstrap.min.css.map diff --git a/static/bootsier/images/caution.png b/pagetop/static/bootsier/images/caution.png similarity index 100% rename from static/bootsier/images/caution.png rename to pagetop/static/bootsier/images/caution.png diff --git a/static/bootsier/js/bootstrap.bundle.min.js b/pagetop/static/bootsier/js/bootstrap.bundle.min.js similarity index 100% rename from static/bootsier/js/bootstrap.bundle.min.js rename to pagetop/static/bootsier/js/bootstrap.bundle.min.js diff --git a/static/bootsier/js/bootstrap.bundle.min.js.map b/pagetop/static/bootsier/js/bootstrap.bundle.min.js.map similarity index 100% rename from static/bootsier/js/bootstrap.bundle.min.js.map rename to pagetop/static/bootsier/js/bootstrap.bundle.min.js.map diff --git a/static/theme/js/jquery.min.js b/pagetop/static/theme/js/jquery.min.js similarity index 100% rename from static/theme/js/jquery.min.js rename to pagetop/static/theme/js/jquery.min.js diff --git a/static/theme/js/jquery.min.map b/pagetop/static/theme/js/jquery.min.map similarity index 100% rename from static/theme/js/jquery.min.map rename to pagetop/static/theme/js/jquery.min.map diff --git a/static/theme/menu/css/menu-blue.css b/pagetop/static/theme/menu/css/menu-blue.css similarity index 100% rename from static/theme/menu/css/menu-blue.css rename to pagetop/static/theme/menu/css/menu-blue.css diff --git a/static/theme/menu/css/menu-clean.css b/pagetop/static/theme/menu/css/menu-clean.css similarity index 100% rename from static/theme/menu/css/menu-clean.css rename to pagetop/static/theme/menu/css/menu-clean.css diff --git a/static/theme/menu/css/menu-mint.css b/pagetop/static/theme/menu/css/menu-mint.css similarity index 100% rename from static/theme/menu/css/menu-mint.css rename to pagetop/static/theme/menu/css/menu-mint.css diff --git a/static/theme/menu/css/menu-simple.css b/pagetop/static/theme/menu/css/menu-simple.css similarity index 100% rename from static/theme/menu/css/menu-simple.css rename to pagetop/static/theme/menu/css/menu-simple.css diff --git a/static/theme/menu/css/menu.css b/pagetop/static/theme/menu/css/menu.css similarity index 100% rename from static/theme/menu/css/menu.css rename to pagetop/static/theme/menu/css/menu.css diff --git a/static/theme/menu/js/menu.min.js b/pagetop/static/theme/menu/js/menu.min.js similarity index 100% rename from static/theme/menu/js/menu.min.js rename to pagetop/static/theme/menu/js/menu.min.js diff --git a/tests/health_check.rs b/pagetop/tests/health_check.rs similarity index 100% rename from tests/health_check.rs rename to pagetop/tests/health_check.rs diff --git a/tests/main.rs b/pagetop/tests/main.rs similarity index 100% rename from tests/main.rs rename to pagetop/tests/main.rs From dce2573f8cd121eee483eacb08816ec3e2b08c3b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 14 Mar 2022 23:59:48 +0100 Subject: [PATCH 027/244] Actualiza el uso opcional de la base de datos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Por defecto PageTop no hace uso de la base de datos. Se deberá indicar explícitamente qué tipo de base de datos usará para que tenga en cuenta la configuración utilizada. --- config/default.toml | 6 +-- drust/Cargo.toml | 6 ++- pagetop/Cargo.toml | 10 +++-- pagetop/config/settings.default.toml | 24 ++++++----- pagetop/src/base/module/mod.rs | 2 + pagetop/src/config.rs | 12 +++--- pagetop/src/core/global.rs | 10 +++-- pagetop/src/core/module/definition.rs | 5 ++- pagetop/src/core/server/app.rs | 52 +++++------------------ pagetop/src/core/server/db.rs | 60 +++++++++++++++++++++++++++ pagetop/src/core/server/locale.rs | 23 ++++++++++ pagetop/src/core/server/mod.rs | 8 +++- pagetop/src/db.rs | 11 +++++ pagetop/src/lib.rs | 5 ++- pagetop/src/locale.rs | 25 +---------- pagetop/src/prelude.rs | 9 ++-- pagetop/src/util.rs | 11 ----- 17 files changed, 166 insertions(+), 113 deletions(-) create mode 100644 pagetop/src/core/server/db.rs create mode 100644 pagetop/src/core/server/locale.rs diff --git a/config/default.toml b/config/default.toml index 26676acb..33280fbd 100644 --- a/config/default.toml +++ b/config/default.toml @@ -9,12 +9,10 @@ language = "es-ES" theme = "Bootsier" [database] +db_type = "mysql" db_name = "drust" db_user = "drust" db_pass = "DrU__#3T" [log] -tracing = "Info" -#Info,actix_server::builder=Error,tracing_actix_web=Warn" -rolling = "Stdout" -format = "Compact" +tracing = "Info,sqlx::query=Warn" diff --git a/drust/Cargo.toml b/drust/Cargo.toml index 0a579e5f..cfa4a264 100644 --- a/drust/Cargo.toml +++ b/drust/Cargo.toml @@ -13,7 +13,11 @@ homepage = "https://suitepro.cillero.es/projects/drust" repository = "https://gitlab.com/manuelcillero/drust" [dependencies] -pagetop = { path = "../pagetop" } actix-web = "3.3.3" maud = { version = "0.23.0" } serde = { version = "1.0", features = ["derive"] } + +[dependencies.pagetop] +path = "../pagetop" +features = ["mysql"] +default-features = false diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index 278b6ba0..0b6c5d7d 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -36,6 +36,7 @@ config_rs = { package = "config", version = "0.11.0", features = ["toml"] } tracing = "0.1" tracing-appender = "0.2" tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] } +tracing-unwrap = { version = "0.9", default-features = false } tracing-actix-web = "0.2" fluent-templates = "0.6.1" @@ -53,16 +54,19 @@ serde = { version = "1.0", features = ["derive"] } version = "0.6" features = ["debug-print", "macros", "runtime-async-std-native-tls"] default-features = false +optional = true [dependencies.sea-schema] version = "0.5" features = ["debug-print", "migration"] default-features = false +optional = true [features] -default = ["mysql"] -mysql = ["sea-orm/sqlx-mysql"] -postgres = ["sea-orm/sqlx-postgres"] +default = [] +mysql = ["sea-orm", "sea-schema", "sea-orm/sqlx-mysql"] +postgres = ["sea-orm", "sea-schema", "sea-orm/sqlx-postgres"] +sqlite = ["sea-orm", "sea-schema", "sea-orm/sqlx-sqlite"] [build-dependencies] actix-web-static-files = "3.0.5" diff --git a/pagetop/config/settings.default.toml b/pagetop/config/settings.default.toml index f22868d2..b9c329cf 100644 --- a/pagetop/config/settings.default.toml +++ b/pagetop/config/settings.default.toml @@ -15,24 +15,26 @@ startup_banner = "Small" # Ejemplos: "Error,actix_server::builder=Info,tracing_actix_web=Debug". tracing = "Info" # En terminal ("Stdout") o archivos "Daily", "Hourly", "Minutely" o "Endless". -rolling = "Daily" +rolling = "Stdout" # Directorio para los archivos de traza (si rolling != "Stdout"). path = "log" # Prefijo para los archivos de traza (si rolling != "Stdout"). prefix = "tracing.log" -# Presentación de las trazas: "Json", "Full", "Compact" o "Pretty". -format = "Json" +# Presentación de las trazas: "Full", "Compact", "Pretty" o "Json". +format = "Full" [database] -# Ajustes para conectar con la base de datos. -# El tipo de base de datos es una característica de compilación. -# Nombre (mysql/postgres) o referencia (sqlite) de la base de datos. -db_name = "dbname" -# Usuario y contraseña (mysql/postgres). -db_user = "dbuser" -db_pass = "dbpass" -# Servidor (mysql/postgres) y puerto predeterminado (0 para 3306 ó 5432). +# Conecta con una base de datos (opcional). +# Tipo de la base de datos (mysql, postgres ó sqlite). +db_type = "" +# Nombre (para mysql/postgres) o referencia (para sqlite) de la base de datos. +db_name = "" +# Usuario y contraseña (para mysql/postgres). +db_user = "" +db_pass = "" +# Servidor (para mysql/postgres). db_host = "localhost" +# Puerto (para mysql/postgres), siendo 0 el puerto predeterminado (3306 ó 5432). db_port = 0 # Número máximo de conexiones habilitadas. max_pool_size = 5 diff --git a/pagetop/src/base/module/mod.rs b/pagetop/src/base/module/mod.rs index 3a4e2d51..ab1169b4 100644 --- a/pagetop/src/base/module/mod.rs +++ b/pagetop/src/base/module/mod.rs @@ -1,3 +1,5 @@ pub mod admin; pub mod homepage; + +#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] pub mod user; diff --git a/pagetop/src/config.rs b/pagetop/src/config.rs index c6232c7a..fedffc21 100644 --- a/pagetop/src/config.rs +++ b/pagetop/src/config.rs @@ -89,6 +89,7 @@ pub struct Log { #[derive(Debug, Deserialize)] pub struct Database { + pub db_type : String, pub db_name : String, pub db_user : String, pub db_pass : String, @@ -127,15 +128,16 @@ Ajustes globales y valores predeterminados para las secciones *\[app\]*, // [log] "log.tracing" => "Info", - "log.rolling" => "Daily", + "log.rolling" => "Stdout", "log.path" => "log", "log.prefix" => "tracing.log", - "log.format" => "json", + "log.format" => "Full", // [database] - "database.db_name" => "dbname", - "database.db_user" => "dbuser", - "database.db_pass" => "dbpass", + "database.db_type" => "", + "database.db_name" => "", + "database.db_user" => "", + "database.db_pass" => "", "database.db_host" => "localhost", "database.db_port" => 0, "database.max_pool_size" => 5, diff --git a/pagetop/src/core/global.rs b/pagetop/src/core/global.rs index 0879fe4c..0b307c56 100644 --- a/pagetop/src/core/global.rs +++ b/pagetop/src/core/global.rs @@ -1,4 +1,4 @@ -use crate::{Lazy, db}; +use crate::{Lazy, trace}; use crate::core::theme::Theme; use crate::core::module::Module; use crate::core::response::page::PageContainer; @@ -42,9 +42,13 @@ pub fn modules(cfg: &mut server::web::ServiceConfig) { } } -pub fn migrations(dbconn: &db::DbConn) { +#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] +pub fn check_migrations() { + trace::info!("Checking migrations."); for m in MODULES.read().unwrap().iter() { - m.migrations(dbconn).expect("Failed to run migrations"); + m.migrations( + &*server::db::DBCONN.read().unwrap() + ).expect("Failed to run migrations"); } } diff --git a/pagetop/src/core/module/definition.rs b/pagetop/src/core/module/definition.rs index e11efd2e..7dc6252b 100644 --- a/pagetop/src/core/module/definition.rs +++ b/pagetop/src/core/module/definition.rs @@ -1,6 +1,8 @@ -use crate::db; use crate::core::server; +#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] +use crate::db; + /// Los módulos deben implementar este *trait*. pub trait Module: Send + Sync { fn name(&self) -> &'static str; @@ -15,6 +17,7 @@ pub trait Module: Send + Sync { fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { } + #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] #[allow(unused_variables)] fn migrations(&self, dbconn: &db::DbConn) -> Result<(), db::DbErr> { Ok(()) diff --git a/pagetop/src/core/server/app.rs b/pagetop/src/core/server/app.rs index b23b38f2..dd794a68 100644 --- a/pagetop/src/core/server/app.rs +++ b/pagetop/src/core/server/app.rs @@ -1,4 +1,4 @@ -use crate::{Lazy, base, db, locale, trace}; +use crate::{Lazy, base, trace}; use crate::config::SETTINGS; use crate::core::{Server, global, server}; use crate::core::theme::register_theme; @@ -13,7 +13,7 @@ pub struct Application { impl Application { pub async fn build(bootstrap: Option<fn()>) -> Result<Self, Error> { - // Imprime rótulo (opcional) de bienvenida. + // Imprime un rótulo de presentación (opcional). if SETTINGS.app.startup_banner.to_lowercase() != "off" { let figfont = figlet_rs::FIGfont::from_content( match SETTINGS.app.startup_banner.to_lowercase().as_str() { @@ -43,42 +43,11 @@ impl Application { Lazy::force(&server::tracing::TRACING); // Valida el identificador de idioma. - Lazy::force(&locale::LANGID); + Lazy::force(&server::locale::LANGID); - // Inicializa la conexión con la base de datos. - trace::info!( - "Connecting to database \"{}\" using a pool of {} connections.", - &SETTINGS.database.db_name, - &SETTINGS.database.max_pool_size - ); - - #[cfg(feature = "mysql")] - let db_type = "mysql"; - - #[cfg(feature = "postgres")] - let db_type = "postgres"; - - // https://github.com/launchbadge/sqlx/issues/1624 - let mut db_uri = db::DbUri::parse(format!( - "{}://{}/{}", - db_type, - &SETTINGS.database.db_host, - &SETTINGS.database.db_name - ).as_str()).unwrap(); - db_uri.set_username(&SETTINGS.database.db_user.as_str()).unwrap(); - db_uri.set_password(Some(&SETTINGS.database.db_pass.as_str())).unwrap(); - if SETTINGS.database.db_port != 0 { - db_uri.set_port(Some(SETTINGS.database.db_port)).unwrap(); - } - - let mut db_options = sea_orm::ConnectOptions::new(db_uri.to_string()); - db_options.max_connections(SETTINGS.database.max_pool_size); - - let dbconn = sea_orm::Database::connect::<sea_orm::ConnectOptions>( - db_options.into() - ) - .await - .expect("Failed to connect to database"); + // Conecta con la base de datos (opcional). + #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] + Lazy::force(&server::db::DBCONN); // Registra los temas predefinidos. register_theme(&base::theme::aliner::AlinerTheme); @@ -87,6 +56,8 @@ impl Application { // Registra los módulos predeterminados. register_module(&base::module::admin::AdminModule); + // Registra los módulos que requieren base de datos. + #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] register_module(&base::module::user::UserModule); // Ejecuta la función de inicio de la aplicación. @@ -99,16 +70,15 @@ impl Application { // Al ser el último, puede sobrecargarse con la función de inicio. register_module(&base::module::homepage::HomepageModule); - // Run migrations. - trace::info!("Running migrations."); - global::migrations(&dbconn); + // Comprueba actualizaciones pendientes de la base de datos (opcional). + #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] + global::check_migrations(); // Prepara el servidor web. let server = server::HttpServer::new(move || { server::App::new() .wrap(tracing_actix_web::TracingLogger) .wrap(NormalizePath::new(TrailingSlash::Trim)) - .data(dbconn.clone()) .configure(&global::themes) .configure(&global::modules) }) diff --git a/pagetop/src/core/server/db.rs b/pagetop/src/core/server/db.rs new file mode 100644 index 00000000..8c5c9f1f --- /dev/null +++ b/pagetop/src/core/server/db.rs @@ -0,0 +1,60 @@ +use crate::{Lazy, db, run_now, trace}; +use crate::config::SETTINGS; + +use std::sync::RwLock; +use sea_orm::{ConnectOptions, Database}; +use tracing_unwrap::ResultExt; + +pub static DBCONN: Lazy<RwLock<db::DbConn>> = Lazy::new(|| { + trace::info!( + "Connecting to database \"{}\" using a pool of {} connections.", + &SETTINGS.database.db_name, + &SETTINGS.database.max_pool_size + ); + + let db_uri = match SETTINGS.database.db_type.as_str() { + "mysql" | "postgres" => { + let mut tmp_uri = db::DbUri::parse(format!( + "{}://{}/{}", + &SETTINGS.database.db_type, + &SETTINGS.database.db_host, + &SETTINGS.database.db_name + ).as_str()).unwrap(); + tmp_uri.set_username( + &SETTINGS.database.db_user.as_str() + ).unwrap(); + // https://github.com/launchbadge/sqlx/issues/1624 + tmp_uri.set_password( + Some(&SETTINGS.database.db_pass.as_str()) + ).unwrap(); + if SETTINGS.database.db_port != 0 { + tmp_uri.set_port( + Some(SETTINGS.database.db_port) + ).unwrap(); + } + tmp_uri + }, + "sqlite" => db::DbUri::parse( + format!("{}://{}", + &SETTINGS.database.db_type, + &SETTINGS.database.db_name + ).as_str()).unwrap(), + _ => { + trace::error!( + "Unrecognized database type \"{}\".", + &SETTINGS.database.db_type + ); + db::DbUri::parse("").unwrap() + } + }; + + let db_conn = run_now( + Database::connect::<ConnectOptions>({ + let mut db_opt = ConnectOptions::new(db_uri.to_string()); + db_opt.max_connections(SETTINGS.database.max_pool_size); + db_opt.into() + }) + ).expect_or_log("Failed to connect to database"); + + RwLock::new(db_conn) +}); diff --git a/pagetop/src/core/server/locale.rs b/pagetop/src/core/server/locale.rs new file mode 100644 index 00000000..8bc6fc10 --- /dev/null +++ b/pagetop/src/core/server/locale.rs @@ -0,0 +1,23 @@ +use crate::{Lazy, trace}; +use crate::config::SETTINGS; + +use unic_langid::LanguageIdentifier; + +/// Almacena el Identificador de Idioma Unicode ([Unicode Language Identifier] +/// (https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier)) de +/// la aplicación, obtenido de `SETTINGS.app.language`. +pub static LANGID: Lazy<LanguageIdentifier> = Lazy::new(|| { + match SETTINGS.app.language.parse() { + Ok(language) => language, + Err(_) => { + trace::warn!( + "Failed to parse language \"{}\". {}. {}. {}.", + SETTINGS.app.language, + "Unrecognized Unicode Language Identifier", + "Using \"en-US\"", + "Check the settings file", + ); + "en-US".parse().unwrap() + } + } +}); diff --git a/pagetop/src/core/server/mod.rs b/pagetop/src/core/server/mod.rs index ef85b53c..394886b4 100644 --- a/pagetop/src/core/server/mod.rs +++ b/pagetop/src/core/server/mod.rs @@ -4,5 +4,9 @@ pub use actix_web::{ mod tracing; -mod app; -pub use app::Application; +pub mod locale; + +#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] +pub mod db; + +pub mod app; diff --git a/pagetop/src/db.rs b/pagetop/src/db.rs index fb3f789e..b487cc19 100644 --- a/pagetop/src/db.rs +++ b/pagetop/src/db.rs @@ -12,3 +12,14 @@ pub mod entity { pub mod migration { pub use sea_schema::migration::prelude::*; } + +#[macro_export] +macro_rules! db_migrations { + ( $DBCONN:ident ) => {{ + $crate::run_now({ + use $crate::db::migration::MigratorTrait; + + migration::Migrator::up($DBCONN, None) + }) + }}; +} diff --git a/pagetop/src/lib.rs b/pagetop/src/lib.rs index 8d75fb08..b8485f96 100644 --- a/pagetop/src/lib.rs +++ b/pagetop/src/lib.rs @@ -11,11 +11,14 @@ pub use futures::executor::block_on as run_now; pub mod config; // Gestión de la configuración. pub mod trace; // Registro de trazas y eventos de la aplicación. pub mod locale; // Localización. + +#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] pub mod db; // Acceso a la base de datos. + pub mod core; // Servidor web y APIs para Temas, Módulos y Respuestas web. pub mod base; // Temas, Módulos y Componentes base. pub mod util; // Macros y funciones útiles. pub mod prelude; // Re-exporta recursos comunes. -pub use crate::core::server::Application; +pub use crate::core::server::app::Application; diff --git a/pagetop/src/locale.rs b/pagetop/src/locale.rs index 07cb0d8e..22a01ba6 100644 --- a/pagetop/src/locale.rs +++ b/pagetop/src/locale.rs @@ -2,35 +2,12 @@ pub use fluent_templates::{static_loader as static_locale, Loader as Locale}; pub use fluent_templates; pub use fluent_templates::fluent_bundle::FluentValue; -use crate::{Lazy, trace}; -use crate::config::SETTINGS; - -use unic_langid::LanguageIdentifier; - -/// Almacena el Identificador de Idioma Unicode ([Unicode Language Identifier] -/// (https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier)) de -/// la aplicación, obtenido de `SETTINGS.app.language`. -pub static LANGID: Lazy<LanguageIdentifier> = Lazy::new(|| { - match SETTINGS.app.language.parse() { - Ok(language) => language, - Err(_) => { - trace::warn!( - "Failed to parse language \"{}\". {}. {}. {}.", - SETTINGS.app.language, - "Unicode Language Identifier not recognized", - "Using \"en-US\"", - "Check the settings file", - ); - "en-US".parse().unwrap() - } - } -}); - #[macro_export] /// Permite integrar fácilmente localización en temas, módulos y componentes. macro_rules! localize { ( $DEF_LANGID:literal, $locales:literal $(, $core_locales:literal)? ) => { use $crate::locale::*; + use $crate::core::server::locale::LANGID; static_locale! { static LOCALES = { diff --git a/pagetop/src/prelude.rs b/pagetop/src/prelude.rs index bcff745b..f0a4b031 100644 --- a/pagetop/src/prelude.rs +++ b/pagetop/src/prelude.rs @@ -1,15 +1,12 @@ //! Re-exporta recursos comunes. -pub use crate::{ - args, - db_migrations, -}; - +pub use crate::args; pub use crate::config::SETTINGS; pub use crate::trace; pub use crate::localize; -pub use crate::db; +#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] +pub use crate::{db, db_migrations}; pub use crate::core::theme::*; pub use crate::core::module::*; diff --git a/pagetop/src/util.rs b/pagetop/src/util.rs index 5150d517..c56d2146 100644 --- a/pagetop/src/util.rs +++ b/pagetop/src/util.rs @@ -18,17 +18,6 @@ macro_rules! args { }}; } -#[macro_export] -macro_rules! db_migrations { - ( $DBCONN:ident ) => {{ - $crate::run_now({ - use $crate::db::migration::MigratorTrait; - - migration::Migrator::up($DBCONN, None) - }) - }}; -} - pub fn valid_id(id: &str) -> Option<String> { let id = id.trim().replace(" ", "_").to_lowercase(); match id.is_empty() { From 1102a76e471baab9ca376548b09d5f81057d4444 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 15 Mar 2022 20:02:39 +0100 Subject: [PATCH 028/244] =?UTF-8?q?Retoca=20dependencias=20para=20la=20ver?= =?UTF-8?q?si=C3=B3n=20de=20desarrollo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- drust/Cargo.toml | 10 ++++------ pagetop/Cargo.toml | 2 +- pagetop/STARTER.Cargo.toml | 15 ++++++++++++++- pagetop/src/core/global.rs | 2 +- pagetop/src/core/server/app.rs | 2 +- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/drust/Cargo.toml b/drust/Cargo.toml index cfa4a264..dd0bfdc5 100644 --- a/drust/Cargo.toml +++ b/drust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "drust" -version = "0.1.0" +version = "0.0.1" edition = "2021" authors = [ @@ -12,12 +12,10 @@ description = """\ homepage = "https://suitepro.cillero.es/projects/drust" repository = "https://gitlab.com/manuelcillero/drust" -[dependencies] -actix-web = "3.3.3" -maud = { version = "0.23.0" } -serde = { version = "1.0", features = ["derive"] } - [dependencies.pagetop] path = "../pagetop" features = ["mysql"] default-features = false + +[dependencies] +actix-web = "3.3.3" diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index 0b6c5d7d..b828e58f 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.1.0" +version = "0.0.1" edition = "2021" authors = [ diff --git a/pagetop/STARTER.Cargo.toml b/pagetop/STARTER.Cargo.toml index 08b251e7..7cddd5fc 100644 --- a/pagetop/STARTER.Cargo.toml +++ b/pagetop/STARTER.Cargo.toml @@ -6,8 +6,21 @@ edition = "2021" # Ver más claves y sus definiciones en # https://doc.rust-lang.org/cargo/reference/manifest.html +[dependencies.pagetop] +path = "../pagetop" +# Opcional. Por defecto se puede usar PageTop sin base de datos. +features = ["mysql"] +# features = ["postgres"] +# features = ["sqlite"] +# PageTop puede dar soporte a todas las bases de datos. +# features = ["mysql", "postgres", "sqlite"] +# Sólo cuando no se usen las características predeterminadas. +default-features = false + [dependencies] -pagetop = { path = "pagetop" } +# Requerido. actix-web = "3.3.3" +# Opcional. Sólo si se usa la macro html!. maud = { version = "0.23.0" } +# Opcional. Si se requiere serialización de estructuras de datos. serde = { version = "1.0", features = ["derive"] } diff --git a/pagetop/src/core/global.rs b/pagetop/src/core/global.rs index 0b307c56..dd9aa909 100644 --- a/pagetop/src/core/global.rs +++ b/pagetop/src/core/global.rs @@ -43,7 +43,7 @@ pub fn modules(cfg: &mut server::web::ServiceConfig) { } #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] -pub fn check_migrations() { +pub fn run_migrations() { trace::info!("Checking migrations."); for m in MODULES.read().unwrap().iter() { m.migrations( diff --git a/pagetop/src/core/server/app.rs b/pagetop/src/core/server/app.rs index dd794a68..7338aa3b 100644 --- a/pagetop/src/core/server/app.rs +++ b/pagetop/src/core/server/app.rs @@ -72,7 +72,7 @@ impl Application { // Comprueba actualizaciones pendientes de la base de datos (opcional). #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] - global::check_migrations(); + global::run_migrations(); // Prepara el servidor web. let server = server::HttpServer::new(move || { From 2167ab94177ee3617b4e0c54774d9ce22609fead Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 16 Mar 2022 20:45:49 +0100 Subject: [PATCH 029/244] Actualiza y afina las dependencias de paquetes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit También normaliza los "traits" para definir temas y módulos usando el mismo criterio visto en SeaORM. --- drust/src/main.rs | 4 ++- pagetop/Cargo.toml | 19 ++++++----- pagetop/src/base/module/admin/mod.rs | 2 +- pagetop/src/base/module/homepage/mod.rs | 2 +- pagetop/src/base/module/user/mod.rs | 2 +- pagetop/src/base/theme/aliner/mod.rs | 2 +- pagetop/src/base/theme/bootsier/mod.rs | 2 +- pagetop/src/base/theme/minimal/mod.rs | 2 +- pagetop/src/core/{global.rs => all.rs} | 36 +++++++-------------- pagetop/src/core/html.rs | 1 + pagetop/src/core/mod.rs | 3 +- pagetop/src/core/module/definition.rs | 2 +- pagetop/src/core/module/mod.rs | 12 +++---- pagetop/src/core/response/page/assets.rs | 13 ++++---- pagetop/src/core/response/page/component.rs | 2 +- pagetop/src/core/response/page/container.rs | 2 +- pagetop/src/core/response/page/page.rs | 17 ++++++---- pagetop/src/core/server/app.rs | 20 ++++++------ pagetop/src/core/server/db.rs | 13 +++----- pagetop/src/core/server/locale.rs | 7 ++-- pagetop/src/core/theme/definition.rs | 6 ++-- pagetop/src/core/theme/mod.rs | 14 ++++---- pagetop/src/lib.rs | 2 -- pagetop/src/locale.rs | 4 +-- pagetop/src/prelude.rs | 2 ++ pagetop/tests/health_check.rs | 9 +++--- 26 files changed, 100 insertions(+), 100 deletions(-) rename pagetop/src/core/{global.rs => all.rs} (53%) create mode 100644 pagetop/src/core/html.rs diff --git a/drust/src/main.rs b/drust/src/main.rs index 6916d3b1..ac96b1ed 100644 --- a/drust/src/main.rs +++ b/drust/src/main.rs @@ -1,4 +1,6 @@ +use pagetop::prelude::*; + #[actix_web::main] async fn main() -> std::io::Result<()> { - pagetop::Application::build(None).await?.run()?.await + Application::prepare(essence).await?.run()?.await } diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index b828e58f..e6cbc75e 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -27,16 +27,16 @@ categories = [ doc-comment = "0.3.3" downcast-rs = "1.2.0" figlet-rs = "0.1.3" -futures = "0.3" -once_cell = "1.9.0" +futures = "0.3.21" +once_cell = "1.10.0" url = "2.2.2" config_rs = { package = "config", version = "0.11.0", features = ["toml"] } -tracing = "0.1" -tracing-appender = "0.2" -tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] } -tracing-unwrap = { version = "0.9", default-features = false } +tracing = "0.1.32" +tracing-appender = "0.2.1" +tracing-subscriber = { version = "0.3.9", features = ["json", "env-filter"] } +tracing-unwrap = { version = "0.9.2", default-features = false } tracing-actix-web = "0.2" fluent-templates = "0.6.1" @@ -51,17 +51,20 @@ sycamore = { version = "0.7.1", features = ["ssr"] } serde = { version = "1.0", features = ["derive"] } [dependencies.sea-orm] -version = "0.6" +version = "0.6.0" features = ["debug-print", "macros", "runtime-async-std-native-tls"] default-features = false optional = true [dependencies.sea-schema] -version = "0.5" +version = "0.6.0" features = ["debug-print", "migration"] default-features = false optional = true +[dev-dependencies] +tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread"] } + [features] default = [] mysql = ["sea-orm", "sea-schema", "sea-orm/sqlx-mysql"] diff --git a/pagetop/src/base/module/admin/mod.rs b/pagetop/src/base/module/admin/mod.rs index 0bb1202d..808aa75e 100644 --- a/pagetop/src/base/module/admin/mod.rs +++ b/pagetop/src/base/module/admin/mod.rs @@ -6,7 +6,7 @@ mod summary; pub struct AdminModule; -impl Module for AdminModule { +impl ModuleTrait for AdminModule { fn name(&self) -> &'static str { "admin" } diff --git a/pagetop/src/base/module/homepage/mod.rs b/pagetop/src/base/module/homepage/mod.rs index de4b98ce..b6aac4fe 100644 --- a/pagetop/src/base/module/homepage/mod.rs +++ b/pagetop/src/base/module/homepage/mod.rs @@ -4,7 +4,7 @@ localize!("en-US", "src/base/module/homepage/locales"); pub struct HomepageModule; -impl Module for HomepageModule { +impl ModuleTrait for HomepageModule { fn name(&self) -> &'static str { "homepage" } diff --git a/pagetop/src/base/module/user/mod.rs b/pagetop/src/base/module/user/mod.rs index 7dc3c043..99096377 100644 --- a/pagetop/src/base/module/user/mod.rs +++ b/pagetop/src/base/module/user/mod.rs @@ -7,7 +7,7 @@ mod migration; pub struct UserModule; -impl Module for UserModule { +impl ModuleTrait for UserModule { fn name(&self) -> &'static str { "user" } diff --git a/pagetop/src/base/theme/aliner/mod.rs b/pagetop/src/base/theme/aliner/mod.rs index b678d4b7..18df448f 100644 --- a/pagetop/src/base/theme/aliner/mod.rs +++ b/pagetop/src/base/theme/aliner/mod.rs @@ -4,7 +4,7 @@ include!(concat!(env!("OUT_DIR"), "/aliner.rs")); pub struct AlinerTheme; -impl Theme for AlinerTheme { +impl ThemeTrait for AlinerTheme { fn name(&self) -> &'static str { "aliner" } diff --git a/pagetop/src/base/theme/bootsier/mod.rs b/pagetop/src/base/theme/bootsier/mod.rs index 3a340a84..dd16d71c 100644 --- a/pagetop/src/base/theme/bootsier/mod.rs +++ b/pagetop/src/base/theme/bootsier/mod.rs @@ -6,7 +6,7 @@ localize!("en-US", "src/base/theme/bootsier/locales"); pub struct BootsierTheme; -impl Theme for BootsierTheme { +impl ThemeTrait for BootsierTheme { fn name(&self) -> &'static str { "bootsier" } diff --git a/pagetop/src/base/theme/minimal/mod.rs b/pagetop/src/base/theme/minimal/mod.rs index c6780005..b3a50906 100644 --- a/pagetop/src/base/theme/minimal/mod.rs +++ b/pagetop/src/base/theme/minimal/mod.rs @@ -2,7 +2,7 @@ use crate::prelude::*; pub struct MinimalTheme; -impl Theme for MinimalTheme { +impl ThemeTrait for MinimalTheme { fn name(&self) -> &'static str { "minimal" } diff --git a/pagetop/src/core/global.rs b/pagetop/src/core/all.rs similarity index 53% rename from pagetop/src/core/global.rs rename to pagetop/src/core/all.rs index dd9aa909..b48e0684 100644 --- a/pagetop/src/core/global.rs +++ b/pagetop/src/core/all.rs @@ -1,21 +1,19 @@ use crate::{Lazy, trace}; -use crate::core::theme::Theme; -use crate::core::module::Module; -use crate::core::response::page::PageContainer; +use crate::core::theme::ThemeTrait; +use crate::core::module::ModuleTrait; use crate::core::server; use std::sync::RwLock; -use std::collections::HashMap; include!(concat!(env!("OUT_DIR"), "/theme.rs")); // ----------------------------------------------------------------------------- -// Temas registrados y tema por defecto. +// Temas registrados y tema predeterminado. // ----------------------------------------------------------------------------- -pub static THEMES: Lazy<RwLock<Vec<&dyn Theme>>> = Lazy::new(|| { - RwLock::new(Vec::new()) -}); +pub static THEMES: Lazy<RwLock<Vec<&dyn ThemeTrait>>> = Lazy::new( + || { RwLock::new(Vec::new()) } +); pub fn themes(cfg: &mut server::web::ServiceConfig) { cfg.service(actix_web_static_files::ResourceFiles::new( @@ -32,9 +30,9 @@ pub fn themes(cfg: &mut server::web::ServiceConfig) { // Módulos registrados. // ----------------------------------------------------------------------------- -pub static MODULES: Lazy<RwLock<Vec<&dyn Module>>> = Lazy::new(|| { - RwLock::new(Vec::new()) -}); +pub static MODULES: Lazy<RwLock<Vec<&dyn ModuleTrait>>> = Lazy::new( + || { RwLock::new(Vec::new()) } +); pub fn modules(cfg: &mut server::web::ServiceConfig) { for m in MODULES.read().unwrap().iter() { @@ -43,19 +41,9 @@ pub fn modules(cfg: &mut server::web::ServiceConfig) { } #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] -pub fn run_migrations() { - trace::info!("Checking migrations."); +pub fn migrations() { + trace::info!("Checking migrations"); for m in MODULES.read().unwrap().iter() { - m.migrations( - &*server::db::DBCONN.read().unwrap() - ).expect("Failed to run migrations"); + m.migrations(&*server::db::DBCONN).expect("Failed to run migrations"); } } - -// ----------------------------------------------------------------------------- -// Componentes globales. -// ----------------------------------------------------------------------------- - -pub static COMPONENTS: Lazy<RwLock<HashMap<&str, PageContainer>>> = Lazy::new( - || { RwLock::new(HashMap::new()) } -); diff --git a/pagetop/src/core/html.rs b/pagetop/src/core/html.rs new file mode 100644 index 00000000..ba885bb3 --- /dev/null +++ b/pagetop/src/core/html.rs @@ -0,0 +1 @@ +pub use maud::{DOCTYPE, Markup, PreEscaped, html}; diff --git a/pagetop/src/core/mod.rs b/pagetop/src/core/mod.rs index 26618959..8db86b83 100644 --- a/pagetop/src/core/mod.rs +++ b/pagetop/src/core/mod.rs @@ -1,7 +1,8 @@ pub use actix_web::dev::Server; -mod global; +mod all; +pub mod html; pub mod theme; pub mod module; pub mod response; diff --git a/pagetop/src/core/module/definition.rs b/pagetop/src/core/module/definition.rs index 7dc6252b..011ef083 100644 --- a/pagetop/src/core/module/definition.rs +++ b/pagetop/src/core/module/definition.rs @@ -4,7 +4,7 @@ use crate::core::server; use crate::db; /// Los módulos deben implementar este *trait*. -pub trait Module: Send + Sync { +pub trait ModuleTrait: Send + Sync { fn name(&self) -> &'static str; fn fullname(&self) -> String; diff --git a/pagetop/src/core/module/mod.rs b/pagetop/src/core/module/mod.rs index 439cff79..2a42352a 100644 --- a/pagetop/src/core/module/mod.rs +++ b/pagetop/src/core/module/mod.rs @@ -1,14 +1,14 @@ -use crate::core::global; +use crate::core::all; mod definition; -pub use definition::Module; +pub use definition::ModuleTrait; -pub fn register_module(m: &'static (dyn Module + 'static)) { - global::MODULES.write().unwrap().push(m); +pub fn register_module(m: &'static (dyn ModuleTrait + 'static)) { + all::MODULES.write().unwrap().push(m); } -pub fn find_module(name: &str) -> Option<&'static (dyn Module + 'static)> { - let modules = global::MODULES.write().unwrap(); +pub fn find_module(name: &str) -> Option<&'static (dyn ModuleTrait + 'static)> { + let modules = all::MODULES.write().unwrap(); match modules.iter().find(|t| t.name() == name) { Some(module) => Some(*module), _ => None, diff --git a/pagetop/src/core/response/page/assets.rs b/pagetop/src/core/response/page/assets.rs index 11cdd35c..2bd96fc2 100644 --- a/pagetop/src/core/response/page/assets.rs +++ b/pagetop/src/core/response/page/assets.rs @@ -1,10 +1,11 @@ use crate::{Lazy, base}; use crate::config::SETTINGS; -use crate::core::global; -use crate::core::theme::{Markup, PreEscaped, Theme, find_theme, html}; +use crate::core::all; +use crate::core::html::{Markup, PreEscaped, html}; +use crate::core::theme::*; -static DEFAULT_THEME: Lazy<&dyn Theme> = Lazy::new(|| { - for t in global::THEMES.read().unwrap().iter() { +static DEFAULT_THEME: Lazy<&dyn ThemeTrait> = Lazy::new(|| { + for t in all::THEMES.read().unwrap().iter() { if t.name().to_lowercase() == SETTINGS.app.theme.to_lowercase() { return *t; } @@ -184,7 +185,7 @@ impl JavaScript { // ----------------------------------------------------------------------------- pub struct PageAssets { - theme : &'static dyn Theme, + theme : &'static dyn ThemeTrait, favicon : Option<Favicon>, metadata : Vec<(String, String)>, stylesheets: Vec<StyleSheet>, @@ -259,7 +260,7 @@ impl PageAssets { /// Assets GETTERS. - pub fn theme(&mut self) -> &'static dyn Theme { + pub fn theme(&mut self) -> &'static dyn ThemeTrait { self.theme } diff --git a/pagetop/src/core/response/page/component.rs b/pagetop/src/core/response/page/component.rs index 1472ffe2..78925468 100644 --- a/pagetop/src/core/response/page/component.rs +++ b/pagetop/src/core/response/page/component.rs @@ -1,4 +1,4 @@ -use crate::core::theme::{Markup, html}; +use crate::core::html::{Markup, html}; use crate::core::response::page::PageAssets; use downcast_rs::{Downcast, impl_downcast}; diff --git a/pagetop/src/core/response/page/container.rs b/pagetop/src/core/response/page/container.rs index 6bf5e56a..4a577b2d 100644 --- a/pagetop/src/core/response/page/container.rs +++ b/pagetop/src/core/response/page/container.rs @@ -1,4 +1,4 @@ -use crate::core::theme::{Markup, html}; +use crate::core::html::{Markup, html}; use crate::core::response::page::{PageAssets, PageComponent, render_component}; use std::sync::Arc; diff --git a/pagetop/src/core/response/page/page.rs b/pagetop/src/core/response/page/page.rs index 8052683d..d47a33f1 100644 --- a/pagetop/src/core/response/page/page.rs +++ b/pagetop/src/core/response/page/page.rs @@ -1,12 +1,17 @@ use crate::{Lazy, trace, util}; use crate::config::SETTINGS; -use crate::core::{global, server}; -use crate::core::theme::{DOCTYPE, Markup, html}; +use crate::core::html::{DOCTYPE, Markup, html}; use crate::core::response::page::{PageAssets, PageComponent, PageContainer}; +use crate::core::server; use std::borrow::Cow; +use std::sync::RwLock; use std::collections::HashMap; +static COMPONENTS: Lazy<RwLock<HashMap<&str, PageContainer>>> = Lazy::new(|| { + RwLock::new(HashMap::new()) +}); + static DEFAULT_LANGUAGE: Lazy<Option<String>> = Lazy::new(|| { let language = SETTINGS.app.language[..2].to_lowercase(); if !language.is_empty() { @@ -25,9 +30,9 @@ static DEFAULT_DIRECTION: Lazy<Option<String>> = Lazy::new(|| { "" => None, _ => { trace::warn!( - "Text direction \"{}\" not valid. {}.", + "Text direction \"{}\" not valid, {}", SETTINGS.app.direction, - "Check the settings file" + "check the settings file" ); None } @@ -63,7 +68,7 @@ impl<'a> Page<'a> { description : None, body_classes: "body".into(), assets : PageAssets::new(), - regions : global::COMPONENTS.read().unwrap().clone(), + regions : COMPONENTS.read().unwrap().clone(), template : "default".to_owned(), } } @@ -208,7 +213,7 @@ pub fn render_component( } pub fn add_component_to(region: &'static str, component: impl PageComponent) { - let mut hmap = global::COMPONENTS.write().unwrap(); + let mut hmap = COMPONENTS.write().unwrap(); if let Some(regions) = hmap.get_mut(region) { regions.add(component); } else { diff --git a/pagetop/src/core/server/app.rs b/pagetop/src/core/server/app.rs index 7338aa3b..cbca9979 100644 --- a/pagetop/src/core/server/app.rs +++ b/pagetop/src/core/server/app.rs @@ -1,6 +1,6 @@ use crate::{Lazy, base, trace}; use crate::config::SETTINGS; -use crate::core::{Server, global, server}; +use crate::core::{Server, all, server}; use crate::core::theme::register_theme; use crate::core::module::register_module; @@ -11,8 +11,12 @@ pub struct Application { server: Server, } +pub fn essence() { + trace::info!("No bootstrap configured"); +} + impl Application { - pub async fn build(bootstrap: Option<fn()>) -> Result<Self, Error> { + pub async fn prepare(bootstrap: fn()) -> Result<Self, Error> { // Imprime un rótulo de presentación (opcional). if SETTINGS.app.startup_banner.to_lowercase() != "off" { let figfont = figlet_rs::FIGfont::from_content( @@ -61,10 +65,8 @@ impl Application { register_module(&base::module::user::UserModule); // Ejecuta la función de inicio de la aplicación. - if bootstrap != None { - trace::info!("Calling application bootstrap."); - let _ = &(bootstrap.unwrap())(); - } + trace::info!("Calling application bootstrap"); + let _ = &bootstrap(); // Registra el módulo para la página de inicio de PageTop. // Al ser el último, puede sobrecargarse con la función de inicio. @@ -72,15 +74,15 @@ impl Application { // Comprueba actualizaciones pendientes de la base de datos (opcional). #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] - global::run_migrations(); + all::migrations(); // Prepara el servidor web. let server = server::HttpServer::new(move || { server::App::new() .wrap(tracing_actix_web::TracingLogger) .wrap(NormalizePath::new(TrailingSlash::Trim)) - .configure(&global::themes) - .configure(&global::modules) + .configure(&all::themes) + .configure(&all::modules) }) .bind(format!("{}:{}", &SETTINGS.webserver.bind_address, diff --git a/pagetop/src/core/server/db.rs b/pagetop/src/core/server/db.rs index 8c5c9f1f..9d196970 100644 --- a/pagetop/src/core/server/db.rs +++ b/pagetop/src/core/server/db.rs @@ -1,13 +1,12 @@ use crate::{Lazy, db, run_now, trace}; use crate::config::SETTINGS; -use std::sync::RwLock; use sea_orm::{ConnectOptions, Database}; use tracing_unwrap::ResultExt; -pub static DBCONN: Lazy<RwLock<db::DbConn>> = Lazy::new(|| { +pub static DBCONN: Lazy<db::DbConn> = Lazy::new(|| { trace::info!( - "Connecting to database \"{}\" using a pool of {} connections.", + "Connecting to database \"{}\" using a pool of {} connections", &SETTINGS.database.db_name, &SETTINGS.database.max_pool_size ); @@ -41,20 +40,18 @@ pub static DBCONN: Lazy<RwLock<db::DbConn>> = Lazy::new(|| { ).as_str()).unwrap(), _ => { trace::error!( - "Unrecognized database type \"{}\".", + "Unrecognized database type \"{}\"", &SETTINGS.database.db_type ); db::DbUri::parse("").unwrap() } }; - let db_conn = run_now( + run_now( Database::connect::<ConnectOptions>({ let mut db_opt = ConnectOptions::new(db_uri.to_string()); db_opt.max_connections(SETTINGS.database.max_pool_size); db_opt.into() }) - ).expect_or_log("Failed to connect to database"); - - RwLock::new(db_conn) + ).expect_or_log("Failed to connect to database") }); diff --git a/pagetop/src/core/server/locale.rs b/pagetop/src/core/server/locale.rs index 8bc6fc10..59fc8468 100644 --- a/pagetop/src/core/server/locale.rs +++ b/pagetop/src/core/server/locale.rs @@ -11,11 +11,12 @@ pub static LANGID: Lazy<LanguageIdentifier> = Lazy::new(|| { Ok(language) => language, Err(_) => { trace::warn!( - "Failed to parse language \"{}\". {}. {}. {}.", + "{}, {} \"{}\"! {}, {}", + "Failed to parse language", + "unrecognized Unicode Language Identifier", SETTINGS.app.language, - "Unrecognized Unicode Language Identifier", "Using \"en-US\"", - "Check the settings file", + "check the settings file", ); "en-US".parse().unwrap() } diff --git a/pagetop/src/core/theme/definition.rs b/pagetop/src/core/theme/definition.rs index 12d9e05f..eb67ec10 100644 --- a/pagetop/src/core/theme/definition.rs +++ b/pagetop/src/core/theme/definition.rs @@ -1,11 +1,11 @@ use crate::config::SETTINGS; -use crate::core::server; -use crate::core::theme::{Markup, html}; +use crate::core::html::{Markup, html}; use crate::core::response::page::{Page, PageAssets, PageComponent}; +use crate::core::server; use crate::base::component::Chunck; /// Los temas deben implementar este "trait". -pub trait Theme: Send + Sync { +pub trait ThemeTrait: Send + Sync { fn name(&self) -> &'static str; fn fullname(&self) -> String; diff --git a/pagetop/src/core/theme/mod.rs b/pagetop/src/core/theme/mod.rs index 8292ade6..e83f4307 100644 --- a/pagetop/src/core/theme/mod.rs +++ b/pagetop/src/core/theme/mod.rs @@ -1,16 +1,14 @@ -use crate::core::global; - -pub use maud::{DOCTYPE, Markup, PreEscaped, html}; +use crate::core::all; mod definition; -pub use definition::Theme; +pub use definition::ThemeTrait; -pub fn register_theme(t: &'static (dyn Theme + 'static)) { - global::THEMES.write().unwrap().push(t); +pub fn register_theme(t: &'static (dyn ThemeTrait + 'static)) { + all::THEMES.write().unwrap().push(t); } -pub fn find_theme(name: &str) -> Option<&'static (dyn Theme + 'static)> { - let themes = global::THEMES.write().unwrap(); +pub fn find_theme(name: &str) -> Option<&'static (dyn ThemeTrait + 'static)> { + let themes = all::THEMES.write().unwrap(); match themes.iter().find(|t| t.name() == name) { Some(theme) => Some(*theme), _ => None, diff --git a/pagetop/src/lib.rs b/pagetop/src/lib.rs index b8485f96..daf0577d 100644 --- a/pagetop/src/lib.rs +++ b/pagetop/src/lib.rs @@ -20,5 +20,3 @@ pub mod base; // Temas, Módulos y Componentes base. pub mod util; // Macros y funciones útiles. pub mod prelude; // Re-exporta recursos comunes. - -pub use crate::core::server::app::Application; diff --git a/pagetop/src/locale.rs b/pagetop/src/locale.rs index 22a01ba6..eac11472 100644 --- a/pagetop/src/locale.rs +++ b/pagetop/src/locale.rs @@ -37,8 +37,8 @@ macro_rules! localize { fn e( key: &str, args: &std::collections::HashMap<String, FluentValue> - ) -> crate::core::theme::PreEscaped<String> { - crate::core::theme::PreEscaped( + ) -> crate::core::html::PreEscaped<String> { + crate::core::html::PreEscaped( LOCALES.lookup_with_args(&LANGID, key, args) ) } diff --git a/pagetop/src/prelude.rs b/pagetop/src/prelude.rs index f0a4b031..1dd8bd79 100644 --- a/pagetop/src/prelude.rs +++ b/pagetop/src/prelude.rs @@ -8,10 +8,12 @@ pub use crate::localize; #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] pub use crate::{db, db_migrations}; +pub use crate::core::html::*; pub use crate::core::theme::*; pub use crate::core::module::*; pub use crate::core::response::page::*; pub use crate::core::server; +pub use crate::core::server::app::{Application, essence}; pub use crate::base::component::*; diff --git a/pagetop/tests/health_check.rs b/pagetop/tests/health_check.rs index 0c309bea..dd980796 100644 --- a/pagetop/tests/health_check.rs +++ b/pagetop/tests/health_check.rs @@ -1,7 +1,8 @@ -use pagetop::core::server; - -fn spawn_app() { - let server = server::run(None).expect("Failed to bind address"); +async fn spawn_app() { + let server = pagetop::Application::prepare(None) + .await? + .run()? + .expect("Failed to prepare server"); let _ = tokio::spawn(server); } From 58afd1f2582fa2b62357d345437199d3c17e150d Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 17 Mar 2022 19:41:41 +0100 Subject: [PATCH 030/244] =?UTF-8?q?Corrige=20ejecuci=C3=B3n=20de=20las=20m?= =?UTF-8?q?igraciones=20en=20m=C3=B3dulos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pagetop/src/base/module/user/migration/mod.rs | 11 ---------- pagetop/src/base/module/user/mod.rs | 8 ++++--- pagetop/src/config.rs | 10 ++++----- pagetop/src/core/all.rs | 22 ++++++++++++++----- pagetop/src/core/module/definition.rs | 4 ++-- pagetop/src/core/server/app.rs | 2 +- pagetop/src/db.rs | 10 +++------ pagetop/src/prelude.rs | 2 +- pagetop/src/util.rs | 4 ++-- 9 files changed, 35 insertions(+), 38 deletions(-) diff --git a/pagetop/src/base/module/user/migration/mod.rs b/pagetop/src/base/module/user/migration/mod.rs index 8b9167a6..60836980 100644 --- a/pagetop/src/base/module/user/migration/mod.rs +++ b/pagetop/src/base/module/user/migration/mod.rs @@ -1,12 +1 @@ -use crate::db::migration::*; - pub mod m20220312_000001_create_table_user; - -pub struct Migrator; - -#[async_trait::async_trait] -impl MigratorTrait for Migrator { - fn migrations() -> Vec<Box<dyn MigrationTrait>> { - vec![Box::new(m20220312_000001_create_table_user::Migration)] - } -} diff --git a/pagetop/src/base/module/user/mod.rs b/pagetop/src/base/module/user/mod.rs index 99096377..362961eb 100644 --- a/pagetop/src/base/module/user/mod.rs +++ b/pagetop/src/base/module/user/mod.rs @@ -1,6 +1,6 @@ use crate::prelude::*; -localize!("en-US", "src/base/module/user/locales"); +localize!("src/base/module/user/locales"); mod entity; mod migration; @@ -24,8 +24,10 @@ impl ModuleTrait for UserModule { cfg.route("/user/login", server::web::get().to(login)); } - fn migrations(&self, dbconn: &db::DbConn) -> Result<(), db::DbErr> { - db_migrations!(dbconn) + fn migrations(&self) -> Vec<Box<dyn db::migration::MigrationTrait>> { + vec![ + boxed_migration!(m20220312_000001_create_table_user) + ] } } diff --git a/pagetop/src/config.rs b/pagetop/src/config.rs index fedffc21..27dbb275 100644 --- a/pagetop/src/config.rs +++ b/pagetop/src/config.rs @@ -45,15 +45,15 @@ pub static CONFIG: Lazy<Config> = Lazy::new(|| { /// seguros. Produce un *panic!* en caso de asignaciones no válidas. macro_rules! config_map { ( - $COMM:expr, - $CONF:ident, - $TYPE:tt + $doc:expr, + $SETTINGS:ident, + $Type:tt $(, $key:expr => $value:expr)* ) => { $crate::doc_comment! { - concat!($COMM), + concat!($doc), - pub static $CONF: $crate::Lazy<$TYPE> = $crate::Lazy::new(|| { + pub static $SETTINGS: $crate::Lazy<$Type> = $crate::Lazy::new(|| { let mut settings = $crate::config::CONFIG.clone(); $( settings.set_default($key, $value).unwrap(); diff --git a/pagetop/src/core/all.rs b/pagetop/src/core/all.rs index b48e0684..20df22bd 100644 --- a/pagetop/src/core/all.rs +++ b/pagetop/src/core/all.rs @@ -1,4 +1,5 @@ -use crate::{Lazy, trace}; +use crate::{Lazy, run_now}; +use crate::db::migration::*; use crate::core::theme::ThemeTrait; use crate::core::module::ModuleTrait; use crate::core::server; @@ -41,9 +42,18 @@ pub fn modules(cfg: &mut server::web::ServiceConfig) { } #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] -pub fn migrations() { - trace::info!("Checking migrations"); - for m in MODULES.read().unwrap().iter() { - m.migrations(&*server::db::DBCONN).expect("Failed to run migrations"); - } +pub fn run_migrations() { + run_now({ + struct Migrator; + impl MigratorTrait for Migrator { + fn migrations() -> Vec<Box<dyn MigrationTrait>> { + let mut migrations = vec![]; + for m in MODULES.read().unwrap().iter() { + migrations.append(&mut m.migrations()); + } + migrations + } + } + Migrator::up(&server::db::DBCONN, None) + }).unwrap(); } diff --git a/pagetop/src/core/module/definition.rs b/pagetop/src/core/module/definition.rs index 011ef083..c50cace3 100644 --- a/pagetop/src/core/module/definition.rs +++ b/pagetop/src/core/module/definition.rs @@ -19,7 +19,7 @@ pub trait ModuleTrait: Send + Sync { #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] #[allow(unused_variables)] - fn migrations(&self, dbconn: &db::DbConn) -> Result<(), db::DbErr> { - Ok(()) + fn migrations(&self) -> Vec<Box<dyn db::migration::MigrationTrait>> { + vec![] } } diff --git a/pagetop/src/core/server/app.rs b/pagetop/src/core/server/app.rs index cbca9979..74e1690d 100644 --- a/pagetop/src/core/server/app.rs +++ b/pagetop/src/core/server/app.rs @@ -74,7 +74,7 @@ impl Application { // Comprueba actualizaciones pendientes de la base de datos (opcional). #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] - all::migrations(); + all::run_migrations(); // Prepara el servidor web. let server = server::HttpServer::new(move || { diff --git a/pagetop/src/db.rs b/pagetop/src/db.rs index b487cc19..d68a5aac 100644 --- a/pagetop/src/db.rs +++ b/pagetop/src/db.rs @@ -14,12 +14,8 @@ pub mod migration { } #[macro_export] -macro_rules! db_migrations { - ( $DBCONN:ident ) => {{ - $crate::run_now({ - use $crate::db::migration::MigratorTrait; - - migration::Migrator::up($DBCONN, None) - }) +macro_rules! boxed_migration { + ( $migration_module:ident ) => {{ + Box::new(migration::$migration_module::Migration) }}; } diff --git a/pagetop/src/prelude.rs b/pagetop/src/prelude.rs index 1dd8bd79..18d160ce 100644 --- a/pagetop/src/prelude.rs +++ b/pagetop/src/prelude.rs @@ -6,7 +6,7 @@ pub use crate::trace; pub use crate::localize; #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] -pub use crate::{db, db_migrations}; +pub use crate::{db, boxed_migration}; pub use crate::core::html::*; pub use crate::core::theme::*; diff --git a/pagetop/src/util.rs b/pagetop/src/util.rs index c56d2146..3fff0a23 100644 --- a/pagetop/src/util.rs +++ b/pagetop/src/util.rs @@ -9,10 +9,10 @@ /// ]; /// ``` macro_rules! args { - ( $($KEY:expr => $VALUE:expr),* ) => {{ + ( $($key:expr => $value:expr),* ) => {{ let mut a = std::collections::HashMap::new(); $( - a.insert(String::from($KEY), $VALUE.into()); + a.insert(String::from($key), $value.into()); )* a }}; From 516d9683da657176dbd671ce669e4c26b2d4acdd Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 17 Mar 2022 19:43:42 +0100 Subject: [PATCH 031/244] Modifica y predetermina los locales para en-US --- pagetop/src/base/module/admin/mod.rs | 2 +- pagetop/src/base/module/homepage/mod.rs | 2 +- pagetop/src/base/theme/bootsier/mod.rs | 2 +- pagetop/src/locale.rs | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pagetop/src/base/module/admin/mod.rs b/pagetop/src/base/module/admin/mod.rs index 808aa75e..e9b58703 100644 --- a/pagetop/src/base/module/admin/mod.rs +++ b/pagetop/src/base/module/admin/mod.rs @@ -1,6 +1,6 @@ use crate::prelude::*; -localize!("en-US", "src/base/module/admin/locales"); +localize!("src/base/module/admin/locales"); mod summary; diff --git a/pagetop/src/base/module/homepage/mod.rs b/pagetop/src/base/module/homepage/mod.rs index b6aac4fe..6b3b9741 100644 --- a/pagetop/src/base/module/homepage/mod.rs +++ b/pagetop/src/base/module/homepage/mod.rs @@ -1,6 +1,6 @@ use crate::prelude::*; -localize!("en-US", "src/base/module/homepage/locales"); +localize!("src/base/module/homepage/locales"); pub struct HomepageModule; diff --git a/pagetop/src/base/theme/bootsier/mod.rs b/pagetop/src/base/theme/bootsier/mod.rs index dd16d71c..3c4176f0 100644 --- a/pagetop/src/base/theme/bootsier/mod.rs +++ b/pagetop/src/base/theme/bootsier/mod.rs @@ -2,7 +2,7 @@ use crate::prelude::*; include!(concat!(env!("OUT_DIR"), "/bootsier.rs")); -localize!("en-US", "src/base/theme/bootsier/locales"); +localize!("src/base/theme/bootsier/locales"); pub struct BootsierTheme; diff --git a/pagetop/src/locale.rs b/pagetop/src/locale.rs index eac11472..a5a136c2 100644 --- a/pagetop/src/locale.rs +++ b/pagetop/src/locale.rs @@ -5,15 +5,15 @@ pub use fluent_templates::fluent_bundle::FluentValue; #[macro_export] /// Permite integrar fácilmente localización en temas, módulos y componentes. macro_rules! localize { - ( $DEF_LANGID:literal, $locales:literal $(, $core_locales:literal)? ) => { + ( $dir_locales:literal $(, $core_locales:literal)? ) => { use $crate::locale::*; use $crate::core::server::locale::LANGID; static_locale! { static LOCALES = { - locales: $locales, + locales: $dir_locales, $( core_locales: $core_locales, )? - fallback_language: $DEF_LANGID, + fallback_language: "en-US", // Elimina las marcas Unicode que delimitan los argumentos. customise: |bundle| bundle.set_use_isolating(false), @@ -37,8 +37,8 @@ macro_rules! localize { fn e( key: &str, args: &std::collections::HashMap<String, FluentValue> - ) -> crate::core::html::PreEscaped<String> { - crate::core::html::PreEscaped( + ) -> $crate::core::html::PreEscaped<String> { + $crate::core::html::PreEscaped( LOCALES.lookup_with_args(&LANGID, key, args) ) } From fbc6ab2adfab1aa4e7da8d3c832d5850ea775366 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 19 Mar 2022 20:10:51 +0100 Subject: [PATCH 032/244] =?UTF-8?q?Libera=20la=20versi=C3=B3n=20de=20desar?= =?UTF-8?q?rollo=200.0.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 3 + drust/Cargo.toml | 3 + drust/src/main.rs | 8 +- pagetop-admin/Cargo.toml | 17 +++ pagetop-admin/src/lib.rs | 24 ++++ .../src}/locales/en-US/admin.ftl | 0 .../src}/locales/es-ES/admin.ftl | 0 .../admin => pagetop-admin/src}/summary.rs | 4 +- pagetop-node/Cargo.toml | 16 +++ pagetop-node/src/lib.rs | 39 +++++++ pagetop-node/src/locales/en-US/homepage.ftl | 2 + pagetop-node/src/locales/es-ES/homepage.ftl | 2 + ...m20220316_000001_create_table_node_type.rs | 90 ++++++++++++++ .../m20220316_000002_create_table_node.rs | 110 ++++++++++++++++++ ...0220316_000003_create_table_node_access.rs | 70 +++++++++++ ...20316_000004_create_table_node_revision.rs | 90 ++++++++++++++ pagetop-node/src/migration/mod.rs | 4 + pagetop-user/Cargo.toml | 22 ++++ .../user => pagetop-user/src}/entity/mod.rs | 0 .../user => pagetop-user/src}/entity/user.rs | 0 .../user/mod.rs => pagetop-user/src/lib.rs | 14 +-- .../src}/locales/en-US/homepage.ftl | 0 .../src}/locales/es-ES/homepage.ftl | 0 .../m20220312_000001_create_table_user.rs | 0 .../src}/migration/mod.rs | 0 pagetop/Cargo.toml | 2 +- ...RTER.Cargo.toml => STARTER.bin.Cargo.toml} | 5 + pagetop/STARTER.lib.Cargo.toml | 29 +++++ pagetop/src/{core => }/all.rs | 13 +-- .../server/app.rs => app/application.rs} | 35 +++--- pagetop/src/{core/server => app}/db.rs | 0 .../{core/server => app}/figfonts/slant.flf | 0 .../{core/server => app}/figfonts/small.flf | 0 .../{core/server => app}/figfonts/speed.flf | 0 .../server => app}/figfonts/starwars.flf | 0 pagetop/src/{core/server => app}/locale.rs | 0 pagetop/src/{core/server => app}/mod.rs | 3 +- pagetop/src/{core/server => app}/tracing.rs | 0 pagetop/src/base/mod.rs | 5 - pagetop/src/base/module/admin/mod.rs | 28 ----- pagetop/src/base/module/mod.rs | 5 - pagetop/src/base/theme/mod.rs | 3 - pagetop/src/{base => }/component/block.rs | 0 pagetop/src/{base => }/component/chunck.rs | 0 pagetop/src/{base => }/component/container.rs | 0 .../src/{base => }/component/form/button.rs | 0 pagetop/src/{base => }/component/form/date.rs | 0 pagetop/src/{base => }/component/form/form.rs | 0 .../src/{base => }/component/form/hidden.rs | 0 .../src/{base => }/component/form/input.rs | 0 pagetop/src/{base => }/component/form/mod.rs | 0 pagetop/src/{base => }/component/menu.rs | 0 pagetop/src/{base => }/component/mod.rs | 0 pagetop/src/core/mod.rs | 9 -- pagetop/src/core/module/mod.rs | 16 --- pagetop/src/{core => }/html.rs | 0 pagetop/src/lib.rs | 12 +- pagetop/src/locale.rs | 6 +- pagetop/src/{core => }/module/definition.rs | 19 ++- .../homepage/locales/en-US/homepage.ftl | 0 .../homepage/locales/es-ES/homepage.ftl | 0 pagetop/src/{base => }/module/homepage/mod.rs | 12 +- pagetop/src/module/mod.rs | 17 +++ pagetop/src/prelude.rs | 15 +-- pagetop/src/{core => }/response/mod.rs | 0 .../src/{core => }/response/page/assets.rs | 9 +- .../src/{core => }/response/page/component.rs | 4 +- .../src/{core => }/response/page/container.rs | 4 +- pagetop/src/{core => }/response/page/mod.rs | 0 pagetop/src/{core => }/response/page/page.rs | 9 +- pagetop/src/{base => }/theme/aliner/mod.rs | 2 +- .../theme/bootsier/locales/en-US/bootsier.ftl | 0 .../theme/bootsier/locales/es-ES/bootsier.ftl | 0 pagetop/src/{base => }/theme/bootsier/mod.rs | 10 +- pagetop/src/{core => }/theme/definition.rs | 12 +- pagetop/src/{base => }/theme/minimal/mod.rs | 0 pagetop/src/{core => }/theme/mod.rs | 10 +- 77 files changed, 651 insertions(+), 161 deletions(-) create mode 100644 pagetop-admin/Cargo.toml create mode 100644 pagetop-admin/src/lib.rs rename {pagetop/src/base/module/admin => pagetop-admin/src}/locales/en-US/admin.ftl (100%) rename {pagetop/src/base/module/admin => pagetop-admin/src}/locales/es-ES/admin.ftl (100%) rename {pagetop/src/base/module/admin => pagetop-admin/src}/summary.rs (95%) create mode 100644 pagetop-node/Cargo.toml create mode 100644 pagetop-node/src/lib.rs create mode 100644 pagetop-node/src/locales/en-US/homepage.ftl create mode 100644 pagetop-node/src/locales/es-ES/homepage.ftl create mode 100644 pagetop-node/src/migration/m20220316_000001_create_table_node_type.rs create mode 100644 pagetop-node/src/migration/m20220316_000002_create_table_node.rs create mode 100644 pagetop-node/src/migration/m20220316_000003_create_table_node_access.rs create mode 100644 pagetop-node/src/migration/m20220316_000004_create_table_node_revision.rs create mode 100644 pagetop-node/src/migration/mod.rs create mode 100644 pagetop-user/Cargo.toml rename {pagetop/src/base/module/user => pagetop-user/src}/entity/mod.rs (100%) rename {pagetop/src/base/module/user => pagetop-user/src}/entity/user.rs (100%) rename pagetop/src/base/module/user/mod.rs => pagetop-user/src/lib.rs (80%) rename {pagetop/src/base/module/user => pagetop-user/src}/locales/en-US/homepage.ftl (100%) rename {pagetop/src/base/module/user => pagetop-user/src}/locales/es-ES/homepage.ftl (100%) rename {pagetop/src/base/module/user => pagetop-user/src}/migration/m20220312_000001_create_table_user.rs (100%) rename {pagetop/src/base/module/user => pagetop-user/src}/migration/mod.rs (100%) rename pagetop/{STARTER.Cargo.toml => STARTER.bin.Cargo.toml} (88%) create mode 100644 pagetop/STARTER.lib.Cargo.toml rename pagetop/src/{core => }/all.rs (83%) rename pagetop/src/{core/server/app.rs => app/application.rs} (73%) rename pagetop/src/{core/server => app}/db.rs (100%) rename pagetop/src/{core/server => app}/figfonts/slant.flf (100%) rename pagetop/src/{core/server => app}/figfonts/small.flf (100%) rename pagetop/src/{core/server => app}/figfonts/speed.flf (100%) rename pagetop/src/{core/server => app}/figfonts/starwars.flf (100%) rename pagetop/src/{core/server => app}/locale.rs (100%) rename pagetop/src/{core/server => app}/mod.rs (81%) rename pagetop/src/{core/server => app}/tracing.rs (100%) delete mode 100644 pagetop/src/base/mod.rs delete mode 100644 pagetop/src/base/module/admin/mod.rs delete mode 100644 pagetop/src/base/module/mod.rs delete mode 100644 pagetop/src/base/theme/mod.rs rename pagetop/src/{base => }/component/block.rs (100%) rename pagetop/src/{base => }/component/chunck.rs (100%) rename pagetop/src/{base => }/component/container.rs (100%) rename pagetop/src/{base => }/component/form/button.rs (100%) rename pagetop/src/{base => }/component/form/date.rs (100%) rename pagetop/src/{base => }/component/form/form.rs (100%) rename pagetop/src/{base => }/component/form/hidden.rs (100%) rename pagetop/src/{base => }/component/form/input.rs (100%) rename pagetop/src/{base => }/component/form/mod.rs (100%) rename pagetop/src/{base => }/component/menu.rs (100%) rename pagetop/src/{base => }/component/mod.rs (100%) delete mode 100644 pagetop/src/core/mod.rs delete mode 100644 pagetop/src/core/module/mod.rs rename pagetop/src/{core => }/html.rs (100%) rename pagetop/src/{core => }/module/definition.rs (56%) rename pagetop/src/{base => }/module/homepage/locales/en-US/homepage.ftl (100%) rename pagetop/src/{base => }/module/homepage/locales/es-ES/homepage.ftl (100%) rename pagetop/src/{base => }/module/homepage/mod.rs (88%) create mode 100644 pagetop/src/module/mod.rs rename pagetop/src/{core => }/response/mod.rs (100%) rename pagetop/src/{core => }/response/page/assets.rs (98%) rename pagetop/src/{core => }/response/page/component.rs (90%) rename pagetop/src/{core => }/response/page/container.rs (86%) rename pagetop/src/{core => }/response/page/mod.rs (100%) rename pagetop/src/{core => }/response/page/page.rs (96%) rename pagetop/src/{base => }/theme/aliner/mod.rs (90%) rename pagetop/src/{base => }/theme/bootsier/locales/en-US/bootsier.ftl (100%) rename pagetop/src/{base => }/theme/bootsier/locales/es-ES/bootsier.ftl (100%) rename pagetop/src/{base => }/theme/bootsier/mod.rs (88%) rename pagetop/src/{core => }/theme/definition.rs (89%) rename pagetop/src/{base => }/theme/minimal/mod.rs (100%) rename pagetop/src/{core => }/theme/mod.rs (58%) diff --git a/Cargo.toml b/Cargo.toml index 2369a8da..00ab4e13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,4 +2,7 @@ members = [ "drust", "pagetop", + "pagetop-admin", + "pagetop-user", + "pagetop-node", ] \ No newline at end of file diff --git a/drust/Cargo.toml b/drust/Cargo.toml index dd0bfdc5..88ebabde 100644 --- a/drust/Cargo.toml +++ b/drust/Cargo.toml @@ -19,3 +19,6 @@ default-features = false [dependencies] actix-web = "3.3.3" +pagetop-admin = { path = "../pagetop-admin" } +pagetop-user = { path = "../pagetop-user" } +pagetop-node = { path = "../pagetop-node" } diff --git a/drust/src/main.rs b/drust/src/main.rs index ac96b1ed..e51f5311 100644 --- a/drust/src/main.rs +++ b/drust/src/main.rs @@ -1,6 +1,12 @@ use pagetop::prelude::*; +fn bootstrap() { + register_module(&pagetop_admin::AdminModule); + register_module(&pagetop_user::UserModule); + register_module(&pagetop_node::NodeModule); +} + #[actix_web::main] async fn main() -> std::io::Result<()> { - Application::prepare(essence).await?.run()?.await + Application::prepare(bootstrap).await?.run()?.await } diff --git a/pagetop-admin/Cargo.toml b/pagetop-admin/Cargo.toml new file mode 100644 index 00000000..1bff0edd --- /dev/null +++ b/pagetop-admin/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "pagetop-admin" +version = "0.0.1" +edition = "2021" + +authors = [ + "Manuel Cillero <manuel@cillero.es>" +] +description = """\ + Allows content to be submitted to the site and displayed on pages.\ +""" +homepage = "https://suitepro.cillero.es/projects/drust" +repository = "https://gitlab.com/manuelcillero/drust" + +[dependencies] +pagetop = { path = "../pagetop" } +maud = { version = "0.23.0" } diff --git a/pagetop-admin/src/lib.rs b/pagetop-admin/src/lib.rs new file mode 100644 index 00000000..e3ad0337 --- /dev/null +++ b/pagetop-admin/src/lib.rs @@ -0,0 +1,24 @@ +use pagetop::prelude::*; + +localize!("src/locales"); + +mod summary; + +pub struct AdminModule; + +impl ModuleTrait for AdminModule { + fn fullname(&self) -> String { + l("module_fullname") + } + + fn description(&self) -> Option<String> { + Some(l("module_description")) + } + + fn configure_module(&self, cfg: &mut app::web::ServiceConfig) { + cfg.service( + app::web::scope("/admin") + .route("", app::web::get().to(summary::summary)) + ); + } +} diff --git a/pagetop/src/base/module/admin/locales/en-US/admin.ftl b/pagetop-admin/src/locales/en-US/admin.ftl similarity index 100% rename from pagetop/src/base/module/admin/locales/en-US/admin.ftl rename to pagetop-admin/src/locales/en-US/admin.ftl diff --git a/pagetop/src/base/module/admin/locales/es-ES/admin.ftl b/pagetop-admin/src/locales/es-ES/admin.ftl similarity index 100% rename from pagetop/src/base/module/admin/locales/es-ES/admin.ftl rename to pagetop-admin/src/locales/es-ES/admin.ftl diff --git a/pagetop/src/base/module/admin/summary.rs b/pagetop-admin/src/summary.rs similarity index 95% rename from pagetop/src/base/module/admin/summary.rs rename to pagetop-admin/src/summary.rs index cee26c22..79bf426e 100644 --- a/pagetop/src/base/module/admin/summary.rs +++ b/pagetop-admin/src/summary.rs @@ -1,7 +1,7 @@ -use crate::prelude::*; +use pagetop::prelude::*; use super::l; -pub async fn summary() -> server::Result<Markup> { +pub async fn summary() -> app::Result<Markup> { let top_menu = Menu::prepare() .add(MenuItem::label(l("module_fullname").as_str())) .add(MenuItem::link("Opción 2", "https://www.google.es")) diff --git a/pagetop-node/Cargo.toml b/pagetop-node/Cargo.toml new file mode 100644 index 00000000..36b43d39 --- /dev/null +++ b/pagetop-node/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "pagetop-node" +version = "0.0.1" +edition = "2021" + +authors = [ + "Manuel Cillero <manuel@cillero.es>" +] +description = """\ + Allows content to be submitted to the site and displayed on pages.\ +""" +homepage = "https://suitepro.cillero.es/projects/drust" +repository = "https://gitlab.com/manuelcillero/drust" + +[dependencies] +pagetop = { path = "../pagetop" } diff --git a/pagetop-node/src/lib.rs b/pagetop-node/src/lib.rs new file mode 100644 index 00000000..af6d8b3f --- /dev/null +++ b/pagetop-node/src/lib.rs @@ -0,0 +1,39 @@ +use pagetop::prelude::*; + +localize!("src/locales"); + +//mod entity; +mod migration; + +pub struct NodeModule; + +impl ModuleTrait for NodeModule { + fn fullname(&self) -> String { + l("module_fullname") + } + + fn description(&self) -> Option<String> { + Some(l("module_description")) + } + + fn configure_module(&self, cfg: &mut app::web::ServiceConfig) { + cfg.route("/node", app::web::get().to(node)); + } + + fn migrations(&self) -> Vec<Box<dyn db::migration::MigrationTrait>> { + vec![ + boxed_migration!(m20220316_000001_create_table_node_type), + boxed_migration!(m20220316_000002_create_table_node), + boxed_migration!(m20220316_000003_create_table_node_access), + boxed_migration!(m20220316_000004_create_table_node_revision), + ] + } +} + +async fn node() -> app::Result<Markup> { + Page::prepare() + .with_title( + "Nodo" + ) + .render() +} diff --git a/pagetop-node/src/locales/en-US/homepage.ftl b/pagetop-node/src/locales/en-US/homepage.ftl new file mode 100644 index 00000000..191dc81f --- /dev/null +++ b/pagetop-node/src/locales/en-US/homepage.ftl @@ -0,0 +1,2 @@ +module_fullname = Node +module_description = Allows content to be submitted to the site and displayed on pages. diff --git a/pagetop-node/src/locales/es-ES/homepage.ftl b/pagetop-node/src/locales/es-ES/homepage.ftl new file mode 100644 index 00000000..b5e6677d --- /dev/null +++ b/pagetop-node/src/locales/es-ES/homepage.ftl @@ -0,0 +1,2 @@ +module_fullname = Nodo +module_description = Permite enviar contenidos al sitio y mostrarlos en páginas. diff --git a/pagetop-node/src/migration/m20220316_000001_create_table_node_type.rs b/pagetop-node/src/migration/m20220316_000001_create_table_node_type.rs new file mode 100644 index 00000000..5180a785 --- /dev/null +++ b/pagetop-node/src/migration/m20220316_000001_create_table_node_type.rs @@ -0,0 +1,90 @@ +use pagetop::db::migration::*; + +/// Stores information about all defined {node} types. +#[derive(Iden)] +enum NodeType { + Table, // Nombre de la tabla: node_type (Tipo de nodo). + Type, // The machine-readable name of this type + Name, // The human-readable name of this type + Description, // Descripción breve del tipo. + Help, // Help information shown to the user when creating a {node} of this type + HasTitle, // Boolean indicating whether this type uses the {node}.title field + TitleLabel, // The label displayed for the title field on the edit form + Custom, // A boolean indicating whether this type is defined by a module (FALSE) or by a user via Add content type (TRUE) + Locked, // A boolean indicating whether the administrator can change the machine name of this type + Disabled, // A boolean indicating whether the node type is disabled + OrigType, // The original machine-readable name of this node type. This may be different from the current type name if the locked field is 0 +} + +pub struct Migration; + +impl MigrationName for Migration { + fn name(&self) -> &str { + "m20220316_000001_create_table_node_type" + } +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(NodeType::Table) + .if_not_exists() + .col(ColumnDef::new(NodeType::Type) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(NodeType::Name) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeType::Description) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeType::Help) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeType::HasTitle) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeType::TitleLabel) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeType::Custom) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeType::Locked) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeType::Disabled) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeType::OrigType) + .string() + .not_null() + ) + .to_owned() + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop() + .table(NodeType::Table) + .to_owned() + ) + .await + } +} diff --git a/pagetop-node/src/migration/m20220316_000002_create_table_node.rs b/pagetop-node/src/migration/m20220316_000002_create_table_node.rs new file mode 100644 index 00000000..fe65fc2c --- /dev/null +++ b/pagetop-node/src/migration/m20220316_000002_create_table_node.rs @@ -0,0 +1,110 @@ +use pagetop::db::migration::*; + +/// The base table for nodes. +#[derive(Iden)] +enum Node { + Table, // Nombre de la tabla: node (Nodo). + Nid, // The primary identifier for a node + Vid, // The current {node_revision}.vid version identifier + Type, // The {node_type}.type of this node + Language, // The {languages}.language of this node + Title, // The title of this node, always treated as non-markup plain text + Uid, // The {users}.uid that owns this node; initially, this is the user that created it + Status, // Boolean indicating whether the node is published (visible to non-administrators) + Created, // The Unix timestamp when the node was created + Changed, // The Unix timestamp when the node was most recently saved + Comment, // Whether comments are allowed on this node: 0 = no, 1 = closed (read only), 2 = open (read/write) + Promote, // Boolean indicating whether the node should be displayed on the front page + Sticky, // Boolean indicating whether the node should be displayed at the top of lists in which it appears + Tnid, // The translation set id for this node, which equals the node id of the source post in each set + Translate, // A boolean indicating whether this translation page needs to be updated +} + +pub struct Migration; + +impl MigrationName for Migration { + fn name(&self) -> &str { + "m20220316_000002_create_table_node" + } +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(Node::Table) + .if_not_exists() + .col(ColumnDef::new(Node::Nid) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(Node::Vid) + .string() + .not_null() + ) + .col(ColumnDef::new(Node::Type) + .string() + .not_null() + ) + .col(ColumnDef::new(Node::Language) + .string() + .not_null() + ) + .col(ColumnDef::new(Node::Title) + .string() + .not_null() + ) + .col(ColumnDef::new(Node::Uid) + .string() + .not_null() + ) + .col(ColumnDef::new(Node::Status) + .string() + .not_null() + ) + .col(ColumnDef::new(Node::Created) + .string() + .not_null() + ) + .col(ColumnDef::new(Node::Changed) + .string() + .not_null() + ) + .col(ColumnDef::new(Node::Comment) + .string() + .not_null() + ) + .col(ColumnDef::new(Node::Promote) + .string() + .not_null() + ) + .col(ColumnDef::new(Node::Sticky) + .string() + .not_null() + ) + .col(ColumnDef::new(Node::Tnid) + .string() + .not_null() + ) + .col(ColumnDef::new(Node::Translate) + .string() + .not_null() + ) + .to_owned() + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop() + .table(Node::Table) + .to_owned() + ) + .await + } +} diff --git a/pagetop-node/src/migration/m20220316_000003_create_table_node_access.rs b/pagetop-node/src/migration/m20220316_000003_create_table_node_access.rs new file mode 100644 index 00000000..a179240f --- /dev/null +++ b/pagetop-node/src/migration/m20220316_000003_create_table_node_access.rs @@ -0,0 +1,70 @@ +use pagetop::db::migration::*; + +// Identifies which realm/grant pairs a user must possess in order to view, update, or delete specific nodes. +#[derive(Iden)] +enum NodeAccess { + Table, // Nombre de la tabla: node_access (Acceso a nodos). + Nid, // The {node}.nid this record affects + Gid, // The grant ID a user must possess in the specified realm to gain this row's privileges on the node + Realm, // The realm in which the user must possess the grant ID. Each node access node can define one or more realms + GrantView, // Boolean indicating whether a user with the realm/grant pair can view this node + GrantUpdate, // Boolean indicating whether a user with the realm/grant pair can edit this node + GrantDelete, // Boolean indicating whether a user with the realm/grant pair can delete this node +} + +pub struct Migration; + +impl MigrationName for Migration { + fn name(&self) -> &str { + "m20220316_000003_create_table_node_access" + } +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(NodeAccess::Table) + .if_not_exists() + .col(ColumnDef::new(NodeAccess::Nid) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(NodeAccess::Gid) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeAccess::Realm) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeAccess::GrantView) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeAccess::GrantUpdate) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeAccess::GrantDelete) + .string() + .not_null() + ) + .to_owned() + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop() + .table(NodeAccess::Table) + .to_owned() + ) + .await + } +} diff --git a/pagetop-node/src/migration/m20220316_000004_create_table_node_revision.rs b/pagetop-node/src/migration/m20220316_000004_create_table_node_revision.rs new file mode 100644 index 00000000..4dc4e1b6 --- /dev/null +++ b/pagetop-node/src/migration/m20220316_000004_create_table_node_revision.rs @@ -0,0 +1,90 @@ +use pagetop::db::migration::*; + +// Stores information about each saved version of a {node}. +#[derive(Iden)] +enum NodeRevision { + Table, // Nombre de la tabla: node_revisión (Versiones de nodos). + Nid, // The {node} this version belongs to + Vid, // The primary identifier for this version + Uid, // The {users}.uid that created this version + Title, // The title of this version + Log, // The log entry explaining the changes in this version + Timestamp, // A Unix timestamp indicating when this version was created + Status, // Boolean indicating whether the node (at the time of this revision) is published (visible to non-administrators) + Comment, // Whether comments are allowed on this node (at the time of this revision): 0 = no, 1 = closed (read only), 2 = open (read/write) + Promote, // Boolean indicating whether the node (at the time of this revision) should be displayed on the front page + Sticky, // Boolean indicating whether the node (at the time of this revision) should be displayed at the top of lists in which it appears +} + +pub struct Migration; + +impl MigrationName for Migration { + fn name(&self) -> &str { + "m20220316_000004_create_table_node_revision" + } +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(NodeRevision::Table) + .if_not_exists() + .col(ColumnDef::new(NodeRevision::Nid) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col(ColumnDef::new(NodeRevision::Vid) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeRevision::Uid) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeRevision::Title) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeRevision::Log) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeRevision::Timestamp) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeRevision::Status) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeRevision::Comment) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeRevision::Promote) + .string() + .not_null() + ) + .col(ColumnDef::new(NodeRevision::Sticky) + .string() + .not_null() + ) + .to_owned() + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop() + .table(NodeRevision::Table) + .to_owned() + ) + .await + } +} diff --git a/pagetop-node/src/migration/mod.rs b/pagetop-node/src/migration/mod.rs new file mode 100644 index 00000000..49f4e057 --- /dev/null +++ b/pagetop-node/src/migration/mod.rs @@ -0,0 +1,4 @@ +pub mod m20220316_000001_create_table_node_type; +pub mod m20220316_000002_create_table_node; +pub mod m20220316_000003_create_table_node_access; +pub mod m20220316_000004_create_table_node_revision; diff --git a/pagetop-user/Cargo.toml b/pagetop-user/Cargo.toml new file mode 100644 index 00000000..37352fe7 --- /dev/null +++ b/pagetop-user/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "pagetop-user" +version = "0.0.1" +edition = "2021" + +authors = [ + "Manuel Cillero <manuel@cillero.es>" +] +description = """\ + Allows content to be submitted to the site and displayed on pages.\ +""" +homepage = "https://suitepro.cillero.es/projects/drust" +repository = "https://gitlab.com/manuelcillero/drust" + +[dependencies] +pagetop = { path = "../pagetop" } +serde = { version = "1.0", features = ["derive"] } + +[dependencies.sea-orm] +version = "0.6.0" +features = ["debug-print", "macros"] +default-features = false diff --git a/pagetop/src/base/module/user/entity/mod.rs b/pagetop-user/src/entity/mod.rs similarity index 100% rename from pagetop/src/base/module/user/entity/mod.rs rename to pagetop-user/src/entity/mod.rs diff --git a/pagetop/src/base/module/user/entity/user.rs b/pagetop-user/src/entity/user.rs similarity index 100% rename from pagetop/src/base/module/user/entity/user.rs rename to pagetop-user/src/entity/user.rs diff --git a/pagetop/src/base/module/user/mod.rs b/pagetop-user/src/lib.rs similarity index 80% rename from pagetop/src/base/module/user/mod.rs rename to pagetop-user/src/lib.rs index 362961eb..c76233e1 100644 --- a/pagetop/src/base/module/user/mod.rs +++ b/pagetop-user/src/lib.rs @@ -1,6 +1,6 @@ -use crate::prelude::*; +use pagetop::prelude::*; -localize!("src/base/module/user/locales"); +localize!("src/locales"); mod entity; mod migration; @@ -8,10 +8,6 @@ mod migration; pub struct UserModule; impl ModuleTrait for UserModule { - fn name(&self) -> &'static str { - "user" - } - fn fullname(&self) -> String { l("module_fullname") } @@ -20,8 +16,8 @@ impl ModuleTrait for UserModule { Some(l("module_description")) } - fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { - cfg.route("/user/login", server::web::get().to(login)); + fn configure_module(&self, cfg: &mut app::web::ServiceConfig) { + cfg.route("/user/login", app::web::get().to(login)); } fn migrations(&self) -> Vec<Box<dyn db::migration::MigrationTrait>> { @@ -50,7 +46,7 @@ fn form_login() -> impl PageComponent { .add(form::Button::submit(l("login").as_str())) } -async fn login() -> server::Result<Markup> { +async fn login() -> app::Result<Markup> { Page::prepare() .with_title( "Identificación del usuario" diff --git a/pagetop/src/base/module/user/locales/en-US/homepage.ftl b/pagetop-user/src/locales/en-US/homepage.ftl similarity index 100% rename from pagetop/src/base/module/user/locales/en-US/homepage.ftl rename to pagetop-user/src/locales/en-US/homepage.ftl diff --git a/pagetop/src/base/module/user/locales/es-ES/homepage.ftl b/pagetop-user/src/locales/es-ES/homepage.ftl similarity index 100% rename from pagetop/src/base/module/user/locales/es-ES/homepage.ftl rename to pagetop-user/src/locales/es-ES/homepage.ftl diff --git a/pagetop/src/base/module/user/migration/m20220312_000001_create_table_user.rs b/pagetop-user/src/migration/m20220312_000001_create_table_user.rs similarity index 100% rename from pagetop/src/base/module/user/migration/m20220312_000001_create_table_user.rs rename to pagetop-user/src/migration/m20220312_000001_create_table_user.rs diff --git a/pagetop/src/base/module/user/migration/mod.rs b/pagetop-user/src/migration/mod.rs similarity index 100% rename from pagetop/src/base/module/user/migration/mod.rs rename to pagetop-user/src/migration/mod.rs diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index e6cbc75e..a9c7993c 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.1" +version = "0.0.2" edition = "2021" authors = [ diff --git a/pagetop/STARTER.Cargo.toml b/pagetop/STARTER.bin.Cargo.toml similarity index 88% rename from pagetop/STARTER.Cargo.toml rename to pagetop/STARTER.bin.Cargo.toml index 7cddd5fc..d05a17bf 100644 --- a/pagetop/STARTER.Cargo.toml +++ b/pagetop/STARTER.bin.Cargo.toml @@ -24,3 +24,8 @@ actix-web = "3.3.3" maud = { version = "0.23.0" } # Opcional. Si se requiere serialización de estructuras de datos. serde = { version = "1.0", features = ["derive"] } + +[dependencies.sea-orm] +version = "0.6.0" +features = ["debug-print", "macros"] +default-features = false diff --git a/pagetop/STARTER.lib.Cargo.toml b/pagetop/STARTER.lib.Cargo.toml new file mode 100644 index 00000000..97389750 --- /dev/null +++ b/pagetop/STARTER.lib.Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "app" +version = "0.1.0" +edition = "2021" + +# Ver más claves y sus definiciones en +# https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies.pagetop] +path = "../pagetop" +# Opcional. Por defecto se puede usar PageTop sin base de datos. +features = ["mysql"] +# features = ["postgres"] +# features = ["sqlite"] +# PageTop puede dar soporte a todas las bases de datos. +# features = ["mysql", "postgres", "sqlite"] +# Sólo cuando no se usen las características predeterminadas. +default-features = false + +[dependencies] +# Opcional. Sólo si se usa la macro html!. +maud = { version = "0.23.0" } +# Opcional. Si se requiere serialización de estructuras de datos. +serde = { version = "1.0", features = ["derive"] } + +[dependencies.sea-orm] +version = "0.6.0" +features = ["debug-print", "macros"] +default-features = false diff --git a/pagetop/src/core/all.rs b/pagetop/src/all.rs similarity index 83% rename from pagetop/src/core/all.rs rename to pagetop/src/all.rs index 20df22bd..a7134172 100644 --- a/pagetop/src/core/all.rs +++ b/pagetop/src/all.rs @@ -1,8 +1,7 @@ -use crate::{Lazy, run_now}; +use crate::{Lazy, run_now, app}; use crate::db::migration::*; -use crate::core::theme::ThemeTrait; -use crate::core::module::ModuleTrait; -use crate::core::server; +use crate::theme::ThemeTrait; +use crate::module::ModuleTrait; use std::sync::RwLock; @@ -16,7 +15,7 @@ pub static THEMES: Lazy<RwLock<Vec<&dyn ThemeTrait>>> = Lazy::new( || { RwLock::new(Vec::new()) } ); -pub fn themes(cfg: &mut server::web::ServiceConfig) { +pub fn themes(cfg: &mut app::web::ServiceConfig) { cfg.service(actix_web_static_files::ResourceFiles::new( "/theme", assets() @@ -35,7 +34,7 @@ pub static MODULES: Lazy<RwLock<Vec<&dyn ModuleTrait>>> = Lazy::new( || { RwLock::new(Vec::new()) } ); -pub fn modules(cfg: &mut server::web::ServiceConfig) { +pub fn modules(cfg: &mut app::web::ServiceConfig) { for m in MODULES.read().unwrap().iter() { m.configure_module(cfg); } @@ -54,6 +53,6 @@ pub fn run_migrations() { migrations } } - Migrator::up(&server::db::DBCONN, None) + Migrator::up(&app::db::DBCONN, None) }).unwrap(); } diff --git a/pagetop/src/core/server/app.rs b/pagetop/src/app/application.rs similarity index 73% rename from pagetop/src/core/server/app.rs rename to pagetop/src/app/application.rs index 74e1690d..12af039c 100644 --- a/pagetop/src/core/server/app.rs +++ b/pagetop/src/app/application.rs @@ -1,14 +1,13 @@ -use crate::{Lazy, base, trace}; +use crate::{Lazy, all, app, trace}; use crate::config::SETTINGS; -use crate::core::{Server, all, server}; -use crate::core::theme::register_theme; -use crate::core::module::register_module; +use crate::theme::*; +use crate::module::*; use std::io::Error; use actix_web::middleware::normalize::{NormalizePath, TrailingSlash}; pub struct Application { - server: Server, + server: app::Server, } pub fn essence() { @@ -44,25 +43,19 @@ impl Application { } // Inicia registro de trazas y eventos. - Lazy::force(&server::tracing::TRACING); + Lazy::force(&app::tracing::TRACING); // Valida el identificador de idioma. - Lazy::force(&server::locale::LANGID); + Lazy::force(&app::locale::LANGID); // Conecta con la base de datos (opcional). #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] - Lazy::force(&server::db::DBCONN); + Lazy::force(&app::db::DBCONN); // Registra los temas predefinidos. - register_theme(&base::theme::aliner::AlinerTheme); - register_theme(&base::theme::minimal::MinimalTheme); - register_theme(&base::theme::bootsier::BootsierTheme); - - // Registra los módulos predeterminados. - register_module(&base::module::admin::AdminModule); - // Registra los módulos que requieren base de datos. - #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] - register_module(&base::module::user::UserModule); + register_theme(&aliner::AlinerTheme); + register_theme(&minimal::MinimalTheme); + register_theme(&bootsier::BootsierTheme); // Ejecuta la función de inicio de la aplicación. trace::info!("Calling application bootstrap"); @@ -70,15 +63,15 @@ impl Application { // Registra el módulo para la página de inicio de PageTop. // Al ser el último, puede sobrecargarse con la función de inicio. - register_module(&base::module::homepage::HomepageModule); + register_module(&homepage::HomepageModule); // Comprueba actualizaciones pendientes de la base de datos (opcional). #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] all::run_migrations(); // Prepara el servidor web. - let server = server::HttpServer::new(move || { - server::App::new() + let server = app::HttpServer::new(move || { + app::App::new() .wrap(tracing_actix_web::TracingLogger) .wrap(NormalizePath::new(TrailingSlash::Trim)) .configure(&all::themes) @@ -93,7 +86,7 @@ impl Application { Ok(Self { server }) } - pub fn run(self) -> Result<Server, Error> { + pub fn run(self) -> Result<app::Server, Error> { Ok(self.server) } } diff --git a/pagetop/src/core/server/db.rs b/pagetop/src/app/db.rs similarity index 100% rename from pagetop/src/core/server/db.rs rename to pagetop/src/app/db.rs diff --git a/pagetop/src/core/server/figfonts/slant.flf b/pagetop/src/app/figfonts/slant.flf similarity index 100% rename from pagetop/src/core/server/figfonts/slant.flf rename to pagetop/src/app/figfonts/slant.flf diff --git a/pagetop/src/core/server/figfonts/small.flf b/pagetop/src/app/figfonts/small.flf similarity index 100% rename from pagetop/src/core/server/figfonts/small.flf rename to pagetop/src/app/figfonts/small.flf diff --git a/pagetop/src/core/server/figfonts/speed.flf b/pagetop/src/app/figfonts/speed.flf similarity index 100% rename from pagetop/src/core/server/figfonts/speed.flf rename to pagetop/src/app/figfonts/speed.flf diff --git a/pagetop/src/core/server/figfonts/starwars.flf b/pagetop/src/app/figfonts/starwars.flf similarity index 100% rename from pagetop/src/core/server/figfonts/starwars.flf rename to pagetop/src/app/figfonts/starwars.flf diff --git a/pagetop/src/core/server/locale.rs b/pagetop/src/app/locale.rs similarity index 100% rename from pagetop/src/core/server/locale.rs rename to pagetop/src/app/locale.rs diff --git a/pagetop/src/core/server/mod.rs b/pagetop/src/app/mod.rs similarity index 81% rename from pagetop/src/core/server/mod.rs rename to pagetop/src/app/mod.rs index 394886b4..b3f7cd6a 100644 --- a/pagetop/src/core/server/mod.rs +++ b/pagetop/src/app/mod.rs @@ -1,6 +1,7 @@ pub use actix_web::{ App, HttpRequest, HttpResponse, HttpServer, Responder, Result, http, web }; +use actix_web::dev::Server; mod tracing; @@ -9,4 +10,4 @@ pub mod locale; #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] pub mod db; -pub mod app; +pub mod application; diff --git a/pagetop/src/core/server/tracing.rs b/pagetop/src/app/tracing.rs similarity index 100% rename from pagetop/src/core/server/tracing.rs rename to pagetop/src/app/tracing.rs diff --git a/pagetop/src/base/mod.rs b/pagetop/src/base/mod.rs deleted file mode 100644 index f40d2d0e..00000000 --- a/pagetop/src/base/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! Temas, Módulos y Componentes base. - -pub mod theme; -pub mod module; -pub mod component; diff --git a/pagetop/src/base/module/admin/mod.rs b/pagetop/src/base/module/admin/mod.rs deleted file mode 100644 index e9b58703..00000000 --- a/pagetop/src/base/module/admin/mod.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::prelude::*; - -localize!("src/base/module/admin/locales"); - -mod summary; - -pub struct AdminModule; - -impl ModuleTrait for AdminModule { - fn name(&self) -> &'static str { - "admin" - } - - fn fullname(&self) -> String { - l("module_fullname") - } - - fn description(&self) -> Option<String> { - Some(l("module_description")) - } - - fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { - cfg.service( - server::web::scope("/admin") - .route("", server::web::get().to(summary::summary)) - ); - } -} diff --git a/pagetop/src/base/module/mod.rs b/pagetop/src/base/module/mod.rs deleted file mode 100644 index ab1169b4..00000000 --- a/pagetop/src/base/module/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod admin; -pub mod homepage; - -#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] -pub mod user; diff --git a/pagetop/src/base/theme/mod.rs b/pagetop/src/base/theme/mod.rs deleted file mode 100644 index 8794ed17..00000000 --- a/pagetop/src/base/theme/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod aliner; -pub mod minimal; -pub mod bootsier; diff --git a/pagetop/src/base/component/block.rs b/pagetop/src/component/block.rs similarity index 100% rename from pagetop/src/base/component/block.rs rename to pagetop/src/component/block.rs diff --git a/pagetop/src/base/component/chunck.rs b/pagetop/src/component/chunck.rs similarity index 100% rename from pagetop/src/base/component/chunck.rs rename to pagetop/src/component/chunck.rs diff --git a/pagetop/src/base/component/container.rs b/pagetop/src/component/container.rs similarity index 100% rename from pagetop/src/base/component/container.rs rename to pagetop/src/component/container.rs diff --git a/pagetop/src/base/component/form/button.rs b/pagetop/src/component/form/button.rs similarity index 100% rename from pagetop/src/base/component/form/button.rs rename to pagetop/src/component/form/button.rs diff --git a/pagetop/src/base/component/form/date.rs b/pagetop/src/component/form/date.rs similarity index 100% rename from pagetop/src/base/component/form/date.rs rename to pagetop/src/component/form/date.rs diff --git a/pagetop/src/base/component/form/form.rs b/pagetop/src/component/form/form.rs similarity index 100% rename from pagetop/src/base/component/form/form.rs rename to pagetop/src/component/form/form.rs diff --git a/pagetop/src/base/component/form/hidden.rs b/pagetop/src/component/form/hidden.rs similarity index 100% rename from pagetop/src/base/component/form/hidden.rs rename to pagetop/src/component/form/hidden.rs diff --git a/pagetop/src/base/component/form/input.rs b/pagetop/src/component/form/input.rs similarity index 100% rename from pagetop/src/base/component/form/input.rs rename to pagetop/src/component/form/input.rs diff --git a/pagetop/src/base/component/form/mod.rs b/pagetop/src/component/form/mod.rs similarity index 100% rename from pagetop/src/base/component/form/mod.rs rename to pagetop/src/component/form/mod.rs diff --git a/pagetop/src/base/component/menu.rs b/pagetop/src/component/menu.rs similarity index 100% rename from pagetop/src/base/component/menu.rs rename to pagetop/src/component/menu.rs diff --git a/pagetop/src/base/component/mod.rs b/pagetop/src/component/mod.rs similarity index 100% rename from pagetop/src/base/component/mod.rs rename to pagetop/src/component/mod.rs diff --git a/pagetop/src/core/mod.rs b/pagetop/src/core/mod.rs deleted file mode 100644 index 8db86b83..00000000 --- a/pagetop/src/core/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub use actix_web::dev::Server; - -mod all; - -pub mod html; -pub mod theme; -pub mod module; -pub mod response; -pub mod server; diff --git a/pagetop/src/core/module/mod.rs b/pagetop/src/core/module/mod.rs deleted file mode 100644 index 2a42352a..00000000 --- a/pagetop/src/core/module/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::core::all; - -mod definition; -pub use definition::ModuleTrait; - -pub fn register_module(m: &'static (dyn ModuleTrait + 'static)) { - all::MODULES.write().unwrap().push(m); -} - -pub fn find_module(name: &str) -> Option<&'static (dyn ModuleTrait + 'static)> { - let modules = all::MODULES.write().unwrap(); - match modules.iter().find(|t| t.name() == name) { - Some(module) => Some(*module), - _ => None, - } -} diff --git a/pagetop/src/core/html.rs b/pagetop/src/html.rs similarity index 100% rename from pagetop/src/core/html.rs rename to pagetop/src/html.rs diff --git a/pagetop/src/lib.rs b/pagetop/src/lib.rs index daf0577d..1ecb2028 100644 --- a/pagetop/src/lib.rs +++ b/pagetop/src/lib.rs @@ -8,6 +8,8 @@ pub use futures::executor::block_on as run_now; // APIs públicas. // ----------------------------------------------------------------------------- +mod all; // Variables globales privadas. + pub mod config; // Gestión de la configuración. pub mod trace; // Registro de trazas y eventos de la aplicación. pub mod locale; // Localización. @@ -15,8 +17,14 @@ pub mod locale; // Localización. #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] pub mod db; // Acceso a la base de datos. -pub mod core; // Servidor web y APIs para Temas, Módulos y Respuestas web. -pub mod base; // Temas, Módulos y Componentes base. +pub mod html; // Publicación de código HTML desde el código. +pub mod theme; // API para crear temas y temas predeterminados. +pub mod module; // API para crear módulos con nuevas funcionalidades. +pub mod response; // Tipos de respuestas web. +pub mod app; // Aplicación y servidor web. + +pub mod component; // Componentes base. + pub mod util; // Macros y funciones útiles. pub mod prelude; // Re-exporta recursos comunes. diff --git a/pagetop/src/locale.rs b/pagetop/src/locale.rs index a5a136c2..93e9e7e8 100644 --- a/pagetop/src/locale.rs +++ b/pagetop/src/locale.rs @@ -7,7 +7,7 @@ pub use fluent_templates::fluent_bundle::FluentValue; macro_rules! localize { ( $dir_locales:literal $(, $core_locales:literal)? ) => { use $crate::locale::*; - use $crate::core::server::locale::LANGID; + use $crate::app::locale::LANGID; static_locale! { static LOCALES = { @@ -37,8 +37,8 @@ macro_rules! localize { fn e( key: &str, args: &std::collections::HashMap<String, FluentValue> - ) -> $crate::core::html::PreEscaped<String> { - $crate::core::html::PreEscaped( + ) -> $crate::html::PreEscaped<String> { + $crate::html::PreEscaped( LOCALES.lookup_with_args(&LANGID, key, args) ) } diff --git a/pagetop/src/core/module/definition.rs b/pagetop/src/module/definition.rs similarity index 56% rename from pagetop/src/core/module/definition.rs rename to pagetop/src/module/definition.rs index c50cace3..ccebe607 100644 --- a/pagetop/src/core/module/definition.rs +++ b/pagetop/src/module/definition.rs @@ -1,20 +1,31 @@ -use crate::core::server; - #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] use crate::db; +use crate::app; + +use std::any::type_name; /// Los módulos deben implementar este *trait*. pub trait ModuleTrait: Send + Sync { - fn name(&self) -> &'static str; + fn name(&self) -> &'static str { + let name = type_name::<Self>(); + match name.rfind("::") { + Some(position) => &name[(position + 2)..], + None => name + } + } fn fullname(&self) -> String; + fn dependencies(&self) -> Vec<&'static dyn ModuleTrait> { + vec![] + } + fn description(&self) -> Option<String> { None } #[allow(unused_variables)] - fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { + fn configure_module(&self, cfg: &mut app::web::ServiceConfig) { } #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] diff --git a/pagetop/src/base/module/homepage/locales/en-US/homepage.ftl b/pagetop/src/module/homepage/locales/en-US/homepage.ftl similarity index 100% rename from pagetop/src/base/module/homepage/locales/en-US/homepage.ftl rename to pagetop/src/module/homepage/locales/en-US/homepage.ftl diff --git a/pagetop/src/base/module/homepage/locales/es-ES/homepage.ftl b/pagetop/src/module/homepage/locales/es-ES/homepage.ftl similarity index 100% rename from pagetop/src/base/module/homepage/locales/es-ES/homepage.ftl rename to pagetop/src/module/homepage/locales/es-ES/homepage.ftl diff --git a/pagetop/src/base/module/homepage/mod.rs b/pagetop/src/module/homepage/mod.rs similarity index 88% rename from pagetop/src/base/module/homepage/mod.rs rename to pagetop/src/module/homepage/mod.rs index 6b3b9741..c74480b3 100644 --- a/pagetop/src/base/module/homepage/mod.rs +++ b/pagetop/src/module/homepage/mod.rs @@ -1,14 +1,10 @@ use crate::prelude::*; -localize!("src/base/module/homepage/locales"); +localize!("src/module/homepage/locales"); pub struct HomepageModule; impl ModuleTrait for HomepageModule { - fn name(&self) -> &'static str { - "homepage" - } - fn fullname(&self) -> String { l("module_fullname") } @@ -17,12 +13,12 @@ impl ModuleTrait for HomepageModule { Some(l("module_description")) } - fn configure_module(&self, cfg: &mut server::web::ServiceConfig) { - cfg.route("/", server::web::get().to(home)); + fn configure_module(&self, cfg: &mut app::web::ServiceConfig) { + cfg.route("/", app::web::get().to(home)); } } -async fn home() -> server::Result<Markup> { +async fn home() -> app::Result<Markup> { Page::prepare() .with_title( l("page_title").as_str() diff --git a/pagetop/src/module/mod.rs b/pagetop/src/module/mod.rs new file mode 100644 index 00000000..cb71dfd2 --- /dev/null +++ b/pagetop/src/module/mod.rs @@ -0,0 +1,17 @@ +use crate::{all, trace}; + +mod definition; +pub use definition::ModuleTrait; + +pub mod homepage; + +pub fn register_module(m: &'static dyn ModuleTrait) { + let mut modules = all::MODULES.write().unwrap(); + match modules.iter().find(|t| t.name() == m.name()) { + None => { + trace::info!("{}", m.name()); + modules.push(m); + }, + Some(_) => {}, + } +} diff --git a/pagetop/src/prelude.rs b/pagetop/src/prelude.rs index 18d160ce..1bfc1817 100644 --- a/pagetop/src/prelude.rs +++ b/pagetop/src/prelude.rs @@ -8,13 +8,14 @@ pub use crate::localize; #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] pub use crate::{db, boxed_migration}; -pub use crate::core::html::*; -pub use crate::core::theme::*; -pub use crate::core::module::*; -pub use crate::core::response::page::*; -pub use crate::core::server; -pub use crate::core::server::app::{Application, essence}; +pub use crate::html::*; +pub use crate::theme::*; +pub use crate::module::*; +pub use crate::response::page::*; -pub use crate::base::component::*; +pub use crate::app; +pub use crate::app::application::{Application, essence}; + +pub use crate::component::*; pub use crate::util; diff --git a/pagetop/src/core/response/mod.rs b/pagetop/src/response/mod.rs similarity index 100% rename from pagetop/src/core/response/mod.rs rename to pagetop/src/response/mod.rs diff --git a/pagetop/src/core/response/page/assets.rs b/pagetop/src/response/page/assets.rs similarity index 98% rename from pagetop/src/core/response/page/assets.rs rename to pagetop/src/response/page/assets.rs index 2bd96fc2..9c30d981 100644 --- a/pagetop/src/core/response/page/assets.rs +++ b/pagetop/src/response/page/assets.rs @@ -1,8 +1,7 @@ -use crate::{Lazy, base}; +use crate::{Lazy, all}; use crate::config::SETTINGS; -use crate::core::all; -use crate::core::html::{Markup, PreEscaped, html}; -use crate::core::theme::*; +use crate::html::{Markup, PreEscaped, html}; +use crate::theme::*; static DEFAULT_THEME: Lazy<&dyn ThemeTrait> = Lazy::new(|| { for t in all::THEMES.read().unwrap().iter() { @@ -10,7 +9,7 @@ static DEFAULT_THEME: Lazy<&dyn ThemeTrait> = Lazy::new(|| { return *t; } } - &base::theme::bootsier::BootsierTheme + &bootsier::BootsierTheme }); // ----------------------------------------------------------------------------- diff --git a/pagetop/src/core/response/page/component.rs b/pagetop/src/response/page/component.rs similarity index 90% rename from pagetop/src/core/response/page/component.rs rename to pagetop/src/response/page/component.rs index 78925468..26151cab 100644 --- a/pagetop/src/core/response/page/component.rs +++ b/pagetop/src/response/page/component.rs @@ -1,5 +1,5 @@ -use crate::core::html::{Markup, html}; -use crate::core::response::page::PageAssets; +use crate::html::{Markup, html}; +use crate::response::page::PageAssets; use downcast_rs::{Downcast, impl_downcast}; diff --git a/pagetop/src/core/response/page/container.rs b/pagetop/src/response/page/container.rs similarity index 86% rename from pagetop/src/core/response/page/container.rs rename to pagetop/src/response/page/container.rs index 4a577b2d..72287560 100644 --- a/pagetop/src/core/response/page/container.rs +++ b/pagetop/src/response/page/container.rs @@ -1,5 +1,5 @@ -use crate::core::html::{Markup, html}; -use crate::core::response::page::{PageAssets, PageComponent, render_component}; +use crate::html::{Markup, html}; +use crate::response::page::{PageAssets, PageComponent, render_component}; use std::sync::Arc; diff --git a/pagetop/src/core/response/page/mod.rs b/pagetop/src/response/page/mod.rs similarity index 100% rename from pagetop/src/core/response/page/mod.rs rename to pagetop/src/response/page/mod.rs diff --git a/pagetop/src/core/response/page/page.rs b/pagetop/src/response/page/page.rs similarity index 96% rename from pagetop/src/core/response/page/page.rs rename to pagetop/src/response/page/page.rs index d47a33f1..58541d22 100644 --- a/pagetop/src/core/response/page/page.rs +++ b/pagetop/src/response/page/page.rs @@ -1,8 +1,7 @@ -use crate::{Lazy, trace, util}; +use crate::{Lazy, app, trace, util}; use crate::config::SETTINGS; -use crate::core::html::{DOCTYPE, Markup, html}; -use crate::core::response::page::{PageAssets, PageComponent, PageContainer}; -use crate::core::server; +use crate::html::{DOCTYPE, Markup, html}; +use crate::response::page::{PageAssets, PageComponent, PageContainer}; use std::borrow::Cow; use std::sync::RwLock; @@ -164,7 +163,7 @@ impl<'a> Page<'a> { // Page RENDER. - pub fn render(&mut self) -> server::Result<Markup> { + pub fn render(&mut self) -> app::Result<Markup> { // Acciones del tema antes de renderizar la página. self.assets.theme().before_render_page(self); diff --git a/pagetop/src/base/theme/aliner/mod.rs b/pagetop/src/theme/aliner/mod.rs similarity index 90% rename from pagetop/src/base/theme/aliner/mod.rs rename to pagetop/src/theme/aliner/mod.rs index 18df448f..676eb25d 100644 --- a/pagetop/src/base/theme/aliner/mod.rs +++ b/pagetop/src/theme/aliner/mod.rs @@ -13,7 +13,7 @@ impl ThemeTrait for AlinerTheme { "Aliner".to_owned() } - fn configure_theme(&self, cfg: &mut server::web::ServiceConfig) { + fn configure_theme(&self, cfg: &mut app::web::ServiceConfig) { cfg.service(actix_web_static_files::ResourceFiles::new( "/aliner", assets() diff --git a/pagetop/src/base/theme/bootsier/locales/en-US/bootsier.ftl b/pagetop/src/theme/bootsier/locales/en-US/bootsier.ftl similarity index 100% rename from pagetop/src/base/theme/bootsier/locales/en-US/bootsier.ftl rename to pagetop/src/theme/bootsier/locales/en-US/bootsier.ftl diff --git a/pagetop/src/base/theme/bootsier/locales/es-ES/bootsier.ftl b/pagetop/src/theme/bootsier/locales/es-ES/bootsier.ftl similarity index 100% rename from pagetop/src/base/theme/bootsier/locales/es-ES/bootsier.ftl rename to pagetop/src/theme/bootsier/locales/es-ES/bootsier.ftl diff --git a/pagetop/src/base/theme/bootsier/mod.rs b/pagetop/src/theme/bootsier/mod.rs similarity index 88% rename from pagetop/src/base/theme/bootsier/mod.rs rename to pagetop/src/theme/bootsier/mod.rs index 3c4176f0..6fba1615 100644 --- a/pagetop/src/base/theme/bootsier/mod.rs +++ b/pagetop/src/theme/bootsier/mod.rs @@ -2,7 +2,7 @@ use crate::prelude::*; include!(concat!(env!("OUT_DIR"), "/bootsier.rs")); -localize!("src/base/theme/bootsier/locales"); +localize!("src/theme/bootsier/locales"); pub struct BootsierTheme; @@ -15,7 +15,7 @@ impl ThemeTrait for BootsierTheme { "Bootsier".to_owned() } - fn configure_theme(&self, cfg: &mut server::web::ServiceConfig) { + fn configure_theme(&self, cfg: &mut app::web::ServiceConfig) { cfg.service(actix_web_static_files::ResourceFiles::new( "/bootsier", assets() @@ -43,16 +43,16 @@ impl ThemeTrait for BootsierTheme { .add_jquery(); } - fn render_error_page(&self, mut s: server::http::StatusCode) -> server::Result<Markup> { + fn render_error_page(&self, mut s: app::http::StatusCode) -> app::Result<Markup> { let mut description = "e500-description"; let mut message = "e500-description"; match s { - server::http::StatusCode::NOT_FOUND => { + app::http::StatusCode::NOT_FOUND => { description = "e404-description"; message = "e404-message"; }, _ => { - s = server::http::StatusCode::INTERNAL_SERVER_ERROR; + s = app::http::StatusCode::INTERNAL_SERVER_ERROR; } } Page::prepare() diff --git a/pagetop/src/core/theme/definition.rs b/pagetop/src/theme/definition.rs similarity index 89% rename from pagetop/src/core/theme/definition.rs rename to pagetop/src/theme/definition.rs index eb67ec10..38ad1bfd 100644 --- a/pagetop/src/core/theme/definition.rs +++ b/pagetop/src/theme/definition.rs @@ -1,8 +1,8 @@ use crate::config::SETTINGS; -use crate::core::html::{Markup, html}; -use crate::core::response::page::{Page, PageAssets, PageComponent}; -use crate::core::server; -use crate::base::component::Chunck; +use crate::html::{Markup, html}; +use crate::response::page::{Page, PageAssets, PageComponent}; +use crate::app; +use crate::component::Chunck; /// Los temas deben implementar este "trait". pub trait ThemeTrait: Send + Sync { @@ -15,7 +15,7 @@ pub trait ThemeTrait: Send + Sync { } #[allow(unused_variables)] - fn configure_theme(&self, cfg: &mut server::web::ServiceConfig) { + fn configure_theme(&self, cfg: &mut app::web::ServiceConfig) { } #[allow(unused_variables)] @@ -93,7 +93,7 @@ pub trait ThemeTrait: Send + Sync { */ } - fn render_error_page(&self, s: server::http::StatusCode) -> server::Result<Markup> { + fn render_error_page(&self, s: app::http::StatusCode) -> app::Result<Markup> { Page::prepare() .with_title(format!("Error {}", s.as_str()).as_str()) .add_to("content", Chunck::markup(html! { diff --git a/pagetop/src/base/theme/minimal/mod.rs b/pagetop/src/theme/minimal/mod.rs similarity index 100% rename from pagetop/src/base/theme/minimal/mod.rs rename to pagetop/src/theme/minimal/mod.rs diff --git a/pagetop/src/core/theme/mod.rs b/pagetop/src/theme/mod.rs similarity index 58% rename from pagetop/src/core/theme/mod.rs rename to pagetop/src/theme/mod.rs index e83f4307..9b045708 100644 --- a/pagetop/src/core/theme/mod.rs +++ b/pagetop/src/theme/mod.rs @@ -1,13 +1,17 @@ -use crate::core::all; +use crate::all; mod definition; pub use definition::ThemeTrait; -pub fn register_theme(t: &'static (dyn ThemeTrait + 'static)) { +pub mod aliner; +pub mod minimal; +pub mod bootsier; + +pub fn register_theme(t: &'static dyn ThemeTrait) { all::THEMES.write().unwrap().push(t); } -pub fn find_theme(name: &str) -> Option<&'static (dyn ThemeTrait + 'static)> { +pub fn find_theme(name: &str) -> Option<&'static dyn ThemeTrait> { let themes = all::THEMES.write().unwrap(); match themes.iter().find(|t| t.name() == name) { Some(theme) => Some(*theme), From 3ee5859eae895ece4487d5c9db7cf809a3e2bb9b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 19 Mar 2022 22:52:05 +0100 Subject: [PATCH 033/244] =?UTF-8?q?Libera=20la=20versi=C3=B3n=20de=20desar?= =?UTF-8?q?rollo=200.0.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pagetop/Cargo.toml | 2 +- pagetop/src/app/application.rs | 22 ++--- pagetop/src/{ => base}/component/block.rs | 0 pagetop/src/{ => base}/component/chunck.rs | 0 pagetop/src/{ => base}/component/container.rs | 0 .../src/{ => base}/component/form/button.rs | 0 pagetop/src/{ => base}/component/form/date.rs | 0 pagetop/src/{ => base}/component/form/form.rs | 0 .../src/{ => base}/component/form/hidden.rs | 0 .../src/{ => base}/component/form/input.rs | 0 pagetop/src/{ => base}/component/form/mod.rs | 0 pagetop/src/{ => base}/component/menu.rs | 0 pagetop/src/{ => base}/component/mod.rs | 0 pagetop/src/base/mod.rs | 3 + .../homepage/locales/en-US/homepage.ftl | 0 .../homepage/locales/es-ES/homepage.ftl | 0 pagetop/src/{ => base}/module/homepage/mod.rs | 2 +- pagetop/src/base/module/mod.rs | 1 + pagetop/src/{ => base}/theme/aliner/mod.rs | 0 .../theme/bootsier/locales/en-US/bootsier.ftl | 0 .../theme/bootsier/locales/es-ES/bootsier.ftl | 0 pagetop/src/{ => base}/theme/bootsier/mod.rs | 2 +- pagetop/src/{ => base}/theme/minimal/mod.rs | 0 pagetop/src/base/theme/mod.rs | 3 + pagetop/src/{all.rs => global.rs} | 86 +++++++++++++------ pagetop/src/lib.rs | 9 +- pagetop/src/module/definition.rs | 3 +- pagetop/src/module/mod.rs | 15 +--- pagetop/src/prelude.rs | 2 +- pagetop/src/response/page/assets.rs | 14 +-- pagetop/src/theme/definition.rs | 4 +- pagetop/src/theme/mod.rs | 19 +--- 32 files changed, 94 insertions(+), 93 deletions(-) rename pagetop/src/{ => base}/component/block.rs (100%) rename pagetop/src/{ => base}/component/chunck.rs (100%) rename pagetop/src/{ => base}/component/container.rs (100%) rename pagetop/src/{ => base}/component/form/button.rs (100%) rename pagetop/src/{ => base}/component/form/date.rs (100%) rename pagetop/src/{ => base}/component/form/form.rs (100%) rename pagetop/src/{ => base}/component/form/hidden.rs (100%) rename pagetop/src/{ => base}/component/form/input.rs (100%) rename pagetop/src/{ => base}/component/form/mod.rs (100%) rename pagetop/src/{ => base}/component/menu.rs (100%) rename pagetop/src/{ => base}/component/mod.rs (100%) create mode 100644 pagetop/src/base/mod.rs rename pagetop/src/{ => base}/module/homepage/locales/en-US/homepage.ftl (100%) rename pagetop/src/{ => base}/module/homepage/locales/es-ES/homepage.ftl (100%) rename pagetop/src/{ => base}/module/homepage/mod.rs (97%) create mode 100644 pagetop/src/base/module/mod.rs rename pagetop/src/{ => base}/theme/aliner/mod.rs (100%) rename pagetop/src/{ => base}/theme/bootsier/locales/en-US/bootsier.ftl (100%) rename pagetop/src/{ => base}/theme/bootsier/locales/es-ES/bootsier.ftl (100%) rename pagetop/src/{ => base}/theme/bootsier/mod.rs (98%) rename pagetop/src/{ => base}/theme/minimal/mod.rs (100%) create mode 100644 pagetop/src/base/theme/mod.rs rename pagetop/src/{all.rs => global.rs} (57%) diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index a9c7993c..db491819 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.2" +version = "0.0.3" edition = "2021" authors = [ diff --git a/pagetop/src/app/application.rs b/pagetop/src/app/application.rs index 12af039c..274203e6 100644 --- a/pagetop/src/app/application.rs +++ b/pagetop/src/app/application.rs @@ -1,7 +1,6 @@ -use crate::{Lazy, all, app, trace}; +use crate::{Lazy, app, base, global, trace}; use crate::config::SETTINGS; -use crate::theme::*; -use crate::module::*; +use crate::module::register_module; use std::io::Error; use actix_web::middleware::normalize::{NormalizePath, TrailingSlash}; @@ -52,30 +51,25 @@ impl Application { #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] Lazy::force(&app::db::DBCONN); - // Registra los temas predefinidos. - register_theme(&aliner::AlinerTheme); - register_theme(&minimal::MinimalTheme); - register_theme(&bootsier::BootsierTheme); - // Ejecuta la función de inicio de la aplicación. trace::info!("Calling application bootstrap"); let _ = &bootstrap(); - // Registra el módulo para la página de inicio de PageTop. - // Al ser el último, puede sobrecargarse con la función de inicio. - register_module(&homepage::HomepageModule); + // Registra el módulo para una página de presentación de PageTop. + // Normalmente se sobrecargará en la función de inicio. + register_module(&base::module::homepage::HomepageModule); // Comprueba actualizaciones pendientes de la base de datos (opcional). #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] - all::run_migrations(); + global::run_migrations(); // Prepara el servidor web. let server = app::HttpServer::new(move || { app::App::new() .wrap(tracing_actix_web::TracingLogger) .wrap(NormalizePath::new(TrailingSlash::Trim)) - .configure(&all::themes) - .configure(&all::modules) + .configure(&global::themes) + .configure(&global::modules) }) .bind(format!("{}:{}", &SETTINGS.webserver.bind_address, diff --git a/pagetop/src/component/block.rs b/pagetop/src/base/component/block.rs similarity index 100% rename from pagetop/src/component/block.rs rename to pagetop/src/base/component/block.rs diff --git a/pagetop/src/component/chunck.rs b/pagetop/src/base/component/chunck.rs similarity index 100% rename from pagetop/src/component/chunck.rs rename to pagetop/src/base/component/chunck.rs diff --git a/pagetop/src/component/container.rs b/pagetop/src/base/component/container.rs similarity index 100% rename from pagetop/src/component/container.rs rename to pagetop/src/base/component/container.rs diff --git a/pagetop/src/component/form/button.rs b/pagetop/src/base/component/form/button.rs similarity index 100% rename from pagetop/src/component/form/button.rs rename to pagetop/src/base/component/form/button.rs diff --git a/pagetop/src/component/form/date.rs b/pagetop/src/base/component/form/date.rs similarity index 100% rename from pagetop/src/component/form/date.rs rename to pagetop/src/base/component/form/date.rs diff --git a/pagetop/src/component/form/form.rs b/pagetop/src/base/component/form/form.rs similarity index 100% rename from pagetop/src/component/form/form.rs rename to pagetop/src/base/component/form/form.rs diff --git a/pagetop/src/component/form/hidden.rs b/pagetop/src/base/component/form/hidden.rs similarity index 100% rename from pagetop/src/component/form/hidden.rs rename to pagetop/src/base/component/form/hidden.rs diff --git a/pagetop/src/component/form/input.rs b/pagetop/src/base/component/form/input.rs similarity index 100% rename from pagetop/src/component/form/input.rs rename to pagetop/src/base/component/form/input.rs diff --git a/pagetop/src/component/form/mod.rs b/pagetop/src/base/component/form/mod.rs similarity index 100% rename from pagetop/src/component/form/mod.rs rename to pagetop/src/base/component/form/mod.rs diff --git a/pagetop/src/component/menu.rs b/pagetop/src/base/component/menu.rs similarity index 100% rename from pagetop/src/component/menu.rs rename to pagetop/src/base/component/menu.rs diff --git a/pagetop/src/component/mod.rs b/pagetop/src/base/component/mod.rs similarity index 100% rename from pagetop/src/component/mod.rs rename to pagetop/src/base/component/mod.rs diff --git a/pagetop/src/base/mod.rs b/pagetop/src/base/mod.rs new file mode 100644 index 00000000..6a8ebdf7 --- /dev/null +++ b/pagetop/src/base/mod.rs @@ -0,0 +1,3 @@ +pub mod component; +pub mod module; +pub mod theme; \ No newline at end of file diff --git a/pagetop/src/module/homepage/locales/en-US/homepage.ftl b/pagetop/src/base/module/homepage/locales/en-US/homepage.ftl similarity index 100% rename from pagetop/src/module/homepage/locales/en-US/homepage.ftl rename to pagetop/src/base/module/homepage/locales/en-US/homepage.ftl diff --git a/pagetop/src/module/homepage/locales/es-ES/homepage.ftl b/pagetop/src/base/module/homepage/locales/es-ES/homepage.ftl similarity index 100% rename from pagetop/src/module/homepage/locales/es-ES/homepage.ftl rename to pagetop/src/base/module/homepage/locales/es-ES/homepage.ftl diff --git a/pagetop/src/module/homepage/mod.rs b/pagetop/src/base/module/homepage/mod.rs similarity index 97% rename from pagetop/src/module/homepage/mod.rs rename to pagetop/src/base/module/homepage/mod.rs index c74480b3..bd364534 100644 --- a/pagetop/src/module/homepage/mod.rs +++ b/pagetop/src/base/module/homepage/mod.rs @@ -1,6 +1,6 @@ use crate::prelude::*; -localize!("src/module/homepage/locales"); +localize!("src/base/module/homepage/locales"); pub struct HomepageModule; diff --git a/pagetop/src/base/module/mod.rs b/pagetop/src/base/module/mod.rs new file mode 100644 index 00000000..070e5b82 --- /dev/null +++ b/pagetop/src/base/module/mod.rs @@ -0,0 +1 @@ +pub mod homepage; diff --git a/pagetop/src/theme/aliner/mod.rs b/pagetop/src/base/theme/aliner/mod.rs similarity index 100% rename from pagetop/src/theme/aliner/mod.rs rename to pagetop/src/base/theme/aliner/mod.rs diff --git a/pagetop/src/theme/bootsier/locales/en-US/bootsier.ftl b/pagetop/src/base/theme/bootsier/locales/en-US/bootsier.ftl similarity index 100% rename from pagetop/src/theme/bootsier/locales/en-US/bootsier.ftl rename to pagetop/src/base/theme/bootsier/locales/en-US/bootsier.ftl diff --git a/pagetop/src/theme/bootsier/locales/es-ES/bootsier.ftl b/pagetop/src/base/theme/bootsier/locales/es-ES/bootsier.ftl similarity index 100% rename from pagetop/src/theme/bootsier/locales/es-ES/bootsier.ftl rename to pagetop/src/base/theme/bootsier/locales/es-ES/bootsier.ftl diff --git a/pagetop/src/theme/bootsier/mod.rs b/pagetop/src/base/theme/bootsier/mod.rs similarity index 98% rename from pagetop/src/theme/bootsier/mod.rs rename to pagetop/src/base/theme/bootsier/mod.rs index 6fba1615..132dce32 100644 --- a/pagetop/src/theme/bootsier/mod.rs +++ b/pagetop/src/base/theme/bootsier/mod.rs @@ -2,7 +2,7 @@ use crate::prelude::*; include!(concat!(env!("OUT_DIR"), "/bootsier.rs")); -localize!("src/theme/bootsier/locales"); +localize!("src/base/theme/bootsier/locales"); pub struct BootsierTheme; diff --git a/pagetop/src/theme/minimal/mod.rs b/pagetop/src/base/theme/minimal/mod.rs similarity index 100% rename from pagetop/src/theme/minimal/mod.rs rename to pagetop/src/base/theme/minimal/mod.rs diff --git a/pagetop/src/base/theme/mod.rs b/pagetop/src/base/theme/mod.rs new file mode 100644 index 00000000..baccfbd9 --- /dev/null +++ b/pagetop/src/base/theme/mod.rs @@ -0,0 +1,3 @@ +pub mod aliner; +pub mod bootsier; +pub mod minimal; diff --git a/pagetop/src/all.rs b/pagetop/src/global.rs similarity index 57% rename from pagetop/src/all.rs rename to pagetop/src/global.rs index a7134172..34280cf4 100644 --- a/pagetop/src/all.rs +++ b/pagetop/src/global.rs @@ -1,31 +1,11 @@ -use crate::{Lazy, run_now, app}; +use crate::{Lazy, app, base, run_now, trace}; +use crate::config::SETTINGS; use crate::db::migration::*; -use crate::theme::ThemeTrait; -use crate::module::ModuleTrait; +use crate::module::*; +use crate::theme::*; use std::sync::RwLock; -include!(concat!(env!("OUT_DIR"), "/theme.rs")); - -// ----------------------------------------------------------------------------- -// Temas registrados y tema predeterminado. -// ----------------------------------------------------------------------------- - -pub static THEMES: Lazy<RwLock<Vec<&dyn ThemeTrait>>> = Lazy::new( - || { RwLock::new(Vec::new()) } -); - -pub fn themes(cfg: &mut app::web::ServiceConfig) { - cfg.service(actix_web_static_files::ResourceFiles::new( - "/theme", - assets() - )); - - for t in THEMES.read().unwrap().iter() { - t.configure_theme(cfg); - } -} - // ----------------------------------------------------------------------------- // Módulos registrados. // ----------------------------------------------------------------------------- @@ -34,6 +14,17 @@ pub static MODULES: Lazy<RwLock<Vec<&dyn ModuleTrait>>> = Lazy::new( || { RwLock::new(Vec::new()) } ); +pub fn register_module(m: &'static dyn ModuleTrait) { + let mut modules = MODULES.write().unwrap(); + match modules.iter().find(|t| t.name() == m.name()) { + None => { + trace::info!("{}", m.name()); + modules.push(m); + }, + Some(_) => {}, + } +} + pub fn modules(cfg: &mut app::web::ServiceConfig) { for m in MODULES.read().unwrap().iter() { m.configure_module(cfg); @@ -56,3 +47,50 @@ pub fn run_migrations() { Migrator::up(&app::db::DBCONN, None) }).unwrap(); } + +// ----------------------------------------------------------------------------- +// Temas registrados y tema predeterminado. +// ----------------------------------------------------------------------------- + +include!(concat!(env!("OUT_DIR"), "/theme.rs")); + +pub static THEMES: Lazy<RwLock<Vec<&dyn ThemeTrait>>> = Lazy::new(|| { + RwLock::new(vec![ + &base::theme::aliner::AlinerTheme, + &base::theme::minimal::MinimalTheme, + &base::theme::bootsier::BootsierTheme, + ]) +}); + +pub static DEFAULT_THEME: Lazy<&dyn ThemeTrait> = Lazy::new(|| { + for t in THEMES.read().unwrap().iter() { + if t.name().to_lowercase() == SETTINGS.app.theme.to_lowercase() { + return *t; + } + } + &base::theme::bootsier::BootsierTheme +}); + +pub fn register_theme(t: &'static dyn ThemeTrait) { + THEMES.write().unwrap().push(t); +} + +pub fn theme_by_name(name: &str) -> Option<&'static dyn ThemeTrait> { + let themes = crate::global::THEMES.write().unwrap(); + match themes.iter().find(|t| t.name() == name) { + Some(theme) => Some(*theme), + _ => None, + } +} + +pub fn themes(cfg: &mut app::web::ServiceConfig) { + cfg.service(actix_web_static_files::ResourceFiles::new( + "/theme", + assets() + )); + + for t in THEMES.read().unwrap().iter() { + t.configure_theme(cfg); + } +} + diff --git a/pagetop/src/lib.rs b/pagetop/src/lib.rs index 1ecb2028..3efe21aa 100644 --- a/pagetop/src/lib.rs +++ b/pagetop/src/lib.rs @@ -8,7 +8,7 @@ pub use futures::executor::block_on as run_now; // APIs públicas. // ----------------------------------------------------------------------------- -mod all; // Variables globales privadas. +mod global; // Ref. privadas globales a todos los temas y módulos. pub mod config; // Gestión de la configuración. pub mod trace; // Registro de trazas y eventos de la aplicación. @@ -17,14 +17,13 @@ pub mod locale; // Localización. #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] pub mod db; // Acceso a la base de datos. -pub mod html; // Publicación de código HTML desde el código. -pub mod theme; // API para crear temas y temas predeterminados. +pub mod html; // Publicación de HTML desde el código. pub mod module; // API para crear módulos con nuevas funcionalidades. +pub mod theme; // API para crear temas y temas predeterminados. pub mod response; // Tipos de respuestas web. pub mod app; // Aplicación y servidor web. -pub mod component; // Componentes base. - +pub mod base; // Componentes, Módulos y Temas base. pub mod util; // Macros y funciones útiles. pub mod prelude; // Re-exporta recursos comunes. diff --git a/pagetop/src/module/definition.rs b/pagetop/src/module/definition.rs index ccebe607..9424fbd8 100644 --- a/pagetop/src/module/definition.rs +++ b/pagetop/src/module/definition.rs @@ -1,6 +1,7 @@ +use crate::app; + #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] use crate::db; -use crate::app; use std::any::type_name; diff --git a/pagetop/src/module/mod.rs b/pagetop/src/module/mod.rs index cb71dfd2..faf51e8b 100644 --- a/pagetop/src/module/mod.rs +++ b/pagetop/src/module/mod.rs @@ -1,17 +1,4 @@ -use crate::{all, trace}; - mod definition; pub use definition::ModuleTrait; -pub mod homepage; - -pub fn register_module(m: &'static dyn ModuleTrait) { - let mut modules = all::MODULES.write().unwrap(); - match modules.iter().find(|t| t.name() == m.name()) { - None => { - trace::info!("{}", m.name()); - modules.push(m); - }, - Some(_) => {}, - } -} +pub use crate::global::register_module; diff --git a/pagetop/src/prelude.rs b/pagetop/src/prelude.rs index 1bfc1817..e9b3617c 100644 --- a/pagetop/src/prelude.rs +++ b/pagetop/src/prelude.rs @@ -16,6 +16,6 @@ pub use crate::response::page::*; pub use crate::app; pub use crate::app::application::{Application, essence}; -pub use crate::component::*; +pub use crate::base::component::*; pub use crate::util; diff --git a/pagetop/src/response/page/assets.rs b/pagetop/src/response/page/assets.rs index 9c30d981..99e42b06 100644 --- a/pagetop/src/response/page/assets.rs +++ b/pagetop/src/response/page/assets.rs @@ -1,17 +1,7 @@ -use crate::{Lazy, all}; -use crate::config::SETTINGS; +use crate::global::DEFAULT_THEME; use crate::html::{Markup, PreEscaped, html}; use crate::theme::*; -static DEFAULT_THEME: Lazy<&dyn ThemeTrait> = Lazy::new(|| { - for t in all::THEMES.read().unwrap().iter() { - if t.name().to_lowercase() == SETTINGS.app.theme.to_lowercase() { - return *t; - } - } - &bootsier::BootsierTheme -}); - // ----------------------------------------------------------------------------- // Favicon. // ----------------------------------------------------------------------------- @@ -207,7 +197,7 @@ impl PageAssets { } pub fn using_theme(&mut self, theme_name: &str) -> &mut Self { - self.theme = find_theme(theme_name).unwrap_or(*DEFAULT_THEME); + self.theme = theme_by_name(theme_name).unwrap_or(*DEFAULT_THEME); self } diff --git a/pagetop/src/theme/definition.rs b/pagetop/src/theme/definition.rs index 38ad1bfd..727df347 100644 --- a/pagetop/src/theme/definition.rs +++ b/pagetop/src/theme/definition.rs @@ -1,8 +1,8 @@ +use crate::app; use crate::config::SETTINGS; use crate::html::{Markup, html}; use crate::response::page::{Page, PageAssets, PageComponent}; -use crate::app; -use crate::component::Chunck; +use crate::base::component::Chunck; /// Los temas deben implementar este "trait". pub trait ThemeTrait: Send + Sync { diff --git a/pagetop/src/theme/mod.rs b/pagetop/src/theme/mod.rs index 9b045708..a1d0e4ca 100644 --- a/pagetop/src/theme/mod.rs +++ b/pagetop/src/theme/mod.rs @@ -1,20 +1,5 @@ -use crate::all; - mod definition; pub use definition::ThemeTrait; -pub mod aliner; -pub mod minimal; -pub mod bootsier; - -pub fn register_theme(t: &'static dyn ThemeTrait) { - all::THEMES.write().unwrap().push(t); -} - -pub fn find_theme(name: &str) -> Option<&'static dyn ThemeTrait> { - let themes = all::THEMES.write().unwrap(); - match themes.iter().find(|t| t.name() == name) { - Some(theme) => Some(*theme), - _ => None, - } -} +pub use crate::global::register_theme; +pub use crate::global::theme_by_name; From e3f592b3b0835e758e0aca1e3dcec038d924de09 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 20 Mar 2022 20:48:54 +0100 Subject: [PATCH 034/244] =?UTF-8?q?A=C3=B1ade=20carga=20de=20archivos=20es?= =?UTF-8?q?t=C3=A1ticos=20desde=20directorio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Con el ajuste de configuración "dev.static_files" se puede elegir entre integrar los archivos estáticos en el binario ejecutable (por defecto) o servirlos desde su propio directorio. Esto facilita el desarrollo al no tener que compilar cada vez que se modifican estos archivos. --- config/default.toml | 7 +++++-- drust/Cargo.toml | 2 +- pagetop-admin/Cargo.toml | 6 +++--- pagetop-node/Cargo.toml | 4 ++-- pagetop-user/Cargo.toml | 10 +++------ pagetop-user/src/locales/es-ES/homepage.ftl | 2 +- pagetop/Cargo.toml | 13 ++++++------ pagetop/STARTER.bin.Cargo.toml | 18 +++++++--------- pagetop/STARTER.lib.Cargo.toml | 23 +++++---------------- pagetop/build.rs | 3 --- pagetop/config/settings.default.toml | 8 +++++++ pagetop/src/base/theme/aliner/mod.rs | 5 +---- pagetop/src/base/theme/bootsier/mod.rs | 7 ++----- pagetop/src/config.rs | 11 +++++++++- pagetop/src/global.rs | 7 ++----- pagetop/src/prelude.rs | 7 ++++++- pagetop/src/util.rs | 18 ++++++++++++++++ pagetop/static/aliner/css/styles.css | 13 ++++++++++++ 18 files changed, 93 insertions(+), 71 deletions(-) diff --git a/config/default.toml b/config/default.toml index 33280fbd..5b6982fe 100644 --- a/config/default.toml +++ b/config/default.toml @@ -1,12 +1,12 @@ [app] name = "Drust" description = """\ - A modern Content Management System for sharing the world.\ + A modern web Content Management System to share your world.\ """ -language = "es-ES" #theme = "Aliner" #theme = "Minimal" theme = "Bootsier" +language = "es-ES" [database] db_type = "mysql" @@ -16,3 +16,6 @@ db_pass = "DrU__#3T" [log] tracing = "Info,sqlx::query=Warn" + +[dev] +#static_files = "pagetop/static" diff --git a/drust/Cargo.toml b/drust/Cargo.toml index 88ebabde..7a5412d5 100644 --- a/drust/Cargo.toml +++ b/drust/Cargo.toml @@ -7,7 +7,7 @@ authors = [ "Manuel Cillero <manuel@cillero.es>" ] description = """\ - A modern Content Management System for sharing the world.\ + A modern web Content Management System to share your world.\ """ homepage = "https://suitepro.cillero.es/projects/drust" repository = "https://gitlab.com/manuelcillero/drust" diff --git a/pagetop-admin/Cargo.toml b/pagetop-admin/Cargo.toml index 1bff0edd..3dfc6e60 100644 --- a/pagetop-admin/Cargo.toml +++ b/pagetop-admin/Cargo.toml @@ -7,10 +7,10 @@ authors = [ "Manuel Cillero <manuel@cillero.es>" ] description = """\ - Allows content to be submitted to the site and displayed on pages.\ + ...\ """ -homepage = "https://suitepro.cillero.es/projects/drust" -repository = "https://gitlab.com/manuelcillero/drust" +homepage = "https://suitepro.cillero.es/projects/pagetop" +repository = "https://gitlab.com/manuelcillero/pagetop" [dependencies] pagetop = { path = "../pagetop" } diff --git a/pagetop-node/Cargo.toml b/pagetop-node/Cargo.toml index 36b43d39..29857822 100644 --- a/pagetop-node/Cargo.toml +++ b/pagetop-node/Cargo.toml @@ -9,8 +9,8 @@ authors = [ description = """\ Allows content to be submitted to the site and displayed on pages.\ """ -homepage = "https://suitepro.cillero.es/projects/drust" -repository = "https://gitlab.com/manuelcillero/drust" +homepage = "https://suitepro.cillero.es/projects/pagetop" +repository = "https://gitlab.com/manuelcillero/pagetop" [dependencies] pagetop = { path = "../pagetop" } diff --git a/pagetop-user/Cargo.toml b/pagetop-user/Cargo.toml index 37352fe7..59c24cb3 100644 --- a/pagetop-user/Cargo.toml +++ b/pagetop-user/Cargo.toml @@ -9,14 +9,10 @@ authors = [ description = """\ Allows content to be submitted to the site and displayed on pages.\ """ -homepage = "https://suitepro.cillero.es/projects/drust" -repository = "https://gitlab.com/manuelcillero/drust" +homepage = "https://suitepro.cillero.es/projects/pagetop" +repository = "https://gitlab.com/manuelcillero/pagetop" [dependencies] pagetop = { path = "../pagetop" } +sea-orm = { version = "0.6.0" } serde = { version = "1.0", features = ["derive"] } - -[dependencies.sea-orm] -version = "0.6.0" -features = ["debug-print", "macros"] -default-features = false diff --git a/pagetop-user/src/locales/es-ES/homepage.ftl b/pagetop-user/src/locales/es-ES/homepage.ftl index ae9a70e0..f5f6e1bb 100644 --- a/pagetop-user/src/locales/es-ES/homepage.ftl +++ b/pagetop-user/src/locales/es-ES/homepage.ftl @@ -1,5 +1,5 @@ module_fullname = Usuario -module_description = Gestion el registro de usuarios y el sistema de accesos. +module_description = Gestiona el registro de usuarios y el sistema de accesos. username = Nombre de usuario password = Contraseña diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index db491819..4d92b378 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -7,10 +7,8 @@ authors = [ "Manuel Cillero <manuel@cillero.es>" ] description = """\ - PageTop es un proyecto personal para aprender Rust. Incluye algunos de los \ - crates más estables y populares para desarrollar soluciones web modulares, \ - extensibles y configurables. También es un sistema para la gestión de \ - contenidos web.\ + PageTop is an opinionated framework for using the most stable and popular \ + Rust packages to build modular, extensible and configurable web solutions.\ """ homepage = "https://suitepro.cillero.es/projects/pagetop" repository = "https://gitlab.com/manuelcillero/pagetop" @@ -44,6 +42,7 @@ unic-langid = "0.9.0" actix-web = "3.3.3" actix-web-static-files = "3.0.5" +actix-files = "0.4.1" maud = { version = "0.23.0", features = ["actix-web"] } sycamore = { version = "0.7.1", features = ["ssr"] } @@ -62,9 +61,6 @@ features = ["debug-print", "migration"] default-features = false optional = true -[dev-dependencies] -tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread"] } - [features] default = [] mysql = ["sea-orm", "sea-schema", "sea-orm/sqlx-mysql"] @@ -74,5 +70,8 @@ sqlite = ["sea-orm", "sea-schema", "sea-orm/sqlx-sqlite"] [build-dependencies] actix-web-static-files = "3.0.5" +[dev-dependencies] +tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread"] } + [lib] name = "pagetop" diff --git a/pagetop/STARTER.bin.Cargo.toml b/pagetop/STARTER.bin.Cargo.toml index d05a17bf..2ee2fd9d 100644 --- a/pagetop/STARTER.bin.Cargo.toml +++ b/pagetop/STARTER.bin.Cargo.toml @@ -8,24 +8,20 @@ edition = "2021" [dependencies.pagetop] path = "../pagetop" -# Opcional. Por defecto se puede usar PageTop sin base de datos. +# PageTop por defecto no requiere base de datos. Hay que habilitarla: features = ["mysql"] # features = ["postgres"] # features = ["sqlite"] -# PageTop puede dar soporte a todas las bases de datos. +# PageTop puede dar soporte a todas las bases de datos: # features = ["mysql", "postgres", "sqlite"] -# Sólo cuando no se usen las características predeterminadas. +# En estos casos hay que deshabilitar las características predeterminadas: default-features = false [dependencies] -# Requerido. actix-web = "3.3.3" -# Opcional. Sólo si se usa la macro html!. +# Opcional. Sólo si se usa la macro html!: maud = { version = "0.23.0" } -# Opcional. Si se requiere serialización de estructuras de datos. +# Opcional. Sólo si se usa base de datos: +sea-orm = { version = "0.6.0" } +# Opcional. Para la serialización de estructuras de datos: serde = { version = "1.0", features = ["derive"] } - -[dependencies.sea-orm] -version = "0.6.0" -features = ["debug-print", "macros"] -default-features = false diff --git a/pagetop/STARTER.lib.Cargo.toml b/pagetop/STARTER.lib.Cargo.toml index 97389750..74e74a8a 100644 --- a/pagetop/STARTER.lib.Cargo.toml +++ b/pagetop/STARTER.lib.Cargo.toml @@ -6,24 +6,11 @@ edition = "2021" # Ver más claves y sus definiciones en # https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies.pagetop] -path = "../pagetop" -# Opcional. Por defecto se puede usar PageTop sin base de datos. -features = ["mysql"] -# features = ["postgres"] -# features = ["sqlite"] -# PageTop puede dar soporte a todas las bases de datos. -# features = ["mysql", "postgres", "sqlite"] -# Sólo cuando no se usen las características predeterminadas. -default-features = false - [dependencies] -# Opcional. Sólo si se usa la macro html!. +pagetop = { path = "../pagetop" } +# Opcional. Sólo si se usa la macro html!: maud = { version = "0.23.0" } -# Opcional. Si se requiere serialización de estructuras de datos. +# Opcional. Sólo si se usa base de datos: +sea-orm = { version = "0.6.0" } +# Opcional. Para la serialización de estructuras de datos: serde = { version = "1.0", features = ["derive"] } - -[dependencies.sea-orm] -version = "0.6.0" -features = ["debug-print", "macros"] -default-features = false diff --git a/pagetop/build.rs b/pagetop/build.rs index 9b252213..bd7e60a0 100644 --- a/pagetop/build.rs +++ b/pagetop/build.rs @@ -9,7 +9,6 @@ fn main() { Path::new(env::var("OUT_DIR").unwrap().as_str()) .join("theme.rs") ) - .with_generated_fn("assets") .build() .unwrap(); @@ -18,7 +17,6 @@ fn main() { Path::new(env::var("OUT_DIR").unwrap().as_str()) .join("aliner.rs") ) - .with_generated_fn("assets") .build() .unwrap(); @@ -27,7 +25,6 @@ fn main() { Path::new(env::var("OUT_DIR").unwrap().as_str()) .join("bootsier.rs") ) - .with_generated_fn("assets") .build() .unwrap(); } diff --git a/pagetop/config/settings.default.toml b/pagetop/config/settings.default.toml index b9c329cf..8ac7ab2d 100644 --- a/pagetop/config/settings.default.toml +++ b/pagetop/config/settings.default.toml @@ -43,3 +43,11 @@ max_pool_size = 5 # Configuración del servidor web. bind_address = "localhost" bind_port = 8088 + +[dev] +# Los archivos estáticos requeridos por temas y componentes incluidos en PageTop +# se integran de manera predeterminada en el binario ejecutable. Sin embargo, es +# útil servir estos archivos desde su propio directorio durante el desarrollo ya +# que no requiere compilar cada vez que se modifican. En este caso, normalmente, +# basta con indicar el directorio "pagetop/static". +static_files = "" diff --git a/pagetop/src/base/theme/aliner/mod.rs b/pagetop/src/base/theme/aliner/mod.rs index 676eb25d..07b1470f 100644 --- a/pagetop/src/base/theme/aliner/mod.rs +++ b/pagetop/src/base/theme/aliner/mod.rs @@ -14,10 +14,7 @@ impl ThemeTrait for AlinerTheme { } fn configure_theme(&self, cfg: &mut app::web::ServiceConfig) { - cfg.service(actix_web_static_files::ResourceFiles::new( - "/aliner", - assets() - )); + theme_static_files!(cfg, "/aliner"); } fn before_render_page(&self, page: &mut Page) { diff --git a/pagetop/src/base/theme/bootsier/mod.rs b/pagetop/src/base/theme/bootsier/mod.rs index 132dce32..dbd31727 100644 --- a/pagetop/src/base/theme/bootsier/mod.rs +++ b/pagetop/src/base/theme/bootsier/mod.rs @@ -16,10 +16,7 @@ impl ThemeTrait for BootsierTheme { } fn configure_theme(&self, cfg: &mut app::web::ServiceConfig) { - cfg.service(actix_web_static_files::ResourceFiles::new( - "/bootsier", - assets() - )); + theme_static_files!(cfg, "/bootsier"); } fn before_render_page(&self, page: &mut Page) { @@ -61,7 +58,7 @@ impl ThemeTrait for BootsierTheme { div class="jumbotron" { div class="media" { img - src="/bootsier/images/caution.png" + src="/static/bootsier/images/caution.png" class="mr-4" style="width: 20%; max-width: 188px" alt="Caution!"; diff --git a/pagetop/src/config.rs b/pagetop/src/config.rs index 27dbb275..0a5e322d 100644 --- a/pagetop/src/config.rs +++ b/pagetop/src/config.rs @@ -104,12 +104,18 @@ pub struct Webserver { pub bind_port : u16, } +#[derive(Debug, Deserialize)] +pub struct Dev { + pub static_files : String, +} + #[derive(Debug, Deserialize)] pub struct Settings { pub app : App, pub log : Log, pub database : Database, pub webserver : Webserver, + pub dev : Dev, } config_map!(r#" @@ -144,5 +150,8 @@ Ajustes globales y valores predeterminados para las secciones *\[app\]*, // [webserver] "webserver.bind_address" => "localhost", - "webserver.bind_port" => 8088 + "webserver.bind_port" => 8088, + + // [dev] + "dev.static_files" => "" ); diff --git a/pagetop/src/global.rs b/pagetop/src/global.rs index 34280cf4..1b4c169f 100644 --- a/pagetop/src/global.rs +++ b/pagetop/src/global.rs @@ -1,4 +1,4 @@ -use crate::{Lazy, app, base, run_now, trace}; +use crate::{Lazy, app, base, run_now, theme_static_files, trace}; use crate::config::SETTINGS; use crate::db::migration::*; use crate::module::*; @@ -84,10 +84,7 @@ pub fn theme_by_name(name: &str) -> Option<&'static dyn ThemeTrait> { } pub fn themes(cfg: &mut app::web::ServiceConfig) { - cfg.service(actix_web_static_files::ResourceFiles::new( - "/theme", - assets() - )); + theme_static_files!(cfg, "/theme"); for t in THEMES.read().unwrap().iter() { t.configure_theme(cfg); diff --git a/pagetop/src/prelude.rs b/pagetop/src/prelude.rs index e9b3617c..7c2e9ef3 100644 --- a/pagetop/src/prelude.rs +++ b/pagetop/src/prelude.rs @@ -1,6 +1,11 @@ //! Re-exporta recursos comunes. -pub use crate::args; +// Macros. +pub use crate::{ + args, + theme_static_files, +}; + pub use crate::config::SETTINGS; pub use crate::trace; pub use crate::localize; diff --git a/pagetop/src/util.rs b/pagetop/src/util.rs index 3fff0a23..c5254618 100644 --- a/pagetop/src/util.rs +++ b/pagetop/src/util.rs @@ -18,6 +18,24 @@ macro_rules! args { }}; } +#[macro_export] +macro_rules! theme_static_files { + ( $cfg:ident, $dir:expr ) => {{ + let static_files = &$crate::config::SETTINGS.dev.static_files; + if static_files.is_empty() { + $cfg.service(actix_web_static_files::ResourceFiles::new( + $dir, + generate() + )); + } else { + $cfg.service(actix_files::Files::new( + $dir, + &[static_files, $dir].join("") + ).show_files_listing()); + } + }}; +} + pub fn valid_id(id: &str) -> Option<String> { let id = id.trim().replace(" ", "_").to_lowercase(); match id.is_empty() { diff --git a/pagetop/static/aliner/css/styles.css b/pagetop/static/aliner/css/styles.css index ffeee7db..1cc2f5dc 100644 --- a/pagetop/static/aliner/css/styles.css +++ b/pagetop/static/aliner/css/styles.css @@ -1,5 +1,16 @@ html { background-color: white; + padding: 1px 3px; +} +body { + padding: 1px 3px; +} +div { + padding: 1px 3px; + margin: 5px; +} +h1, h2, h3, h4,h5, h6, p { + background-color: snow; } * * { outline: 5px solid rgba(255,0,0,.1); @@ -21,7 +32,9 @@ html { background: #faa; border-radius: 3px; font: normal normal 400 10px/1.2 monospace; + vertical-align: middle; padding: 1px 3px; + margin: 0 3px; } *::before { content: "("; From d72e1ccad56221bdafec9568dfb2e443272c7347 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 23 Mar 2022 22:29:07 +0100 Subject: [PATCH 035/244] =?UTF-8?q?Actualiza=20la=20presentaci=C3=B3n=20de?= =?UTF-8?q?l=20r=C3=B3tulo=20de=20arranque?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pagetop/STARTER.bin.Cargo.toml | 10 +- pagetop/STARTER.lib.Cargo.toml | 6 +- pagetop/config/settings.default.toml | 4 +- pagetop/src/app/application.rs | 40 ++------ pagetop/src/app/banner/mod.rs | 40 ++++++++ .../src/app/{figfonts => banner}/slant.flf | 0 .../src/app/{figfonts => banner}/small.flf | 0 .../src/app/{figfonts => banner}/speed.flf | 0 .../src/app/{figfonts => banner}/starwars.flf | 0 pagetop/src/app/mod.rs | 2 + pagetop/src/config.rs | 2 +- pagetop/src/global.rs | 93 ------------------- pagetop/src/lib.rs | 2 - pagetop/src/module/all.rs | 44 +++++++++ pagetop/src/module/mod.rs | 3 +- pagetop/src/response/page/assets.rs | 10 +- pagetop/src/theme/all.rs | 43 +++++++++ pagetop/src/theme/mod.rs | 7 +- 18 files changed, 164 insertions(+), 142 deletions(-) create mode 100644 pagetop/src/app/banner/mod.rs rename pagetop/src/app/{figfonts => banner}/slant.flf (100%) rename pagetop/src/app/{figfonts => banner}/small.flf (100%) rename pagetop/src/app/{figfonts => banner}/speed.flf (100%) rename pagetop/src/app/{figfonts => banner}/starwars.flf (100%) delete mode 100644 pagetop/src/global.rs create mode 100644 pagetop/src/module/all.rs create mode 100644 pagetop/src/theme/all.rs diff --git a/pagetop/STARTER.bin.Cargo.toml b/pagetop/STARTER.bin.Cargo.toml index 2ee2fd9d..9c6c8979 100644 --- a/pagetop/STARTER.bin.Cargo.toml +++ b/pagetop/STARTER.bin.Cargo.toml @@ -8,20 +8,20 @@ edition = "2021" [dependencies.pagetop] path = "../pagetop" -# PageTop por defecto no requiere base de datos. Hay que habilitarla: +# Si se usa base de datos: features = ["mysql"] # features = ["postgres"] # features = ["sqlite"] -# PageTop puede dar soporte a todas las bases de datos: +# Soporte alternativo a todas las bases de datos: # features = ["mysql", "postgres", "sqlite"] # En estos casos hay que deshabilitar las características predeterminadas: default-features = false [dependencies] actix-web = "3.3.3" -# Opcional. Sólo si se usa la macro html!: +# Si se usa la macro html!: maud = { version = "0.23.0" } -# Opcional. Sólo si se usa base de datos: +# Si se usa base de datos: sea-orm = { version = "0.6.0" } -# Opcional. Para la serialización de estructuras de datos: +# Si se requiere serialización de estructuras de datos: serde = { version = "1.0", features = ["derive"] } diff --git a/pagetop/STARTER.lib.Cargo.toml b/pagetop/STARTER.lib.Cargo.toml index 74e74a8a..e98fed13 100644 --- a/pagetop/STARTER.lib.Cargo.toml +++ b/pagetop/STARTER.lib.Cargo.toml @@ -8,9 +8,9 @@ edition = "2021" [dependencies] pagetop = { path = "../pagetop" } -# Opcional. Sólo si se usa la macro html!: +# Si se usa la macro html!: maud = { version = "0.23.0" } -# Opcional. Sólo si se usa base de datos: +# Si se usa base de datos: sea-orm = { version = "0.6.0" } -# Opcional. Para la serialización de estructuras de datos: +# Si se requiere serialización de estructuras de datos: serde = { version = "1.0", features = ["derive"] } diff --git a/pagetop/config/settings.default.toml b/pagetop/config/settings.default.toml index 8ac7ab2d..115b4cb7 100644 --- a/pagetop/config/settings.default.toml +++ b/pagetop/config/settings.default.toml @@ -8,7 +8,7 @@ language = "en-US" # Dirección predeterminada para el texto: "ltr", "rtl" o "auto". direction = "ltr" # Rótulo al inicio: "Off", "Slant", "Small", "Speed" o "Starwars". -startup_banner = "Small" +startup_banner = "Slant" [log] # Traza de ejecución: "Error", "Warn", "Info", "Debug" o "Trace". @@ -25,7 +25,7 @@ format = "Full" [database] # Conecta con una base de datos (opcional). -# Tipo de la base de datos (mysql, postgres ó sqlite). +# Tipo de base de datos (mysql, postgres ó sqlite). db_type = "" # Nombre (para mysql/postgres) o referencia (para sqlite) de la base de datos. db_name = "" diff --git a/pagetop/src/app/application.rs b/pagetop/src/app/application.rs index 274203e6..4ed2c1da 100644 --- a/pagetop/src/app/application.rs +++ b/pagetop/src/app/application.rs @@ -1,6 +1,5 @@ -use crate::{Lazy, app, base, global, trace}; +use crate::{Lazy, app, base, module, theme, trace}; use crate::config::SETTINGS; -use crate::module::register_module; use std::io::Error; use actix_web::middleware::normalize::{NormalizePath, TrailingSlash}; @@ -15,31 +14,8 @@ pub fn essence() { impl Application { pub async fn prepare(bootstrap: fn()) -> Result<Self, Error> { - // Imprime un rótulo de presentación (opcional). - if SETTINGS.app.startup_banner.to_lowercase() != "off" { - let figfont = figlet_rs::FIGfont::from_content( - match SETTINGS.app.startup_banner.to_lowercase().as_str() { - "slant" => include_str!("figfonts/slant.flf"), - "small" => include_str!("figfonts/small.flf"), - "speed" => include_str!("figfonts/speed.flf"), - "starwars" => include_str!("figfonts/starwars.flf"), - _ => { - println!( - "FIGfont \"{}\" not found for banner. {}. {}.", - SETTINGS.app.startup_banner, - "Using \"Small\"", - "Check the settings file", - ); - include_str!("figfonts/small.flf") - } - } - ).unwrap(); - println!("\n{} {}\n\n Powered by PageTop {}\n", - figfont.convert(&SETTINGS.app.name).unwrap(), - &SETTINGS.app.description, - env!("CARGO_PKG_VERSION") - ); - } + // Rótulo de presentación. + app::banner::print_on_startup(); // Inicia registro de trazas y eventos. Lazy::force(&app::tracing::TRACING); @@ -57,19 +33,19 @@ impl Application { // Registra el módulo para una página de presentación de PageTop. // Normalmente se sobrecargará en la función de inicio. - register_module(&base::module::homepage::HomepageModule); + module::register_module(&base::module::homepage::HomepageModule); - // Comprueba actualizaciones pendientes de la base de datos (opcional). + // Actualizaciones pendientes de la base de datos (opcional). #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] - global::run_migrations(); + module::all::migrations(); // Prepara el servidor web. let server = app::HttpServer::new(move || { app::App::new() .wrap(tracing_actix_web::TracingLogger) .wrap(NormalizePath::new(TrailingSlash::Trim)) - .configure(&global::themes) - .configure(&global::modules) + .configure(&module::all::modules) + .configure(&theme::all::themes) }) .bind(format!("{}:{}", &SETTINGS.webserver.bind_address, diff --git a/pagetop/src/app/banner/mod.rs b/pagetop/src/app/banner/mod.rs new file mode 100644 index 00000000..f6d63841 --- /dev/null +++ b/pagetop/src/app/banner/mod.rs @@ -0,0 +1,40 @@ +use crate::Lazy; +use crate::config::SETTINGS; + +use figlet_rs::FIGfont; + +static FIGFONT: Lazy<FIGfont> = Lazy::new(|| { + let slant = include_str!("slant.flf"); + let small = include_str!("small.flf"); + let speed = include_str!("speed.flf"); + let starwars = include_str!("starwars.flf"); + + FIGfont::from_content( + match SETTINGS.app.startup_banner.to_lowercase().as_str() { + "off" => slant, + "slant" => slant, + "small" => small, + "speed" => speed, + "starwars" => starwars, + _ => { + println!( + "\n FIGfont \"{}\" not found for banner. {}. {}.", + SETTINGS.app.startup_banner, + "Using \"Slant\"", + "Check the settings file", + ); + slant + } + } + ).unwrap() +}); + +pub fn print_on_startup() { + if SETTINGS.app.startup_banner.to_lowercase() != "off" { + println!("\n{} {}\n\n Powered by PageTop {}\n", + FIGFONT.convert(&SETTINGS.app.name).unwrap(), + &SETTINGS.app.description, + env!("CARGO_PKG_VERSION") + ); + } +} diff --git a/pagetop/src/app/figfonts/slant.flf b/pagetop/src/app/banner/slant.flf similarity index 100% rename from pagetop/src/app/figfonts/slant.flf rename to pagetop/src/app/banner/slant.flf diff --git a/pagetop/src/app/figfonts/small.flf b/pagetop/src/app/banner/small.flf similarity index 100% rename from pagetop/src/app/figfonts/small.flf rename to pagetop/src/app/banner/small.flf diff --git a/pagetop/src/app/figfonts/speed.flf b/pagetop/src/app/banner/speed.flf similarity index 100% rename from pagetop/src/app/figfonts/speed.flf rename to pagetop/src/app/banner/speed.flf diff --git a/pagetop/src/app/figfonts/starwars.flf b/pagetop/src/app/banner/starwars.flf similarity index 100% rename from pagetop/src/app/figfonts/starwars.flf rename to pagetop/src/app/banner/starwars.flf diff --git a/pagetop/src/app/mod.rs b/pagetop/src/app/mod.rs index b3f7cd6a..07404f64 100644 --- a/pagetop/src/app/mod.rs +++ b/pagetop/src/app/mod.rs @@ -3,6 +3,8 @@ pub use actix_web::{ }; use actix_web::dev::Server; +mod banner; + mod tracing; pub mod locale; diff --git a/pagetop/src/config.rs b/pagetop/src/config.rs index 0a5e322d..775cc4a6 100644 --- a/pagetop/src/config.rs +++ b/pagetop/src/config.rs @@ -130,7 +130,7 @@ Ajustes globales y valores predeterminados para las secciones *\[app\]*, "app.theme" => "Bootsier", "app.language" => "en-US", "app.direction" => "ltr", - "app.startup_banner" => "Small", + "app.startup_banner" => "Slant", // [log] "log.tracing" => "Info", diff --git a/pagetop/src/global.rs b/pagetop/src/global.rs deleted file mode 100644 index 1b4c169f..00000000 --- a/pagetop/src/global.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::{Lazy, app, base, run_now, theme_static_files, trace}; -use crate::config::SETTINGS; -use crate::db::migration::*; -use crate::module::*; -use crate::theme::*; - -use std::sync::RwLock; - -// ----------------------------------------------------------------------------- -// Módulos registrados. -// ----------------------------------------------------------------------------- - -pub static MODULES: Lazy<RwLock<Vec<&dyn ModuleTrait>>> = Lazy::new( - || { RwLock::new(Vec::new()) } -); - -pub fn register_module(m: &'static dyn ModuleTrait) { - let mut modules = MODULES.write().unwrap(); - match modules.iter().find(|t| t.name() == m.name()) { - None => { - trace::info!("{}", m.name()); - modules.push(m); - }, - Some(_) => {}, - } -} - -pub fn modules(cfg: &mut app::web::ServiceConfig) { - for m in MODULES.read().unwrap().iter() { - m.configure_module(cfg); - } -} - -#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] -pub fn run_migrations() { - run_now({ - struct Migrator; - impl MigratorTrait for Migrator { - fn migrations() -> Vec<Box<dyn MigrationTrait>> { - let mut migrations = vec![]; - for m in MODULES.read().unwrap().iter() { - migrations.append(&mut m.migrations()); - } - migrations - } - } - Migrator::up(&app::db::DBCONN, None) - }).unwrap(); -} - -// ----------------------------------------------------------------------------- -// Temas registrados y tema predeterminado. -// ----------------------------------------------------------------------------- - -include!(concat!(env!("OUT_DIR"), "/theme.rs")); - -pub static THEMES: Lazy<RwLock<Vec<&dyn ThemeTrait>>> = Lazy::new(|| { - RwLock::new(vec![ - &base::theme::aliner::AlinerTheme, - &base::theme::minimal::MinimalTheme, - &base::theme::bootsier::BootsierTheme, - ]) -}); - -pub static DEFAULT_THEME: Lazy<&dyn ThemeTrait> = Lazy::new(|| { - for t in THEMES.read().unwrap().iter() { - if t.name().to_lowercase() == SETTINGS.app.theme.to_lowercase() { - return *t; - } - } - &base::theme::bootsier::BootsierTheme -}); - -pub fn register_theme(t: &'static dyn ThemeTrait) { - THEMES.write().unwrap().push(t); -} - -pub fn theme_by_name(name: &str) -> Option<&'static dyn ThemeTrait> { - let themes = crate::global::THEMES.write().unwrap(); - match themes.iter().find(|t| t.name() == name) { - Some(theme) => Some(*theme), - _ => None, - } -} - -pub fn themes(cfg: &mut app::web::ServiceConfig) { - theme_static_files!(cfg, "/theme"); - - for t in THEMES.read().unwrap().iter() { - t.configure_theme(cfg); - } -} - diff --git a/pagetop/src/lib.rs b/pagetop/src/lib.rs index 3efe21aa..73e17c8d 100644 --- a/pagetop/src/lib.rs +++ b/pagetop/src/lib.rs @@ -8,8 +8,6 @@ pub use futures::executor::block_on as run_now; // APIs públicas. // ----------------------------------------------------------------------------- -mod global; // Ref. privadas globales a todos los temas y módulos. - pub mod config; // Gestión de la configuración. pub mod trace; // Registro de trazas y eventos de la aplicación. pub mod locale; // Localización. diff --git a/pagetop/src/module/all.rs b/pagetop/src/module/all.rs new file mode 100644 index 00000000..120c59b6 --- /dev/null +++ b/pagetop/src/module/all.rs @@ -0,0 +1,44 @@ +use crate::{Lazy, app, run_now, trace}; +use crate::db::migration::*; +use super::ModuleTrait; + +use std::sync::RwLock; + +// Módulos registrados. +static MODULES: Lazy<RwLock<Vec<&dyn ModuleTrait>>> = Lazy::new(|| { + RwLock::new(Vec::new()) +}); + +pub fn register_module(module: &'static dyn ModuleTrait) { + let mut modules = MODULES.write().unwrap(); + match modules.iter().find(|m| m.name() == module.name()) { + None => { + trace::info!("{}", module.name()); + modules.push(module); + }, + Some(_) => {}, + } +} + +pub fn modules(cfg: &mut app::web::ServiceConfig) { + for m in MODULES.read().unwrap().iter() { + m.configure_module(cfg); + } +} + +#[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] +pub fn migrations() { + run_now({ + struct Migrator; + impl MigratorTrait for Migrator { + fn migrations() -> Vec<Box<dyn MigrationTrait>> { + let mut migrations = vec![]; + for m in MODULES.read().unwrap().iter() { + migrations.append(&mut m.migrations()); + } + migrations + } + } + Migrator::up(&app::db::DBCONN, None) + }).unwrap(); +} diff --git a/pagetop/src/module/mod.rs b/pagetop/src/module/mod.rs index faf51e8b..a767683b 100644 --- a/pagetop/src/module/mod.rs +++ b/pagetop/src/module/mod.rs @@ -1,4 +1,5 @@ mod definition; pub use definition::ModuleTrait; -pub use crate::global::register_module; +pub(crate) mod all; +pub use all::register_module; \ No newline at end of file diff --git a/pagetop/src/response/page/assets.rs b/pagetop/src/response/page/assets.rs index 99e42b06..ffc566ea 100644 --- a/pagetop/src/response/page/assets.rs +++ b/pagetop/src/response/page/assets.rs @@ -1,7 +1,15 @@ -use crate::global::DEFAULT_THEME; +use crate::{Lazy, base}; +use crate::config::SETTINGS; use crate::html::{Markup, PreEscaped, html}; use crate::theme::*; +static DEFAULT_THEME: Lazy<&dyn ThemeTrait> = Lazy::new(|| { + match theme_by_name(&SETTINGS.app.theme) { + Some(theme) => theme, + None => &base::theme::bootsier::BootsierTheme, + } +}); + // ----------------------------------------------------------------------------- // Favicon. // ----------------------------------------------------------------------------- diff --git a/pagetop/src/theme/all.rs b/pagetop/src/theme/all.rs new file mode 100644 index 00000000..cc25d9d8 --- /dev/null +++ b/pagetop/src/theme/all.rs @@ -0,0 +1,43 @@ +use crate::{Lazy, app, base, theme_static_files, trace}; +use super::ThemeTrait; + +use std::sync::RwLock; + +include!(concat!(env!("OUT_DIR"), "/theme.rs")); + +// Temas registrados. +static THEMES: Lazy<RwLock<Vec<&dyn ThemeTrait>>> = Lazy::new(|| { + RwLock::new(vec![ + &base::theme::aliner::AlinerTheme, + &base::theme::minimal::MinimalTheme, + &base::theme::bootsier::BootsierTheme, + ]) +}); + +pub fn register_theme(theme: &'static dyn ThemeTrait) { + let mut themes = THEMES.write().unwrap(); + match themes.iter().find(|t| t.name() == theme.name()) { + None => { + trace::info!("{}", theme.name()); + themes.push(theme); + }, + Some(_) => {}, + } +} + +pub fn theme_by_name(name: &str) -> Option<&'static dyn ThemeTrait> { + match THEMES.write().unwrap().iter().find( + |t| t.name().to_lowercase() == name.to_lowercase() + ) { + Some(theme) => Some(*theme), + _ => None, + } +} + +pub fn themes(cfg: &mut app::web::ServiceConfig) { + theme_static_files!(cfg, "/theme"); + + for t in THEMES.read().unwrap().iter() { + t.configure_theme(cfg); + } +} diff --git a/pagetop/src/theme/mod.rs b/pagetop/src/theme/mod.rs index a1d0e4ca..4456189e 100644 --- a/pagetop/src/theme/mod.rs +++ b/pagetop/src/theme/mod.rs @@ -1,5 +1,8 @@ mod definition; pub use definition::ThemeTrait; -pub use crate::global::register_theme; -pub use crate::global::theme_by_name; +pub(crate) mod all; +pub use all::{ + register_theme, + theme_by_name, +}; From 5b1064fda2a4ffd6f7bbdbc87b98d2a0b2a4762c Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 25 Mar 2022 20:24:19 +0100 Subject: [PATCH 036/244] =?UTF-8?q?Libera=20la=20versi=C3=B3n=20de=20desar?= =?UTF-8?q?rollo=200.0.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CREDITS.md | 11 ++++++-- config/default.toml | 2 +- pagetop-admin/src/lib.rs | 4 +++ pagetop-node/src/lib.rs | 4 +++ pagetop-user/src/lib.rs | 4 +++ pagetop/Cargo.toml | 2 +- pagetop/src/app/application.rs | 9 +++++-- pagetop/src/base/component/block.rs | 2 +- pagetop/src/base/component/form/button.rs | 2 +- pagetop/src/base/component/form/date.rs | 8 +++--- pagetop/src/base/component/form/form.rs | 4 +-- pagetop/src/base/component/form/hidden.rs | 2 +- pagetop/src/base/component/form/input.rs | 8 +++--- .../locales/en-US/demopage.ftl} | 2 +- .../locales/es-ES/demopage.ftl} | 2 +- .../base/module/{homepage => demopage}/mod.rs | 14 +++++++--- pagetop/src/base/module/mod.rs | 2 +- pagetop/src/base/theme/aliner/mod.rs | 6 ++++- pagetop/src/base/theme/bootsier/mod.rs | 4 +-- pagetop/src/base/theme/minimal/mod.rs | 2 +- pagetop/src/module/all.rs | 25 +++++++++++++----- pagetop/src/module/definition.rs | 10 +------ pagetop/src/response/page/page.rs | 6 ++--- pagetop/src/theme/all.rs | 17 ++++-------- pagetop/src/theme/definition.rs | 7 ++++- pagetop/src/util.rs | 12 ++++----- pagetop/static/theme/favicon.png | Bin 0 -> 11471 bytes 27 files changed, 104 insertions(+), 67 deletions(-) rename pagetop/src/base/module/{homepage/locales/en-US/homepage.ftl => demopage/locales/en-US/demopage.ftl} (95%) rename pagetop/src/base/module/{homepage/locales/es-ES/homepage.ftl => demopage/locales/es-ES/demopage.ftl} (93%) rename pagetop/src/base/module/{homepage => demopage}/mod.rs (91%) create mode 100644 pagetop/static/theme/favicon.png diff --git a/CREDITS.md b/CREDITS.md index 5b9979f4..4254ed59 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -1,9 +1,9 @@ # FIGfonts PageTop utiliza el paquete [figlet-rs](https://crates.io/crates/figlet-rs) de -*yuanbohan*, que muestra al inicio de la ejecución un rótulo con el nombre de +*yuanbohan*. Muestra en el terminal un rótulo de presentación con el nombre de la aplicación usando caracteres [FIGlet](http://www.figlet.org/). Las fuentes -incluidas en `resources` son: +incluidas en `src/app/banner` son: * [slant.flf](http://www.figlet.org/fontdb_example.cgi?font=slant.flf) por *Glenn Chappell*. @@ -13,3 +13,10 @@ incluidas en `resources` son: por *Claude Martins*. * [starwars.flf](http://www.figlet.org/fontdb_example.cgi?font=starwars.flf) por *Ryan Youck*. + +# Icono + +El monstruo sonriente de Frankenstein es una divertida creación de +[Webalys](https://www.iconfinder.com/webalys). Puede encontrarse en su colección +[Nasty Icons](https://www.iconfinder.com/iconsets/nasty) disponible en +[ICONFINDER](https://www.iconfinder.com/). \ No newline at end of file diff --git a/config/default.toml b/config/default.toml index 5b6982fe..13012a93 100644 --- a/config/default.toml +++ b/config/default.toml @@ -15,7 +15,7 @@ db_user = "drust" db_pass = "DrU__#3T" [log] -tracing = "Info,sqlx::query=Warn" +tracing = "Info,pagetop=Debug,sqlx::query=Warn" [dev] #static_files = "pagetop/static" diff --git a/pagetop-admin/src/lib.rs b/pagetop-admin/src/lib.rs index e3ad0337..a00e7fae 100644 --- a/pagetop-admin/src/lib.rs +++ b/pagetop-admin/src/lib.rs @@ -7,6 +7,10 @@ mod summary; pub struct AdminModule; impl ModuleTrait for AdminModule { + fn name(&self) -> &'static str { + "Admin" + } + fn fullname(&self) -> String { l("module_fullname") } diff --git a/pagetop-node/src/lib.rs b/pagetop-node/src/lib.rs index af6d8b3f..afcd729f 100644 --- a/pagetop-node/src/lib.rs +++ b/pagetop-node/src/lib.rs @@ -8,6 +8,10 @@ mod migration; pub struct NodeModule; impl ModuleTrait for NodeModule { + fn name(&self) -> &'static str { + "Node" + } + fn fullname(&self) -> String { l("module_fullname") } diff --git a/pagetop-user/src/lib.rs b/pagetop-user/src/lib.rs index c76233e1..343daa7a 100644 --- a/pagetop-user/src/lib.rs +++ b/pagetop-user/src/lib.rs @@ -8,6 +8,10 @@ mod migration; pub struct UserModule; impl ModuleTrait for UserModule { + fn name(&self) -> &'static str { + "User" + } + fn fullname(&self) -> String { l("module_fullname") } diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index 4d92b378..a260d17f 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.3" +version = "0.0.4" edition = "2021" authors = [ diff --git a/pagetop/src/app/application.rs b/pagetop/src/app/application.rs index 4ed2c1da..070390c8 100644 --- a/pagetop/src/app/application.rs +++ b/pagetop/src/app/application.rs @@ -27,13 +27,18 @@ impl Application { #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] Lazy::force(&app::db::DBCONN); + // Registra los temas predeterminados. + theme::register_theme(&base::theme::aliner::AlinerTheme); + theme::register_theme(&base::theme::minimal::MinimalTheme); + theme::register_theme(&base::theme::bootsier::BootsierTheme); + // Ejecuta la función de inicio de la aplicación. trace::info!("Calling application bootstrap"); let _ = &bootstrap(); - // Registra el módulo para una página de presentación de PageTop. + // Registra el módulo de presentación de PageTop. // Normalmente se sobrecargará en la función de inicio. - module::register_module(&base::module::homepage::HomepageModule); + module::register_module(&base::module::demopage::DemopageModule); // Actualizaciones pendientes de la base de datos (opcional). #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] diff --git a/pagetop/src/base/component/block.rs b/pagetop/src/base/component/block.rs index 4f658c9e..96fce677 100644 --- a/pagetop/src/base/component/block.rs +++ b/pagetop/src/base/component/block.rs @@ -71,7 +71,7 @@ impl Block { } pub fn with_title(mut self, title: &str) -> Self { - self.title = util::optional_str(title); + self.title = util::valid_str(title); self } diff --git a/pagetop/src/base/component/form/button.rs b/pagetop/src/base/component/form/button.rs index c76c49dd..57810fea 100644 --- a/pagetop/src/base/component/form/button.rs +++ b/pagetop/src/base/component/form/button.rs @@ -101,7 +101,7 @@ impl Button { } pub fn with_value(mut self, value: &str) -> Self { - self.value = util::optional_str(value); + self.value = util::valid_str(value); self } diff --git a/pagetop/src/base/component/form/date.rs b/pagetop/src/base/component/form/date.rs index ccc6ab31..6614670a 100644 --- a/pagetop/src/base/component/form/date.rs +++ b/pagetop/src/base/component/form/date.rs @@ -112,17 +112,17 @@ impl Date { } pub fn with_value(mut self, value: &str) -> Self { - self.value = util::optional_str(value); + self.value = util::valid_str(value); self } pub fn with_label(mut self, label: &str) -> Self { - self.label = util::optional_str(label); + self.label = util::valid_str(label); self } pub fn with_placeholder(mut self, placeholder: &str) -> Self { - self.placeholder = util::optional_str(placeholder); + self.placeholder = util::valid_str(placeholder); self } @@ -167,7 +167,7 @@ impl Date { } pub fn with_help_text(mut self, help_text: &str) -> Self { - self.help_text = util::optional_str(help_text); + self.help_text = util::valid_str(help_text); self } diff --git a/pagetop/src/base/component/form/form.rs b/pagetop/src/base/component/form/form.rs index 63eace0c..2fac4403 100644 --- a/pagetop/src/base/component/form/form.rs +++ b/pagetop/src/base/component/form/form.rs @@ -76,7 +76,7 @@ impl Form { } pub fn with_action(mut self, action: &str) -> Self { - self.action = util::optional_str(action); + self.action = util::valid_str(action); self } @@ -86,7 +86,7 @@ impl Form { } pub fn with_charset(mut self, charset: &str) -> Self { - self.charset = util::optional_str(charset); + self.charset = util::valid_str(charset); self } diff --git a/pagetop/src/base/component/form/hidden.rs b/pagetop/src/base/component/form/hidden.rs index 9ac0a4f9..bd158b85 100644 --- a/pagetop/src/base/component/form/hidden.rs +++ b/pagetop/src/base/component/form/hidden.rs @@ -54,7 +54,7 @@ impl Hidden { } pub fn with_value(mut self, value: &str) -> Self { - self.value = util::optional_str(value); + self.value = util::valid_str(value); self } diff --git a/pagetop/src/base/component/form/input.rs b/pagetop/src/base/component/form/input.rs index 884d2232..f0e73a63 100644 --- a/pagetop/src/base/component/form/input.rs +++ b/pagetop/src/base/component/form/input.rs @@ -167,12 +167,12 @@ impl Input { } pub fn with_value(mut self, value: &str) -> Self { - self.value = util::optional_str(value); + self.value = util::valid_str(value); self } pub fn with_label(mut self, label: &str) -> Self { - self.label = util::optional_str(label); + self.label = util::valid_str(label); self } @@ -192,7 +192,7 @@ impl Input { } pub fn with_placeholder(mut self, placeholder: &str) -> Self { - self.placeholder = util::optional_str(placeholder); + self.placeholder = util::valid_str(placeholder); self } @@ -237,7 +237,7 @@ impl Input { } pub fn with_help_text(mut self, help_text: &str) -> Self { - self.help_text = util::optional_str(help_text); + self.help_text = util::valid_str(help_text); self } diff --git a/pagetop/src/base/module/homepage/locales/en-US/homepage.ftl b/pagetop/src/base/module/demopage/locales/en-US/demopage.ftl similarity index 95% rename from pagetop/src/base/module/homepage/locales/en-US/homepage.ftl rename to pagetop/src/base/module/demopage/locales/en-US/demopage.ftl index 39a5e426..14c93f2f 100644 --- a/pagetop/src/base/module/homepage/locales/en-US/homepage.ftl +++ b/pagetop/src/base/module/demopage/locales/en-US/demopage.ftl @@ -1,5 +1,5 @@ module_fullname = Default homepage -module_description = Displays a default homepage when none is configured. +module_description = Displays a demo homepage when none is configured. page_title = Hello world! diff --git a/pagetop/src/base/module/homepage/locales/es-ES/homepage.ftl b/pagetop/src/base/module/demopage/locales/es-ES/demopage.ftl similarity index 93% rename from pagetop/src/base/module/homepage/locales/es-ES/homepage.ftl rename to pagetop/src/base/module/demopage/locales/es-ES/demopage.ftl index f1d85b2e..39720fcd 100644 --- a/pagetop/src/base/module/homepage/locales/es-ES/homepage.ftl +++ b/pagetop/src/base/module/demopage/locales/es-ES/demopage.ftl @@ -1,5 +1,5 @@ module_fullname = Página de inicio predeterminada -module_description = Muestra una página de inicio predeterminada cuando no hay ninguna configurada. +module_description = Muestra una página de demostración predeterminada cuando no hay ninguna configurada. page_title = ¡Hola mundo! diff --git a/pagetop/src/base/module/homepage/mod.rs b/pagetop/src/base/module/demopage/mod.rs similarity index 91% rename from pagetop/src/base/module/homepage/mod.rs rename to pagetop/src/base/module/demopage/mod.rs index bd364534..bb6e3b94 100644 --- a/pagetop/src/base/module/homepage/mod.rs +++ b/pagetop/src/base/module/demopage/mod.rs @@ -1,10 +1,14 @@ use crate::prelude::*; -localize!("src/base/module/homepage/locales"); +localize!("src/base/module/demopage/locales"); -pub struct HomepageModule; +pub struct DemopageModule; + +impl ModuleTrait for DemopageModule { + fn name(&self) -> &'static str { + "Demopage" + } -impl ModuleTrait for HomepageModule { fn fullname(&self) -> String { l("module_fullname") } @@ -20,9 +24,13 @@ impl ModuleTrait for HomepageModule { async fn home() -> app::Result<Markup> { Page::prepare() + .using_theme("Bootsier") .with_title( l("page_title").as_str() ) + + + .add_to("content", Container::prepare() .with_id("welcome") .add(Chunck::markup(html! { diff --git a/pagetop/src/base/module/mod.rs b/pagetop/src/base/module/mod.rs index 070e5b82..7107d180 100644 --- a/pagetop/src/base/module/mod.rs +++ b/pagetop/src/base/module/mod.rs @@ -1 +1 @@ -pub mod homepage; +pub mod demopage; diff --git a/pagetop/src/base/theme/aliner/mod.rs b/pagetop/src/base/theme/aliner/mod.rs index 07b1470f..d4f4f252 100644 --- a/pagetop/src/base/theme/aliner/mod.rs +++ b/pagetop/src/base/theme/aliner/mod.rs @@ -6,7 +6,7 @@ pub struct AlinerTheme; impl ThemeTrait for AlinerTheme { fn name(&self) -> &'static str { - "aliner" + "Aliner" } fn fullname(&self) -> String { @@ -19,6 +19,10 @@ impl ThemeTrait for AlinerTheme { fn before_render_page(&self, page: &mut Page) { page.assets() + .with_favicon( + Favicon::new() + .with_icon("/theme/favicon.png") + ) .add_stylesheet( StyleSheet::source( "/aliner/css/styles.css" diff --git a/pagetop/src/base/theme/bootsier/mod.rs b/pagetop/src/base/theme/bootsier/mod.rs index dbd31727..ada65b0e 100644 --- a/pagetop/src/base/theme/bootsier/mod.rs +++ b/pagetop/src/base/theme/bootsier/mod.rs @@ -8,7 +8,7 @@ pub struct BootsierTheme; impl ThemeTrait for BootsierTheme { fn name(&self) -> &'static str { - "bootsier" + "Bootsier" } fn fullname(&self) -> String { @@ -23,7 +23,7 @@ impl ThemeTrait for BootsierTheme { page.assets() .with_favicon( Favicon::new() - .with_icon("/bootsier/favicon.png") + .with_icon("/theme/favicon.png") ) .add_stylesheet( StyleSheet::source( diff --git a/pagetop/src/base/theme/minimal/mod.rs b/pagetop/src/base/theme/minimal/mod.rs index b3a50906..471b3738 100644 --- a/pagetop/src/base/theme/minimal/mod.rs +++ b/pagetop/src/base/theme/minimal/mod.rs @@ -4,7 +4,7 @@ pub struct MinimalTheme; impl ThemeTrait for MinimalTheme { fn name(&self) -> &'static str { - "minimal" + "Minimal" } fn fullname(&self) -> String { diff --git a/pagetop/src/module/all.rs b/pagetop/src/module/all.rs index 120c59b6..c95583e9 100644 --- a/pagetop/src/module/all.rs +++ b/pagetop/src/module/all.rs @@ -10,13 +10,24 @@ static MODULES: Lazy<RwLock<Vec<&dyn ModuleTrait>>> = Lazy::new(|| { }); pub fn register_module(module: &'static dyn ModuleTrait) { - let mut modules = MODULES.write().unwrap(); - match modules.iter().find(|m| m.name() == module.name()) { - None => { - trace::info!("{}", module.name()); - modules.push(module); - }, - Some(_) => {}, + let mut list: Vec<&dyn ModuleTrait> = Vec::new(); + add_to(&mut list, module); + list.reverse(); + MODULES.write().unwrap().append(&mut list); +} + +fn add_to(list: &mut Vec<&dyn ModuleTrait>, module: &'static dyn ModuleTrait) { + if !MODULES.read().unwrap().iter().any(|m| m.name() == module.name()) { + if !list.iter().any(|m| m.name() == module.name()) { + trace::debug!("Registering \"{}\" module", module.name()); + list.push(module); + + let mut dependencies = module.dependencies(); + dependencies.reverse(); + for d in dependencies.iter() { + add_to(list, *d); + } + } } } diff --git a/pagetop/src/module/definition.rs b/pagetop/src/module/definition.rs index 9424fbd8..b01f9801 100644 --- a/pagetop/src/module/definition.rs +++ b/pagetop/src/module/definition.rs @@ -3,17 +3,9 @@ use crate::app; #[cfg(any(feature = "mysql", feature = "postgres", feature = "sqlite"))] use crate::db; -use std::any::type_name; - /// Los módulos deben implementar este *trait*. pub trait ModuleTrait: Send + Sync { - fn name(&self) -> &'static str { - let name = type_name::<Self>(); - match name.rfind("::") { - Some(position) => &name[(position + 2)..], - None => name - } - } + fn name(&self) -> &'static str; fn fullname(&self) -> String; diff --git a/pagetop/src/response/page/page.rs b/pagetop/src/response/page/page.rs index 58541d22..eff38daa 100644 --- a/pagetop/src/response/page/page.rs +++ b/pagetop/src/response/page/page.rs @@ -75,7 +75,7 @@ impl<'a> Page<'a> { // Page BUILDER. pub fn with_language(&mut self, language: &str) -> &mut Self { - self.language = util::optional_str(language); + self.language = util::valid_str(language); self } @@ -89,12 +89,12 @@ impl<'a> Page<'a> { } pub fn with_title(&mut self, title: &str) -> &mut Self { - self.title = util::optional_str(title); + self.title = util::valid_str(title); self } pub fn with_description(&mut self, description: &str) -> &mut Self { - self.description = util::optional_str(description); + self.description = util::valid_str(description); self } diff --git a/pagetop/src/theme/all.rs b/pagetop/src/theme/all.rs index cc25d9d8..ee0bfedb 100644 --- a/pagetop/src/theme/all.rs +++ b/pagetop/src/theme/all.rs @@ -1,4 +1,4 @@ -use crate::{Lazy, app, base, theme_static_files, trace}; +use crate::{Lazy, app, theme_static_files, trace}; use super::ThemeTrait; use std::sync::RwLock; @@ -7,21 +7,14 @@ include!(concat!(env!("OUT_DIR"), "/theme.rs")); // Temas registrados. static THEMES: Lazy<RwLock<Vec<&dyn ThemeTrait>>> = Lazy::new(|| { - RwLock::new(vec![ - &base::theme::aliner::AlinerTheme, - &base::theme::minimal::MinimalTheme, - &base::theme::bootsier::BootsierTheme, - ]) + RwLock::new(Vec::new()) }); pub fn register_theme(theme: &'static dyn ThemeTrait) { let mut themes = THEMES.write().unwrap(); - match themes.iter().find(|t| t.name() == theme.name()) { - None => { - trace::info!("{}", theme.name()); - themes.push(theme); - }, - Some(_) => {}, + if !themes.iter().any(|t| t.name() == theme.name()) { + trace::debug!("Registering \"{}\" theme", theme.name()); + themes.push(theme); } } diff --git a/pagetop/src/theme/definition.rs b/pagetop/src/theme/definition.rs index 727df347..733736e2 100644 --- a/pagetop/src/theme/definition.rs +++ b/pagetop/src/theme/definition.rs @@ -1,7 +1,7 @@ use crate::app; use crate::config::SETTINGS; use crate::html::{Markup, html}; -use crate::response::page::{Page, PageAssets, PageComponent}; +use crate::response::page::{Favicon, Page, PageAssets, PageComponent}; use crate::base::component::Chunck; /// Los temas deben implementar este "trait". @@ -20,6 +20,11 @@ pub trait ThemeTrait: Send + Sync { #[allow(unused_variables)] fn before_render_page(&self, page: &mut Page) { + page.assets() + .with_favicon( + Favicon::new() + .with_icon("/theme/favicon.png") + ); } fn render_page_head(&self, page: &mut Page) -> Markup { diff --git a/pagetop/src/util.rs b/pagetop/src/util.rs index c5254618..4ba4f76e 100644 --- a/pagetop/src/util.rs +++ b/pagetop/src/util.rs @@ -37,24 +37,24 @@ macro_rules! theme_static_files { } pub fn valid_id(id: &str) -> Option<String> { - let id = id.trim().replace(" ", "_").to_lowercase(); + let id = id.trim(); match id.is_empty() { true => None, - false => Some(id), + false => Some(id.replace(" ", "_").to_lowercase()), } } -pub fn optional_str(s: &str) -> Option<String> { - let s = s.to_owned(); +pub fn valid_str(s: &str) -> Option<String> { + let s = s.trim(); match s.is_empty() { true => None, - false => Some(s), + false => Some(s.to_owned()), } } pub fn assigned_str(optional: &Option<String>) -> &str { match optional { Some(o) => o.as_str(), - _ => "", + None => "", } } diff --git a/pagetop/static/theme/favicon.png b/pagetop/static/theme/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..7d38ea4a847b5697db4437972cfc28baba5e05e3 GIT binary patch literal 11471 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 literal 0 HcmV?d00001 From c6bbd565ab2399c0988c6cfb4042acca487ee77a Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 27 Mar 2022 06:05:37 +0200 Subject: [PATCH 037/244] =?UTF-8?q?A=C3=B1ade=20nuevas=20caracter=C3=ADsti?= =?UTF-8?q?cas=20a=20la=20p=C3=A1gina=20demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pagetop-admin/src/summary.rs | 22 +- pagetop-node/src/lib.rs | 2 +- pagetop-user/src/lib.rs | 6 +- pagetop/src/base/component/block.rs | 41 +-- pagetop/src/base/component/chunck.rs | 18 +- pagetop/src/base/component/container.rs | 81 ++++-- pagetop/src/base/component/form/button.rs | 73 +++-- pagetop/src/base/component/form/date.rs | 155 +++++------ pagetop/src/base/component/form/form.rs | 32 +-- pagetop/src/base/component/form/hidden.rs | 26 +- pagetop/src/base/component/form/input.rs | 167 ++++++------ pagetop/src/base/component/grid/column.rs | 82 ++++++ pagetop/src/base/component/grid/mod.rs | 4 + pagetop/src/base/component/grid/row.rs | 82 ++++++ pagetop/src/base/component/image.rs | 70 +++++ pagetop/src/base/component/menu.rs | 24 +- pagetop/src/base/component/mod.rs | 5 + .../demopage/locales/en-US/demopage.ftl | 28 +- .../demopage/locales/es-ES/demopage.ftl | 28 +- pagetop/src/base/module/demopage/mod.rs | 253 ++++++++++++++---- pagetop/src/base/theme/bootsier/mod.rs | 4 +- pagetop/src/html.rs | 1 - pagetop/src/html/classes.rs | 63 +++++ pagetop/src/html/mod.rs | 8 + pagetop/src/html/optional_attr.rs | 41 +++ pagetop/src/html/optional_id.rs | 33 +++ pagetop/src/response/page/component.rs | 2 +- pagetop/src/response/page/page.rs | 76 +++--- pagetop/src/theme/definition.rs | 4 +- pagetop/src/util.rs | 23 -- .../static/bootsier/images/demo-header.svg | 1 + .../static/bootsier/images/demo-pagetop.svg | 1 + .../static/bootsier/images/demo-visiting.svg | 1 + 33 files changed, 987 insertions(+), 470 deletions(-) create mode 100644 pagetop/src/base/component/grid/column.rs create mode 100644 pagetop/src/base/component/grid/mod.rs create mode 100644 pagetop/src/base/component/grid/row.rs create mode 100644 pagetop/src/base/component/image.rs delete mode 100644 pagetop/src/html.rs create mode 100644 pagetop/src/html/classes.rs create mode 100644 pagetop/src/html/mod.rs create mode 100644 pagetop/src/html/optional_attr.rs create mode 100644 pagetop/src/html/optional_id.rs create mode 100644 pagetop/static/bootsier/images/demo-header.svg create mode 100644 pagetop/static/bootsier/images/demo-pagetop.svg create mode 100644 pagetop/static/bootsier/images/demo-visiting.svg diff --git a/pagetop-admin/src/summary.rs b/pagetop-admin/src/summary.rs index 79bf426e..b91b97fa 100644 --- a/pagetop-admin/src/summary.rs +++ b/pagetop-admin/src/summary.rs @@ -2,37 +2,37 @@ use pagetop::prelude::*; use super::l; pub async fn summary() -> app::Result<Markup> { - let top_menu = Menu::prepare() + let top_menu = Menu::new() .add(MenuItem::label(l("module_fullname").as_str())) .add(MenuItem::link("Opción 2", "https://www.google.es")) .add(MenuItem::link_blank("Opción 3", "https://www.google.es")) - .add(MenuItem::submenu("Submenú 1", Menu::prepare() + .add(MenuItem::submenu("Submenú 1", Menu::new() .add(MenuItem::label("Opción 1")) .add(MenuItem::label("Opción 2")) )) .add(MenuItem::separator()) - .add(MenuItem::submenu("Submenú 2", Menu::prepare() + .add(MenuItem::submenu("Submenú 2", Menu::new() .add(MenuItem::label("Opción 1")) .add(MenuItem::label("Opción 2")) )) .add(MenuItem::label("Opción 4")); - let side_menu = Menu::prepare() + let side_menu = Menu::new() .add(MenuItem::label("Opción 1")) .add(MenuItem::link("Opción 2", "https://www.google.es")) .add(MenuItem::link_blank("Opción 3", "https://www.google.es")) - .add(MenuItem::submenu("Submenú 1", Menu::prepare() + .add(MenuItem::submenu("Submenú 1", Menu::new() .add(MenuItem::label("Opción 1")) .add(MenuItem::label("Opción 2")) )) .add(MenuItem::separator()) - .add(MenuItem::submenu("Submenú 2", Menu::prepare() + .add(MenuItem::submenu("Submenú 2", Menu::new() .add(MenuItem::label("Opción 1")) .add(MenuItem::label("Opción 2")) )) .add(MenuItem::label("Opción 4")); - Page::prepare() + Page::new() .using_theme("bootsier") @@ -40,12 +40,12 @@ pub async fn summary() -> app::Result<Markup> { .add_to("top-menu", top_menu) - .add_to("content", Container::row() - .add(Container::column() + .add_to("content", grid::Row::new() + .add_column(grid::Column::new() .add(side_menu) ) - .add(Container::column() - .add(Chunck::markup(html! { + .add_column(grid::Column::new() + .add(Chunck::with(html! { p { "Columna 2"} })) ) diff --git a/pagetop-node/src/lib.rs b/pagetop-node/src/lib.rs index afcd729f..0f5c4662 100644 --- a/pagetop-node/src/lib.rs +++ b/pagetop-node/src/lib.rs @@ -35,7 +35,7 @@ impl ModuleTrait for NodeModule { } async fn node() -> app::Result<Markup> { - Page::prepare() + Page::new() .with_title( "Nodo" ) diff --git a/pagetop-user/src/lib.rs b/pagetop-user/src/lib.rs index 343daa7a..7ef2ecf3 100644 --- a/pagetop-user/src/lib.rs +++ b/pagetop-user/src/lib.rs @@ -32,7 +32,7 @@ impl ModuleTrait for UserModule { } fn form_login() -> impl PageComponent { - Form::prepare() + Form::new() .with_id("user-login") .add(form::Input::textfield() .with_name("name") @@ -51,11 +51,11 @@ fn form_login() -> impl PageComponent { } async fn login() -> app::Result<Markup> { - Page::prepare() + Page::new() .with_title( "Identificación del usuario" ) - .add_to("content", Container::prepare() + .add_to("content", Container::new() .with_id("welcome") .add(form_login()) ) diff --git a/pagetop/src/base/component/block.rs b/pagetop/src/base/component/block.rs index 96fce677..b857712f 100644 --- a/pagetop/src/base/component/block.rs +++ b/pagetop/src/base/component/block.rs @@ -3,21 +3,21 @@ use crate::prelude::*; pub struct Block { renderable: fn() -> bool, weight : i8, - id : Option<String>, - title : Option<String>, - markup : Vec<Markup>, + id : OptionId, + title : OptionAttr, + html : Vec<Markup>, template : String, } impl PageComponent for Block { - fn prepare() -> Self { + fn new() -> Self { Block { renderable: always, weight : 0, - id : None, - title : None, - markup : Vec::new(), + id : OptionId::none(), + title : OptionAttr::none(), + html : Vec::new(), template : "default".to_owned(), } } @@ -31,15 +31,16 @@ impl PageComponent for Block { } fn default_render(&self, assets: &mut PageAssets) -> Markup { - let id = assets.serial_id(self.name(), self.id()); + let id = assets.serial_id(self.name(), self.id.value()); + let title = self.title.value(); html! { div id=(id) class="block" { - @if self.title != None { - h2 class="block-title" { (self.title()) } + @if !title.is_empty() { + h2 class="block-title" { (title) } } div class="block-body" { - @for markup in self.markup.iter() { - (*markup) + @for html in self.html.iter() { + (*html) } } } @@ -49,8 +50,8 @@ impl PageComponent for Block { impl Block { - pub fn markup(markup: Markup) -> Self { - Block::prepare().add_markup(markup) + pub fn with(html: Markup) -> Self { + Block::new().add(html) } // Block BUILDER. @@ -66,17 +67,17 @@ impl Block { } pub fn with_id(mut self, id: &str) -> Self { - self.id = util::valid_id(id); + self.id.with_value(id); self } pub fn with_title(mut self, title: &str) -> Self { - self.title = util::valid_str(title); + self.title.with_value(title); self } - pub fn add_markup(mut self, markup: Markup) -> Self { - self.markup.push(markup); + pub fn add(mut self, html: Markup) -> Self { + self.html.push(html); self } @@ -88,11 +89,11 @@ impl Block { // Block GETTERS. pub fn id(&self) -> &str { - util::assigned_str(&self.id) + self.id.value() } pub fn title(&self) -> &str { - util::assigned_str(&self.title) + self.title.value() } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/chunck.rs b/pagetop/src/base/component/chunck.rs index 63cc20f7..b03ac0c8 100644 --- a/pagetop/src/base/component/chunck.rs +++ b/pagetop/src/base/component/chunck.rs @@ -3,17 +3,17 @@ use crate::prelude::*; pub struct Chunck { renderable: fn() -> bool, weight : i8, - markup : Vec<Markup>, + html : Vec<Markup>, template : String, } impl PageComponent for Chunck { - fn prepare() -> Self { + fn new() -> Self { Chunck { renderable: always, weight : 0, - markup : Vec::new(), + html : Vec::new(), template : "default".to_owned(), } } @@ -28,8 +28,8 @@ impl PageComponent for Chunck { fn default_render(&self, _: &mut PageAssets) -> Markup { html! { - @for markup in self.markup.iter() { - (*markup) + @for html in self.html.iter() { + (*html) } } } @@ -37,8 +37,8 @@ impl PageComponent for Chunck { impl Chunck { - pub fn markup(markup: Markup) -> Self { - Chunck::prepare().add_markup(markup) + pub fn with(html: Markup) -> Self { + Chunck::new().add(html) } // Chunck BUILDER. @@ -53,8 +53,8 @@ impl Chunck { self } - pub fn add_markup(mut self, markup: Markup) -> Self { - self.markup.push(markup); + pub fn add(mut self, html: Markup) -> Self { + self.html.push(html); self } diff --git a/pagetop/src/base/component/container.rs b/pagetop/src/base/component/container.rs index 161bea78..18d6337a 100644 --- a/pagetop/src/base/component/container.rs +++ b/pagetop/src/base/component/container.rs @@ -1,11 +1,11 @@ use crate::prelude::*; -enum ContainerType { Column, Row, Wrapper } +enum ContainerType { Header, Footer, Main, Section, Wrapper } pub struct Container { renderable: fn() -> bool, weight : i8, - id : Option<String>, + id : OptionId, container : ContainerType, components: PageContainer, template : String, @@ -13,11 +13,11 @@ pub struct Container { impl PageComponent for Container { - fn prepare() -> Self { + fn new() -> Self { Container { renderable: always, weight : 0, - id : None, + id : OptionId::none(), container : ContainerType::Wrapper, components: PageContainer::new(), template : "default".to_owned(), @@ -33,14 +33,39 @@ impl PageComponent for Container { } fn default_render(&self, assets: &mut PageAssets) -> Markup { - let classes = match self.container { - ContainerType::Wrapper => "container", - ContainerType::Row => "row", - ContainerType::Column => "col", - }; - html! { - div id=[&self.id] class=(classes) { - (self.components.render(assets)) + match self.container { + ContainerType::Header => html! { + header id=[&self.id.option()] class="header" { + div class="container" { + (self.components.render(assets)) + } + } + }, + ContainerType::Footer => html! { + footer id=[&self.id.option()] class="footer" { + div class="container" { + (self.components.render(assets)) + } + } + }, + ContainerType::Main => html! { + main id=[&self.id.option()] class="main" { + div class="container" { + (self.components.render(assets)) + } + } + }, + ContainerType::Section => html! { + section id=[&self.id.option()] class="section" { + div class="container" { + (self.components.render(assets)) + } + } + }, + _ => html! { + div id=[&self.id.option()] class="container" { + (self.components.render(assets)) + } } } } @@ -48,16 +73,28 @@ impl PageComponent for Container { impl Container { - pub fn row() -> Self { - let mut grid = Container::prepare(); - grid.container = ContainerType::Row; - grid + pub fn header() -> Self { + let mut c = Container::new(); + c.container = ContainerType::Header; + c } - pub fn column() -> Self { - let mut grid = Container::prepare(); - grid.container = ContainerType::Column; - grid + pub fn footer() -> Self { + let mut c = Container::new(); + c.container = ContainerType::Footer; + c + } + + pub fn main() -> Self { + let mut c = Container::new(); + c.container = ContainerType::Main; + c + } + + pub fn section() -> Self { + let mut c = Container::new(); + c.container = ContainerType::Section; + c } // Container BUILDER. @@ -73,7 +110,7 @@ impl Container { } pub fn with_id(mut self, id: &str) -> Self { - self.id = util::valid_id(id); + self.id.with_value(id); self } @@ -90,7 +127,7 @@ impl Container { // Container GETTERS. pub fn id(&self) -> &str { - util::assigned_str(&self.id) + self.id.value() } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/form/button.rs b/pagetop/src/base/component/form/button.rs index 57810fea..a1975ea4 100644 --- a/pagetop/src/base/component/form/button.rs +++ b/pagetop/src/base/component/form/button.rs @@ -6,24 +6,24 @@ pub struct Button { renderable : fn() -> bool, weight : i8, button_type: ButtonType, - name : Option<String>, - value : Option<String>, - autofocus : Option<String>, - disabled : Option<String>, + name : OptionAttr, + value : OptionAttr, + autofocus : OptionAttr, + disabled : OptionAttr, template : String, } impl PageComponent for Button { - fn prepare() -> Self { + fn new() -> Self { Button { renderable : always, weight : 0, button_type: ButtonType::Button, - name : None, - value : None, - autofocus : None, - disabled : None, + name : OptionAttr::none(), + value : OptionAttr::none(), + autofocus : OptionAttr::none(), + disabled : OptionAttr::none(), template : "default".to_owned(), } } @@ -42,7 +42,7 @@ impl PageComponent for Button { ButtonType::Reset => ("reset", "btn btn-primary form-reset" ), ButtonType::Submit => ("submit", "btn btn-primary form-submit") }; - let id_item = match &self.name { + let id_item = match &self.name.option() { Some(name) => Some(format!("edit-{}", name)), _ => None }; @@ -51,15 +51,12 @@ impl PageComponent for Button { type=(button_type) id=[&id_item] class=(button_class) - name=[&self.name] - value=[&self.value] - autofocus=[&self.autofocus] - disabled=[&self.disabled] + name=[&self.name.option()] + value=[&self.value.option()] + autofocus=[&self.autofocus.option()] + disabled=[&self.disabled.option()] { - @match &self.value { - Some(value) => (value), - _ => "" - }; + (self.value.value()) } } } @@ -68,17 +65,17 @@ impl PageComponent for Button { impl Button { pub fn button(value: &str) -> Self { - Button::prepare().with_value(value) + Button::new().with_value(value) } pub fn reset(value: &str) -> Self { - let mut button = Button::prepare().with_value(value); + let mut button = Button::new().with_value(value); button.button_type = ButtonType::Reset; button } pub fn submit(value: &str) -> Self { - let mut button = Button::prepare().with_value(value); + let mut button = Button::new().with_value(value); button.button_type = ButtonType::Submit; button } @@ -96,28 +93,28 @@ impl Button { } pub fn with_name(mut self, name: &str) -> Self { - self.name = util::valid_id(name); + self.name.with_value(name); self } pub fn with_value(mut self, value: &str) -> Self { - self.value = util::valid_str(value); + self.value.with_value(value); self } pub fn autofocus(mut self, toggle: bool) -> Self { - self.autofocus = match toggle { - true => Some("autofocus".to_owned()), - false => None - }; + self.autofocus.with_value(match toggle { + true => "autofocus", + false => "", + }); self } pub fn disabled(mut self, toggle: bool) -> Self { - self.disabled = match toggle { - true => Some("disabled".to_owned()), - false => None - }; + self.disabled.with_value(match toggle { + true => "disabled", + false => "", + }); self } @@ -129,25 +126,19 @@ impl Button { // Button GETTERS. pub fn name(&self) -> &str { - util::assigned_str(&self.name) + self.name.value() } pub fn value(&self) -> &str { - util::assigned_str(&self.value) + self.value.value() } pub fn has_autofocus(&self) -> bool { - match &self.autofocus { - Some(_) => true, - _ => false - } + self.autofocus.has_value() } pub fn is_disabled(&self) -> bool { - match &self.disabled { - Some(_) => true, - _ => false - } + self.disabled.has_value() } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/form/date.rs b/pagetop/src/base/component/form/date.rs index 6614670a..7f04691b 100644 --- a/pagetop/src/base/component/form/date.rs +++ b/pagetop/src/base/component/form/date.rs @@ -3,35 +3,35 @@ use crate::prelude::*; pub struct Date { renderable : fn() -> bool, weight : i8, - name : Option<String>, - value : Option<String>, - label : Option<String>, - placeholder : Option<String>, - autofocus : Option<String>, - autocomplete: Option<String>, - disabled : Option<String>, - readonly : Option<String>, - required : Option<String>, - help_text : Option<String>, + name : OptionAttr, + value : OptionAttr, + label : OptionAttr, + placeholder : OptionAttr, + autofocus : OptionAttr, + autocomplete: OptionAttr, + disabled : OptionAttr, + readonly : OptionAttr, + required : OptionAttr, + help_text : OptionAttr, template : String, } impl PageComponent for Date { - fn prepare() -> Self { + fn new() -> Self { Date { renderable : always, weight : 0, - name : None, - value : None, - label : None, - placeholder : None, - autofocus : None, - autocomplete: None, - disabled : None, - readonly : None, - required : None, - help_text : None, + name : OptionAttr::none(), + value : OptionAttr::none(), + label : OptionAttr::none(), + placeholder : OptionAttr::none(), + autofocus : OptionAttr::none(), + autocomplete: OptionAttr::none(), + disabled : OptionAttr::none(), + readonly : OptionAttr::none(), + required : OptionAttr::none(), + help_text : OptionAttr::none(), template : "default".to_owned(), } } @@ -45,7 +45,7 @@ impl PageComponent for Date { } fn default_render(&self, _: &mut PageAssets) -> Markup { - let (class_item, id_item) = match &self.name { + let (class_item, id_item) = match self.name.option() { Some(name) => ( format!("form-item form-item-{} form-type-date", name), Some(format!("edit-{}", name)) @@ -57,10 +57,10 @@ impl PageComponent for Date { }; html! { div class=(class_item) { - @if self.label != None { + @if self.label.has_value() { label class="form-label" for=[&id_item] { - (self.label()) " " - @if self.required != None { + (self.label.value()) " " + @if self.required.has_value() { span class="form-required" title="Este campo es obligatorio." @@ -74,17 +74,17 @@ impl PageComponent for Date { type="date" id=[&id_item] class="form-control" - name=[&self.name] - value=[&self.value] - placeholder=[&self.placeholder] - autofocus=[&self.autofocus] - autocomplete=[&self.autocomplete] - readonly=[&self.readonly] - required=[&self.required] - disabled=[&self.disabled]; - @if self.help_text != None { + name=[&self.name.option()] + value=[&self.value.option()] + placeholder=[&self.placeholder.option()] + autofocus=[&self.autofocus.option()] + autocomplete=[&self.autocomplete.option()] + readonly=[&self.readonly.option()] + required=[&self.required.option()] + disabled=[&self.disabled.option()]; + @if self.help_text.has_value() { div class="form-text" { - (self.help_text()) + (self.help_text.value()) } } } @@ -107,67 +107,67 @@ impl Date { } pub fn with_name(mut self, name: &str) -> Self { - self.name = util::valid_id(name); + self.name.with_value(name); self } pub fn with_value(mut self, value: &str) -> Self { - self.value = util::valid_str(value); + self.value.with_value(value); self } pub fn with_label(mut self, label: &str) -> Self { - self.label = util::valid_str(label); + self.label.with_value(label); self } pub fn with_placeholder(mut self, placeholder: &str) -> Self { - self.placeholder = util::valid_str(placeholder); + self.placeholder.with_value(placeholder); self } pub fn autofocus(mut self, toggle: bool) -> Self { - self.autofocus = match toggle { - true => Some("autofocus".to_owned()), - false => None - }; + self.autofocus.with_value(match toggle { + true => "autofocus", + false => "", + }); self } pub fn autocomplete(mut self, toggle: bool) -> Self { - self.autocomplete = match toggle { - true => None, - false => Some("off".to_owned()) - }; + self.autocomplete.with_value(match toggle { + true => "", + false => "off", + }); self } pub fn disabled(mut self, toggle: bool) -> Self { - self.disabled = match toggle { - true => Some("disabled".to_owned()), - false => None - }; + self.disabled.with_value(match toggle { + true => "disabled", + false => "", + }); self } pub fn readonly(mut self, toggle: bool) -> Self { - self.readonly = match toggle { - true => Some("readonly".to_owned()), - false => None - }; + self.readonly.with_value(match toggle { + true => "readonly", + false => "", + }); self } pub fn required(mut self, toggle: bool) -> Self { - self.required = match toggle { - true => Some("required".to_owned()), - false => None - }; + self.required.with_value(match toggle { + true => "required", + false => "", + }); self } pub fn with_help_text(mut self, help_text: &str) -> Self { - self.help_text = util::valid_str(help_text); + self.help_text.with_value(help_text); self } @@ -179,58 +179,43 @@ impl Date { // Date GETTERS. pub fn name(&self) -> &str { - util::assigned_str(&self.name) + self.name.value() } pub fn value(&self) -> &str { - util::assigned_str(&self.value) + self.value.value() } pub fn label(&self) -> &str { - util::assigned_str(&self.label) + self.label.value() } pub fn placeholder(&self) -> &str { - util::assigned_str(&self.placeholder) + self.placeholder.value() } pub fn has_autofocus(&self) -> bool { - match &self.autofocus { - Some(_) => true, - _ => false - } + self.autofocus.has_value() } pub fn has_autocomplete(&self) -> bool { - match &self.autocomplete { - Some(_) => false, - _ => true - } + !self.autocomplete.has_value() } pub fn is_disabled(&self) -> bool { - match &self.disabled { - Some(_) => true, - _ => false - } + self.disabled.has_value() } pub fn is_readonly(&self) -> bool { - match &self.readonly { - Some(_) => true, - _ => false - } + self.readonly.has_value() } pub fn is_required(&self) -> bool { - match &self.required { - Some(_) => true, - _ => false - } + self.required.has_value() } pub fn help_text(&self) -> &str { - util::assigned_str(&self.help_text) + self.help_text.value() } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/form/form.rs b/pagetop/src/base/component/form/form.rs index 2fac4403..e93926a7 100644 --- a/pagetop/src/base/component/form/form.rs +++ b/pagetop/src/base/component/form/form.rs @@ -5,24 +5,24 @@ pub enum FormMethod {Get, Post} pub struct Form { renderable: fn() -> bool, weight : i8, - id : Option<String>, - action : Option<String>, + id : OptionId, + action : OptionAttr, method : FormMethod, - charset : Option<String>, + charset : OptionAttr, elements : PageContainer, template : String, } impl PageComponent for Form { - fn prepare() -> Self { + fn new() -> Self { Form { renderable: always, weight : 0, - id : None, - action : None, + id : OptionId::none(), + action : OptionAttr::none(), method : FormMethod::Post, - charset : Some("UTF-8".to_owned()), + charset : OptionAttr::some("UTF-8"), elements : PageContainer::new(), template : "default".to_owned(), } @@ -43,10 +43,10 @@ impl PageComponent for Form { }; html! { form - id=[&self.id] - action=[&self.action] + id=[&self.id.option()] + action=[&self.action.option()] method=[method] - accept-charset=[&self.charset] + accept-charset=[&self.charset.option()] { div { (self.elements.render(assets)) @@ -71,12 +71,12 @@ impl Form { } pub fn with_id(mut self, id: &str) -> Self { - self.id = util::valid_id(id); + self.id.with_value(id); self } pub fn with_action(mut self, action: &str) -> Self { - self.action = util::valid_str(action); + self.action.with_value(action); self } @@ -86,7 +86,7 @@ impl Form { } pub fn with_charset(mut self, charset: &str) -> Self { - self.charset = util::valid_str(charset); + self.charset.with_value(charset); self } @@ -103,11 +103,11 @@ impl Form { // Form GETTERS. pub fn id(&self) -> &str { - util::assigned_str(&self.id) + self.id.value() } pub fn action(&self) -> &str { - util::assigned_str(&self.action) + self.action.value() } pub fn method(&self) -> &str { @@ -118,7 +118,7 @@ impl Form { } pub fn charset(&self) -> &str { - util::assigned_str(&self.charset) + self.charset.value() } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/form/hidden.rs b/pagetop/src/base/component/form/hidden.rs index bd158b85..b27caf37 100644 --- a/pagetop/src/base/component/form/hidden.rs +++ b/pagetop/src/base/component/form/hidden.rs @@ -2,17 +2,17 @@ use crate::prelude::*; pub struct Hidden { weight : i8, - name : Option<String>, - value : Option<String>, + name : OptionId, + value : OptionAttr, } impl PageComponent for Hidden { - fn prepare() -> Self { + fn new() -> Self { Hidden { weight : 0, - name : None, - value : None, + name : OptionId::none(), + value : OptionAttr::none(), } } @@ -21,7 +21,7 @@ impl PageComponent for Hidden { } fn default_render(&self, _: &mut PageAssets) -> Markup { - let id_item = match &self.name { + let id_item = match self.name.option() { Some(name) => Some(format!("value-{}", name)), _ => None }; @@ -29,8 +29,8 @@ impl PageComponent for Hidden { input type="hidden" id=[&id_item] - name=[&self.name] - value=[&self.value]; + name=[&self.name.option()] + value=[&self.value.option()]; } } } @@ -38,7 +38,7 @@ impl PageComponent for Hidden { impl Hidden { pub fn set(name: &str, value: &str) -> Self { - Hidden::prepare().with_name(name).with_value(value) + Hidden::new().with_name(name).with_value(value) } // Hidden BUILDER. @@ -49,22 +49,22 @@ impl Hidden { } pub fn with_name(mut self, name: &str) -> Self { - self.name = util::valid_id(name); + self.name.with_value(name); self } pub fn with_value(mut self, value: &str) -> Self { - self.value = util::valid_str(value); + self.value.with_value(value); self } // Hidden GETTERS. pub fn name(&self) -> &str { - util::assigned_str(&self.name) + self.name.value() } pub fn value(&self) -> &str { - util::assigned_str(&self.value) + self.value.value() } } diff --git a/pagetop/src/base/component/form/input.rs b/pagetop/src/base/component/form/input.rs index f0e73a63..c483c9a9 100644 --- a/pagetop/src/base/component/form/input.rs +++ b/pagetop/src/base/component/form/input.rs @@ -6,42 +6,42 @@ pub struct Input { renderable : fn() -> bool, weight : i8, input_type : InputType, - name : Option<String>, - value : Option<String>, - label : Option<String>, + name : OptionId, + value : OptionAttr, + label : OptionAttr, size : Option<u16>, minlength : Option<u16>, maxlength : Option<u16>, - placeholder : Option<String>, - autofocus : Option<String>, - autocomplete: Option<String>, - disabled : Option<String>, - readonly : Option<String>, - required : Option<String>, - help_text : Option<String>, + placeholder : OptionAttr, + autofocus : OptionAttr, + autocomplete: OptionAttr, + disabled : OptionAttr, + readonly : OptionAttr, + required : OptionAttr, + help_text : OptionAttr, template : String, } impl PageComponent for Input { - fn prepare() -> Self { + fn new() -> Self { Input { renderable : always, weight : 0, input_type : InputType::Textfield, - name : None, - value : None, - label : None, + name : OptionId::none(), + value : OptionAttr::none(), + label : OptionAttr::none(), size : Some(60), minlength : None, maxlength : Some(128), - placeholder : None, - autofocus : None, - autocomplete: None, - disabled : None, - readonly : None, - required : None, - help_text : None, + placeholder : OptionAttr::none(), + autofocus : OptionAttr::none(), + autocomplete: OptionAttr::none(), + disabled : OptionAttr::none(), + readonly : OptionAttr::none(), + required : OptionAttr::none(), + help_text : OptionAttr::none(), template : "default".to_owned(), } } @@ -63,7 +63,7 @@ impl PageComponent for Input { InputType::Textfield => ("text", "form-type-textfield"), InputType::Url => ("url", "form-type-url") }; - let (class_item, id_item) = match &self.name { + let (class_item, id_item) = match &self.name.option() { Some(name) => ( format!("form-item form-item-{} {}", name, class_type), Some(format!("edit-{}", name)) @@ -75,10 +75,10 @@ impl PageComponent for Input { }; html! { div class=(class_item) { - @if self.label != None { + @if self.label.has_value() { label class="form-label" for=[&id_item] { - (self.label()) " " - @if self.required != None { + (self.label.value()) " " + @if self.required.has_value() { span class="form-required" title="Este campo es obligatorio." @@ -92,20 +92,20 @@ impl PageComponent for Input { type=(input_type) id=[&id_item] class="form-control" - name=[&self.name] - value=[&self.value] + name=[&self.name.option()] + value=[&self.value.option()] size=[self.size] minlength=[self.minlength] maxlength=[self.maxlength] - placeholder=[&self.placeholder] - autofocus=[&self.autofocus] - autocomplete=[&self.autocomplete] - readonly=[&self.readonly] - required=[&self.required] - disabled=[&self.disabled]; - @if self.help_text != None { + placeholder=[&self.placeholder.option()] + autofocus=[&self.autofocus.option()] + autocomplete=[&self.autocomplete.option()] + readonly=[&self.readonly.option()] + required=[&self.required.option()] + disabled=[&self.disabled.option()]; + @if self.help_text.has_value() { div class="form-text" { - (self.help_text()) + (self.help_text.value()) } } } @@ -116,35 +116,35 @@ impl PageComponent for Input { impl Input { pub fn textfield() -> Self { - Input::prepare() + Input::new() } pub fn password() -> Self { - let mut input = Input::prepare(); + let mut input = Input::new(); input.input_type = InputType::Password; input } pub fn search() -> Self { - let mut input = Input::prepare(); + let mut input = Input::new(); input.input_type = InputType::Search; input } pub fn email() -> Self { - let mut input = Input::prepare(); + let mut input = Input::new(); input.input_type = InputType::Email; input } pub fn telephone() -> Self { - let mut input = Input::prepare(); + let mut input = Input::new(); input.input_type = InputType::Telephone; input } pub fn url() -> Self { - let mut input = Input::prepare(); + let mut input = Input::new(); input.input_type = InputType::Url; input } @@ -162,17 +162,17 @@ impl Input { } pub fn with_name(mut self, name: &str) -> Self { - self.name = util::valid_id(name); + self.name.with_value(name); self } pub fn with_value(mut self, value: &str) -> Self { - self.value = util::valid_str(value); + self.value.with_value(value); self } pub fn with_label(mut self, label: &str) -> Self { - self.label = util::valid_str(label); + self.label.with_value(label); self } @@ -192,52 +192,52 @@ impl Input { } pub fn with_placeholder(mut self, placeholder: &str) -> Self { - self.placeholder = util::valid_str(placeholder); + self.placeholder.with_value(placeholder); self } pub fn autofocus(mut self, toggle: bool) -> Self { - self.autofocus = match toggle { - true => Some("autofocus".to_owned()), - false => None - }; + self.autofocus.with_value(match toggle { + true => "autofocus", + false => "", + }); self } pub fn autocomplete(mut self, toggle: bool) -> Self { - self.autocomplete = match toggle { - true => None, - false => Some("off".to_owned()) - }; + self.autocomplete.with_value(match toggle { + true => "", + false => "off", + }); self } pub fn disabled(mut self, toggle: bool) -> Self { - self.disabled = match toggle { - true => Some("disabled".to_owned()), - false => None - }; + self.disabled.with_value(match toggle { + true => "disabled", + false => "", + }); self } pub fn readonly(mut self, toggle: bool) -> Self { - self.readonly = match toggle { - true => Some("readonly".to_owned()), - false => None - }; + self.readonly.with_value(match toggle { + true => "readonly", + false => "", + }); self } pub fn required(mut self, toggle: bool) -> Self { - self.required = match toggle { - true => Some("required".to_owned()), - false => None - }; + self.required.with_value(match toggle { + true => "required", + false => "", + }); self } pub fn with_help_text(mut self, help_text: &str) -> Self { - self.help_text = util::valid_str(help_text); + self.help_text.with_value(help_text); self } @@ -249,15 +249,15 @@ impl Input { // Input GETTERS. pub fn name(&self) -> &str { - util::assigned_str(&self.name) + self.name.value() } pub fn value(&self) -> &str { - util::assigned_str(&self.value) + self.value.value() } pub fn label(&self) -> &str { - util::assigned_str(&self.label) + self.label.value() } pub fn size(&self) -> Option<u16> { @@ -273,46 +273,31 @@ impl Input { } pub fn placeholder(&self) -> &str { - util::assigned_str(&self.placeholder) + self.placeholder.value() } pub fn has_autofocus(&self) -> bool { - match &self.autofocus { - Some(_) => true, - _ => false - } + self.autofocus.has_value() } pub fn has_autocomplete(&self) -> bool { - match &self.autocomplete { - Some(_) => false, - _ => true - } + !self.autocomplete.has_value() } pub fn is_disabled(&self) -> bool { - match &self.disabled { - Some(_) => true, - _ => false - } + self.disabled.has_value() } pub fn is_readonly(&self) -> bool { - match &self.readonly { - Some(_) => true, - _ => false - } + self.readonly.has_value() } pub fn is_required(&self) -> bool { - match &self.required { - Some(_) => true, - _ => false - } + self.required.has_value() } pub fn help_text(&self) -> &str { - util::assigned_str(&self.help_text) + self.help_text.value() } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/grid/column.rs b/pagetop/src/base/component/grid/column.rs new file mode 100644 index 00000000..96463490 --- /dev/null +++ b/pagetop/src/base/component/grid/column.rs @@ -0,0 +1,82 @@ +use crate::prelude::*; + +pub struct Column { + renderable: fn() -> bool, + weight : i8, + id : OptionId, + components: PageContainer, + template : String, +} + +impl PageComponent for Column { + + fn new() -> Self { + Column { + renderable: always, + weight : 0, + id : OptionId::none(), + components: PageContainer::new(), + template : "default".to_owned(), + } + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> i8 { + self.weight + } + + fn default_render(&self, assets: &mut PageAssets) -> Markup { + html! { + div id=[&self.id.option()] class="col" { + (self.components.render(assets)) + } + } + } +} + +impl Column { + + // Column BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_id(mut self, id: &str) -> Self { + self.id.with_value(id); + self + } + + pub fn add(mut self, component: impl PageComponent) -> Self { + self.components.add(component); + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.template = template.to_owned(); + self + } + + // Column GETTERS. + + pub fn id(&self) -> &str { + self.id.value() + } + + pub fn template(&self) -> &str { + self.template.as_str() + } +} + +fn always() -> bool { + true +} diff --git a/pagetop/src/base/component/grid/mod.rs b/pagetop/src/base/component/grid/mod.rs new file mode 100644 index 00000000..ca7796ef --- /dev/null +++ b/pagetop/src/base/component/grid/mod.rs @@ -0,0 +1,4 @@ +mod row; +pub use row::Row; +mod column; +pub use column::Column; diff --git a/pagetop/src/base/component/grid/row.rs b/pagetop/src/base/component/grid/row.rs new file mode 100644 index 00000000..6aed7d0f --- /dev/null +++ b/pagetop/src/base/component/grid/row.rs @@ -0,0 +1,82 @@ +use crate::prelude::*; + +pub struct Row { + renderable: fn() -> bool, + weight : i8, + id : OptionId, + columns : PageContainer, + template : String, +} + +impl PageComponent for Row { + + fn new() -> Self { + Row { + renderable: always, + weight : 0, + id : OptionId::none(), + columns : PageContainer::new(), + template : "default".to_owned(), + } + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> i8 { + self.weight + } + + fn default_render(&self, assets: &mut PageAssets) -> Markup { + html! { + div id=[&self.id.option()] class="row" { + (self.columns.render(assets)) + } + } + } +} + +impl Row { + + // Row BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_id(mut self, id: &str) -> Self { + self.id.with_value(id); + self + } + + pub fn add_column(mut self, column: grid::Column) -> Self { + self.columns.add(column); + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.template = template.to_owned(); + self + } + + // Row GETTERS. + + pub fn id(&self) -> &str { + self.id.value() + } + + pub fn template(&self) -> &str { + self.template.as_str() + } +} + +fn always() -> bool { + true +} diff --git a/pagetop/src/base/component/image.rs b/pagetop/src/base/component/image.rs new file mode 100644 index 00000000..b330b374 --- /dev/null +++ b/pagetop/src/base/component/image.rs @@ -0,0 +1,70 @@ +use crate::prelude::*; + +pub struct Image { + renderable: fn() -> bool, + weight : i8, + source : Option<String>, + template : String, +} + +impl PageComponent for Image { + + fn new() -> Self { + Image { + renderable: always, + weight : 0, + source : None, + template : "default".to_owned(), + } + } + + fn is_renderable(&self) -> bool { + (self.renderable)() + } + + fn weight(&self) -> i8 { + self.weight + } + + fn default_render(&self, _: &mut PageAssets) -> Markup { + html! { + img src=[&self.source] class="img-fluid" {} + } + } +} + +impl Image { + + pub fn image(source: &str) -> Self { + let mut i = Image::new(); + i.source = Some(source.to_owned()); + i + } + + // Image BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.template = template.to_owned(); + self + } + + // Image GETTERS. + + pub fn template(&self) -> &str { + self.template.as_str() + } +} + +fn always() -> bool { + true +} diff --git a/pagetop/src/base/component/menu.rs b/pagetop/src/base/component/menu.rs index d3cdb6b8..10ac8ca5 100644 --- a/pagetop/src/base/component/menu.rs +++ b/pagetop/src/base/component/menu.rs @@ -4,7 +4,7 @@ enum MenuItemType { Label(String), Link(String, String), LinkBlank(String, String), - Markup(Markup), + Html(Markup), Separator, Submenu(String, Menu), } @@ -21,7 +21,7 @@ pub struct MenuItem { impl PageComponent for MenuItem { - fn prepare() -> Self { + fn new() -> Self { MenuItem { renderable: always, weight : 0, @@ -50,8 +50,8 @@ impl PageComponent for MenuItem { a href=(path) target="_blank" { (label) } } }, - Some(MenuItemType::Markup(markup)) => html! { - li class="markup" { (*markup) } + Some(MenuItemType::Html(html)) => html! { + li class="html" { (*html) } }, Some(MenuItemType::Submenu(label, menu)) => html! { li class="submenu" { @@ -101,11 +101,11 @@ impl MenuItem { } } - pub fn markup(markup: Markup) -> Self { + pub fn html(html: Markup) -> Self { MenuItem { renderable: always, weight : 0, - item_type : Some(MenuItemType::Markup(markup)), + item_type : Some(MenuItemType::Html(html)), } } @@ -148,18 +148,18 @@ impl MenuItem { pub struct Menu { renderable: fn() -> bool, weight : i8, - id : Option<String>, + id : OptionId, items : PageContainer, template : String, } impl PageComponent for Menu { - fn prepare() -> Self { + fn new() -> Self { Menu { renderable: always, weight : 0, - id : None, + id : OptionId::none(), items : PageContainer::new(), template : "default".to_owned(), } @@ -186,7 +186,7 @@ impl PageComponent for Menu { )) .add_jquery(); - let id = assets.serial_id(self.name(), self.id()); + let id = assets.serial_id(self.name(), self.id.value()); html! { ul id=(id) class="sm sm-clean" { (self.render_items(assets)) @@ -216,7 +216,7 @@ impl Menu { } pub fn with_id(mut self, id: &str) -> Self { - self.id = util::valid_id(id); + self.id.with_value(id); self } @@ -233,7 +233,7 @@ impl Menu { // Menu GETTERS. pub fn id(&self) -> &str { - util::assigned_str(&self.id) + self.id.value() } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/mod.rs b/pagetop/src/base/component/mod.rs index f9973108..4619c937 100644 --- a/pagetop/src/base/component/mod.rs +++ b/pagetop/src/base/component/mod.rs @@ -1,9 +1,14 @@ mod container; pub use container::Container; + +pub mod grid; + mod chunck; pub use chunck::Chunck; mod block; pub use block::Block; +mod image; +pub use image::Image; mod menu; pub use menu::{Menu, MenuItem}; diff --git a/pagetop/src/base/module/demopage/locales/en-US/demopage.ftl b/pagetop/src/base/module/demopage/locales/en-US/demopage.ftl index 14c93f2f..d23f6ce6 100644 --- a/pagetop/src/base/module/demopage/locales/en-US/demopage.ftl +++ b/pagetop/src/base/module/demopage/locales/en-US/demopage.ftl @@ -3,19 +3,23 @@ module_description = Displays a demo homepage when none is configured. page_title = Hello world! -text_welcome = This page is used to test the proper operation of { $app } after installation. This web solution is powered by { $pagetop }. If you can read this page, it means that the PageTop server is working properly, but has not yet been configured. +welcome_to = Welcome to { $app } +welcome_intro = This page is used to test the proper operation of { $app } after installation. +welcome_pagetop = This web solution is powered by { $pagetop }. -title_normal_user = Just visiting? -text1_normal_user = If you are a normal user of this web site and don't know what this page is about, this probably means that the site is either experiencing problems or is undergoing routine maintenance. -text2_normal_user = If the problem persists, please contact your system administrator. +visiting_title = Just visiting? +visiting_subtitle = Are you user of this website? +visiting_text1 = If you don't know what this page is about, this probably means that the site is either experiencing problems or is undergoing routine maintenance. +visiting_text2 = If the problem persists, please contact your system administrator. -title_about_pagetop = About PageTop -text1_about_pagetop = PageTop defines an interface for the most stable and popular Rust packages to build modular, extensible and configurable web solutions. -text2_about_pagetop = For information on PageTop please visit the "PageTop website". +pagetop_title = About PageTop +pagetop_text1 = If you can read this page, it means that the PageTop server is working properly, but has not yet been configured. +pagetop_text2 = PageTop defines an interface for the most stable and popular Rust packages to build modular, extensible and configurable web solutions. +pagetop_text3 = For information on PageTop please visit the "PageTop website". -title_promo_pagetop = Promoting PageTop -text1_promo_pagetop = You are free to use the image below on applications powered by { $pagetop }. Thanks for using PageTop! +pagetop_promo_title = Promoting PageTop +pagetop_promo_text1 = You are free to use the image below on applications powered by { $pagetop }. Thanks for using PageTop! -title_report_problems = Reporting Problems -text1_report_problems = Please use the GitLab tool to report bugs in PageTop. However, check "existing bug reports" before reporting a new bug. -text2_report_problems = Please report bugs specific to modules (such as admin, and others) to respective packages, not to PageTop itself. +report_problems_title = Reporting Problems +report_problems_text1 = Please use the GitLab tool to report bugs in PageTop. However, check "existing bug reports" before reporting a new bug. +report_problems_text2 = Please report bugs specific to modules (such as admin, and others) to respective packages, not to PageTop itself. diff --git a/pagetop/src/base/module/demopage/locales/es-ES/demopage.ftl b/pagetop/src/base/module/demopage/locales/es-ES/demopage.ftl index 39720fcd..70706ca8 100644 --- a/pagetop/src/base/module/demopage/locales/es-ES/demopage.ftl +++ b/pagetop/src/base/module/demopage/locales/es-ES/demopage.ftl @@ -3,19 +3,23 @@ module_description = Muestra una página de demostración predeterminada cuando page_title = ¡Hola mundo! -text_welcome = Esta página se utiliza para probar el correcto funcionamiento de { $app } después de la instalación. Esta solución web funciona con { $pagetop }. Si puede leer esta página, significa que el servidor PageTop funciona correctamente, pero aún no se ha configurado. +welcome_to = Bienvenido a { $app } +welcome_intro = Esta página se utiliza para probar el correcto funcionamiento de { $app } después de la instalación. +welcome_pagetop = Esta solución web funciona con { $pagetop }. -title_normal_user = ¿Sólo de visita? -text1_normal_user = Si usted es un usuario normal de este sitio web y no sabe de qué trata esta página, probablemente significa que el sitio está experimentando problemas o está pasando por un mantenimiento de rutina. -text2_normal_user = Si el problema persiste, póngase en contacto con el administrador del sistema. +visiting_title = ¿Sólo de visita? +visiting_subtitle = ¿Eres usuario de este sitio web? +visiting_text1 = Si no sabes de qué trata esta página, probablemente significa que el sitio está experimentando problemas o está pasando por un mantenimiento de rutina. +visiting_text2 = Si el problema persiste, póngase en contacto con el administrador del sistema. -title_about_pagetop = Sobre PageTop -text1_about_pagetop = PageTop define una interfaz para los paquetes Rust más estables y populares para crear soluciones web modulares, extensibles y configurables. -text2_about_pagetop = Para obtener información sobre PageTop, visite el "sitio web de PageTop". +pagetop_title = Sobre PageTop +pagetop_text1 = Si puedes leer esta página, significa que el servidor PageTop funciona correctamente, pero aún no se ha configurado. +pagetop_text2 = PageTop define una interfaz para los paquetes Rust más estables y populares para crear soluciones web modulares, extensibles y configurables. +pagetop_text3 = Para obtener información sobre PageTop, visita el "sitio web de PageTop". -title_promo_pagetop = Promociona PageTop -text1_promo_pagetop = Puede usar la siguiente imagen en aplicaciones desarrolladas sobre { $pagetop }. ¡Gracias por usar PageTop! +pagetop_promo_title = Promociona PageTop +pagetop_promo_text1 = Puedes usar la siguiente imagen en aplicaciones desarrolladas sobre { $pagetop }. ¡Gracias por usar PageTop! -title_report_problems = Informando Problemas -text1_report_problems = Utilice la herramienta GitLab para informar errores en PageTop. Sin embargo, verifique los "informes de errores existentes" antes de informar de un nuevo error. -text2_report_problems = Informe los errores específicos de los módulos (como admin y otros) a los paquetes respectivos, no a PageTop en sí. +report_problems_title = Informando Problemas +report_problems_text1 = Utilice la herramienta GitLab para informar errores en PageTop. Sin embargo, verifique los "informes de errores existentes" antes de informar de un nuevo error. +report_problems_text2 = Informe los errores específicos de los módulos (como admin y otros) a los paquetes respectivos, no a PageTop en sí. diff --git a/pagetop/src/base/module/demopage/mod.rs b/pagetop/src/base/module/demopage/mod.rs index bb6e3b94..f3d3a903 100644 --- a/pagetop/src/base/module/demopage/mod.rs +++ b/pagetop/src/base/module/demopage/mod.rs @@ -18,61 +18,210 @@ impl ModuleTrait for DemopageModule { } fn configure_module(&self, cfg: &mut app::web::ServiceConfig) { - cfg.route("/", app::web::get().to(home)); + cfg.route("/", app::web::get().to(demo)); } } -async fn home() -> app::Result<Markup> { - Page::prepare() +async fn demo() -> app::Result<Markup> { + Page::new() .using_theme("Bootsier") - .with_title( - l("page_title").as_str() - ) - - - - .add_to("content", Container::prepare() - .with_id("welcome") - .add(Chunck::markup(html! { - h1 { (l("page_title")) } - p { (e("text_welcome", &args![ - "app" => format!("<strong>{}</strong>", &SETTINGS.app.name), - "pagetop" => "<a href=\"https://pagetop-rs\">PageTop</a>" - ])) } - })) - ) - .add_to("content", Container::prepare() - .add(Container::row() - .add(Container::column() - .with_id("visitors") - .add(Chunck::markup(html! { - h2 { (l("title_normal_user")) } - p { (l("text1_normal_user")) } - p { (l("text2_normal_user")) } - }))) - .add(Container::column() - .with_id("pagetop") - .add(Chunck::markup(html! { - h2 { (l("title_about_pagetop")) } - p { (l("text1_about_pagetop")) } - p { (l("text2_about_pagetop")) } - - h2 { (l("title_promo_pagetop")) } - p { (e("text1_promo_pagetop", &args![ - "pagetop" => - "<a href=\"https://pagetop-rs\">PageTop</a>" - ])) } - })) - ) - ) - ) - .add_to("content", Container::prepare() - .with_id("reporting") - .add(Chunck::markup(html! { - h2 { (l("title_report_problems")) } - p { (l("text1_report_problems")) } - p { (l("text2_report_problems")) } - })) - ) + .with_title(l("page_title").as_str()) + .add_to("content", hello_world()) + .add_to("content", hello_world2()) + .add_to("content", just_visiting()) + .add_to("content", about_pagetop()) + .add_to("content", promo_pagetop()) + .add_to("content", reporting_problems()) .render() } + +fn hello_world2() -> Container { + Container::header() + .add(grid::Row::new() + .add_column(grid::Column::new() + .add(Chunck::with(html! { + div class="section-title" { + (t("welcome_to", &args![ + "app" => SETTINGS.app.name.as_str() + ])) + } + h1 class="h1-large" { + (l("page_title")) + } + p class="p-large" { + (e("welcome_intro", &args![ + "app" => format!( + "<strong>{}</strong>", + &SETTINGS.app.name + ) + ])) + } + p { + (e("welcome_pagetop", &args![ + "pagetop" => "<a href=\"https://pagetop-rs\">PageTop</a>" + ])) + } + a class="btn-solid-lg" href="#services" { + "Offered services" + } + a class="quote" href="#contact" { + i class="fas fa-paper-plane" {} + "Get quote" + } + })) + ) + .add_column(grid::Column::new() + .add(Image::image("/bootsier/images/demo-header.svg")) + ) + ) +} + +fn hello_world() -> Chunck { + Chunck::with(html! { + header id="header" class="header" { + div class="container" { + div class="row" { + div class="col-lg-6 col-xl-5" { + div class="text-container" { + div class="section-title" { + (t("welcome_to", &args![ + "app" => SETTINGS.app.name.as_str() + ])) + } + h1 class="h1-large" { + (l("page_title")) + } + p class="p-large" { + (e("welcome_intro", &args![ + "app" => format!( + "<strong>{}</strong>", + &SETTINGS.app.name + ) + ])) + } + p { + (e("welcome_pagetop", &args![ + "pagetop" => "<a href=\"https://pagetop-rs\">PageTop</a>" + ])) + } + a class="btn-solid-lg" href="#services" { + "Offered services" + } + a class="quote" href="#contact" { + i class="fas fa-paper-plane" {} + "Get quote" + } + } + } + div class="col-lg-6 col-xl-7" { + div class="image-container" { + img class="img-fluid" src="/bootsier/images/demo-header.svg" alt="alternative" {} + } + } + } + } + } + }) +} + +fn just_visiting() -> Chunck { + Chunck::with(html! { + div id="details" class="basic-1" { + div class="container" { + div class="row" { + div class="col-lg-6 col-xl-7" { + div class="image-container" { + img class="img-fluid" src="/bootsier/images/demo-visiting.svg" alt="alternative" {} + } + } + div class="col-lg-6 col-xl-5" { + div class="text-container" { + h2 { + span { + (l("visiting_title")) + } + br {} + (l("visiting_subtitle")) + } + p { (l("visiting_text1")) } + p { (l("visiting_text2")) } + a class="btn-solid-reg" data-bs-toggle="modal" data-bs-target="#staticBackdrop" { "Modal" } + } + } + } + } + } + }) +} + +fn about_pagetop() -> Chunck { + Chunck::with(html! { + div id="pagetop" class="basic-2" { + div class="container" { + div class="row" { + div class="col-lg-6 col-xl-5" { + div class="text-container" { + h2 { (l("pagetop_title")) } + p { (l("pagetop_text1")) } + p { (l("pagetop_text2")) } + p { (l("pagetop_text3")) } + } + } + div class="col-lg-6 col-xl-7" { + div class="image-container" { + img class="img-fluid" src="/bootsier/images/demo-pagetop.svg" alt="alternative" {} + } + } + } + } + } + }) +} + +fn promo_pagetop() -> Chunck { + Chunck::with(html! { + div id="promo" class="basic-3" { + div class="container" { + div class="row" { + div class="col-lg-6 col-xl-5" { + div class="text-container" { + h2 { (l("pagetop_promo_title")) } + p { (e("pagetop_promo_text1", &args![ + "pagetop" => + "<a href=\"https://pagetop-rs\">PageTop</a>" + ])) } + } + } + div class="col-lg-6 col-xl-7" { + div class="image-container" { + img class="img-fluid" src="/bootsier/images/demo-pagetop.svg" alt="alternative" {} + } + } + } + } + } + }) +} + +fn reporting_problems() -> Chunck { + Chunck::with(html! { + div id="reporting" class="basic-4" { + div class="container" { + div class="row" { + div class="col-lg-6 col-xl-5" { + div class="text-container" { + h2 { (l("report_problems_title")) } + p { (l("report_problems_text1")) } + p { (l("report_problems_text2")) } + } + } + div class="col-lg-6 col-xl-7" { + div class="image-container" { + img class="img-fluid" src="/bootsier/images/demo-pagetop.svg" alt="alternative" {} + } + } + } + } + } + }) +} diff --git a/pagetop/src/base/theme/bootsier/mod.rs b/pagetop/src/base/theme/bootsier/mod.rs index ada65b0e..90111723 100644 --- a/pagetop/src/base/theme/bootsier/mod.rs +++ b/pagetop/src/base/theme/bootsier/mod.rs @@ -52,9 +52,9 @@ impl ThemeTrait for BootsierTheme { s = app::http::StatusCode::INTERNAL_SERVER_ERROR; } } - Page::prepare() + Page::new() .with_title(format!("Error {}", s.as_str()).as_str()) - .add_to("content", Chunck::markup(html! { + .add_to("content", Chunck::with(html! { div class="jumbotron" { div class="media" { img diff --git a/pagetop/src/html.rs b/pagetop/src/html.rs deleted file mode 100644 index ba885bb3..00000000 --- a/pagetop/src/html.rs +++ /dev/null @@ -1 +0,0 @@ -pub use maud::{DOCTYPE, Markup, PreEscaped, html}; diff --git a/pagetop/src/html/classes.rs b/pagetop/src/html/classes.rs new file mode 100644 index 00000000..16c5ac73 --- /dev/null +++ b/pagetop/src/html/classes.rs @@ -0,0 +1,63 @@ +pub struct Classes { + classes: Vec<String>, + option : Option<String>, + updated: bool, +} + +impl Classes { + pub fn none() -> Self { + Classes { + classes: Vec::new(), + option : None, + updated: true, + } + } + + pub fn some_class(class: &str) -> Self { + let mut c = Classes::none(); + c.add_class(class); + c + } + + pub fn some_classes(classes: Vec<String>) -> Self { + let mut c = Classes::none(); + c.add_classes(classes); + c + } + + pub fn add_class(&mut self, class: &str) { + let class = class.trim().replace(" ", "_"); + if !class.is_empty() && !self.classes.iter().any(|c| *c == class) { + self.classes.push(class.to_owned()); + self.updated = false; + } + } + + pub fn add_classes(&mut self, classes: Vec<String>) { + for class in classes.iter() { + self.add_class(class); + } + } + + pub fn classes(&mut self) -> &str { + match self.option() { + Some(classes) => classes.as_str(), + None => "", + } + } + + pub fn has_classes(&self) -> bool { + self.classes.len() > 0 + } + + pub fn option(&mut self) -> &Option<String> { + if !self.updated { + self.option = match self.classes.len() { + 0 => None, + _ => Some(self.classes.join(" ")), + }; + self.updated = true; + } + &self.option + } +} diff --git a/pagetop/src/html/mod.rs b/pagetop/src/html/mod.rs new file mode 100644 index 00000000..60a9bd82 --- /dev/null +++ b/pagetop/src/html/mod.rs @@ -0,0 +1,8 @@ +pub use maud::{DOCTYPE, Markup, PreEscaped, html}; + +mod optional_id; +pub use optional_id::OptionId; +mod optional_attr; +pub use optional_attr::OptionAttr; +mod classes; +pub use classes::Classes; diff --git a/pagetop/src/html/optional_attr.rs b/pagetop/src/html/optional_attr.rs new file mode 100644 index 00000000..f6b48189 --- /dev/null +++ b/pagetop/src/html/optional_attr.rs @@ -0,0 +1,41 @@ +pub struct OptionAttr(Option<String>); + +impl OptionAttr { + pub fn none() -> Self { + OptionAttr(None) + } + + pub fn some(value: &str) -> Self { + let value = value.trim(); + match value.is_empty() { + true => OptionAttr(None), + false => OptionAttr(Some(value.to_owned())), + } + } + + pub fn with_value(&mut self, value: &str) { + let value = value.trim(); + self.0 = match value.is_empty() { + true => None, + false => Some(value.to_owned()), + }; + } + + pub fn value(&self) -> &str { + match &self.0 { + Some(value) => value.as_str(), + None => "", + } + } + + pub fn has_value(&self) -> bool { + match &self.0 { + Some(_) => true, + None => false, + } + } + + pub fn option(&self) -> &Option<String> { + &self.0 + } +} diff --git a/pagetop/src/html/optional_id.rs b/pagetop/src/html/optional_id.rs new file mode 100644 index 00000000..678ff5c8 --- /dev/null +++ b/pagetop/src/html/optional_id.rs @@ -0,0 +1,33 @@ +pub struct OptionId(Option<String>); + +impl OptionId { + pub fn none() -> Self { + OptionId(None) + } + + pub fn with_value(&mut self, id: &str) { + let id = id.trim(); + self.0 = match id.is_empty() { + true => None, + false => Some(id.replace(" ", "_")), + }; + } + + pub fn value(&self) -> &str { + match &self.0 { + Some(id) => id.as_str(), + None => "", + } + } + + pub fn has_value(&self) -> bool { + match &self.0 { + Some(_) => true, + None => false, + } + } + + pub fn option(&self) -> &Option<String> { + &self.0 + } +} diff --git a/pagetop/src/response/page/component.rs b/pagetop/src/response/page/component.rs index 26151cab..630b8a9b 100644 --- a/pagetop/src/response/page/component.rs +++ b/pagetop/src/response/page/component.rs @@ -7,7 +7,7 @@ use std::any::type_name; pub trait PageComponent: Downcast + Send + Sync { - fn prepare() -> Self where Self: Sized; + fn new() -> Self where Self: Sized; fn name(&self) -> &'static str { let name = type_name::<Self>(); diff --git a/pagetop/src/response/page/page.rs b/pagetop/src/response/page/page.rs index eff38daa..1ccb9603 100644 --- a/pagetop/src/response/page/page.rs +++ b/pagetop/src/response/page/page.rs @@ -1,9 +1,8 @@ -use crate::{Lazy, app, trace, util}; +use crate::{Lazy, app, trace}; use crate::config::SETTINGS; -use crate::html::{DOCTYPE, Markup, html}; +use crate::html::{Classes, DOCTYPE, Markup, OptionAttr, html}; use crate::response::page::{PageAssets, PageComponent, PageContainer}; -use std::borrow::Cow; use std::sync::RwLock; use std::collections::HashMap; @@ -41,31 +40,31 @@ static DEFAULT_DIRECTION: Lazy<Option<String>> = Lazy::new(|| { pub enum TextDirection { Auto, LeftToRight, RightToLeft } pub struct Page<'a> { - language : Option<String>, - direction : Option<String>, - title : Option<String>, - description : Option<String>, + language : OptionAttr, + direction : OptionAttr, + title : OptionAttr, + description : OptionAttr, assets : PageAssets, - body_classes: Cow<'a, str>, + body_classes: Classes, regions : HashMap<&'a str, PageContainer>, template : String, } impl<'a> Page<'a> { - pub fn prepare() -> Self { + pub fn new() -> Self { Page { language : match &*DEFAULT_LANGUAGE { - Some(language) => Some(language.to_owned()), - _ => None, + Some(language) => OptionAttr::some(language), + _ => OptionAttr::none(), }, direction : match &*DEFAULT_DIRECTION { - Some(direction) => Some(direction.to_owned()), - _ => None, + Some(direction) => OptionAttr::some(direction), + _ => OptionAttr::none(), }, - title : None, - description : None, - body_classes: "body".into(), + title : OptionAttr::none(), + description : OptionAttr::none(), + body_classes: Classes::some_class("body"), assets : PageAssets::new(), regions : COMPONENTS.read().unwrap().clone(), template : "default".to_owned(), @@ -75,38 +74,36 @@ impl<'a> Page<'a> { // Page BUILDER. pub fn with_language(&mut self, language: &str) -> &mut Self { - self.language = util::valid_str(language); + self.language.with_value(language); self } pub fn with_direction(&mut self, dir: TextDirection) -> &mut Self { - self.direction = match dir { - TextDirection::Auto => Some("auto".to_owned()), - TextDirection::LeftToRight => Some("ltr".to_owned()), - TextDirection::RightToLeft => Some("rtl".to_owned()), - }; + self.direction.with_value(match dir { + TextDirection::Auto => "auto", + TextDirection::LeftToRight => "ltr", + TextDirection::RightToLeft => "rtl", + }); self } pub fn with_title(&mut self, title: &str) -> &mut Self { - self.title = util::valid_str(title); + self.title.with_value(title); self } pub fn with_description(&mut self, description: &str) -> &mut Self { - self.description = util::valid_str(description); + self.description.with_value(description); self } - pub fn with_body_classes(&mut self, body_classes: &'a str) -> &mut Self { - self.body_classes = body_classes.into(); + pub fn add_body_class(&mut self, class: &str) -> &mut Self { + self.body_classes.add_class(class); self } - pub fn add_body_classes(&mut self, body_classes: &'a str) -> &mut Self { - self.body_classes = String::from( - format!("{} {}", self.body_classes, body_classes).trim() - ).into(); + pub fn add_body_classes(&mut self, classes: Vec<String>) -> &mut Self { + self.body_classes.add_classes(classes); self } @@ -131,26 +128,23 @@ impl<'a> Page<'a> { // Page GETTERS. pub fn language(&self) -> &str { - util::assigned_str(&self.language) + self.language.value() } pub fn direction(&self) -> &str { - util::assigned_str(&self.direction) + self.direction.value() } pub fn title(&self) -> &str { - util::assigned_str(&self.title) + self.title.value() } pub fn description(&self) -> &str { - util::assigned_str(&self.description) + self.description.value() } - pub fn body_classes(&self) -> &str { - if self.body_classes.is_empty() { - return "body"; - } - &self.body_classes + pub fn body_classes(&mut self) -> &str { + self.body_classes.classes() } pub fn assets(&mut self) -> &mut PageAssets { @@ -176,7 +170,7 @@ impl<'a> Page<'a> { // Finalmente, renderizar la página. return Ok(html! { (DOCTYPE) - html lang=[&self.language] dir=[&self.direction] { + html lang=[&self.language.option()] dir=[&self.direction.option()] { (head) (body) } @@ -204,7 +198,7 @@ pub fn render_component( ) -> Markup { match component.is_renderable() { true => match assets.theme().render_component(component, assets) { - Some(markup) => markup, + Some(html) => html, None => component.default_render(assets) }, false => html! {} diff --git a/pagetop/src/theme/definition.rs b/pagetop/src/theme/definition.rs index 733736e2..15f6566e 100644 --- a/pagetop/src/theme/definition.rs +++ b/pagetop/src/theme/definition.rs @@ -99,9 +99,9 @@ pub trait ThemeTrait: Send + Sync { } fn render_error_page(&self, s: app::http::StatusCode) -> app::Result<Markup> { - Page::prepare() + Page::new() .with_title(format!("Error {}", s.as_str()).as_str()) - .add_to("content", Chunck::markup(html! { + .add_to("content", Chunck::with(html! { div { h1 { (s) } } diff --git a/pagetop/src/util.rs b/pagetop/src/util.rs index 4ba4f76e..c2fd58d3 100644 --- a/pagetop/src/util.rs +++ b/pagetop/src/util.rs @@ -35,26 +35,3 @@ macro_rules! theme_static_files { } }}; } - -pub fn valid_id(id: &str) -> Option<String> { - let id = id.trim(); - match id.is_empty() { - true => None, - false => Some(id.replace(" ", "_").to_lowercase()), - } -} - -pub fn valid_str(s: &str) -> Option<String> { - let s = s.trim(); - match s.is_empty() { - true => None, - false => Some(s.to_owned()), - } -} - -pub fn assigned_str(optional: &Option<String>) -> &str { - match optional { - Some(o) => o.as_str(), - None => "", - } -} diff --git a/pagetop/static/bootsier/images/demo-header.svg b/pagetop/static/bootsier/images/demo-header.svg new file mode 100644 index 00000000..060757ee --- /dev/null +++ b/pagetop/static/bootsier/images/demo-header.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 317.059 189.688"><defs><style>.cls-1{isolation:isolate;}.cls-2{fill:url(#linear-gradient);}.cls-3{fill:#e0e3fd;}.cls-4{fill:#d1d4fc;}.cls-5{fill:#b2b8fa;}.cls-6{fill:#f3f4fe;}.cls-55,.cls-7{fill:#c1c6fb;}.cls-8{fill:#ffcebd;}.cls-9{fill:#ff5574;}.cls-10,.cls-145{fill:#191c3c;}.cls-11{fill:#6168ff;}.cls-12,.cls-22{fill:#fff;}.cls-13{fill:#4d5068;}.cls-14,.cls-18{fill:#231f20;}.cls-14{opacity:0.15;}.cls-15{fill:#474963;}.cls-16{fill:#75778a;}.cls-17{fill:#3b479a;}.cls-145,.cls-18{opacity:0.3;}.cls-19{fill:#ffc043;}.cls-20,.cls-30{fill:#f0f1fe;}.cls-21{mix-blend-mode:multiply;}.cls-22,.cls-66{opacity:0;}.cls-23,.cls-68{fill:#fdfdff;}.cls-23,.cls-67{opacity:0.024;}.cls-24,.cls-70{fill:#fbfcff;}.cls-24,.cls-69{opacity:0.049;}.cls-25,.cls-72{fill:#f9faff;}.cls-25,.cls-71{opacity:0.073;}.cls-26,.cls-74{fill:#f7f8ff;}.cls-26,.cls-73{opacity:0.098;}.cls-27,.cls-76{fill:#f6f6fe;}.cls-27,.cls-75{opacity:0.122;}.cls-28,.cls-78{fill:#f4f5fe;}.cls-28,.cls-77{opacity:0.146;}.cls-29,.cls-80{fill:#f2f3fe;}.cls-29,.cls-79{opacity:0.171;}.cls-30,.cls-81{opacity:0.195;}.cls-31,.cls-83{fill:#eeeffe;}.cls-31,.cls-82{opacity:0.22;}.cls-32,.cls-85{fill:#eceefe;}.cls-32,.cls-84{opacity:0.244;}.cls-33,.cls-87{fill:#eaecfe;}.cls-33,.cls-86{opacity:0.268;}.cls-34,.cls-89{fill:#e8eafe;}.cls-34,.cls-88{opacity:0.293;}.cls-35,.cls-91{fill:#e7e8fd;}.cls-35,.cls-90{opacity:0.317;}.cls-36,.cls-93{fill:#e5e7fd;}.cls-36,.cls-92{opacity:0.341;}.cls-37,.cls-95{fill:#e3e5fd;}.cls-37,.cls-94{opacity:0.366;}.cls-38,.cls-97{fill:#e1e3fd;}.cls-38,.cls-96{opacity:0.39;}.cls-39,.cls-99{fill:#dfe2fd;}.cls-39,.cls-98{opacity:0.415;}.cls-101,.cls-40{fill:#dde0fd;}.cls-100,.cls-40{opacity:0.439;}.cls-103,.cls-41{fill:#dbdefd;}.cls-102,.cls-41{opacity:0.463;}.cls-105,.cls-42{fill:#d9dcfd;}.cls-104,.cls-42{opacity:0.488;}.cls-107,.cls-43{fill:#d8dbfc;}.cls-106,.cls-43{opacity:0.512;}.cls-109,.cls-44{fill:#d6d9fc;}.cls-108,.cls-44{opacity:0.537;}.cls-111,.cls-45{fill:#d4d7fc;}.cls-110,.cls-45{opacity:0.561;}.cls-113,.cls-46{fill:#d2d5fc;}.cls-112,.cls-46{opacity:0.585;}.cls-115,.cls-47{fill:#d0d4fc;}.cls-114,.cls-47{opacity:0.61;}.cls-117,.cls-48{fill:#ced2fc;}.cls-116,.cls-48{opacity:0.634;}.cls-119,.cls-49{fill:#ccd0fc;}.cls-118,.cls-49{opacity:0.659;}.cls-121,.cls-50{fill:#cacffc;}.cls-120,.cls-50{opacity:0.683;}.cls-123,.cls-51{fill:#c9cdfb;}.cls-122,.cls-51{opacity:0.707;}.cls-125,.cls-52{fill:#c7cbfb;}.cls-124,.cls-52{opacity:0.732;}.cls-127,.cls-53{fill:#c5c9fb;}.cls-126,.cls-53{opacity:0.756;}.cls-129,.cls-54{fill:#c3c8fb;}.cls-128,.cls-54{opacity:0.78;}.cls-130,.cls-55{opacity:0.805;}.cls-132,.cls-56{fill:#bfc4fb;}.cls-131,.cls-56{opacity:0.829;}.cls-134,.cls-57{fill:#bdc2fb;}.cls-133,.cls-57{opacity:0.854;}.cls-136,.cls-58{fill:#bbc1fb;}.cls-135,.cls-58{opacity:0.878;}.cls-138,.cls-59{fill:#babffa;}.cls-137,.cls-59{opacity:0.902;}.cls-140,.cls-60{fill:#b8bdfa;}.cls-139,.cls-60{opacity:0.927;}.cls-142,.cls-61{fill:#b6bbfa;}.cls-141,.cls-61{opacity:0.951;}.cls-144,.cls-62{fill:#b4bafa;}.cls-143,.cls-62{opacity:0.976;}.cls-63{fill:#ffdfd6;}.cls-64{fill:#717386;}.cls-65{fill:#3a3c4e;}.cls-146{fill:#fe5e31;}.cls-147{opacity:0.35;}.cls-148{fill:#ff5f00;}.cls-149{fill:#ff7f33;}</style><linearGradient id="linear-gradient" x1="35.199" y1="214.99" x2="282.198" y2="54.991" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#dfe1fd"/><stop offset="0.454" stop-color="#ebecfe"/><stop offset="1" stop-color="#f4f5fe"/></linearGradient></defs><title>header-illustration</title><g class="cls-1"><g id="Graphics"><g id="Layer_8" data-name="Layer 8"><path class="cls-2" d="M311.36,131.746c5.5,8.781,8.206,19.733,2.628,28.063-4.8,7.174-14.327,10.048-19.137,17.218-2.43,3.621-3.709,8.358-7.5,10.507-2.33,1.32-5.145,1.355-7.822,1.355l-242.153.024c-2.706,0-5.518-.022-7.958-1.194-2.927-1.405-4.879-4.26-6.327-7.167a40.233,40.233,0,0,1,5.029-42.707c5.92-7.08,14.329-12.083,18.9-20.1,3.979-6.984,4.514-15.317,5.829-23.247C54.509,84.448,58.633,74.2,68.311,69.88c11.6-5.184,23.242-9.56,32.252-18.972,9.73-10.166,15.217-24.632,27.315-31.82,11.6-6.89,26.347-5.225,39.267-1.353s25.442,9.757,38.892,10.761c16.491,1.231,33.543-4.96,49.327-.024a37.007,37.007,0,0,1,23.519,22.784c5.28,15.178.224,32.69,6.431,47.513,4.646,11.1,14.781,18.742,22.455,28.006A46.526,46.526,0,0,1,311.36,131.746Z"/></g><g id="Layer_6" data-name="Layer 6"><rect class="cls-3" x="193.476" y="114.758" width="63.825" height="74.808" rx="3.34" ry="3.34"/><rect class="cls-4" x="198.555" y="120.566" width="53.667" height="17.333" rx="1.813" ry="1.813"/><rect class="cls-4" x="198.555" y="143.399" width="53.667" height="17.333" rx="1.813" ry="1.813"/><rect class="cls-4" x="198.555" y="166.233" width="53.667" height="17.333" rx="1.813" ry="1.813"/><circle class="cls-3" cx="225.389" cy="129.233" r="1.833"/><circle class="cls-3" cx="225.389" cy="152.162" r="1.833"/><circle class="cls-3" cx="225.389" cy="175.091" r="1.833"/><path class="cls-4" d="M77.631,80.66c-14.357,8.89-9.89,29.678-9.7,44.046q0.32,23.762.64,47.524a0.742,0.742,0,0,1-1.482,0q-0.383-28.4-.765-56.8c-0.18-13.368-2.467-27.989,10.556-36.053a0.742,0.742,0,0,1,.748,1.28h0Z"/><path class="cls-4" d="M69.658,87.891a18.1,18.1,0,0,1,2.316-3.934,19.26,19.26,0,0,1,5.607-4.1l0.3,0.16a17.793,17.793,0,0,1,1.172,9.617,10.681,10.681,0,0,1-5.521,7.682c-2.163,1.04-4.719,1.176-6.737,2.474C66.223,95.687,67.884,91.631,69.658,87.891Z"/><path class="cls-4" d="M54.619,62.676c14.259,5.656,11.19,27.286,11.765,39.475,0.974,20.671,1.5,41.341,1.366,62.037a0.742,0.742,0,0,1-1.482,0q0.169-25.811-.891-51.607c-0.326-7.769-.716-15.536-1.084-23.3-0.426-9.018-.011-21.184-10.068-25.173-0.876-.348-0.494-1.782.394-1.429h0Z"/><path class="cls-4" d="M64.38,87.554c0.026-.071.044-0.145,0.069-0.217a6.7,6.7,0,0,1,.577,1.09Z"/><path class="cls-4" d="M53.807,63.935a0.732,0.732,0,0,1,1.089-.492,15.576,15.576,0,0,1,9.887,9.88,21.46,21.46,0,0,1-.333,14.014c-1.772-2.8-5.372-4.2-7.893-6.519C52.082,76.7,51.395,69.519,53.807,63.935Z"/><path class="cls-5" d="M60.281,164.207h12.93a5.822,5.822,0,0,1,5.822,5.822V189a0,0,0,0,1,0,0H54.459a0,0,0,0,1,0,0V170.028A5.822,5.822,0,0,1,60.281,164.207Z" transform="translate(133.493 353.202) rotate(180)"/><path class="cls-4" d="M66.1,134.774c0.223-5.728.483-12.512-3.771-17-3.321-3.5-11.838-5.92-16.612-6.044a0.742,0.742,0,0,1,0-1.482c3.641,0.094,7.439,1.538,10.868,2.7,2.523,0.856,4.91,1.8,6.792,3.776,4.57,4.788,4.444,11.9,4.205,18.05a0.742,0.742,0,0,1-1.482,0h0Z"/><path class="cls-4" d="M44.119,109.65a0.463,0.463,0,0,1,.363-0.1l5.376,0.046a18.955,18.955,0,0,1,4.624.419c3.03,0.788,5.484,3.027,7.4,5.5l0.558,0.085c-2.8.892-5.542,2.063-8.462,2.367s-6.155-.436-7.984-2.732a11.122,11.122,0,0,1-1.926-5.2A0.462,0.462,0,0,1,44.119,109.65Z"/><g id="_Group_" data-name="&lt;Group&gt;"><g id="_Group_2" data-name="&lt;Group&gt;"><g id="_Group_3" data-name="&lt;Group&gt;"><path id="_Path_" data-name="&lt;Path&gt;" class="cls-3" d="M232.03,104.1H222.024v3.042a8.623,8.623,0,0,0,2.277,5.838h0V114.5h5.451v-1.518h0a8.623,8.623,0,0,0,2.277-5.838V104.1Z"/></g></g><g id="_Group_4" data-name="&lt;Group&gt;"><g id="_Group_5" data-name="&lt;Group&gt;"><path id="_Path_2" data-name="&lt;Path&gt;" class="cls-6" d="M229.972,104.1v3.042a8.623,8.623,0,0,1-2.277,5.838h0V114.5h1.176v-1.518h0a8.623,8.623,0,0,0,2.277-5.838V104.1h-1.176Z"/></g></g><g id="_Group_6" data-name="&lt;Group&gt;"><g id="_Group_7" data-name="&lt;Group&gt;"><g id="_Group_8" data-name="&lt;Group&gt;"><path id="_Path_3" data-name="&lt;Path&gt;" class="cls-3" d="M223.108,110.429h-1.646a2.714,2.714,0,1,1,0-5.428h1.058v1.15h-1.058a1.564,1.564,0,1,0,0,3.128h1.646v1.15Z"/></g></g></g><path id="_Path_4" data-name="&lt;Path&gt;" class="cls-4" d="M223.547,104.124v2.6a0.753,0.753,0,0,0,.753.753h0a0.753,0.753,0,0,0,.753-0.753v-0.1a0.641,0.641,0,0,1,.641-0.641h0a0.64,0.64,0,0,1,.64.641v4.247a0.736,0.736,0,0,0,.736.736h0a0.736,0.736,0,0,0,.736-0.736v-1.763a0.722,0.722,0,0,1,.722-0.722h0a0.75,0.75,0,0,0,.75-0.75v-3.513h-5.732Z"/></g><path class="cls-3" d="M292.388,141.31a11.256,11.256,0,0,0-.885-4.378,23.868,23.868,0,0,0-4.61,20.924l1.393,1.294a14.47,14.47,0,0,0,4.029-8.385A43.082,43.082,0,0,0,292.388,141.31Z"/><path class="cls-3" d="M305.092,149.429a0.734,0.734,0,0,0-.407-0.19,10.624,10.624,0,0,0-12.943,10.375l0.939,1.134c1.981,0.54,4.051-.469,5.695-1.7a20.268,20.268,0,0,0,6.714-8.856A0.759,0.759,0,0,0,305.092,149.429Z"/><path class="cls-3" d="M274.342,149.258c-2.106-1.711-4.557-3.384-7.266-3.219a0.861,0.861,0,0,0-.75.339c-0.3.561,0.652,0.984,0.836,1.591a2.282,2.282,0,0,1-.14,1.086,3.54,3.54,0,0,0,.328,1.974,15.509,15.509,0,0,0,16.114,9.324l0.824-1.294A73.172,73.172,0,0,0,274.342,149.258Z"/><path class="cls-3" d="M282.105,159.452c4.725,4.487,5.332,11.144,4.517,17.287-0.177,1.337,1.927,1.324,2.1,0,0.887-6.691-.026-13.924-5.133-18.773a1.052,1.052,0,0,0-1.487,1.487h0Z"/><path class="cls-3" d="M286.72,157.32c1,5.906-.275,11.872.356,17.806,0.142,1.332,2.246,1.346,2.1,0-0.652-6.129.6-12.257-.431-18.365-0.225-1.331-2.252-.767-2.028.559h0Z"/><path class="cls-3" d="M292.882,156.9a29.613,29.613,0,0,0-4.3,8.494c-0.88,3.311-.628,7.035-0.78,10.436a1.052,1.052,0,0,0,2.1,0c0.143-3.205-.089-6.762.705-9.877a27.463,27.463,0,0,1,4.085-7.992c0.752-1.129-1.068-2.183-1.816-1.061h0Z"/><path class="cls-5" d="M295.251,189.073H283.514a1.063,1.063,0,0,1-1.027-.791l-4-15.082a1.063,1.063,0,0,1,1.027-1.335h19.728a1.063,1.063,0,0,1,1.027,1.335l-4,15.082A1.063,1.063,0,0,1,295.251,189.073Z"/><path class="cls-7" d="M290.969,139.2c-1.563,5.891-1.576,12.034-3,17.952a0.152,0.152,0,0,0,.293.081c1.423-5.918,1.436-12.062,3-17.952a0.152,0.152,0,0,0-.293-0.081h0Z"/><path class="cls-7" d="M292.9,158.927a20.1,20.1,0,0,1,10.417-8.243c0.183-.064.1-0.358-0.081-0.293a20.431,20.431,0,0,0-10.6,8.383,0.152,0.152,0,0,0,.262.153h0Z"/><path class="cls-7" d="M267.778,147.92a12.182,12.182,0,0,0,4.69,5.493c3,2.1,6.853,3.135,9.6,5.49,0.173,0.149.427-.1,0.252-0.252-1.911-1.639-4.346-2.315-6.51-3.55-3.107-1.773-6.314-3.82-7.689-7.275-0.084-.211-0.429-0.119-0.344.095h0Z"/><rect class="cls-8" x="246.49" y="175.423" width="4.657" height="7.091" transform="translate(497.637 357.937) rotate(180)"/><path class="cls-9" d="M251.775,180.688a29.085,29.085,0,0,0,1.072,5.476,3.129,3.129,0,0,1,.366.911v2.613H242.2V188.3a2.971,2.971,0,0,1,.588-1.768c0.937-1.269,3.725-3.892,3.287-5.844h5.7Z"/><path class="cls-10" d="M251.749,180.688h0.026l-0.013.071C251.759,180.736,251.752,180.71,251.749,180.688Z"/><path class="cls-10" d="M253.213,187.8v1.884H242.2V188.3a2.935,2.935,0,0,1,.044-0.5h10.973Z"/><rect class="cls-10" x="246.856" y="182.174" width="3.035" height="0.68" rx="0.271" ry="0.271" transform="translate(496.747 365.028) rotate(180)"/><rect class="cls-10" x="246.49" y="183.691" width="3.035" height="0.68" rx="0.271" ry="0.271" transform="translate(496.015 368.063) rotate(180)"/><rect class="cls-8" x="276.786" y="175.423" width="4.657" height="7.091" transform="translate(558.229 357.937) rotate(180)"/><path class="cls-11" d="M268.728,115.127c-1.3,3.207-9.181,31.063-9.181,31.063l-7.106,33.372H245.5l3.58-37.87,2.616-40.211,15.044,1.79,2.721,7.45Z"/><polygon class="cls-11" points="284.494 109.055 284.06 142.656 282.407 179.562 275.797 179.562 273.134 150.138 266.742 115.49 266.742 103.271 283.234 104.785 284.494 109.055"/><path class="cls-8" d="M267.672,60.9h9.915V47.842H266.742C269.256,51.106,267.672,60.9,267.672,60.9Z"/><path class="cls-12" d="M283.234,107.54c-0.322,7.734-25.339-4.731-30.793-1.836l6.61-45.492s6.056-2.408,8.621-.526c3.535,2.594,9.915,0,9.915,0l4.453,1.767S283.509,100.93,283.234,107.54Z"/><path class="cls-9" d="M268.123,52.721s1.8,30.026-13.055,49.035c0,0-4.539,11.222-8.212,11.773,0,0-3.834-9.732.848-17.419,2.876-4.722,8.43-15.067,8.76-20.586l0.945-15.839Z"/><path class="cls-9" d="M277.587,52.721s-4.34,19.673-4.453,29.724c-0.092,8.171,12.6,35.42,12.6,35.42s7.833-8.175,3.7-17.624c-2.723-6.229-5.762-11.154-5.375-15.245l-0.1-28.117Z"/><path class="cls-8" d="M263.306,45.366a17.024,17.024,0,0,1,.725-3.887,3.15,3.15,0,0,0-1.136-.244,0.517,0.517,0,0,1-.322-0.856c1.206-1.343,3.415-3.539,3.783-4.343a6.387,6.387,0,0,1,.718-1.335,10.1,10.1,0,0,0,.565-0.992,1.768,1.768,0,0,1,1.21-.952,4.1,4.1,0,0,1,1.483.166,27.692,27.692,0,0,1,5.949,1.857,11.555,11.555,0,0,1,2.071,1.2A6.278,6.278,0,0,1,280.4,38.8a11.211,11.211,0,0,1,.015,5.97,5.147,5.147,0,0,1-.432,1.405,4.476,4.476,0,0,1-1.719,1.627c-1.181.725-2.409,1.369-3.646,1.991a13.466,13.466,0,0,1-2.285.975,13.119,13.119,0,0,1-3.989.32,6.321,6.321,0,0,1-3.034-.6,4.014,4.014,0,0,1-1.72-2.255A7.72,7.72,0,0,1,263.306,45.366Z"/><path class="cls-13" d="M266.378,27.073a12.941,12.941,0,0,0,6.894,2.494,36.564,36.564,0,0,1,7.327,1.18c1.456,0.494,3.722,1.408,4.421,2.9,0.979,2.091.822,5.194,0.285,7.371a10.972,10.972,0,0,1-2.288,4.5,12.452,12.452,0,0,1-4.347,2.914c-0.139.068-.276,0.138-0.413,0.212a2.111,2.111,0,0,1-.431.25c-0.277.057-.339-0.42-0.337-0.635a2.432,2.432,0,0,1,.381-1.191,7.178,7.178,0,0,1,.706-0.864A4.941,4.941,0,0,0,279.3,43.3a3.683,3.683,0,0,0-.094-1.485,1.4,1.4,0,0,0-1.037-.977,1.857,1.857,0,0,0-1.41.587,7.55,7.55,0,0,0-1.866,2.468q-0.041-1.307-.081-2.614a6.391,6.391,0,0,0-.225-1.784c-0.244-.751-0.774-1.487-0.586-2.254a8.052,8.052,0,0,0,.358-1.02,1.36,1.36,0,0,0-.79-1.253,5.035,5.035,0,0,0-1.513-.4c-0.81-.143-1.571-0.411-2.357-0.627a4.965,4.965,0,0,1-2.046-.979A3.945,3.945,0,0,1,266.52,30.9a10.716,10.716,0,0,1-.2-2.381A11.631,11.631,0,0,1,266.378,27.073Z"/><path class="cls-8" d="M296.132,74.122l5.327,13.74a4.852,4.852,0,0,1-.375,4.282L284.151,113.7l-3-4.51,10.859-17.183a5.137,5.137,0,0,0-.115-4.685l-5.26-9.255S293.01,80.442,296.132,74.122Z"/><path class="cls-8" d="M281.147,109.192l-1.939.345-1.34,1.234a1.208,1.208,0,0,0-.092,1.683l0.4,0.456-0.6.96a1.108,1.108,0,0,0,.08,1.287l1.873,2.3a1.108,1.108,0,0,0,1.444.242l2.03-1.26a1.9,1.9,0,0,0,.862-1.25l0.29-1.486Z"/><path class="cls-9" d="M282.071,180.688a6.575,6.575,0,0,0,1.623,5.476,1.385,1.385,0,0,1,.366.911v2.613H273.594V188.3a2.972,2.972,0,0,1,.588-1.768c0.937-1.269,2.623-3.892,2.186-5.844h5.7Z"/><path class="cls-10" d="M282.045,180.688h0.026l-0.013.071C282.055,180.736,282.048,180.71,282.045,180.688Z"/><path class="cls-10" d="M284.06,187.8v1.884H273.594V188.3a2.935,2.935,0,0,1,.044-0.5H284.06Z"/><rect class="cls-10" x="277.152" y="182.174" width="3.035" height="0.68" rx="0.271" ry="0.271" transform="translate(557.34 365.028) rotate(180)"/><rect class="cls-10" x="276.786" y="183.691" width="3.035" height="0.68" rx="0.271" ry="0.271" transform="translate(556.607 368.063) rotate(180)"/><path class="cls-9" d="M277.587,52.721l6.907,4.509,3.078,1.464a8.646,8.646,0,0,1,4.342,4.669l5.549,12.625c-6,1.163-6.243,6.58-10.515,5.57l-6.132-14.6-3.229-7.276V52.721Z"/><path class="cls-9" d="M268.123,52.721L261.2,55.692,257.34,56.7a8.194,8.194,0,0,0-5.395,4.551L245.5,74.062c4.131,0,8.425,5.535,9.089,4.467l7.918-13.886Z"/><path class="cls-14" d="M265.934,49.735a1.944,1.944,0,0,1,.96-1.934h0a1.04,1.04,0,0,0,.46-0.548l0.611-1.688a2.833,2.833,0,0,0,.138-1.38l-0.195-1.309a1.092,1.092,0,0,0-1.529-.835l-2.227,1.005-1.374,1.348-0.009.019a9.021,9.021,0,0,0,.293,3.519,4.479,4.479,0,0,0,1.919,2.516,4.217,4.217,0,0,0,1.1.417Z"/><path class="cls-8" d="M246.261,74.584l15.044-24.178V46.364a1.885,1.885,0,0,1,.565-1.346l1.7-1.662,2-.9a0.979,0.979,0,0,1,1.371.748l0.174,1.173a2.538,2.538,0,0,1-.124,1.237l-0.548,1.514a0.933,0.933,0,0,1-.412.491h0a1.743,1.743,0,0,0-.86,1.734l0.147,1.138,2.653,0.524-3.324,2.558L253.8,78.54a4.27,4.27,0,0,1-5.73,2.167h0A4.271,4.271,0,0,1,246.261,74.584Z"/><path class="cls-10" d="M166.722,186.321l0.008,0a0.488,0.488,0,0,0,.664-0.187l15.432-27.483a0.488,0.488,0,0,0-.186-0.665l-0.008,0a0.487,0.487,0,0,0-.664.186l-15.433,27.484A0.488,0.488,0,0,0,166.722,186.321Z"/><path class="cls-15" d="M129.607,186.1H169.1a1.041,1.041,0,0,1,1.041,1.041v1.2a1.042,1.042,0,0,1-1.042,1.042H129.606a1.041,1.041,0,0,1-1.041-1.041v-1.2a1.042,1.042,0,0,1,1.042-1.042Z" transform="translate(298.604 375.561) rotate(-179.969)"/><path class="cls-10" d="M128.565,187.615a1.5,1.5,0,0,1,.371-0.966,1.528,1.528,0,0,0,1.526,1.522l38.517,0.021a1.5,1.5,0,0,0,1.158-.561v0.235a1.529,1.529,0,0,1-1.53,1.528l-38.517-.021a1.529,1.529,0,0,1-1.528-1.53v-0.228Z"/><rect class="cls-16" x="139.329" y="186.971" width="3.022" height="1.159"/><rect class="cls-16" x="135.748" y="186.969" width="3.022" height="1.159"/><rect class="cls-16" x="161.172" y="186.983" width="3.022" height="1.159"/><rect class="cls-8" x="19.685" y="154.12" width="6.235" height="9.087" transform="translate(-87.475 42.332) rotate(-35.292)"/><path class="cls-11" d="M19.067,158.782L6.534,160.109,3.793,161.65a1.829,1.829,0,0,1-2.389-.537l-1.085-1.532,17.672-12.509a2.185,2.185,0,0,1,3.046.521l0.976,1.379a11.216,11.216,0,0,1,1.94,4.839l0.2,1.369h0a2.483,2.483,0,0,0-3.461-.592l-1.036.733a2.483,2.483,0,0,0-.592,3.461h0Z"/><path class="cls-13" d="M18.995,148.552L1.658,160.823A0.766,0.766,0,0,1,.59,160.64L0,159.806l17.962-12.714a2.2,2.2,0,0,1,3.075.5l0.976,1.379c0.012,0.017.021,0.036,0.032,0.053A2.2,2.2,0,0,0,18.995,148.552Z"/><polygon class="cls-17" points="50.007 185.331 48.228 181.081 25.909 156.76 20.159 161.062 41.408 189.463 45.444 187.549 50.007 185.331"/><rect class="cls-8" x="46.36" y="151.731" width="6.235" height="9.087" transform="translate(35.289 -7.03) rotate(12.602)"/><path class="cls-11" d="M46.885,153.583L37.5,145.175l-2.981-1a1.829,1.829,0,0,1-1.2-2.133l0.41-1.832,21.129,4.724a2.185,2.185,0,0,1,1.655,2.609l-0.369,1.649a11.216,11.216,0,0,1-2.289,4.684l-0.88,1.068h0a2.483,2.483,0,0,0-1.881-2.965L49.85,151.7a2.483,2.483,0,0,0-2.965,1.881h0Z"/><path class="cls-13" d="M54.462,146.678l-20.828-4.7a0.775,0.775,0,0,1-.586-0.925l0.221-.989,21.583,4.869a2.185,2.185,0,0,1,1.656,2.609l-0.369,1.649c0,0.02-.013.039-0.017,0.059A2.183,2.183,0,0,0,54.462,146.678Z"/><path class="cls-18" d="M45.51,178.118l-7.739-8.433-3.947,9.64L41.4,189.454h0.026l4.017-1.905,4.563-2.217-1.779-4.251-1.305-1.423a1.119,1.119,0,0,1-1.466-1.348Z"/><path class="cls-17" d="M79.44,169.065l-2.555.229a47.964,47.964,0,0,0-17.564,5.069l-10.267,5.251a1.126,1.126,0,0,1-1.6-1.3l6.518-23.525h-8.1L35.72,179.578a7.169,7.169,0,0,0,6.783,9.883l39.17-.315Z"/><path class="cls-11" d="M120.372,174.029l-3.9,6.323a6.105,6.105,0,0,1-8,2.223l-1.948-1.005-11.65,5.158a18.047,18.047,0,0,1-6.471,1.526L78.8,189.526s-5.245-12.8-1.081-20.9h0a32.21,32.21,0,0,0,27.79-5.749l8.148-6.326Z"/><polygon class="cls-8" points="130.051 162.437 121.602 168.622 120.372 163.112 126.449 157.384 130.051 162.437"/><path class="cls-8" d="M124.414,159.355c-0.075-2.366,1.679-3.555,3.413-4.4a23.454,23.454,0,0,1,12.3-2.263l1.006,0.244a8.506,8.506,0,0,1-.764,3.611,9.272,9.272,0,0,0,.079,4.639,0.2,0.2,0,0,1-.18.28,14.26,14.26,0,0,0-2.346.163c-0.222.368-.38,0.771-0.57,1.157a5.567,5.567,0,0,1-.849,1.371c-1.112,1.2-2.99,1.186-4.608.959-2.289-.322-4.652-0.956-6.224-2.727A4.857,4.857,0,0,1,124.414,159.355Z"/><path class="cls-8" d="M122.982,165.822l2.664,15.366a1.93,1.93,0,0,0,1.642,1.582l22.92,2.492,4.864,0.769,4.443,1.164,3.51,0.112h0a1.9,1.9,0,0,1-1.6,1.995h-2.588L152.671,189l-27.963.69a4.657,4.657,0,0,1-4.494-3.013l-7.606-20.185Z"/><path class="cls-19" d="M102.559,164.849a12.2,12.2,0,0,1,2.525-3.536,16.731,16.731,0,0,1,3.291-2.827c1.775-1.1,3.563-1.41,5.154-2.823a17.06,17.06,0,0,0,3.685-4.649c0.49-.909.9-1.863,1.436-2.745a12.5,12.5,0,0,1,8.029-5.4,26.361,26.361,0,0,1,5.684-.879,20.341,20.341,0,0,1,6.441,1.141,10.543,10.543,0,0,1,4.128,2.163,5.072,5.072,0,0,1,1.19,5.222,5.5,5.5,0,0,1-.9,2c-1.644,2.178-5.16,2.3-7.631,2.85-1.526.337-3.134-.15-4.606,0.46a9.724,9.724,0,0,0-3.2,2.781,25.882,25.882,0,0,0-3.654,4.753c-0.52.951-.918,1.962-1.361,2.951a17.719,17.719,0,0,1-5.915,7.7,10.357,10.357,0,0,1-10.746.608C102.844,172.706,101.092,168.337,102.559,164.849Z"/><rect id="_Rectangle_" data-name="&lt;Rectangle&gt;" class="cls-12" x="125.891" y="36.047" width="76.607" height="92.263" rx="2.858" ry="2.858"/><path id="_Path_5" data-name="&lt;Path&gt;" class="cls-9" d="M202.5,45.795V38.7a2.654,2.654,0,0,0-2.654-2.654h-71.3a2.654,2.654,0,0,0-2.654,2.654v7.093H202.5Z"/><circle id="_Path_6" data-name="&lt;Path&gt;" class="cls-12" cx="131.696" cy="40.921" r="0.836"/><circle id="_Path_7" data-name="&lt;Path&gt;" class="cls-12" cx="135.446" cy="40.921" r="0.836"/><circle id="_Path_8" data-name="&lt;Path&gt;" class="cls-12" cx="139.196" cy="40.921" r="0.836"/><circle class="cls-3" cx="141.137" cy="90.542" r="6.833"/><circle class="cls-3" cx="141.137" cy="109.192" r="6.833"/><rect class="cls-20" x="155.946" y="86.125" width="38.012" height="1.417"/><rect class="cls-20" x="155.946" y="91.708" width="21" height="1.417"/><rect class="cls-20" x="155.946" y="104.958" width="38.012" height="1.417"/><rect class="cls-20" x="155.946" y="110.542" width="21" height="1.417"/><circle class="cls-3" cx="141.137" cy="70.542" r="6.833"/><rect class="cls-20" x="155.946" y="66.125" width="38.012" height="1.417"/><rect class="cls-20" x="155.946" y="71.708" width="21" height="1.417"/><g class="cls-21"><path class="cls-22" d="M199.951,35.974H181.774V69.4a4.938,4.938,0,0,0,4.938,4.938H202.5V38.521A2.547,2.547,0,0,0,199.951,35.974Z"/><path class="cls-23" d="M199.969,35.974H181.915V69.311a4.9,4.9,0,0,0,4.9,4.9H202.5V38.5A2.529,2.529,0,0,0,199.969,35.974Z"/><path class="cls-24" d="M199.986,35.974H182.055V69.226a4.871,4.871,0,0,0,4.871,4.871H202.5V38.486A2.512,2.512,0,0,0,199.986,35.974Z"/><path class="cls-25" d="M200,35.974H182.2V69.141a4.838,4.838,0,0,0,4.838,4.838H202.5V38.469A2.5,2.5,0,0,0,200,35.974Z"/><path class="cls-26" d="M200.02,35.974H182.336V69.056a4.8,4.8,0,0,0,4.8,4.8H202.5V38.452A2.478,2.478,0,0,0,200.02,35.974Z"/><path class="cls-27" d="M200.038,35.974H182.476v33a4.771,4.771,0,0,0,4.771,4.771H202.5V38.434A2.46,2.46,0,0,0,200.038,35.974Z"/><path class="cls-28" d="M200.055,35.974H182.617V68.887a4.737,4.737,0,0,0,4.737,4.737H202.5V38.417A2.443,2.443,0,0,0,200.055,35.974Z"/><path class="cls-29" d="M200.072,35.974H182.757V68.8a4.7,4.7,0,0,0,4.7,4.7H202.5V38.4A2.426,2.426,0,0,0,200.072,35.974Z"/><path class="cls-30" d="M200.089,35.974H182.9V68.718a4.67,4.67,0,0,0,4.67,4.67H202.5V38.383A2.409,2.409,0,0,0,200.089,35.974Z"/><path class="cls-31" d="M200.107,35.974H183.038V68.633a4.637,4.637,0,0,0,4.637,4.637H202.5v-34.9A2.391,2.391,0,0,0,200.107,35.974Z"/><path class="cls-32" d="M200.124,35.974H183.178V68.548a4.6,4.6,0,0,0,4.6,4.6H202.5v-34.8A2.374,2.374,0,0,0,200.124,35.974Z"/><path class="cls-33" d="M200.141,35.974H183.319V68.463a4.57,4.57,0,0,0,4.57,4.57H202.5v-34.7A2.357,2.357,0,0,0,200.141,35.974Z"/><path class="cls-34" d="M200.158,35.974h-16.7v32.4A4.536,4.536,0,0,0,188,72.915h14.5v-34.6A2.34,2.34,0,0,0,200.158,35.974Z"/><path class="cls-35" d="M200.176,35.974H183.6v32.32a4.5,4.5,0,0,0,4.5,4.5h14.4V38.3A2.322,2.322,0,0,0,200.176,35.974Z"/><path class="cls-36" d="M200.193,35.974H183.74V68.209a4.47,4.47,0,0,0,4.47,4.47H202.5v-34.4A2.305,2.305,0,0,0,200.193,35.974Z"/><path class="cls-37" d="M200.21,35.974H183.88v32.15a4.436,4.436,0,0,0,4.436,4.436H202.5v-34.3A2.288,2.288,0,0,0,200.21,35.974Z"/><path class="cls-38" d="M200.227,35.974H184.021V68.04a4.4,4.4,0,0,0,4.4,4.4H202.5v-34.2A2.271,2.271,0,0,0,200.227,35.974Z"/><path class="cls-39" d="M200.245,35.974H184.161V67.955a4.369,4.369,0,0,0,4.369,4.369H202.5v-34.1A2.253,2.253,0,0,0,200.245,35.974Z"/><path class="cls-40" d="M200.262,35.974H184.3v31.9a4.336,4.336,0,0,0,4.336,4.336H202.5v-34A2.236,2.236,0,0,0,200.262,35.974Z"/><path class="cls-41" d="M200.279,35.974H184.442V67.786a4.3,4.3,0,0,0,4.3,4.3H202.5v-33.9A2.219,2.219,0,0,0,200.279,35.974Z"/><path class="cls-42" d="M200.3,35.974H184.582V67.7a4.269,4.269,0,0,0,4.269,4.269H202.5V38.176A2.2,2.2,0,0,0,200.3,35.974Z"/><path class="cls-43" d="M200.314,35.974H184.723V67.616a4.235,4.235,0,0,0,4.235,4.235H202.5V38.158A2.184,2.184,0,0,0,200.314,35.974Z"/><path class="cls-44" d="M200.331,35.974H184.863V67.532a4.2,4.2,0,0,0,4.2,4.2H202.5V38.141A2.167,2.167,0,0,0,200.331,35.974Z"/><path class="cls-45" d="M200.348,35.974H185V67.447a4.168,4.168,0,0,0,4.168,4.168H202.5V38.124A2.15,2.15,0,0,0,200.348,35.974Z"/><path class="cls-46" d="M200.365,35.974H185.144V67.362a4.135,4.135,0,0,0,4.135,4.135H202.5V38.107A2.132,2.132,0,0,0,200.365,35.974Z"/><path class="cls-47" d="M200.383,35.974h-15.1v31.3a4.1,4.1,0,0,0,4.1,4.1H202.5V38.089A2.115,2.115,0,0,0,200.383,35.974Z"/><path class="cls-48" d="M200.4,35.974H185.424V67.193a4.068,4.068,0,0,0,4.068,4.068H202.5V38.072A2.1,2.1,0,0,0,200.4,35.974Z"/><path class="cls-49" d="M200.417,35.974H185.565V67.108a4.035,4.035,0,0,0,4.035,4.035h12.9V38.055A2.081,2.081,0,0,0,200.417,35.974Z"/><path class="cls-50" d="M200.434,35.974H185.705V67.023a4,4,0,0,0,4,4H202.5V38.038A2.063,2.063,0,0,0,200.434,35.974Z"/><path class="cls-51" d="M200.452,35.974H185.846V66.938a3.968,3.968,0,0,0,3.968,3.968H202.5V38.02A2.046,2.046,0,0,0,200.452,35.974Z"/><path class="cls-52" d="M200.469,35.974H185.986v30.88a3.934,3.934,0,0,0,3.934,3.934H202.5V38A2.029,2.029,0,0,0,200.469,35.974Z"/><path class="cls-53" d="M200.486,35.974h-14.36V66.769a3.9,3.9,0,0,0,3.9,3.9H202.5V37.986A2.012,2.012,0,0,0,200.486,35.974Z"/><path class="cls-54" d="M200.5,35.974H186.267v30.71a3.867,3.867,0,0,0,3.867,3.867H202.5V37.969A1.994,1.994,0,0,0,200.5,35.974Z"/><path class="cls-55" d="M200.521,35.974H186.407V66.6a3.834,3.834,0,0,0,3.834,3.834H202.5V37.951A1.977,1.977,0,0,0,200.521,35.974Z"/><path class="cls-56" d="M200.538,35.974h-13.99V66.515a3.8,3.8,0,0,0,3.8,3.8H202.5V37.934A1.96,1.96,0,0,0,200.538,35.974Z"/><path class="cls-57" d="M200.555,35.974H186.688V66.43a3.767,3.767,0,0,0,3.767,3.767H202.5V37.917A1.943,1.943,0,0,0,200.555,35.974Z"/><path class="cls-58" d="M200.572,35.974H186.828V66.345a3.734,3.734,0,0,0,3.734,3.734H202.5V37.9A1.925,1.925,0,0,0,200.572,35.974Z"/><path class="cls-59" d="M200.59,35.974H186.969V66.261a3.7,3.7,0,0,0,3.7,3.7H202.5V37.882A1.908,1.908,0,0,0,200.59,35.974Z"/><path class="cls-60" d="M200.607,35.974h-13.5v30.2a3.667,3.667,0,0,0,3.667,3.667H202.5V37.865A1.891,1.891,0,0,0,200.607,35.974Z"/><path class="cls-61" d="M200.624,35.974H187.25V66.091a3.633,3.633,0,0,0,3.633,3.633H202.5V37.848A1.874,1.874,0,0,0,200.624,35.974Z"/><path class="cls-62" d="M200.641,35.974H187.39V66.007a3.6,3.6,0,0,0,3.6,3.6H202.5V37.831A1.856,1.856,0,0,0,200.641,35.974Z"/><path class="cls-5" d="M200.659,35.974H187.53V65.922a3.566,3.566,0,0,0,3.566,3.566h11.4V37.813A1.839,1.839,0,0,0,200.659,35.974Z"/></g><rect class="cls-12" x="186.896" y="22.275" width="55.3" height="48.256" rx="5.147" ry="5.147"/><path class="cls-9" d="M237.591,22.275H191.5a4.6,4.6,0,0,0-4.6,4.6v5.243h55.3V26.88A4.6,4.6,0,0,0,237.591,22.275Z"/><circle class="cls-12" cx="193.115" cy="27.199" r="0.844"/><circle class="cls-12" cx="196.779" cy="27.199" r="0.844"/><circle class="cls-12" cx="196.779" cy="27.199" r="0.844"/><circle class="cls-12" cx="200.444" cy="27.199" r="0.844"/><circle class="cls-4" cx="197.623" cy="45.032" r="6.596"/><rect class="cls-20" x="207.772" y="41.479" width="30.204" height="1.777"/><rect class="cls-20" x="207.772" y="46.652" width="30.204" height="1.777"/><rect class="cls-63" x="207.772" y="51.825" width="11.326" height="1.777"/><path class="cls-19" d="M286.646,9.058a9.058,9.058,0,1,0-14.01,7.579v5.78h9.9v-5.78A9.045,9.045,0,0,0,286.646,9.058Z"/><polygon id="_Path_9" data-name="&lt;Path&gt;" class="cls-13" points="283.182 22.821 279.888 25.575 274.986 25.575 271.993 22.821 271.993 18.494 283.182 18.494 283.182 22.821"/><rect id="_Rectangle_2" data-name="&lt;Rectangle&gt;" class="cls-64" x="271.507" y="18.889" width="12.137" height="0.83" rx="0.365" ry="0.365"/><rect id="_Rectangle_3" data-name="&lt;Rectangle&gt;" class="cls-64" x="271.507" y="20.275" width="12.137" height="0.83" rx="0.365" ry="0.365"/><rect id="_Rectangle_4" data-name="&lt;Rectangle&gt;" class="cls-64" x="271.507" y="21.662" width="12.137" height="0.83" rx="0.365" ry="0.365"/><path id="_Rectangle_5" data-name="&lt;Rectangle&gt;" class="cls-65" d="M274.845,25.446h5.082a0,0,0,0,1,0,0v0.2a1.43,1.43,0,0,1-1.43,1.43h-2.222a1.43,1.43,0,0,1-1.43-1.43v-0.2A0,0,0,0,1,274.845,25.446Z"/><polygon class="cls-12" points="277.022 11.422 274.702 9.103 275.409 8.396 277.022 10.008 280.55 6.48 281.257 7.186 277.022 11.422"/><path class="cls-22" d="M152.4,54.256H125.891V84.768H152.4a3.55,3.55,0,0,0,3.55-3.55V57.806A3.55,3.55,0,0,0,152.4,54.256Z"/><path class="cls-23" d="M152.258,54.256H125.891V84.608h26.367a3.531,3.531,0,0,0,3.531-3.531V57.787A3.531,3.531,0,0,0,152.258,54.256Z"/><path class="cls-24" d="M152.119,54.256H125.891V84.449h26.228a3.513,3.513,0,0,0,3.513-3.513V57.769A3.513,3.513,0,0,0,152.119,54.256Z"/><path class="cls-25" d="M151.981,54.256h-26.09V84.29h26.09a3.494,3.494,0,0,0,3.494-3.494V57.75A3.494,3.494,0,0,0,151.981,54.256Z"/><path class="cls-26" d="M151.842,54.256H125.891V84.13h25.951a3.476,3.476,0,0,0,3.476-3.476V57.732A3.476,3.476,0,0,0,151.842,54.256Z"/><path class="cls-27" d="M151.7,54.256H125.891V83.971H151.7a3.457,3.457,0,0,0,3.457-3.457v-22.8A3.457,3.457,0,0,0,151.7,54.256Z"/><path class="cls-28" d="M151.565,54.256H125.891V83.812h25.674A3.438,3.438,0,0,0,155,80.373V57.695A3.438,3.438,0,0,0,151.565,54.256Z"/><path class="cls-29" d="M151.427,54.256H125.891v29.4h25.536a3.42,3.42,0,0,0,3.42-3.42V57.676A3.42,3.42,0,0,0,151.427,54.256Z"/><path class="cls-30" d="M151.288,54.256h-25.4V83.493h25.4a3.4,3.4,0,0,0,3.4-3.4V57.657A3.4,3.4,0,0,0,151.288,54.256Z"/><path class="cls-31" d="M151.15,54.256H125.891V83.333H151.15a3.383,3.383,0,0,0,3.383-3.383V57.639A3.383,3.383,0,0,0,151.15,54.256Z"/><path class="cls-32" d="M151.012,54.256H125.891V83.174h25.121a3.364,3.364,0,0,0,3.364-3.364V57.62A3.364,3.364,0,0,0,151.012,54.256Z"/><path class="cls-33" d="M150.873,54.256H125.891V83.015h24.982a3.346,3.346,0,0,0,3.346-3.346V57.6A3.346,3.346,0,0,0,150.873,54.256Z"/><path class="cls-34" d="M150.735,54.256H125.891v28.6h24.844a3.327,3.327,0,0,0,3.327-3.327V57.583A3.327,3.327,0,0,0,150.735,54.256Z"/><path class="cls-35" d="M150.6,54.256H125.891V82.7H150.6a3.309,3.309,0,0,0,3.309-3.309V57.565A3.309,3.309,0,0,0,150.6,54.256Z"/><path class="cls-36" d="M150.458,54.256H125.891V82.536h24.567a3.29,3.29,0,0,0,3.29-3.29v-21.7A3.29,3.29,0,0,0,150.458,54.256Z"/><path class="cls-37" d="M150.319,54.256H125.891V82.377h24.428a3.272,3.272,0,0,0,3.272-3.272V57.528A3.272,3.272,0,0,0,150.319,54.256Z"/><path class="cls-38" d="M150.181,54.256h-24.29V82.218h24.29a3.253,3.253,0,0,0,3.253-3.253V57.509A3.253,3.253,0,0,0,150.181,54.256Z"/><path class="cls-39" d="M150.042,54.256H125.891v27.8h24.151a3.235,3.235,0,0,0,3.234-3.235V57.491A3.235,3.235,0,0,0,150.042,54.256Z"/><path class="cls-40" d="M149.9,54.256H125.891V81.9H149.9a3.216,3.216,0,0,0,3.216-3.216V57.472A3.216,3.216,0,0,0,149.9,54.256Z"/><path class="cls-41" d="M149.765,54.256H125.891V81.74h23.875a3.2,3.2,0,0,0,3.2-3.2V57.453A3.2,3.2,0,0,0,149.765,54.256Z"/><path class="cls-42" d="M149.627,54.256H125.891V81.58h23.736a3.179,3.179,0,0,0,3.179-3.179V57.435A3.179,3.179,0,0,0,149.627,54.256Z"/><path class="cls-43" d="M149.488,54.256h-23.6V81.421h23.6a3.16,3.16,0,0,0,3.16-3.16V57.416A3.16,3.16,0,0,0,149.488,54.256Z"/><path class="cls-44" d="M149.35,54.256H125.891V81.261H149.35a3.142,3.142,0,0,0,3.142-3.142V57.4A3.142,3.142,0,0,0,149.35,54.256Z"/><path class="cls-45" d="M149.212,54.256H125.891V81.1h23.321a3.123,3.123,0,0,0,3.123-3.123v-20.6A3.123,3.123,0,0,0,149.212,54.256Z"/><path class="cls-46" d="M149.073,54.256H125.891V80.943h23.182a3.1,3.1,0,0,0,3.1-3.1V57.361A3.1,3.1,0,0,0,149.073,54.256Z"/><path class="cls-47" d="M148.935,54.256H125.891V80.783h23.044a3.086,3.086,0,0,0,3.086-3.086V57.342A3.086,3.086,0,0,0,148.935,54.256Z"/><path class="cls-48" d="M148.8,54.256H125.891V80.624H148.8a3.068,3.068,0,0,0,3.068-3.068V57.324A3.068,3.068,0,0,0,148.8,54.256Z"/><path class="cls-49" d="M148.658,54.256H125.891V80.464h22.767a3.049,3.049,0,0,0,3.049-3.049V57.305A3.049,3.049,0,0,0,148.658,54.256Z"/><path class="cls-50" d="M148.519,54.256H125.891V80.305h22.628a3.031,3.031,0,0,0,3.031-3.031V57.287A3.031,3.031,0,0,0,148.519,54.256Z"/><path class="cls-51" d="M148.381,54.256h-22.49v25.89h22.49a3.012,3.012,0,0,0,3.012-3.012V57.268A3.012,3.012,0,0,0,148.381,54.256Z"/><path class="cls-52" d="M148.242,54.256H125.891v25.73h22.351a2.994,2.994,0,0,0,2.994-2.993V57.249A2.994,2.994,0,0,0,148.242,54.256Z"/><path class="cls-53" d="M148.1,54.256H125.891V79.827H148.1a2.975,2.975,0,0,0,2.975-2.975V57.231A2.975,2.975,0,0,0,148.1,54.256Z"/><path class="cls-54" d="M147.965,54.256H125.891V79.668h22.075a2.957,2.957,0,0,0,2.956-2.957v-19.5A2.956,2.956,0,0,0,147.965,54.256Z"/><path class="cls-55" d="M147.827,54.256H125.891V79.508h21.936a2.938,2.938,0,0,0,2.938-2.938V57.194A2.938,2.938,0,0,0,147.827,54.256Z"/><path class="cls-56" d="M147.689,54.256h-21.8V79.349h21.8a2.919,2.919,0,0,0,2.919-2.919V57.175A2.919,2.919,0,0,0,147.689,54.256Z"/><path class="cls-57" d="M147.55,54.256H125.891V79.189H147.55a2.9,2.9,0,0,0,2.9-2.9V57.157A2.9,2.9,0,0,0,147.55,54.256Z"/><path class="cls-58" d="M147.412,54.256H125.891V79.03h21.521a2.882,2.882,0,0,0,2.882-2.882V57.138A2.882,2.882,0,0,0,147.412,54.256Z"/><path class="cls-59" d="M147.273,54.256H125.891V78.871h21.382a2.864,2.864,0,0,0,2.864-2.864V57.12A2.864,2.864,0,0,0,147.273,54.256Z"/><path class="cls-60" d="M147.135,54.256H125.891V78.711h21.244a2.845,2.845,0,0,0,2.845-2.845V57.1A2.845,2.845,0,0,0,147.135,54.256Z"/><path class="cls-61" d="M147,54.256H125.891v24.3H147a2.827,2.827,0,0,0,2.827-2.827V57.083A2.827,2.827,0,0,0,147,54.256Z"/><path class="cls-62" d="M146.858,54.256H125.891V78.392h20.967a2.808,2.808,0,0,0,2.808-2.808V57.064A2.808,2.808,0,0,0,146.858,54.256Z"/><path class="cls-5" d="M146.719,54.256H125.891V78.233h20.828a2.79,2.79,0,0,0,2.79-2.79v-18.4A2.79,2.79,0,0,0,146.719,54.256Z"/><rect class="cls-12" x="100.573" y="49.764" width="50.635" height="29.763" rx="3.463" ry="3.463"/><circle id="_Path_10" data-name="&lt;Path&gt;" class="cls-9" cx="113.674" cy="64.645" r="8.194"/><path id="_Path_11" data-name="&lt;Path&gt;" class="cls-12" d="M116.7,65.108l-5.273,3.044a0.534,0.534,0,0,1-.8-0.462V61.6a0.534,0.534,0,0,1,.8-0.462l5.273,3.044A0.534,0.534,0,0,1,116.7,65.108Z"/><rect class="cls-20" x="124.866" y="58.066" width="22.464" height="2"/><rect class="cls-20" x="124.866" y="63.645" width="22.464" height="2"/><rect class="cls-11" x="124.866" y="69.224" width="11.232" height="2"/><g class="cls-66"><path class="cls-12" d="M202.5,83.625H184.636a2.188,2.188,0,0,0-2.188,2.188v20.966a2.188,2.188,0,0,0,2.188,2.188H202.5V83.625Z"/></g><g class="cls-67"><path class="cls-68" d="M202.5,83.625H184.755a2.173,2.173,0,0,0-2.173,2.173v20.826a2.173,2.173,0,0,0,2.173,2.173H202.5V83.625Z"/></g><g class="cls-69"><path class="cls-70" d="M202.5,83.625H184.874a2.159,2.159,0,0,0-2.159,2.159V106.47a2.158,2.158,0,0,0,2.159,2.159H202.5v-25Z"/></g><g class="cls-71"><path class="cls-72" d="M202.5,83.625h-17.5a2.144,2.144,0,0,0-2.144,2.144v20.546a2.144,2.144,0,0,0,2.144,2.144h17.5V83.625Z"/></g><g class="cls-73"><path class="cls-74" d="M202.5,83.625H185.113a2.129,2.129,0,0,0-2.13,2.129v20.407a2.129,2.129,0,0,0,2.13,2.129H202.5V83.625Z"/></g><g class="cls-75"><path class="cls-76" d="M202.5,83.625H185.232a2.115,2.115,0,0,0-2.115,2.115v20.267a2.115,2.115,0,0,0,2.115,2.115H202.5v-24.5Z"/></g><g class="cls-77"><path class="cls-78" d="M202.5,83.625H185.351a2.1,2.1,0,0,0-2.1,2.1v20.127a2.1,2.1,0,0,0,2.1,2.1H202.5V83.625Z"/></g><g class="cls-79"><path class="cls-80" d="M202.5,83.625H185.47a2.086,2.086,0,0,0-2.086,2.086V105.7a2.086,2.086,0,0,0,2.086,2.086H202.5V83.625Z"/></g><g class="cls-81"><path class="cls-20" d="M202.5,83.625H185.589a2.071,2.071,0,0,0-2.071,2.071v19.847a2.071,2.071,0,0,0,2.071,2.071H202.5V83.625Z"/></g><g class="cls-82"><path class="cls-83" d="M202.5,83.625H185.708a2.057,2.057,0,0,0-2.056,2.057v19.707a2.056,2.056,0,0,0,2.056,2.056H202.5V83.625Z"/></g><g class="cls-84"><path class="cls-85" d="M202.5,83.625h-16.67a2.042,2.042,0,0,0-2.042,2.042v19.567a2.042,2.042,0,0,0,2.042,2.042H202.5V83.625Z"/></g><g class="cls-86"><path class="cls-87" d="M202.5,83.625H185.947a2.027,2.027,0,0,0-2.027,2.027V105.08a2.027,2.027,0,0,0,2.027,2.027H202.5V83.625Z"/></g><g class="cls-88"><path class="cls-89" d="M202.5,83.625H186.066a2.013,2.013,0,0,0-2.013,2.013v19.288a2.013,2.013,0,0,0,2.013,2.013H202.5V83.625Z"/></g><g class="cls-90"><path class="cls-91" d="M202.5,83.625H186.185a2,2,0,0,0-2,2v19.148a2,2,0,0,0,2,2H202.5V83.625Z"/></g><g class="cls-92"><path class="cls-93" d="M202.5,83.625H186.3a1.984,1.984,0,0,0-1.984,1.984v19.008A1.983,1.983,0,0,0,186.3,106.6H202.5V83.625Z"/></g><g class="cls-94"><path class="cls-95" d="M202.5,83.625H186.423a1.969,1.969,0,0,0-1.969,1.969v18.868a1.969,1.969,0,0,0,1.969,1.969H202.5V83.625Z"/></g><g class="cls-96"><path class="cls-97" d="M202.5,83.625H186.543a1.954,1.954,0,0,0-1.954,1.954v18.728a1.954,1.954,0,0,0,1.954,1.954H202.5V83.625Z"/></g><g class="cls-98"><path class="cls-99" d="M202.5,83.625H186.662a1.94,1.94,0,0,0-1.94,1.94v18.588a1.94,1.94,0,0,0,1.94,1.94H202.5V83.625Z"/></g><g class="cls-100"><path class="cls-101" d="M202.5,83.625H186.781a1.925,1.925,0,0,0-1.925,1.925V104a1.925,1.925,0,0,0,1.925,1.925H202.5v-22.3Z"/></g><g class="cls-102"><path class="cls-103" d="M202.5,83.625H186.9a1.911,1.911,0,0,0-1.911,1.91v18.308a1.91,1.91,0,0,0,1.911,1.91h15.6V83.625Z"/></g><g class="cls-104"><path class="cls-105" d="M202.5,83.625H187.019a1.9,1.9,0,0,0-1.9,1.9v18.168a1.9,1.9,0,0,0,1.9,1.9H202.5V83.625Z"/></g><g class="cls-106"><path class="cls-107" d="M202.5,83.625H187.138a1.881,1.881,0,0,0-1.881,1.881v18.029a1.881,1.881,0,0,0,1.881,1.881H202.5V83.625Z"/></g><g class="cls-108"><path class="cls-109" d="M202.5,83.625h-15.24a1.867,1.867,0,0,0-1.867,1.867V103.38a1.867,1.867,0,0,0,1.867,1.867H202.5V83.625Z"/></g><g class="cls-110"><path class="cls-111" d="M202.5,83.625H187.377a1.852,1.852,0,0,0-1.852,1.852v17.749a1.852,1.852,0,0,0,1.852,1.852H202.5V83.625Z"/></g><g class="cls-112"><path class="cls-113" d="M202.5,83.625h-15a1.838,1.838,0,0,0-1.838,1.838v17.609a1.837,1.837,0,0,0,1.838,1.838h15V83.625Z"/></g><g class="cls-114"><path class="cls-115" d="M202.5,83.625H187.615a1.823,1.823,0,0,0-1.823,1.823v17.469a1.823,1.823,0,0,0,1.823,1.823H202.5V83.625Z"/></g><g class="cls-116"><path class="cls-117" d="M202.5,83.625H187.734a1.808,1.808,0,0,0-1.808,1.808v17.329a1.808,1.808,0,0,0,1.808,1.808H202.5V83.625Z"/></g><g class="cls-118"><path class="cls-119" d="M202.5,83.625H187.853a1.794,1.794,0,0,0-1.794,1.794v17.189a1.794,1.794,0,0,0,1.794,1.794H202.5V83.625Z"/></g><g class="cls-120"><path class="cls-121" d="M202.5,83.625H187.973a1.779,1.779,0,0,0-1.779,1.779v17.049a1.779,1.779,0,0,0,1.779,1.779H202.5V83.625Z"/></g><g class="cls-122"><path class="cls-123" d="M202.5,83.625H188.092a1.765,1.765,0,0,0-1.765,1.765V102.3a1.765,1.765,0,0,0,1.765,1.764H202.5V83.625Z"/></g><g class="cls-124"><path class="cls-125" d="M202.5,83.625H188.211a1.75,1.75,0,0,0-1.75,1.75v16.77a1.75,1.75,0,0,0,1.75,1.75H202.5V83.625Z"/></g><g class="cls-126"><path class="cls-127" d="M202.5,83.625H188.33a1.735,1.735,0,0,0-1.735,1.735v16.63a1.735,1.735,0,0,0,1.735,1.735H202.5v-20.1Z"/></g><g class="cls-128"><path class="cls-129" d="M202.5,83.625H188.449a1.721,1.721,0,0,0-1.721,1.721v16.49a1.721,1.721,0,0,0,1.721,1.721H202.5V83.625Z"/></g><g class="cls-130"><path class="cls-7" d="M202.5,83.625H188.569a1.706,1.706,0,0,0-1.706,1.706v16.35a1.706,1.706,0,0,0,1.706,1.706H202.5V83.625Z"/></g><g class="cls-131"><path class="cls-132" d="M202.5,83.625h-13.81A1.692,1.692,0,0,0,187,85.317v16.21a1.691,1.691,0,0,0,1.691,1.692H202.5V83.625Z"/></g><g class="cls-133"><path class="cls-134" d="M202.5,83.625H188.807A1.677,1.677,0,0,0,187.13,85.3v16.07a1.677,1.677,0,0,0,1.677,1.677H202.5V83.625Z"/></g><g class="cls-135"><path class="cls-136" d="M202.5,83.625H188.926a1.662,1.662,0,0,0-1.662,1.662v15.93a1.662,1.662,0,0,0,1.662,1.662H202.5V83.625Z"/></g><g class="cls-137"><path class="cls-138" d="M202.5,83.625H189.045a1.648,1.648,0,0,0-1.648,1.648v15.79a1.648,1.648,0,0,0,1.648,1.648H202.5V83.625Z"/></g><g class="cls-139"><path class="cls-140" d="M202.5,83.625H189.164a1.633,1.633,0,0,0-1.633,1.633v15.65a1.633,1.633,0,0,0,1.633,1.633H202.5V83.625Z"/></g><g class="cls-141"><path class="cls-142" d="M202.5,83.625H189.284a1.619,1.619,0,0,0-1.619,1.619v15.511a1.619,1.619,0,0,0,1.619,1.618H202.5V83.625Z"/></g><g class="cls-143"><path class="cls-144" d="M202.5,83.625H189.4a1.6,1.6,0,0,0-1.6,1.6V100.6a1.6,1.6,0,0,0,1.6,1.6h13.1V83.625Z"/></g><path class="cls-5" d="M202.5,83.625H189.522a1.589,1.589,0,0,0-1.589,1.589v15.231a1.589,1.589,0,0,0,1.589,1.589H202.5V83.625Z"/><rect class="cls-12" x="186.896" y="80.062" width="33.507" height="23.292" rx="2.011" ry="2.011"/><rect class="cls-3" x="189.395" y="82.3" width="28.51" height="17.779"/><polygon class="cls-5" points="193.803 88.84 189.417 95.173 189.395 100.079 200.686 100.079 193.803 88.84"/><polygon class="cls-12" points="194.497 92.139 194.891 92.791 195.586 91.787 193.803 88.84 191.781 91.759 192.406 92.791 192.884 92.101 193.649 93.364 194.497 92.139"/><polygon class="cls-5" points="199.155 97.635 202.491 92.664 207.083 100.079 200.674 100.079 199.155 97.635"/><circle class="cls-4" cx="209.486" cy="88.355" r="3.13"/><polygon class="cls-12" points="203.225 95.963 203.62 96.615 204.315 95.611 202.491 92.664 200.51 95.582 201.134 96.615 201.612 95.924 202.377 97.188 203.225 95.963"/><rect class="cls-12" x="79.679" y="107.534" width="41.923" height="36.584" rx="3.684" ry="3.684"/><path class="cls-9" d="M118.111,107.534H83.17a3.491,3.491,0,0,0-3.491,3.491V115H121.6v-3.975A3.491,3.491,0,0,0,118.111,107.534Z"/><circle class="cls-12" cx="84.393" cy="111.267" r="0.639"/><circle class="cls-12" cx="87.171" cy="111.267" r="0.639"/><circle class="cls-12" cx="87.171" cy="111.267" r="0.639"/><circle class="cls-12" cx="89.949" cy="111.267" r="0.64"/><polygon class="cls-11" points="98.111 128.187 93.283 130.87 94.347 142.737 106.025 142.737 107.805 131.184 102.411 128.187 98.111 128.187"/><polygon class="cls-8" points="102.411 128.32 100.261 132.253 98.111 128.32 98.111 125.528 102.411 125.528 102.411 128.32"/><path class="cls-13" d="M104.265,119.731a2.327,2.327,0,0,0-.216-0.521l-0.527-1.029a1.4,1.4,0,0,0-1.209-.714,6.072,6.072,0,0,0-1.536-.54,1.985,1.985,0,0,0-.992.268,1.836,1.836,0,0,1-.392.177,3.36,3.36,0,0,1-.725.008,1.369,1.369,0,0,0-1.249,1,0.96,0.96,0,0,1-.088.272,0.943,0.943,0,0,1-.167.179c-0.737.705-.3,1.887-0.185,2.754a1.946,1.946,0,0,0,.41,1.354l-0.2-.049a3.464,3.464,0,0,0,1.814.88,10.324,10.324,0,0,0,2.04.113l2.463-.026a0.723,0.723,0,0,0,.447-0.1,0.708,0.708,0,0,0,.2-0.479c0.13-.936.044-1.87,0.123-2.82A2.328,2.328,0,0,0,104.265,119.731Z"/><path class="cls-145" d="M98.111,127.132l0.6,1.046a2.212,2.212,0,0,0,3.7.21v-2.861h-4.3v1.6Z"/><path class="cls-8" d="M97.765,121.216v3.276a4.208,4.208,0,0,0,.563,2.1l0.632,1.095a2.216,2.216,0,0,0,1.92,1.109h0a2.217,2.217,0,0,0,1.894-1.066l0.128-.21a4.208,4.208,0,0,0,.611-2.183V119.3H97.846Z"/><path class="cls-8" d="M97.809,124.977l-0.658-.347a2.156,2.156,0,0,1-.373-1.707s0.24-.587.693-0.32l0.64,0.64Z"/><path class="cls-8" d="M103.354,124.977l0.658-.347a2.156,2.156,0,0,0,.373-1.707s-0.24-.587-0.694-0.32l-0.64.64Z"/><path class="cls-13" d="M97.582,121.745a10.891,10.891,0,0,1,.124,1.54c-0.006.2-.091,0.8,0.344,0.641a0.358,0.358,0,0,0,.187-0.333c0.033-.5-0.379-0.921-0.143-1.379a3.885,3.885,0,0,0,.649-0.929,2.748,2.748,0,0,0-.127-0.824,0.806,0.806,0,0,1,.154-0.609,0.545,0.545,0,0,1,.578-0.185,1.444,1.444,0,0,1,.471.405,1.289,1.289,0,0,0,1.343.269,4.79,4.79,0,0,0,.75-0.467,1.056,1.056,0,0,1,.837-0.191,1.215,1.215,0,0,1,.674,1.008,4.739,4.739,0,0,1,.146,1.4,9.656,9.656,0,0,1-.335,1.059,0.914,0.914,0,0,0-.034.264,0.988,0.988,0,0,0,.181.442,0.1,0.1,0,0,0,.045.047,0.1,0.1,0,0,0,.1-0.033,1.489,1.489,0,0,0,.373-0.88,2.351,2.351,0,0,0,.111-1.136c-0.164-.871.044-1.778-0.1-2.653a0.543,0.543,0,0,0-.09-0.252,0.56,0.56,0,0,0-.27-0.159,10.618,10.618,0,0,0-3.9-.327,2.743,2.743,0,0,0-1.341.285,1.878,1.878,0,0,0-.794,1.37A6.527,6.527,0,0,0,97.582,121.745Z"/><path class="cls-8" d="M86.258,137.9l-0.192-.548-5.788-3.708h0a1.017,1.017,0,0,1,1.256-.144l1.149,0.715,0.414-.09a1.3,1.3,0,0,1,.975.175l0.568,0.363,1.915,0.577a1.735,1.735,0,0,1,1.12,1.042l0.409,1.069Z"/><path class="cls-8" d="M114.265,137.9l0.192-.548,5.788-3.708h0a1.017,1.017,0,0,0-1.256-.144l-1.149.715-0.414-.09a1.3,1.3,0,0,0-.975.175l-0.567.363-1.915.577a1.735,1.735,0,0,0-1.12,1.042l-0.408,1.069Z"/><path class="cls-11" d="M98.111,128.187l-5.7,3.168a3.432,3.432,0,0,0-1.755,2.74l-0.471,6.2-1.834-3.016-2.446.734,2.178,4.828,4.77-.1,1.326-6.6,3.934-5.839v-2.109Z"/><path class="cls-11" d="M102.411,128.187l5.7,3.168a3.432,3.432,0,0,1,1.755,2.74l0.471,6.2,1.834-3.016,2.446,0.734-2.18,4.833-4.762-.078-1.332-6.63-3.934-5.839v-2.109Z"/><polygon class="cls-12" points="98.111 128.187 96.845 128.89 98.336 134.201 100.261 132.253 98.111 128.187"/><polygon class="cls-12" points="102.411 128.187 103.677 128.89 102.187 134.201 100.261 132.253 102.411 128.187"/><path class="cls-13" d="M99.368,125.815c-0.08.158-.107,0.339-0.191,0.5a0.4,0.4,0,0,1-.428.239,0.548,0.548,0,0,1-.279-0.5,7.862,7.862,0,0,0-.122-1.658,2.1,2.1,0,0,1-.129-0.428c-0.016-.136,0-0.276-0.023-0.41a0.31,0.31,0,0,0-.267-0.269,0.283,0.283,0,0,0-.248.233,0.876,0.876,0,0,0,.022.363,6.335,6.335,0,0,1,.132,1.785,4.282,4.282,0,0,0,.367,1.727,2.72,2.72,0,0,0,.249.565,2.1,2.1,0,0,0,1.275.859,6.25,6.25,0,0,0,1.564.139,2.522,2.522,0,0,0,1.01-.134c0.922-.394,1.214-2.129,1.313-2.983a5.148,5.148,0,0,0-.066-1.077,6.954,6.954,0,0,1,.166-1.36,0.183,0.183,0,0,0-.032-0.165,0.293,0.293,0,0,1-.164-0.108,1.017,1.017,0,0,0-.346.507,1.2,1.2,0,0,0-.018.279,3.731,3.731,0,0,1-.076,1.095,10.535,10.535,0,0,0-.3,1.258,0.53,0.53,0,0,1-.287.493,0.352,0.352,0,0,1-.374-0.237,1.3,1.3,0,0,1-.055-0.476,0.726,0.726,0,0,0-.123-0.457,0.822,0.822,0,0,0-.6-0.213C100.675,125.327,99.762,125.028,99.368,125.815Z"/><path class="cls-8" d="M99.467,126.257h0.447a0.685,0.685,0,0,0,.452-0.17l0.272-.239,0.3,0.249a0.685,0.685,0,0,0,.44.16h0.434a1.211,1.211,0,0,1-1.286,1.236C99.645,127.47,99.76,126.954,99.467,126.257Z"/><polygon class="cls-12" points="85.903 138.01 88.348 137.277 88.962 138.286 86.369 139.044 85.903 138.01"/><polygon class="cls-12" points="114.665 138.01 112.22 137.277 111.606 138.286 114.199 139.044 114.665 138.01"/><circle class="cls-146" cx="85.562" cy="120.593" r="2.307"/><polygon class="cls-12" points="86.192 120.593 84.933 121.32 84.933 119.866 86.192 120.593"/><g id="_Group_9" data-name="&lt;Group&gt;"><g id="_Group_10" data-name="&lt;Group&gt;"><g id="_Group_11" data-name="&lt;Group&gt;"><path id="_Rectangle_6" data-name="&lt;Rectangle&gt;" class="cls-5" d="M149.124,161.423H166a2.086,2.086,0,0,1,2.086,2.086v9.906a1.175,1.175,0,0,1-1.175,1.175H147.976a1.159,1.159,0,0,1-1.159-1.159v-9.7A2.307,2.307,0,0,1,149.124,161.423Z" transform="translate(314.903 336.012) rotate(180)"/></g></g><g id="_Group_12" data-name="&lt;Group&gt;"><g id="_Group_13" data-name="&lt;Group&gt;"><path id="_Path_12" data-name="&lt;Path&gt;" class="cls-5" d="M147.058,161.9l8.905-7.256a2.619,2.619,0,0,1,3.091,0l8.42,6.962Z"/></g></g><g id="_Group_14" data-name="&lt;Group&gt;"><g id="_Group_15" data-name="&lt;Group&gt;"><path id="_Path_13" data-name="&lt;Path&gt;" class="cls-12" d="M153.018,151.352l-3.116,3.026v16.612h14.757V152.6a1.25,1.25,0,0,0-1.25-1.25H153.018Z"/></g></g><g id="_Group_16" data-name="&lt;Group&gt;" class="cls-147"><g id="_Group_17" data-name="&lt;Group&gt;"><polygon id="_Path_14" data-name="&lt;Path&gt;" class="cls-5" points="152.833 154.064 149.902 157.415 149.902 154.378 152.833 154.064"/></g></g><g id="_Group_18" data-name="&lt;Group&gt;"><g id="_Group_19" data-name="&lt;Group&gt;"><path id="_Path_15" data-name="&lt;Path&gt;" class="cls-5" d="M153.018,151.352l-3.116,3.026h2.285a0.831,0.831,0,0,0,.831-0.831v-2.195Z"/></g></g><g id="_Group_20" data-name="&lt;Group&gt;"><g id="_Group_21" data-name="&lt;Group&gt;"><path id="_Path_16" data-name="&lt;Path&gt;" class="cls-3" d="M147.433,174.641s8.214-5.73,8.214-6.249l-8.589-6.493a4.9,4.9,0,0,0-.241,1.7v10.462A0.585,0.585,0,0,0,147.433,174.641Z"/></g></g><g id="_Group_22" data-name="&lt;Group&gt;"><g id="_Group_23" data-name="&lt;Group&gt;"><path id="_Path_17" data-name="&lt;Path&gt;" class="cls-3" d="M167.626,174.641s-8.034-5.852-8.034-6.371l8.339-6.127a2.309,2.309,0,0,1,.311,1.455v10.462A0.585,0.585,0,0,1,167.626,174.641Z"/></g></g><g id="_Group_24" data-name="&lt;Group&gt;"><g id="_Group_25" data-name="&lt;Group&gt;"><path id="_Path_18" data-name="&lt;Path&gt;" class="cls-5" d="M147.349,174.654l8.644-7.107a2.59,2.59,0,0,1,3.056,0l8.644,7.107H147.349Z"/></g></g><g id="_Group_26" data-name="&lt;Group&gt;"><g id="_Group_27" data-name="&lt;Group&gt;"><g id="_Group_28" data-name="&lt;Group&gt;"><path id="_Compound_Path_" data-name="&lt;Compound Path&gt;" class="cls-3" d="M159.274,162.069a4.048,4.048,0,0,1-1.976.444,3.305,3.305,0,0,1-3.365-3.465,4.062,4.062,0,0,1,4.053-4.264,3.084,3.084,0,0,1,3.231,3.21c0,1.666-.933,2.643-1.976,2.643a0.822,0.822,0,0,1-.822-0.977h-0.044a1.744,1.744,0,0,1-1.566.977,1.259,1.259,0,0,1-1.2-1.4,2.621,2.621,0,0,1,2.631-2.631,2.92,2.92,0,0,1,1.189.233l-0.378,2.009c-0.166.845-.033,1.233,0.333,1.244,0.567,0.011,1.2-.744,1.2-2.032A2.545,2.545,0,0,0,157.9,155.3a3.409,3.409,0,0,0-3.331,3.687,2.774,2.774,0,0,0,2.854,3,3.469,3.469,0,0,0,1.677-.389Zm-0.611-4.8a1.806,1.806,0,0,0-2.321,1.92,0.733,0.733,0,0,0,.733.844,1.772,1.772,0,0,0,1.355-1.511Z"/></g></g></g></g><path id="_Compound_Path_2" data-name="&lt;Compound Path&gt;" class="cls-11" d="M107.837,95.989h1.075a0.394,0.394,0,0,0,.394-0.394V94.224a0.394,0.394,0,0,0-.394-0.393h-0.841a0.331,0.331,0,0,1-.308-0.22q-0.045-.118-0.1-0.232A0.331,0.331,0,0,1,107.726,93l0.594-.595a0.394,0.394,0,0,0,0-.557l-0.97-.969a0.394,0.394,0,0,0-.557,0l-0.6.6a0.325,0.325,0,0,1-.359.069c-0.086-.037-0.178-0.074-0.258-0.1a0.324,0.324,0,0,1-.206-0.3V90.3a0.394,0.394,0,0,0-.394-0.394h-1.37a0.394,0.394,0,0,0-.394.394v0.841a0.331,0.331,0,0,1-.22.308q-0.123.046-.244,0.1a0.33,0.33,0,0,1-.374-0.06l-0.6-.593a0.394,0.394,0,0,0-.557,0l-0.966.972a0.394,0.394,0,0,0,0,.557l0.6,0.6a0.325,0.325,0,0,1,.07.359c-0.036.086-.073,0.178-0.1,0.258a0.324,0.324,0,0,1-.3.207l-0.85,0a0.394,0.394,0,0,0-.393.395l0,1.371a0.394,0.394,0,0,0,.395.393l0.841,0a0.332,0.332,0,0,1,.308.22q0.045,0.118.1,0.232a0.331,0.331,0,0,1-.061.374l-0.594.6a0.394,0.394,0,0,0,0,.557l0.971,0.967a0.394,0.394,0,0,0,.557,0l0.6-.6a0.325,0.325,0,0,1,.359-0.069c0.085,0.036.178,0.073,0.257,0.1a0.324,0.324,0,0,1,.207.3v0.85a0.394,0.394,0,0,0,.395.393l1.37,0a0.394,0.394,0,0,0,.393-0.394V98.688a0.331,0.331,0,0,1,.22-0.308q0.118-.044.232-0.1a0.331,0.331,0,0,1,.374.061l0.6,0.594a0.394,0.394,0,0,0,.557,0l0.968-.97a0.394,0.394,0,0,0,0-.557l-0.6-.6a0.326,0.326,0,0,1-.069-0.359C107.742,96.248,107.832,96,107.837,95.989Zm-5.454-1.426a1.942,1.942,0,1,1,1.209,2.16A1.942,1.942,0,0,1,102.383,94.563Z"/><rect class="cls-12" x="95.071" y="3.813" width="86.357" height="28.158" rx="4.055" ry="4.055"/><path class="cls-9" d="M177.373,3.813H99.126a4.055,4.055,0,0,0-4.055,4.055v2.6h86.357v-2.6A4.055,4.055,0,0,0,177.373,3.813Z"/><circle class="cls-4" cx="107.842" cy="21.568" r="6.596"/><rect class="cls-20" x="117.992" y="15.515" width="56.173" height="1.777"/><rect class="cls-20" x="117.992" y="20.688" width="56.173" height="1.777"/><rect class="cls-63" x="117.992" y="25.861" width="21.065" height="1.777"/><circle class="cls-12" cx="102.089" cy="7.142" r="0.844"/><circle class="cls-12" cx="105.754" cy="7.142" r="0.844"/><circle class="cls-12" cx="109.418" cy="7.142" r="0.844"/><rect class="cls-11" x="195.097" y="5.397" width="12.381" height="12.381" rx="2.612" ry="2.612"/><path class="cls-12" d="M198.044,11.956v0.018l1.677,0.55v0.933l-2.685-1.094V11.555l2.685-1.094v0.929Z"/><path class="cls-12" d="M201.015,13.989h-1.036l1.51-4.8h1.036Z"/><path class="cls-12" d="M204.53,11.968V11.95l-1.662-.553v-0.93l2.67,1.094v0.808l-2.67,1.094V12.533Z"/><g id="_Group_29" data-name="&lt;Group&gt;"><path id="_Path_19" data-name="&lt;Path&gt;" class="cls-11" d="M234.8,100.061l-1.255-.836a0.522,0.522,0,0,0-.579,0l-1.255.836a0.242,0.242,0,0,1-.333-0.224v-5.5h3.754v5.5A0.242,0.242,0,0,1,234.8,100.061Z"/><path id="_Path_20" data-name="&lt;Path&gt;" class="cls-19" d="M237.161,96.887l-3.771-1.921a0.251,0.251,0,0,0-.234,0l-3.72,2.018a0.251,0.251,0,0,1-.368-0.26l0.661-4.18a0.251,0.251,0,0,0-.075-0.221l-3.068-2.914a0.251,0.251,0,0,1,.133-0.43l4.18-.663a0.251,0.251,0,0,0,.187-0.14l1.823-3.819a0.251,0.251,0,0,1,.45-0.006l1.922,3.77a0.252,0.252,0,0,0,.191.135l4.2,0.554a0.251,0.251,0,0,1,.145.427l-2.992,2.993a0.251,0.251,0,0,0-.069.223l0.769,4.162A0.251,0.251,0,0,1,237.161,96.887Z"/></g><circle id="_Path_21" data-name="&lt;Path&gt;" class="cls-11" cx="80.277" cy="54.208" r="6.48"/><g id="_Group_30" data-name="&lt;Group&gt;"><polygon id="_Path_22" data-name="&lt;Path&gt;" class="cls-12" points="79.421 56.834 77.17 54.583 78.456 53.297 79.421 54.262 82.099 51.582 83.385 52.868 79.421 56.834"/></g><g id="_Group_31" data-name="&lt;Group&gt;"><polygon id="_Path_23" data-name="&lt;Path&gt;" class="cls-148" points="175.871 139.654 174.156 137.383 177.586 137.383 175.871 139.654"/><polygon id="_Path_24" data-name="&lt;Path&gt;" class="cls-148" points="172.46 139.654 170.745 137.383 174.174 137.383 172.46 139.654"/><polygon id="_Path_25" data-name="&lt;Path&gt;" class="cls-148" points="174.165 145.45 169.048 139.63 179.283 139.63 174.165 145.45"/><polygon id="_Path_26" data-name="&lt;Path&gt;" class="cls-149" points="174.165 145.45 172.46 139.63 175.889 139.63 174.165 145.45"/><polygon id="_Path_27" data-name="&lt;Path&gt;" class="cls-149" points="170.745 137.383 169.048 139.63 172.442 139.63 170.745 137.383"/><polygon id="_Path_28" data-name="&lt;Path&gt;" class="cls-149" points="174.156 137.383 172.46 139.63 175.853 139.63 174.156 137.383"/><polygon id="_Path_29" data-name="&lt;Path&gt;" class="cls-149" points="177.586 137.383 175.889 139.63 179.283 139.63 177.586 137.383"/></g></g></g></g></svg> \ No newline at end of file diff --git a/pagetop/static/bootsier/images/demo-pagetop.svg b/pagetop/static/bootsier/images/demo-pagetop.svg new file mode 100644 index 00000000..08fbbb09 --- /dev/null +++ b/pagetop/static/bootsier/images/demo-pagetop.svg @@ -0,0 +1 @@ +<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 658.099 325.932"><defs><style>.cls-1{fill:none;}.cls-1,.cls-2,.cls-3{stroke:#394599;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.785px;}.cls-2{fill:#fff;}.cls-3{fill:#d3d5f9;}</style></defs><title>details-2</title><line class="cls-1" x1="94.914" y1="299.503" x2="613.96" y2="300.329"/><line class="cls-1" x1="46.984" y1="299.426" x2="73.565" y2="299.469"/><rect class="cls-1" x="308.149" y="170.126" width="139.98" height="128.937" transform="translate(1.267 0.291) rotate(0.091)"/><rect class="cls-2" x="190.277" y="158.431" width="87.839" height="165.138" transform="translate(1.277 0.52) rotate(0.091)"/><rect class="cls-3" x="278.116" y="158.516" width="19.029" height="165.138" transform="translate(1.277 0.435) rotate(0.091)"/><rect class="cls-3" x="208.401" y="174.282" width="19.52" height="21.641" transform="translate(1.188 0.545) rotate(0.091)"/><rect class="cls-3" x="240.651" y="174.333" width="19.52" height="21.641" transform="translate(1.188 0.494) rotate(0.091)"/><rect class="cls-3" x="208.344" y="209.502" width="19.52" height="21.641" transform="translate(1.244 0.546) rotate(0.091)"/><rect class="cls-3" x="240.595" y="209.554" width="19.52" height="21.641" transform="translate(1.244 0.494) rotate(0.091)"/><rect class="cls-2" x="509.427" y="213.189" width="65.247" height="110.871" transform="translate(1.321 0.03) rotate(0.091)"/><rect class="cls-3" x="574.673" y="213.258" width="22.222" height="110.871" transform="translate(1.321 -0.04) rotate(0.091)"/><rect class="cls-3" x="522.877" y="226.25" width="14.499" height="16.075" transform="translate(1.266 0.049) rotate(0.091)"/><rect class="cls-3" x="546.833" y="226.288" width="14.499" height="16.075" transform="translate(1.267 0.01) rotate(0.091)"/><rect class="cls-3" x="522.836" y="252.412" width="14.499" height="16.075" transform="translate(1.308 0.049) rotate(0.091)"/><rect class="cls-3" x="546.791" y="252.45" width="14.499" height="16.075" transform="translate(1.308 0.011) rotate(0.091)"/><polygon class="cls-3" points="387.247 0.926 366.423 0.893 366.395 18.212 376.569 18.229 350.467 60.524 387.152 60.583 423.836 60.641 387.247 0.926"/><rect class="cls-2" x="323.029" y="83.472" width="84.434" height="240.306" transform="translate(1.217 0.311) rotate(0.091)"/><rect class="cls-3" x="407.463" y="83.552" width="16.959" height="240.306" transform="translate(1.218 0.23) rotate(0.091)"/><rect class="cls-3" x="387.427" y="59.705" width="16.959" height="23.815" transform="translate(1.007 0.262) rotate(0.091)"/><line class="cls-1" x1="344.005" y1="306.325" x2="344.238" y2="110.068"/><line class="cls-1" x1="366.016" y1="306.36" x2="366.249" y2="110.104"/><line class="cls-1" x1="388.026" y1="306.395" x2="388.259" y2="110.139"/><rect class="cls-1" x="343.406" y="59.657" width="44.021" height="23.815" transform="translate(1.007 0.311) rotate(0.091)"/><polygon class="cls-2" points="366.423 0.893 329.643 60.491 366.328 60.55 403.012 60.608 366.423 0.893"/><circle class="cls-3" cx="448.084" cy="262.515" r="30.044" transform="translate(185.749 711.073) rotate(-89.909)"/><line class="cls-3" x1="448.879" y1="324.803" x2="448.946" y2="282.984"/><path class="cls-2" d="M494.42,182.269s-23.679,65.633-23.714,87.644,7.521,35.734,23.517,35.76,23.6-13.674,23.631-35.685S494.42,182.269,494.42,182.269Z" transform="translate(0.893 0.893)"/><line class="cls-3" x1="495.087" y1="324.876" x2="495.154" y2="283.057"/><polyline class="cls-1" points="165.563 324.351 165.637 277.665 165.679 251.296"/><path class="cls-2" d="M137.45,245.293a10.134,10.134,0,0,0-10.15,10.118l20.268,0.032A10.134,10.134,0,0,0,137.45,245.293Z" transform="translate(0.893 0.893)"/><path class="cls-3" d="M137.418,265.561a10.134,10.134,0,0,0,10.15-10.118l-20.268-.032A10.134,10.134,0,0,0,137.418,265.561Z" transform="translate(0.893 0.893)"/><path class="cls-2" d="M192.139,245.38a10.134,10.134,0,0,0-10.15,10.118l20.268,0.032A10.134,10.134,0,0,0,192.139,245.38Z" transform="translate(0.893 0.893)"/><path class="cls-3" d="M192.107,265.648a10.134,10.134,0,0,0,10.15-10.118l-20.268-.032A10.134,10.134,0,0,0,192.107,265.648Z" transform="translate(0.893 0.893)"/><path class="cls-2" d="M164.822,228.306a10.134,10.134,0,0,0-10.15,10.118l20.268,0.032A10.134,10.134,0,0,0,164.822,228.306Z" transform="translate(0.893 0.893)"/><path class="cls-3" d="M164.789,248.573a10.134,10.134,0,0,0,10.15-10.118l-20.268-.032A10.134,10.134,0,0,0,164.789,248.573Z" transform="translate(0.893 0.893)"/><path class="cls-1" d="M164.738,281.089l-17.211-.027c-7.889-.013-10.127-4.457-10.109-15.5" transform="translate(0.893 0.893)"/><path class="cls-1" d="M164.738,281.089l17.211,0.027c7.889,0.013,10.141-4.424,10.159-15.468" transform="translate(0.893 0.893)"/><rect class="cls-2" x="221.7" y="277.478" width="28.542" height="27.784" transform="translate(1.357 0.517) rotate(0.091)"/><rect class="cls-3" x="250.241" y="277.508" width="9.76" height="27.784" transform="translate(1.357 0.487) rotate(0.091)"/><line class="cls-2" x1="222.57" y1="306.131" x2="222.541" y2="324.442"/><line class="cls-2" x1="251.112" y1="306.177" x2="251.083" y2="324.488"/><line class="cls-2" x1="232.914" y1="306.148" x2="232.885" y2="324.459"/><line class="cls-2" x1="260.872" y1="306.192" x2="260.843" y2="324.503"/><path class="cls-2" d="M94.33,104.534l85.772,0.137S137.287,60.491,94.33,104.534Z" transform="translate(0.893 0.893)"/><path class="cls-3" d="M143.962,104.613l85.772,0.137S186.918,60.57,143.962,104.613Z" transform="translate(0.893 0.893)"/><path class="cls-2" d="M504.1,139.769l85.772,0.137S547.053,95.726,504.1,139.769Z" transform="translate(0.893 0.893)"/><path class="cls-3" d="M552.726,139.847l60.625,0.1S583.089,108.716,552.726,139.847Z" transform="translate(0.893 0.893)"/><line class="cls-1" x1="657.207" y1="325.04" x2="0.893" y2="325.04"/></svg> \ No newline at end of file diff --git a/pagetop/static/bootsier/images/demo-visiting.svg b/pagetop/static/bootsier/images/demo-visiting.svg new file mode 100644 index 00000000..d06680b3 --- /dev/null +++ b/pagetop/static/bootsier/images/demo-visiting.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 698.629 654.126"><defs><style>.cls-1{isolation:isolate;}.cls-2,.cls-6{fill:#e1e2fe;}.cls-2,.cls-4{opacity:0.5;}.cls-10,.cls-3{opacity:0.66;}.cls-5{fill:#c9ccf7;}.cls-7{fill:#3e479b;}.cls-8{opacity:0.81;}.cls-10,.cls-9{fill:#fff;}.cls-11{fill:#ea8b9b;opacity:0.39;}.cls-12{fill:#f7a9b4;}.cls-13{fill:#e58898;}.cls-14{fill:#ccc;}.cls-15{fill:#6c63ff;}.cls-16{fill:#9e9eef;}.cls-17{fill:#db7183;}.cls-18{fill:#599af2;}.cls-19{fill:#293d7c;}.cls-20{fill:#1a2b63;}.cls-21{fill:#445ea0;}.cls-22{fill:#69cdff;}.cls-23{fill:#52bbef;}.cls-24{fill:#d9eafc;}.cls-25{opacity:0.12;mix-blend-mode:multiply;}.cls-26,.cls-27,.cls-28{fill:none;stroke-linecap:round;stroke-miterlimit:10;}.cls-26,.cls-28{stroke:#9e9eef;}.cls-26{stroke-width:2px;}.cls-27{stroke:#f7a9b4;}.cls-27,.cls-28{stroke-width:1.311px;}.cls-28{stroke-dasharray:3 6;}</style></defs><title>details-1</title><g class="cls-1"><g id="Layer_1" data-name="Layer 1"><path class="cls-2" d="M650.949,632.81s-55.6,48.672-145.533-1.079S393.365,529.949,275.74,537.814s-143.365,26.7-218.732-30.089-72.48-175.274-12.056-239c33.01-34.808,67.739-44.639,104.007-51.425,6.314-1.18,12.674-2.27,19.078-3.382,15.629-2.708,31.527-5.562,47.683-10.224a219.368,219.368,0,0,0,25.954-9.236c0.258-.112.517-0.213,0.775-0.337,7.348-3.191,14.539-6.809,21.527-10.707,5.067-2.82,10.033-5.8,14.865-8.876,0.663-.416,1.326-0.843,1.977-1.27,7.719-4.989,15.112-10.247,22.1-15.572,7.314-5.562,14.179-11.191,20.527-16.7A432.8,432.8,0,0,0,369.77,94.574S443.228-29,557.459,6.365,690.071,122.731,664.218,211.1,638.792,351.912,666.6,416.842C694.431,481.772,728.609,567.206,650.949,632.81Z"/><g class="cls-3"><g class="cls-4"><path class="cls-5" d="M266.019,199.966l-11.96-.92a61.036,61.036,0,0,0-3.62-15.39c-0.13-.36-0.27-0.72-0.41-1.08-0.44.73-.89,1.47-1.35,2.21-3.52,5.7-7.36,11.59-11.51,17.52a42.5,42.5,0,0,1-.02,6.48,44.8,44.8,0,0,1-41.91,41.31,193.288,193.288,0,0,1-19.49,14.88c0.37,0.11.74,0.21,1.12,0.31l-0.91,11.96a10.991,10.991,0,0,0,10.13,11.8c0.29,0.02.58,0.03,0.86,0.03a11,11,0,0,0,10.94-10.16l0.91-11.95a61.627,61.627,0,0,0,25-8.19l7.81,9.1a11,11,0,0,0,16.7-14.33l-7.81-9.1a61.529,61.529,0,0,0,11.88-23.46l11.96,0.91a11.007,11.007,0,0,0,11.81-10.13c0.02-.28.03-0.57,0.03-0.84A11,11,0,0,0,266.019,199.966Z"/></g><g class="cls-4"><path class="cls-6" d="M254.969,166.246l-9.1,7.81a60.468,60.468,0,0,1,4.16,8.52c-0.44.73-.89,1.47-1.35,2.21-4.3,2.74-8.72,5.39-13.23,7.9a44.81,44.81,0,1,0-85.39,27.15c-5.7.99-11.36,1.96-16.98,3.01a61.354,61.354,0,0,1-2.19-11.14l-11.95-.91a11,11,0,0,1-10.16-10.94c0-.28.01-0.57,0.03-0.86a10.985,10.985,0,0,1,11.8-10.13l11.96,0.91a61.449,61.449,0,0,1,11.89-23.47l-7.81-9.1a11,11,0,1,1,16.69-14.32l7.81,9.1a61.525,61.525,0,0,1,25-8.19l0.91-11.96a11.006,11.006,0,0,1,10.96-10.16q0.42,0,.84.03a11,11,0,0,1,10.13,11.81l-0.91,11.95a61.733,61.733,0,0,1,23.47,11.89l9.1-7.81A11,11,0,0,1,254.969,166.246Z"/></g><g class="cls-4"><path class="cls-5" d="M195.239,250.1a193.288,193.288,0,0,1-19.49,14.88,61.382,61.382,0,0,1-22.34-11.58l-9.11,7.81a11,11,0,0,1-14.32-16.69l9.1-7.81a61.3,61.3,0,0,1-6-13.86c5.62-1.05,11.28-2.02,16.98-3.01a44.771,44.771,0,0,0,39,30.22A44.016,44.016,0,0,0,195.239,250.1Z"/></g><g class="cls-4"><path class="cls-5" d="M248.679,184.786c-3.52,5.7-7.36,11.59-11.51,17.52a44.473,44.473,0,0,0-1.72-9.62C239.959,190.176,244.379,187.526,248.679,184.786Z"/></g><path class="cls-7" d="M521.5,537.152a9.178,9.178,0,0,1-8.725-6.4l-2.148-6.783a43.972,43.972,0,0,1-16.435-1.417l-3.278,6.315a9.164,9.164,0,1,1-16.268-8.443l3.277-6.315A44.02,44.02,0,0,1,467.3,501.482l-6.783,2.148a9.164,9.164,0,1,1-5.533-17.473l6.783-2.148a44.012,44.012,0,0,1,1.417-16.437l-6.315-3.278a9.164,9.164,0,0,1,8.443-16.268l6.315,3.278a44.07,44.07,0,0,1,12.625-10.62L482.1,433.9a9.164,9.164,0,1,1,17.473-5.533l2.148,6.783a43.951,43.951,0,0,1,16.437,1.417l3.278-6.317a9.165,9.165,0,0,1,16.268,8.444l-3.278,6.314a44.054,44.054,0,0,1,10.62,12.626l6.783-2.148a9.164,9.164,0,1,1,5.532,17.473l-6.783,2.148a44.012,44.012,0,0,1-1.417,16.437l6.317,3.277a9.165,9.165,0,1,1-8.445,16.268l-6.314-3.276A44.066,44.066,0,0,1,528.1,518.434l2.148,6.783A9.18,9.18,0,0,1,521.5,537.152Zm-8.761-16.472,2.9,9.163a6.16,6.16,0,0,0,11.744-3.72l-2.9-9.162,1.112-.586a41.165,41.165,0,0,0,13.534-11.383L539.89,504l8.531,4.426a6.159,6.159,0,0,0,5.674-10.933l-8.531-4.427,0.373-1.2a41.151,41.151,0,0,0,1.52-17.618L547.294,473l9.163-2.9a6.159,6.159,0,0,0-3.718-11.744l-9.162,2.9-0.586-1.112a41.139,41.139,0,0,0-11.385-13.534l-1-.766,4.428-8.531a6.159,6.159,0,0,0-10.933-5.674l-4.428,8.531-1.2-.373a41.2,41.2,0,0,0-17.618-1.52l-1.247.163-2.9-9.163a6.16,6.16,0,1,0-11.744,3.72l2.9,9.16-1.112.585a41.168,41.168,0,0,0-13.533,11.385l-0.766,1-8.532-4.428a6.158,6.158,0,1,0-5.673,10.933l8.529,4.428-0.373,1.2a41.149,41.149,0,0,0-1.52,17.618l0.163,1.247-9.163,2.9a6.16,6.16,0,0,0,3.72,11.744l9.162-2.9,0.585,1.112a41.148,41.148,0,0,0,11.383,13.533l0.995,0.766-4.425,8.532a6.159,6.159,0,0,0,10.933,5.673l4.428-8.53,1.2,0.373a41.2,41.2,0,0,0,17.617,1.52Zm-6.6-8.389a32.809,32.809,0,1,1,9.915-1.542A32.572,32.572,0,0,1,506.136,512.292Zm0.072-62.458a29.76,29.76,0,1,0,13.652,3.354A29.792,29.792,0,0,0,506.208,449.834Z"/><path class="cls-7" d="M600.4,481.063a11.813,11.813,0,0,1-11.684-13.5l1.435-9.881a58.753,58.753,0,0,1-19.6-11.664l-8,5.971a11.8,11.8,0,0,1-14.114-18.914l8-5.971A58.719,58.719,0,0,1,550.83,405l-9.879-1.437a11.8,11.8,0,1,1,3.391-23.354l9.882,1.435a58.7,58.7,0,0,1,11.664-19.6l-5.972-8a11.8,11.8,0,1,1,18.914-14.116l5.972,8a58.736,58.736,0,0,1,22.1-5.607l1.436-9.879a11.8,11.8,0,1,1,23.354,3.391l-1.435,9.882a58.706,58.706,0,0,1,19.6,11.664l8-5.972a11.8,11.8,0,1,1,14.114,18.914l-8,5.972a58.712,58.712,0,0,1,5.607,22.1l9.881,1.437a11.8,11.8,0,1,1-3.392,23.354l-9.881-1.435a58.729,58.729,0,0,1-11.664,19.6l5.97,8a11.8,11.8,0,1,1-18.914,14.114l-5.97-8a58.729,58.729,0,0,1-22.1,5.607l-1.436,9.881A11.819,11.819,0,0,1,600.4,481.063ZM570.76,442.116l0.918,0.858a55.831,55.831,0,0,0,20.611,12.271l1.192,0.4L591.686,468a8.8,8.8,0,1,0,17.408,2.53l1.794-12.356,1.256-.041a55.814,55.814,0,0,0,23.251-5.9l1.124-.562,7.467,10.006a8.794,8.794,0,1,0,14.1-10.521l-7.466-10.005,0.858-.919a55.812,55.812,0,0,0,12.271-20.611l0.4-1.192L676.5,420.22a8.8,8.8,0,1,0,2.53-17.408l-12.356-1.794-0.041-1.256a55.8,55.8,0,0,0-5.9-23.25l-0.562-1.124,10-7.469a8.794,8.794,0,0,0-10.521-14.095h0l-10.006,7.467-0.918-.858a55.79,55.79,0,0,0-20.611-12.271l-1.192-.4,1.795-12.355a8.8,8.8,0,0,0-17.408-2.528l-1.794,12.355-1.256.041a55.819,55.819,0,0,0-23.25,5.9l-1.124.562-7.469-10a8.794,8.794,0,0,0-14.1,10.521l7.467,10-0.858.918a55.786,55.786,0,0,0-12.271,20.611l-0.4,1.191-12.355-1.794a8.8,8.8,0,0,0-2.528,17.408l12.355,1.795,0.041,1.256a55.813,55.813,0,0,0,5.9,23.251l0.562,1.124-10.007,7.467a8.795,8.795,0,1,0,10.522,14.095Zm39.5,3.024a43.414,43.414,0,1,1,25.936-8.612h0A43.229,43.229,0,0,1,610.258,445.14Zm-0.139-83.894a40.453,40.453,0,1,0,24.28,72.873h0a40.449,40.449,0,0,0-18.38-72.444A41.088,41.088,0,0,0,610.119,361.246ZM635.3,435.324h0Z"/></g><g class="cls-8"><path class="cls-9" d="M406.124,487.112H375.259a1.5,1.5,0,0,1,0-3.005h30.865A1.5,1.5,0,0,1,406.124,487.112Z"/><path class="cls-9" d="M406.124,519.2H375.259a1.5,1.5,0,0,1,0-3.005h30.865A1.5,1.5,0,0,1,406.124,519.2Z"/><path class="cls-9" d="M429.424,551.6H238.8a4.078,4.078,0,0,1-4.074-4.073V448.585a4.079,4.079,0,0,1,4.074-4.075H429.424a4.08,4.08,0,0,1,4.075,4.075v98.939A4.079,4.079,0,0,1,429.424,551.6ZM238.8,447.515a1.071,1.071,0,0,0-1.069,1.07v98.939a1.07,1.07,0,0,0,1.069,1.068H429.424a1.071,1.071,0,0,0,1.07-1.068V448.585a1.071,1.071,0,0,0-1.07-1.07H238.8Z"/><path class="cls-10" d="M429.424,551.6H238.8a4.078,4.078,0,0,1-4.074-4.073V448.585a4.079,4.079,0,0,1,4.074-4.075H429.424a4.08,4.08,0,0,1,4.075,4.075v98.939A4.079,4.079,0,0,1,429.424,551.6ZM238.8,447.515a1.071,1.071,0,0,0-1.069,1.07v98.939a1.07,1.07,0,0,0,1.069,1.068H429.424a1.071,1.071,0,0,0,1.07-1.068V448.585a1.071,1.071,0,0,0-1.07-1.07H238.8Z"/><path class="cls-9" d="M406.124,471.543H259.043a1.5,1.5,0,0,1,0-3.005H406.124A1.5,1.5,0,0,1,406.124,471.543Z"/><path class="cls-9" d="M406.124,502.683H259.043a1.5,1.5,0,0,1,0-3.005H406.124A1.5,1.5,0,0,1,406.124,502.683Z"/><path class="cls-9" d="M338.34,487.112h-79.3a1.5,1.5,0,0,1,0-3.005h79.3A1.5,1.5,0,0,1,338.34,487.112Z"/><path class="cls-9" d="M338.34,519.2h-79.3a1.5,1.5,0,0,1,0-3.005h79.3A1.5,1.5,0,0,1,338.34,519.2Z"/><path class="cls-9" d="M312.521,534.061H259.043a1.5,1.5,0,0,1,0-3.005h53.478A1.5,1.5,0,0,1,312.521,534.061Z"/></g><g class="cls-8"><path class="cls-9" d="M110.813,390.912H76.122a1.5,1.5,0,0,1,0-3.005h34.691A1.5,1.5,0,0,1,110.813,390.912Z"/><path class="cls-9" d="M110.813,354.852H76.122a1.5,1.5,0,1,1,0-3.005h34.691A1.5,1.5,0,1,1,110.813,354.852Z"/><path class="cls-9" d="M264.5,435.417H49.615a4.079,4.079,0,0,1-4.074-4.075V319.5a4.079,4.079,0,0,1,4.074-4.075H264.5a4.079,4.079,0,0,1,4.074,4.075V431.343A4.079,4.079,0,0,1,264.5,435.417ZM49.615,318.434a1.071,1.071,0,0,0-1.069,1.07V431.343a1.071,1.071,0,0,0,1.069,1.07H264.5a1.071,1.071,0,0,0,1.069-1.07V319.5a1.071,1.071,0,0,0-1.069-1.07H49.615Z"/><path class="cls-10" d="M264.5,435.417H49.615a4.079,4.079,0,0,1-4.074-4.075V319.5a4.079,4.079,0,0,1,4.074-4.075H264.5a4.079,4.079,0,0,1,4.074,4.075V431.343A4.079,4.079,0,0,1,264.5,435.417ZM49.615,318.434a1.071,1.071,0,0,0-1.069,1.07V431.343a1.071,1.071,0,0,0,1.069,1.07H264.5a1.071,1.071,0,0,0,1.069-1.07V319.5a1.071,1.071,0,0,0-1.069-1.07H49.615Z"/><path class="cls-9" d="M241.431,408.412H76.122a1.5,1.5,0,1,1,0-3.005h165.31A1.5,1.5,0,1,1,241.431,408.412Z"/><path class="cls-9" d="M241.431,373.412H76.122a1.5,1.5,0,0,1,0-3.005h165.31A1.5,1.5,0,0,1,241.431,373.412Z"/><path class="cls-9" d="M241.431,390.912H152.307a1.5,1.5,0,0,1,0-3.005h89.125A1.5,1.5,0,0,1,241.431,390.912Z"/><path class="cls-9" d="M241.431,354.852H152.307a1.5,1.5,0,0,1,0-3.005h89.125A1.5,1.5,0,1,1,241.431,354.852Z"/><path class="cls-9" d="M241.431,338.146H181.326a1.5,1.5,0,0,1,0-3.005h60.106A1.5,1.5,0,0,1,241.431,338.146Z"/></g><path class="cls-11" d="M554.7,549.817H177.169A13.907,13.907,0,0,1,163.28,535.2l13.27-259.122a13.907,13.907,0,0,1,13.888-13.2h45.819a13.907,13.907,0,0,1,7.982,2.519l51.293,35.953a13.907,13.907,0,0,0,7.982,2.519H567.731a13.907,13.907,0,0,1,13.882,14.736L568.58,536.739A13.907,13.907,0,0,1,554.7,549.817Z"/><path class="cls-12" d="M575.139,209.076a17.555,17.555,0,0,1-.77,5.16,0.048,0.048,0,0,0-.01.04l-1.16,2.8L472.959,460.5a3.352,3.352,0,0,1-4.37,1.82l-234.24-96.47a3.341,3.341,0,0,1-1.81-4.36l100.5-244.02,0.7-1.71a0.145,0.145,0,0,0,.02-0.04,17.492,17.492,0,0,1,19.87-9.41l4.95,2.04,203.61,83.84,4.15,1.72a3.846,3.846,0,0,1,.39.22A17.49,17.49,0,0,1,575.139,209.076Z"/><path class="cls-13" d="M389.072,229.757l-58.1-23.926a3.011,3.011,0,0,1-1.636-3.927l23.926-58.1a3.011,3.011,0,0,1,3.927-1.636l58.1,23.926a3.011,3.011,0,0,1,1.636,3.927L393,228.121A3.011,3.011,0,0,1,389.072,229.757Z"/><path class="cls-9" d="M500.972,309.092L319.267,234.261a3.008,3.008,0,1,1,2.291-5.562h0L503.263,303.53a3.008,3.008,0,0,1-2.291,5.562h0Z"/><path class="cls-9" d="M449.2,310.18l-137.824-56.76a3.008,3.008,0,0,1,2.291-5.562h0l137.824,56.76A3.008,3.008,0,1,1,449.2,310.18Z"/><path class="cls-9" d="M529.37,238.381l-80.346-33.089a3.008,3.008,0,1,1,2.291-5.562h0l80.346,33.089a3.008,3.008,0,0,1-2.291,5.562h0Z"/><path class="cls-9" d="M501.428,249.282l-60.294-24.831a3.008,3.008,0,1,1,2.291-5.562l60.294,24.831a3.008,3.008,0,1,1-2.291,5.562h0Z"/><path class="cls-9" d="M485.192,347.411L303.487,272.58a3.008,3.008,0,0,1,2.291-5.562h0l181.705,74.831a3.008,3.008,0,0,1-2.291,5.562h0Z"/><path class="cls-9" d="M433.42,348.5L295.6,291.739a3.008,3.008,0,0,1,2.291-5.562h0l137.824,56.76a3.008,3.008,0,1,1-2.291,5.562h0Z"/><path class="cls-9" d="M469.411,385.73L287.706,310.9A3.008,3.008,0,0,1,290,305.336L471.7,380.168A3.008,3.008,0,0,1,469.411,385.73Z"/><path class="cls-14" d="M461.52,404.889L279.815,330.058a3.008,3.008,0,0,1,2.291-5.562l181.705,74.831a3.008,3.008,0,0,1-2.291,5.562h0Z"/><path class="cls-15" d="M372.876,403.466a65.513,65.513,0,0,0,10.9-.333c3.258-.381,6.652-0.905,9.508-2.618a9.036,9.036,0,0,0,4.5-6.833,6.359,6.359,0,0,0-3.848-6.448,7.586,7.586,0,0,0-7.7,1.078,10.023,10.023,0,0,0-3.442,8.006c0.15,6.191,5.048,12.3,10.487,14.88,6.126,2.9,14.492.436,16.061-6.707,0.326-1.486-1.7-2-2.543-1.047a6.745,6.745,0,0,0,9.414,9.628l-2.277-.938a16.234,16.234,0,0,0,11.166,11.793,15.058,15.058,0,0,0,4.155.633c1.711,0,3.468.863,5.1,1.4l11.79,3.841c1.734,0.565,2.835-2.068,1.086-2.637l-10.678-3.479c-1.779-.58-3.555-1.175-5.339-1.739-1.276-.4-2.672-0.185-4-0.422a13.371,13.371,0,0,1-10.456-9.78,1.443,1.443,0,0,0-2.277-.938,3.9,3.9,0,0,1-5.431-5.61l-2.543-1.047c-1.012,4.608-6.633,6.337-10.684,5a16.185,16.185,0,0,1-9.775-10.367,8.361,8.361,0,0,1,.608-6.653,4.983,4.983,0,0,1,5.221-2.557,3.575,3.575,0,0,1,3.055,3.921,6.4,6.4,0,0,1-3.561,4.845c-2.55,1.369-5.6,1.709-8.435,2.02a60.944,60.944,0,0,1-9.725.277c-1.821-.092-2.186,2.739-0.346,2.832h0Z"/><path class="cls-16" d="M567.8,337.351V535.673a14.143,14.143,0,0,1-14.143,14.143H176.675a14.143,14.143,0,0,1-14.143-14.143V296.36a14.143,14.143,0,0,1,14.143-14.143h44.813a14.143,14.143,0,0,1,8.118,2.562l51.168,35.867a14.143,14.143,0,0,0,8.118,2.562H553.655A14.143,14.143,0,0,1,567.8,337.351Z"/><rect class="cls-7" x="187.281" y="507.279" width="165.51" height="13.148" rx="6.574" ry="6.574"/><rect class="cls-7" x="187.281" y="481.757" width="82.755" height="13.148" rx="6.574" ry="6.574"/><path class="cls-17" d="M408.686,229.522L350.59,205.6a3.346,3.346,0,0,1-1.818-4.363l23.926-58.1a3.346,3.346,0,0,1,4.363-1.818l58.1,23.926a3.346,3.346,0,0,1,1.818,4.363l-23.926,58.1A3.346,3.346,0,0,1,408.686,229.522Zm-32.134-86.966a2.007,2.007,0,0,0-2.618,1.091l-23.926,58.1a2.007,2.007,0,0,0,1.091,2.618l58.1,23.926a2.007,2.007,0,0,0,2.618-1.091l23.926-58.1a2.007,2.007,0,0,0-1.09-2.618Z"/><path class="cls-18" d="M568.856,465.353l-25.865,26.528,46.921,48.495a18.371,18.371,0,0,0,26.4-.044l0.258-.266a18.305,18.305,0,0,0-.049-25.452Z"/><path class="cls-19" d="M581.977,463.212L564.384,445.62a104.094,104.094,0,0,1-42.425,42.491l17.56,17.559a5.178,5.178,0,0,0,7.3,0l35.155-35.155A5.18,5.18,0,0,0,581.977,463.212Z"/><path class="cls-20" d="M551.568,493.62L536.551,478.6a103.162,103.162,0,0,1-14.593,9.506l17.56,17.559a5.178,5.178,0,0,0,7.3,0l12.049-12.049A5.177,5.177,0,0,1,551.568,493.62Z"/><path class="cls-21" d="M547.759,322.165a105.563,105.563,0,1,1-149.29,0A105.564,105.564,0,0,1,547.759,322.165Z"/><path class="cls-22" d="M525.452,449.146a74.016,74.016,0,1,1,0-104.673A74.015,74.015,0,0,1,525.452,449.146Z"/><path class="cls-23" d="M525.452,449.146a74.505,74.505,0,0,0,7.171-8.32A74.019,74.019,0,0,1,429.1,337.3,74.017,74.017,0,1,0,525.452,449.146Z"/><circle class="cls-24" cx="485.827" cy="347.25" r="12.393"/><circle class="cls-24" cx="511.864" cy="360.129" r="8.779"/><image class="cls-25" width="372" height="116" transform="translate(2.129 319.626)" xlink:href="data:image/png;base64,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"/><path class="cls-9" d="M51.383,342.373H308.264a27.174,27.174,0,0,1,27.174,27.174v0a27.174,27.174,0,0,1-27.174,27.174H51.382a27.173,27.173,0,0,1-27.173-27.173v0a27.174,27.174,0,0,1,27.174-27.174Z"/><path class="cls-18" d="M308.264,396.72H266.483l-0.2-54.347h41.983a27.174,27.174,0,0,1,27.174,27.174h0A27.174,27.174,0,0,1,308.264,396.72Z"/><path class="cls-9" d="M297.69,379.069a11.887,11.887,0,1,1,8.4-3.481A11.9,11.9,0,0,1,297.69,379.069Zm0-20.767a8.881,8.881,0,1,0,8.882,8.881A8.891,8.891,0,0,0,297.69,358.3Z"/><path class="cls-9" d="M314.412,385.509a1.5,1.5,0,0,1-1.062-.44l-9.43-9.43a1.5,1.5,0,1,1,2.125-2.125l9.429,9.43A1.5,1.5,0,0,1,314.412,385.509Z"/><rect class="cls-2" x="48.546" y="362.247" width="194.388" height="14.599" rx="7.299" ry="7.299"/><path class="cls-26" d="M488.844,95.305l10.688,11.957a2.449,2.449,0,0,0,3.652,0l8.861-9.914a2.449,2.449,0,0,1,3.652,0l8.858,9.913a2.449,2.449,0,0,0,3.653,0l8.861-9.914a2.449,2.449,0,0,1,3.652,0l8.865,9.915a2.449,2.449,0,0,0,3.652,0l8.862-9.915a2.449,2.449,0,0,1,3.652,0l8.87,9.917a2.449,2.449,0,0,0,3.651,0l10.7-11.959"/><circle class="cls-27" cx="103.757" cy="502.683" r="19.585"/><circle class="cls-28" cx="329.113" cy="33.96" r="19.585"/></g></g></svg> \ No newline at end of file From b02a92dbb055906df4402329c59e8f2465b836d1 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 27 Mar 2022 13:07:16 +0200 Subject: [PATCH 038/244] =?UTF-8?q?Libera=20la=20versi=C3=B3n=20de=20desar?= =?UTF-8?q?rollo=200.0.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pagetop/Cargo.toml | 2 +- pagetop/src/base/component/block.rs | 8 +-- pagetop/src/base/component/container.rs | 4 +- pagetop/src/base/component/form/button.rs | 20 +++---- pagetop/src/base/component/form/date.rs | 48 ++++++++-------- pagetop/src/base/component/form/form.rs | 12 ++-- pagetop/src/base/component/form/hidden.rs | 12 ++-- pagetop/src/base/component/form/input.rs | 56 +++++++++---------- pagetop/src/base/component/grid/column.rs | 4 +- pagetop/src/base/component/grid/row.rs | 4 +- pagetop/src/base/component/menu.rs | 4 +- pagetop/src/base/module/demopage/mod.rs | 6 +- pagetop/src/html/mod.rs | 8 +-- .../src/html/{optional_attr.rs => optattr.rs} | 10 ++-- .../src/html/{optional_id.rs => optiden.rs} | 6 +- pagetop/src/response/page/page.rs | 22 ++++---- 16 files changed, 113 insertions(+), 113 deletions(-) rename pagetop/src/html/{optional_attr.rs => optattr.rs} (80%) rename pagetop/src/html/{optional_id.rs => optiden.rs} (88%) diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index a260d17f..514ab6e9 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.4" +version = "0.0.5" edition = "2021" authors = [ diff --git a/pagetop/src/base/component/block.rs b/pagetop/src/base/component/block.rs index b857712f..5e5a7159 100644 --- a/pagetop/src/base/component/block.rs +++ b/pagetop/src/base/component/block.rs @@ -3,8 +3,8 @@ use crate::prelude::*; pub struct Block { renderable: fn() -> bool, weight : i8, - id : OptionId, - title : OptionAttr, + id : OptIden, + title : OptAttr, html : Vec<Markup>, template : String, } @@ -15,8 +15,8 @@ impl PageComponent for Block { Block { renderable: always, weight : 0, - id : OptionId::none(), - title : OptionAttr::none(), + id : OptIden::none(), + title : OptAttr::none(), html : Vec::new(), template : "default".to_owned(), } diff --git a/pagetop/src/base/component/container.rs b/pagetop/src/base/component/container.rs index 18d6337a..e76b48b4 100644 --- a/pagetop/src/base/component/container.rs +++ b/pagetop/src/base/component/container.rs @@ -5,7 +5,7 @@ enum ContainerType { Header, Footer, Main, Section, Wrapper } pub struct Container { renderable: fn() -> bool, weight : i8, - id : OptionId, + id : OptIden, container : ContainerType, components: PageContainer, template : String, @@ -17,7 +17,7 @@ impl PageComponent for Container { Container { renderable: always, weight : 0, - id : OptionId::none(), + id : OptIden::none(), container : ContainerType::Wrapper, components: PageContainer::new(), template : "default".to_owned(), diff --git a/pagetop/src/base/component/form/button.rs b/pagetop/src/base/component/form/button.rs index a1975ea4..fa9794f2 100644 --- a/pagetop/src/base/component/form/button.rs +++ b/pagetop/src/base/component/form/button.rs @@ -6,10 +6,10 @@ pub struct Button { renderable : fn() -> bool, weight : i8, button_type: ButtonType, - name : OptionAttr, - value : OptionAttr, - autofocus : OptionAttr, - disabled : OptionAttr, + name : OptAttr, + value : OptAttr, + autofocus : OptAttr, + disabled : OptAttr, template : String, } @@ -20,10 +20,10 @@ impl PageComponent for Button { renderable : always, weight : 0, button_type: ButtonType::Button, - name : OptionAttr::none(), - value : OptionAttr::none(), - autofocus : OptionAttr::none(), - disabled : OptionAttr::none(), + name : OptAttr::none(), + value : OptAttr::none(), + autofocus : OptAttr::none(), + disabled : OptAttr::none(), template : "default".to_owned(), } } @@ -42,14 +42,14 @@ impl PageComponent for Button { ButtonType::Reset => ("reset", "btn btn-primary form-reset" ), ButtonType::Submit => ("submit", "btn btn-primary form-submit") }; - let id_item = match &self.name.option() { + let id = match &self.name.option() { Some(name) => Some(format!("edit-{}", name)), _ => None }; html! { button type=(button_type) - id=[&id_item] + id=[&id] class=(button_class) name=[&self.name.option()] value=[&self.value.option()] diff --git a/pagetop/src/base/component/form/date.rs b/pagetop/src/base/component/form/date.rs index 7f04691b..5e42bc6b 100644 --- a/pagetop/src/base/component/form/date.rs +++ b/pagetop/src/base/component/form/date.rs @@ -3,16 +3,16 @@ use crate::prelude::*; pub struct Date { renderable : fn() -> bool, weight : i8, - name : OptionAttr, - value : OptionAttr, - label : OptionAttr, - placeholder : OptionAttr, - autofocus : OptionAttr, - autocomplete: OptionAttr, - disabled : OptionAttr, - readonly : OptionAttr, - required : OptionAttr, - help_text : OptionAttr, + name : OptAttr, + value : OptAttr, + label : OptAttr, + placeholder : OptAttr, + autofocus : OptAttr, + autocomplete: OptAttr, + disabled : OptAttr, + readonly : OptAttr, + required : OptAttr, + help_text : OptAttr, template : String, } @@ -22,16 +22,16 @@ impl PageComponent for Date { Date { renderable : always, weight : 0, - name : OptionAttr::none(), - value : OptionAttr::none(), - label : OptionAttr::none(), - placeholder : OptionAttr::none(), - autofocus : OptionAttr::none(), - autocomplete: OptionAttr::none(), - disabled : OptionAttr::none(), - readonly : OptionAttr::none(), - required : OptionAttr::none(), - help_text : OptionAttr::none(), + name : OptAttr::none(), + value : OptAttr::none(), + label : OptAttr::none(), + placeholder : OptAttr::none(), + autofocus : OptAttr::none(), + autocomplete: OptAttr::none(), + disabled : OptAttr::none(), + readonly : OptAttr::none(), + required : OptAttr::none(), + help_text : OptAttr::none(), template : "default".to_owned(), } } @@ -45,7 +45,7 @@ impl PageComponent for Date { } fn default_render(&self, _: &mut PageAssets) -> Markup { - let (class_item, id_item) = match self.name.option() { + let (class, id) = match self.name.option() { Some(name) => ( format!("form-item form-item-{} form-type-date", name), Some(format!("edit-{}", name)) @@ -56,9 +56,9 @@ impl PageComponent for Date { ) }; html! { - div class=(class_item) { + div class=(class) { @if self.label.has_value() { - label class="form-label" for=[&id_item] { + label class="form-label" for=[&id] { (self.label.value()) " " @if self.required.has_value() { span @@ -72,7 +72,7 @@ impl PageComponent for Date { } input type="date" - id=[&id_item] + id=[&id] class="form-control" name=[&self.name.option()] value=[&self.value.option()] diff --git a/pagetop/src/base/component/form/form.rs b/pagetop/src/base/component/form/form.rs index e93926a7..385dd369 100644 --- a/pagetop/src/base/component/form/form.rs +++ b/pagetop/src/base/component/form/form.rs @@ -5,10 +5,10 @@ pub enum FormMethod {Get, Post} pub struct Form { renderable: fn() -> bool, weight : i8, - id : OptionId, - action : OptionAttr, + id : OptIden, + action : OptAttr, method : FormMethod, - charset : OptionAttr, + charset : OptAttr, elements : PageContainer, template : String, } @@ -19,10 +19,10 @@ impl PageComponent for Form { Form { renderable: always, weight : 0, - id : OptionId::none(), - action : OptionAttr::none(), + id : OptIden::none(), + action : OptAttr::none(), method : FormMethod::Post, - charset : OptionAttr::some("UTF-8"), + charset : OptAttr::some("UTF-8"), elements : PageContainer::new(), template : "default".to_owned(), } diff --git a/pagetop/src/base/component/form/hidden.rs b/pagetop/src/base/component/form/hidden.rs index b27caf37..b7eca015 100644 --- a/pagetop/src/base/component/form/hidden.rs +++ b/pagetop/src/base/component/form/hidden.rs @@ -2,8 +2,8 @@ use crate::prelude::*; pub struct Hidden { weight : i8, - name : OptionId, - value : OptionAttr, + name : OptIden, + value : OptAttr, } impl PageComponent for Hidden { @@ -11,8 +11,8 @@ impl PageComponent for Hidden { fn new() -> Self { Hidden { weight : 0, - name : OptionId::none(), - value : OptionAttr::none(), + name : OptIden::none(), + value : OptAttr::none(), } } @@ -21,14 +21,14 @@ impl PageComponent for Hidden { } fn default_render(&self, _: &mut PageAssets) -> Markup { - let id_item = match self.name.option() { + let id = match self.name.option() { Some(name) => Some(format!("value-{}", name)), _ => None }; html! { input type="hidden" - id=[&id_item] + id=[&id] name=[&self.name.option()] value=[&self.value.option()]; } diff --git a/pagetop/src/base/component/form/input.rs b/pagetop/src/base/component/form/input.rs index c483c9a9..7622fd08 100644 --- a/pagetop/src/base/component/form/input.rs +++ b/pagetop/src/base/component/form/input.rs @@ -6,19 +6,19 @@ pub struct Input { renderable : fn() -> bool, weight : i8, input_type : InputType, - name : OptionId, - value : OptionAttr, - label : OptionAttr, + name : OptIden, + value : OptAttr, + label : OptAttr, size : Option<u16>, minlength : Option<u16>, maxlength : Option<u16>, - placeholder : OptionAttr, - autofocus : OptionAttr, - autocomplete: OptionAttr, - disabled : OptionAttr, - readonly : OptionAttr, - required : OptionAttr, - help_text : OptionAttr, + placeholder : OptAttr, + autofocus : OptAttr, + autocomplete: OptAttr, + disabled : OptAttr, + readonly : OptAttr, + required : OptAttr, + help_text : OptAttr, template : String, } @@ -29,19 +29,19 @@ impl PageComponent for Input { renderable : always, weight : 0, input_type : InputType::Textfield, - name : OptionId::none(), - value : OptionAttr::none(), - label : OptionAttr::none(), + name : OptIden::none(), + value : OptAttr::none(), + label : OptAttr::none(), size : Some(60), minlength : None, maxlength : Some(128), - placeholder : OptionAttr::none(), - autofocus : OptionAttr::none(), - autocomplete: OptionAttr::none(), - disabled : OptionAttr::none(), - readonly : OptionAttr::none(), - required : OptionAttr::none(), - help_text : OptionAttr::none(), + placeholder : OptAttr::none(), + autofocus : OptAttr::none(), + autocomplete: OptAttr::none(), + disabled : OptAttr::none(), + readonly : OptAttr::none(), + required : OptAttr::none(), + help_text : OptAttr::none(), template : "default".to_owned(), } } @@ -55,7 +55,7 @@ impl PageComponent for Input { } fn default_render(&self, _: &mut PageAssets) -> Markup { - let (input_type, class_type) = match &self.input_type { + let (type_input, type_class) = match &self.input_type { InputType::Email => ("email", "form-type-email"), InputType::Password => ("password", "form-type-password"), InputType::Search => ("search", "form-type-search"), @@ -63,20 +63,20 @@ impl PageComponent for Input { InputType::Textfield => ("text", "form-type-textfield"), InputType::Url => ("url", "form-type-url") }; - let (class_item, id_item) = match &self.name.option() { + let (class, id) = match &self.name.option() { Some(name) => ( - format!("form-item form-item-{} {}", name, class_type), + format!("form-item form-item-{} {}", name, type_class), Some(format!("edit-{}", name)) ), None => ( - format!("form-item {}", class_type), + format!("form-item {}", type_class), None ) }; html! { - div class=(class_item) { + div class=(class) { @if self.label.has_value() { - label class="form-label" for=[&id_item] { + label class="form-label" for=[&id] { (self.label.value()) " " @if self.required.has_value() { span @@ -89,8 +89,8 @@ impl PageComponent for Input { } } input - type=(input_type) - id=[&id_item] + type=(type_input) + id=[&id] class="form-control" name=[&self.name.option()] value=[&self.value.option()] diff --git a/pagetop/src/base/component/grid/column.rs b/pagetop/src/base/component/grid/column.rs index 96463490..8bcfb54f 100644 --- a/pagetop/src/base/component/grid/column.rs +++ b/pagetop/src/base/component/grid/column.rs @@ -3,7 +3,7 @@ use crate::prelude::*; pub struct Column { renderable: fn() -> bool, weight : i8, - id : OptionId, + id : OptIden, components: PageContainer, template : String, } @@ -14,7 +14,7 @@ impl PageComponent for Column { Column { renderable: always, weight : 0, - id : OptionId::none(), + id : OptIden::none(), components: PageContainer::new(), template : "default".to_owned(), } diff --git a/pagetop/src/base/component/grid/row.rs b/pagetop/src/base/component/grid/row.rs index 6aed7d0f..7c94fea6 100644 --- a/pagetop/src/base/component/grid/row.rs +++ b/pagetop/src/base/component/grid/row.rs @@ -3,7 +3,7 @@ use crate::prelude::*; pub struct Row { renderable: fn() -> bool, weight : i8, - id : OptionId, + id : OptIden, columns : PageContainer, template : String, } @@ -14,7 +14,7 @@ impl PageComponent for Row { Row { renderable: always, weight : 0, - id : OptionId::none(), + id : OptIden::none(), columns : PageContainer::new(), template : "default".to_owned(), } diff --git a/pagetop/src/base/component/menu.rs b/pagetop/src/base/component/menu.rs index 10ac8ca5..0f529874 100644 --- a/pagetop/src/base/component/menu.rs +++ b/pagetop/src/base/component/menu.rs @@ -148,7 +148,7 @@ impl MenuItem { pub struct Menu { renderable: fn() -> bool, weight : i8, - id : OptionId, + id : OptIden, items : PageContainer, template : String, } @@ -159,7 +159,7 @@ impl PageComponent for Menu { Menu { renderable: always, weight : 0, - id : OptionId::none(), + id : OptIden::none(), items : PageContainer::new(), template : "default".to_owned(), } diff --git a/pagetop/src/base/module/demopage/mod.rs b/pagetop/src/base/module/demopage/mod.rs index f3d3a903..7fa78181 100644 --- a/pagetop/src/base/module/demopage/mod.rs +++ b/pagetop/src/base/module/demopage/mod.rs @@ -27,7 +27,7 @@ async fn demo() -> app::Result<Markup> { .using_theme("Bootsier") .with_title(l("page_title").as_str()) .add_to("content", hello_world()) - .add_to("content", hello_world2()) + .add_to("content", hello_world_original()) .add_to("content", just_visiting()) .add_to("content", about_pagetop()) .add_to("content", promo_pagetop()) @@ -35,7 +35,7 @@ async fn demo() -> app::Result<Markup> { .render() } -fn hello_world2() -> Container { +fn hello_world() -> Container { Container::header() .add(grid::Row::new() .add_column(grid::Column::new() @@ -76,7 +76,7 @@ fn hello_world2() -> Container { ) } -fn hello_world() -> Chunck { +fn hello_world_original() -> Chunck { Chunck::with(html! { header id="header" class="header" { div class="container" { diff --git a/pagetop/src/html/mod.rs b/pagetop/src/html/mod.rs index 60a9bd82..52f735fe 100644 --- a/pagetop/src/html/mod.rs +++ b/pagetop/src/html/mod.rs @@ -1,8 +1,8 @@ pub use maud::{DOCTYPE, Markup, PreEscaped, html}; -mod optional_id; -pub use optional_id::OptionId; -mod optional_attr; -pub use optional_attr::OptionAttr; +mod optiden; +pub use optiden::OptIden; +mod optattr; +pub use optattr::OptAttr; mod classes; pub use classes::Classes; diff --git a/pagetop/src/html/optional_attr.rs b/pagetop/src/html/optattr.rs similarity index 80% rename from pagetop/src/html/optional_attr.rs rename to pagetop/src/html/optattr.rs index f6b48189..af82751c 100644 --- a/pagetop/src/html/optional_attr.rs +++ b/pagetop/src/html/optattr.rs @@ -1,15 +1,15 @@ -pub struct OptionAttr(Option<String>); +pub struct OptAttr(Option<String>); -impl OptionAttr { +impl OptAttr { pub fn none() -> Self { - OptionAttr(None) + OptAttr(None) } pub fn some(value: &str) -> Self { let value = value.trim(); match value.is_empty() { - true => OptionAttr(None), - false => OptionAttr(Some(value.to_owned())), + true => OptAttr(None), + false => OptAttr(Some(value.to_owned())), } } diff --git a/pagetop/src/html/optional_id.rs b/pagetop/src/html/optiden.rs similarity index 88% rename from pagetop/src/html/optional_id.rs rename to pagetop/src/html/optiden.rs index 678ff5c8..ca10155e 100644 --- a/pagetop/src/html/optional_id.rs +++ b/pagetop/src/html/optiden.rs @@ -1,8 +1,8 @@ -pub struct OptionId(Option<String>); +pub struct OptIden(Option<String>); -impl OptionId { +impl OptIden { pub fn none() -> Self { - OptionId(None) + OptIden(None) } pub fn with_value(&mut self, id: &str) { diff --git a/pagetop/src/response/page/page.rs b/pagetop/src/response/page/page.rs index 1ccb9603..5bd4696a 100644 --- a/pagetop/src/response/page/page.rs +++ b/pagetop/src/response/page/page.rs @@ -1,6 +1,6 @@ use crate::{Lazy, app, trace}; use crate::config::SETTINGS; -use crate::html::{Classes, DOCTYPE, Markup, OptionAttr, html}; +use crate::html::{Classes, DOCTYPE, Markup, OptAttr, html}; use crate::response::page::{PageAssets, PageComponent, PageContainer}; use std::sync::RwLock; @@ -40,10 +40,10 @@ static DEFAULT_DIRECTION: Lazy<Option<String>> = Lazy::new(|| { pub enum TextDirection { Auto, LeftToRight, RightToLeft } pub struct Page<'a> { - language : OptionAttr, - direction : OptionAttr, - title : OptionAttr, - description : OptionAttr, + language : OptAttr, + direction : OptAttr, + title : OptAttr, + description : OptAttr, assets : PageAssets, body_classes: Classes, regions : HashMap<&'a str, PageContainer>, @@ -55,15 +55,15 @@ impl<'a> Page<'a> { pub fn new() -> Self { Page { language : match &*DEFAULT_LANGUAGE { - Some(language) => OptionAttr::some(language), - _ => OptionAttr::none(), + Some(language) => OptAttr::some(language), + _ => OptAttr::none(), }, direction : match &*DEFAULT_DIRECTION { - Some(direction) => OptionAttr::some(direction), - _ => OptionAttr::none(), + Some(direction) => OptAttr::some(direction), + _ => OptAttr::none(), }, - title : OptionAttr::none(), - description : OptionAttr::none(), + title : OptAttr::none(), + description : OptAttr::none(), body_classes: Classes::some_class("body"), assets : PageAssets::new(), regions : COMPONENTS.read().unwrap().clone(), From 2476b2b9c8ff636d6028430fb6bbba3d3054931b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 28 Mar 2022 01:08:22 +0200 Subject: [PATCH 039/244] =?UTF-8?q?Corrige=20el=20r=C3=B3tulo=20de=20inici?= =?UTF-8?q?o=20en=20terminales?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajusta el número de caracteres que se pueden mostrar en el rótulo de inicio según el número de columnas del terminal. Si es menor de 80 columnas mostrará directamente texto. --- pagetop/Cargo.toml | 2 ++ pagetop/src/app/banner/mod.rs | 20 ++++++++++++++++++-- pagetop/src/lib.rs | 8 ++++---- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index 514ab6e9..a4db3d98 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -27,6 +27,8 @@ downcast-rs = "1.2.0" figlet-rs = "0.1.3" futures = "0.3.21" once_cell = "1.10.0" +substring = "1.4.5" +term_size = "0.3.2" url = "2.2.2" config_rs = { package = "config", version = "0.11.0", features = ["toml"] } diff --git a/pagetop/src/app/banner/mod.rs b/pagetop/src/app/banner/mod.rs index f6d63841..1cce7146 100644 --- a/pagetop/src/app/banner/mod.rs +++ b/pagetop/src/app/banner/mod.rs @@ -2,6 +2,7 @@ use crate::Lazy; use crate::config::SETTINGS; use figlet_rs::FIGfont; +use substring::Substring; static FIGFONT: Lazy<FIGfont> = Lazy::new(|| { let slant = include_str!("slant.flf"); @@ -31,8 +32,23 @@ static FIGFONT: Lazy<FIGfont> = Lazy::new(|| { pub fn print_on_startup() { if SETTINGS.app.startup_banner.to_lowercase() != "off" { - println!("\n{} {}\n\n Powered by PageTop {}\n", - FIGFONT.convert(&SETTINGS.app.name).unwrap(), + if let Some((term_width, _)) = term_size::dimensions() { + if term_width >= 80 { + let maxlen = (term_width / 10) - 2; + let mut app = SETTINGS.app.name.substring(0, maxlen).to_owned(); + if SETTINGS.app.name.len() > maxlen { + app = format!("{}...", app); + } + println!("\n{} {}\n\n Powered by PageTop {}\n", + FIGFONT.convert(&app).unwrap(), + &SETTINGS.app.description, + env!("CARGO_PKG_VERSION") + ); + return; + } + } + println!("\n{}\n{}\n\nPowered by PageTop {}\n", + &SETTINGS.app.name, &SETTINGS.app.description, env!("CARGO_PKG_VERSION") ); diff --git a/pagetop/src/lib.rs b/pagetop/src/lib.rs index 73e17c8d..72ab7328 100644 --- a/pagetop/src/lib.rs +++ b/pagetop/src/lib.rs @@ -1,8 +1,8 @@ -// Global. +// Local. -pub use doc_comment::doc_comment; -pub use once_cell::sync::Lazy; -pub use futures::executor::block_on as run_now; +pub(crate) use doc_comment::doc_comment; +pub(crate) use once_cell::sync::Lazy; +pub(crate) use futures::executor::block_on as run_now; // ----------------------------------------------------------------------------- // APIs públicas. From 5aee113f547e93212a977ffbbda00e618660b697 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 28 Mar 2022 21:19:02 +0200 Subject: [PATCH 040/244] =?UTF-8?q?A=C3=B1ade=20el=20tema=20Bulmix=20basad?= =?UTF-8?q?o=20en=20el=20framework=20Bulma?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/default.toml | 1 + pagetop/Cargo.toml | 17 +++--- pagetop/build.rs | 8 +++ pagetop/src/app/application.rs | 1 + pagetop/src/base/component/grid/column.rs | 9 ++- pagetop/src/base/component/grid/row.rs | 9 ++- pagetop/src/base/module/demopage/mod.rs | 2 +- pagetop/src/base/theme/bulmix/mod.rs | 34 +++++++++++ pagetop/src/base/theme/mod.rs | 3 +- pagetop/src/html/classes.rs | 61 +++++++------------ pagetop/src/html/optattr.rs | 13 ++-- pagetop/src/html/optiden.rs | 11 ++-- pagetop/src/lib.rs | 1 + pagetop/src/response/page/page.rs | 9 +-- pagetop/static/bulmix/css/bulma-rtl.min.css | 1 + .../static/bulmix/css/bulma-rtl.min.css.map | 1 + pagetop/static/bulmix/css/bulma.min.css | 1 + pagetop/static/bulmix/css/bulma.min.css.map | 1 + 18 files changed, 113 insertions(+), 70 deletions(-) create mode 100644 pagetop/src/base/theme/bulmix/mod.rs create mode 100644 pagetop/static/bulmix/css/bulma-rtl.min.css create mode 100644 pagetop/static/bulmix/css/bulma-rtl.min.css.map create mode 100644 pagetop/static/bulmix/css/bulma.min.css create mode 100644 pagetop/static/bulmix/css/bulma.min.css.map diff --git a/config/default.toml b/config/default.toml index 13012a93..6d6317f3 100644 --- a/config/default.toml +++ b/config/default.toml @@ -6,6 +6,7 @@ description = """\ #theme = "Aliner" #theme = "Minimal" theme = "Bootsier" +#theme = "Bulmix" language = "es-ES" [database] diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index a4db3d98..01eb60ec 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -22,14 +22,15 @@ categories = [ ] [dependencies] -doc-comment = "0.3.3" -downcast-rs = "1.2.0" -figlet-rs = "0.1.3" -futures = "0.3.21" -once_cell = "1.10.0" -substring = "1.4.5" -term_size = "0.3.2" -url = "2.2.2" +concat-string = "1.0.1" +doc-comment = "0.3.3" +downcast-rs = "1.2.0" +figlet-rs = "0.1.3" +futures = "0.3.21" +once_cell = "1.10.0" +substring = "1.4.5" +term_size = "0.3.2" +url = "2.2.2" config_rs = { package = "config", version = "0.11.0", features = ["toml"] } diff --git a/pagetop/build.rs b/pagetop/build.rs index bd7e60a0..a8c287a8 100644 --- a/pagetop/build.rs +++ b/pagetop/build.rs @@ -27,4 +27,12 @@ fn main() { ) .build() .unwrap(); + + resource_dir("./static/bulmix") + .with_generated_filename( + Path::new(env::var("OUT_DIR").unwrap().as_str()) + .join("bulmix.rs") + ) + .build() + .unwrap(); } diff --git a/pagetop/src/app/application.rs b/pagetop/src/app/application.rs index 070390c8..f0473180 100644 --- a/pagetop/src/app/application.rs +++ b/pagetop/src/app/application.rs @@ -31,6 +31,7 @@ impl Application { theme::register_theme(&base::theme::aliner::AlinerTheme); theme::register_theme(&base::theme::minimal::MinimalTheme); theme::register_theme(&base::theme::bootsier::BootsierTheme); + theme::register_theme(&base::theme::bulmix::BulmixTheme); // Ejecuta la función de inicio de la aplicación. trace::info!("Calling application bootstrap"); diff --git a/pagetop/src/base/component/grid/column.rs b/pagetop/src/base/component/grid/column.rs index 8bcfb54f..19eb577b 100644 --- a/pagetop/src/base/component/grid/column.rs +++ b/pagetop/src/base/component/grid/column.rs @@ -4,6 +4,7 @@ pub struct Column { renderable: fn() -> bool, weight : i8, id : OptIden, + classes : Classes, components: PageContainer, template : String, } @@ -15,6 +16,7 @@ impl PageComponent for Column { renderable: always, weight : 0, id : OptIden::none(), + classes : Classes::some(vec!["col"]), components: PageContainer::new(), template : "default".to_owned(), } @@ -30,7 +32,7 @@ impl PageComponent for Column { fn default_render(&self, assets: &mut PageAssets) -> Markup { html! { - div id=[&self.id.option()] class="col" { + div id=[&self.id.option()] class=[&self.classes.option()] { (self.components.render(assets)) } } @@ -56,6 +58,11 @@ impl Column { self } + pub fn add_classes(mut self, classes: Vec<&str>) -> Self { + self.classes.add_classes(classes); + self + } + pub fn add(mut self, component: impl PageComponent) -> Self { self.components.add(component); self diff --git a/pagetop/src/base/component/grid/row.rs b/pagetop/src/base/component/grid/row.rs index 7c94fea6..53719e3f 100644 --- a/pagetop/src/base/component/grid/row.rs +++ b/pagetop/src/base/component/grid/row.rs @@ -4,6 +4,7 @@ pub struct Row { renderable: fn() -> bool, weight : i8, id : OptIden, + classes : Classes, columns : PageContainer, template : String, } @@ -15,6 +16,7 @@ impl PageComponent for Row { renderable: always, weight : 0, id : OptIden::none(), + classes : Classes::some(vec!["row"]), columns : PageContainer::new(), template : "default".to_owned(), } @@ -30,7 +32,7 @@ impl PageComponent for Row { fn default_render(&self, assets: &mut PageAssets) -> Markup { html! { - div id=[&self.id.option()] class="row" { + div id=[&self.id.option()] class=[&self.classes.option()] { (self.columns.render(assets)) } } @@ -56,6 +58,11 @@ impl Row { self } + pub fn add_classes(mut self, classes: Vec<&str>) -> Self { + self.classes.add_classes(classes); + self + } + pub fn add_column(mut self, column: grid::Column) -> Self { self.columns.add(column); self diff --git a/pagetop/src/base/module/demopage/mod.rs b/pagetop/src/base/module/demopage/mod.rs index 7fa78181..c9fc9cc0 100644 --- a/pagetop/src/base/module/demopage/mod.rs +++ b/pagetop/src/base/module/demopage/mod.rs @@ -24,7 +24,7 @@ impl ModuleTrait for DemopageModule { async fn demo() -> app::Result<Markup> { Page::new() - .using_theme("Bootsier") + .using_theme("Bulmix") .with_title(l("page_title").as_str()) .add_to("content", hello_world()) .add_to("content", hello_world_original()) diff --git a/pagetop/src/base/theme/bulmix/mod.rs b/pagetop/src/base/theme/bulmix/mod.rs new file mode 100644 index 00000000..b8d57ba7 --- /dev/null +++ b/pagetop/src/base/theme/bulmix/mod.rs @@ -0,0 +1,34 @@ +use crate::prelude::*; + +include!(concat!(env!("OUT_DIR"), "/bulmix.rs")); + +pub struct BulmixTheme; + +impl ThemeTrait for BulmixTheme { + fn name(&self) -> &'static str { + "Bulmix" + } + + fn fullname(&self) -> String { + "Bulmix".to_owned() + } + + fn configure_theme(&self, cfg: &mut app::web::ServiceConfig) { + theme_static_files!(cfg, "/bulmix"); + } + + fn before_render_page(&self, page: &mut Page) { + page.assets() + .with_favicon( + Favicon::new() + .with_icon("/theme/favicon.png") + ) + .add_stylesheet( + StyleSheet::source( + "/bulmix/css/bulma.min.css?ver=0.9.3" + ) + .with_weight(-99) + ) + .add_jquery(); + } +} diff --git a/pagetop/src/base/theme/mod.rs b/pagetop/src/base/theme/mod.rs index baccfbd9..293e4e88 100644 --- a/pagetop/src/base/theme/mod.rs +++ b/pagetop/src/base/theme/mod.rs @@ -1,3 +1,4 @@ pub mod aliner; -pub mod bootsier; pub mod minimal; +pub mod bootsier; +pub mod bulmix; diff --git a/pagetop/src/html/classes.rs b/pagetop/src/html/classes.rs index 16c5ac73..c2a35984 100644 --- a/pagetop/src/html/classes.rs +++ b/pagetop/src/html/classes.rs @@ -1,63 +1,48 @@ -pub struct Classes { - classes: Vec<String>, - option : Option<String>, - updated: bool, -} +use crate::concat_string; + +pub struct Classes(Option<String>); impl Classes { pub fn none() -> Self { - Classes { - classes: Vec::new(), - option : None, - updated: true, - } + Classes(None) } - pub fn some_class(class: &str) -> Self { - let mut c = Classes::none(); - c.add_class(class); - c - } - - pub fn some_classes(classes: Vec<String>) -> Self { + pub fn some(classes: Vec<&str>) -> Self { let mut c = Classes::none(); c.add_classes(classes); c } - pub fn add_class(&mut self, class: &str) { - let class = class.trim().replace(" ", "_"); - if !class.is_empty() && !self.classes.iter().any(|c| *c == class) { - self.classes.push(class.to_owned()); - self.updated = false; - } - } - - pub fn add_classes(&mut self, classes: Vec<String>) { + pub fn add_classes(&mut self, classes: Vec<&str>) { for class in classes.iter() { self.add_class(class); } } - pub fn classes(&mut self) -> &str { - match self.option() { + fn add_class(&mut self, class: &str) { + let class = class.trim().replace(" ", "_"); + if !class.is_empty() { + match &self.0 { + None => self.0 = Some(class), + Some(classes) => if !classes.split(" ").any(|c| *c == class) { + self.0 = Some(concat_string!(classes, " ", class)) + } + } + } + } + + pub fn classes(&self) -> &str { + match &self.0 { Some(classes) => classes.as_str(), None => "", } } pub fn has_classes(&self) -> bool { - self.classes.len() > 0 + self.0 != None } - pub fn option(&mut self) -> &Option<String> { - if !self.updated { - self.option = match self.classes.len() { - 0 => None, - _ => Some(self.classes.join(" ")), - }; - self.updated = true; - } - &self.option + pub fn option(&self) -> &Option<String> { + &self.0 } } diff --git a/pagetop/src/html/optattr.rs b/pagetop/src/html/optattr.rs index af82751c..3eed9aab 100644 --- a/pagetop/src/html/optattr.rs +++ b/pagetop/src/html/optattr.rs @@ -6,11 +6,9 @@ impl OptAttr { } pub fn some(value: &str) -> Self { - let value = value.trim(); - match value.is_empty() { - true => OptAttr(None), - false => OptAttr(Some(value.to_owned())), - } + let mut o = OptAttr::none(); + o.with_value(value); + o } pub fn with_value(&mut self, value: &str) { @@ -29,10 +27,7 @@ impl OptAttr { } pub fn has_value(&self) -> bool { - match &self.0 { - Some(_) => true, - None => false, - } + self.0 != None } pub fn option(&self) -> &Option<String> { diff --git a/pagetop/src/html/optiden.rs b/pagetop/src/html/optiden.rs index ca10155e..93caf18a 100644 --- a/pagetop/src/html/optiden.rs +++ b/pagetop/src/html/optiden.rs @@ -5,6 +5,12 @@ impl OptIden { OptIden(None) } + pub fn some(id: &str) -> Self { + let mut o = OptIden::none(); + o.with_value(id); + o + } + pub fn with_value(&mut self, id: &str) { let id = id.trim(); self.0 = match id.is_empty() { @@ -21,10 +27,7 @@ impl OptIden { } pub fn has_value(&self) -> bool { - match &self.0 { - Some(_) => true, - None => false, - } + self.0 != None } pub fn option(&self) -> &Option<String> { diff --git a/pagetop/src/lib.rs b/pagetop/src/lib.rs index 72ab7328..731271d3 100644 --- a/pagetop/src/lib.rs +++ b/pagetop/src/lib.rs @@ -1,5 +1,6 @@ // Local. +pub(crate) use concat_string::concat_string; pub(crate) use doc_comment::doc_comment; pub(crate) use once_cell::sync::Lazy; pub(crate) use futures::executor::block_on as run_now; diff --git a/pagetop/src/response/page/page.rs b/pagetop/src/response/page/page.rs index 5bd4696a..fedf05e4 100644 --- a/pagetop/src/response/page/page.rs +++ b/pagetop/src/response/page/page.rs @@ -64,7 +64,7 @@ impl<'a> Page<'a> { }, title : OptAttr::none(), description : OptAttr::none(), - body_classes: Classes::some_class("body"), + body_classes: Classes::some(vec!["body"]), assets : PageAssets::new(), regions : COMPONENTS.read().unwrap().clone(), template : "default".to_owned(), @@ -97,12 +97,7 @@ impl<'a> Page<'a> { self } - pub fn add_body_class(&mut self, class: &str) -> &mut Self { - self.body_classes.add_class(class); - self - } - - pub fn add_body_classes(&mut self, classes: Vec<String>) -> &mut Self { + pub fn add_body_classes(&mut self, classes: Vec<&str>) -> &mut Self { self.body_classes.add_classes(classes); self } diff --git a/pagetop/static/bulmix/css/bulma-rtl.min.css b/pagetop/static/bulmix/css/bulma-rtl.min.css new file mode 100644 index 00000000..36fa65bc --- /dev/null +++ b/pagetop/static/bulmix/css/bulma-rtl.min.css @@ -0,0 +1 @@ +/*! bulma.io v0.9.3 | MIT License | github.com/jgthms/bulma */.button,.file-cta,.file-name,.input,.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous,.select select,.textarea{-moz-appearance:none;-webkit-appearance:none;align-items:center;border:1px solid transparent;border-radius:4px;box-shadow:none;display:inline-flex;font-size:1rem;height:2.5em;justify-content:flex-start;line-height:1.5;padding-bottom:calc(.5em - 1px);padding-left:calc(.75em - 1px);padding-right:calc(.75em - 1px);padding-top:calc(.5em - 1px);position:relative;vertical-align:top}.button:active,.button:focus,.file-cta:active,.file-cta:focus,.file-name:active,.file-name:focus,.input:active,.input:focus,.is-active.button,.is-active.file-cta,.is-active.file-name,.is-active.input,.is-active.pagination-ellipsis,.is-active.pagination-link,.is-active.pagination-next,.is-active.pagination-previous,.is-active.textarea,.is-focused.button,.is-focused.file-cta,.is-focused.file-name,.is-focused.input,.is-focused.pagination-ellipsis,.is-focused.pagination-link,.is-focused.pagination-next,.is-focused.pagination-previous,.is-focused.textarea,.pagination-ellipsis:active,.pagination-ellipsis:focus,.pagination-link:active,.pagination-link:focus,.pagination-next:active,.pagination-next:focus,.pagination-previous:active,.pagination-previous:focus,.select select.is-active,.select select.is-focused,.select select:active,.select select:focus,.textarea:active,.textarea:focus{outline:0}.button[disabled],.file-cta[disabled],.file-name[disabled],.input[disabled],.pagination-ellipsis[disabled],.pagination-link[disabled],.pagination-next[disabled],.pagination-previous[disabled],.select fieldset[disabled] select,.select select[disabled],.textarea[disabled],fieldset[disabled] .button,fieldset[disabled] .file-cta,fieldset[disabled] .file-name,fieldset[disabled] .input,fieldset[disabled] .pagination-ellipsis,fieldset[disabled] .pagination-link,fieldset[disabled] .pagination-next,fieldset[disabled] .pagination-previous,fieldset[disabled] .select select,fieldset[disabled] .textarea{cursor:not-allowed}.breadcrumb,.button,.file,.is-unselectable,.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous,.tabs{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.navbar-link:not(.is-arrowless)::after,.select:not(.is-multiple):not(.is-loading)::after{border:3px solid transparent;border-radius:2px;border-right:0;border-top:0;content:" ";display:block;height:.625em;margin-top:-.4375em;pointer-events:none;position:absolute;top:50%;transform:rotate(-45deg);transform-origin:center;width:.625em}.block:not(:last-child),.box:not(:last-child),.breadcrumb:not(:last-child),.content:not(:last-child),.level:not(:last-child),.message:not(:last-child),.notification:not(:last-child),.pagination:not(:last-child),.progress:not(:last-child),.subtitle:not(:last-child),.table-container:not(:last-child),.table:not(:last-child),.tabs:not(:last-child),.title:not(:last-child){margin-bottom:1.5rem}.delete,.modal-close{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-moz-appearance:none;-webkit-appearance:none;background-color:rgba(10,10,10,.2);border:none;border-radius:9999px;cursor:pointer;pointer-events:auto;display:inline-block;flex-grow:0;flex-shrink:0;font-size:0;height:20px;max-height:20px;max-width:20px;min-height:20px;min-width:20px;outline:0;position:relative;vertical-align:top;width:20px}.delete::after,.delete::before,.modal-close::after,.modal-close::before{background-color:#fff;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.delete::before,.modal-close::before{height:2px;width:50%}.delete::after,.modal-close::after{height:50%;width:2px}.delete:focus,.delete:hover,.modal-close:focus,.modal-close:hover{background-color:rgba(10,10,10,.3)}.delete:active,.modal-close:active{background-color:rgba(10,10,10,.4)}.is-small.delete,.is-small.modal-close{height:16px;max-height:16px;max-width:16px;min-height:16px;min-width:16px;width:16px}.is-medium.delete,.is-medium.modal-close{height:24px;max-height:24px;max-width:24px;min-height:24px;min-width:24px;width:24px}.is-large.delete,.is-large.modal-close{height:32px;max-height:32px;max-width:32px;min-height:32px;min-width:32px;width:32px}.button.is-loading::after,.control.is-loading::after,.loader,.select.is-loading::after{-webkit-animation:spinAround .5s infinite linear;animation:spinAround .5s infinite linear;border:2px solid #dbdbdb;border-radius:9999px;border-right-color:transparent;border-top-color:transparent;content:"";display:block;height:1em;position:relative;width:1em}.hero-video,.image.is-16by9 .has-ratio,.image.is-16by9 img,.image.is-1by1 .has-ratio,.image.is-1by1 img,.image.is-1by2 .has-ratio,.image.is-1by2 img,.image.is-1by3 .has-ratio,.image.is-1by3 img,.image.is-2by1 .has-ratio,.image.is-2by1 img,.image.is-2by3 .has-ratio,.image.is-2by3 img,.image.is-3by1 .has-ratio,.image.is-3by1 img,.image.is-3by2 .has-ratio,.image.is-3by2 img,.image.is-3by4 .has-ratio,.image.is-3by4 img,.image.is-3by5 .has-ratio,.image.is-3by5 img,.image.is-4by3 .has-ratio,.image.is-4by3 img,.image.is-4by5 .has-ratio,.image.is-4by5 img,.image.is-5by3 .has-ratio,.image.is-5by3 img,.image.is-5by4 .has-ratio,.image.is-5by4 img,.image.is-9by16 .has-ratio,.image.is-9by16 img,.image.is-square .has-ratio,.image.is-square img,.is-overlay,.modal,.modal-background{bottom:0;left:0;position:absolute;right:0;top:0}.navbar-burger{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:0 0;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0}/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */blockquote,body,dd,dl,dt,fieldset,figure,h1,h2,h3,h4,h5,h6,hr,html,iframe,legend,li,ol,p,pre,textarea,ul{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:400}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,::after,::before{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}td:not([align]),th:not([align]){text-align:inherit}html{background-color:#fff;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:hidden;overflow-y:scroll;text-rendering:optimizeLegibility;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%}article,aside,figure,footer,header,hgroup,section{display:block}body,button,input,optgroup,select,textarea{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif}code,pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:monospace}body{color:#4a4a4a;font-size:1em;font-weight:400;line-height:1.5}a{color:#485fc7;cursor:pointer;text-decoration:none}a strong{color:currentColor}a:hover{color:#363636}code{background-color:#f5f5f5;color:#da1039;font-size:.875em;font-weight:400;padding:.25em .5em .25em}hr{background-color:#f5f5f5;border:none;display:block;height:2px;margin:1.5rem 0}img{height:auto;max-width:100%}input[type=checkbox],input[type=radio]{vertical-align:baseline}small{font-size:.875em}span{font-style:inherit;font-weight:inherit}strong{color:#363636;font-weight:700}fieldset{border:none}pre{-webkit-overflow-scrolling:touch;background-color:#f5f5f5;color:#4a4a4a;font-size:.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}table td,table th{vertical-align:top}table td:not([align]),table th:not([align]){text-align:inherit}table th{color:#363636}@-webkit-keyframes spinAround{from{transform:rotate(0)}to{transform:rotate(359deg)}}@keyframes spinAround{from{transform:rotate(0)}to{transform:rotate(359deg)}}.box{background-color:#fff;border-radius:6px;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);color:#4a4a4a;display:block;padding:1.25rem}a.box:focus,a.box:hover{box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px #485fc7}a.box:active{box-shadow:inset 0 1px 2px rgba(10,10,10,.2),0 0 0 1px #485fc7}.button{background-color:#fff;border-color:#dbdbdb;border-width:1px;color:#363636;cursor:pointer;justify-content:center;padding-bottom:calc(.5em - 1px);padding-left:1em;padding-right:1em;padding-top:calc(.5em - 1px);text-align:center;white-space:nowrap}.button strong{color:inherit}.button .icon,.button .icon.is-large,.button .icon.is-medium,.button .icon.is-small{height:1.5em;width:1.5em}.button .icon:first-child:not(:last-child){margin-right:calc(-.5em - 1px);margin-left:.25em}.button .icon:last-child:not(:first-child){margin-right:.25em;margin-left:calc(-.5em - 1px)}.button .icon:first-child:last-child{margin-left:calc(-.5em - 1px);margin-right:calc(-.5em - 1px)}.button.is-hovered,.button:hover{border-color:#b5b5b5;color:#363636}.button.is-focused,.button:focus{border-color:#485fc7;color:#363636}.button.is-focused:not(:active),.button:focus:not(:active){box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.button.is-active,.button:active{border-color:#4a4a4a;color:#363636}.button.is-text{background-color:transparent;border-color:transparent;color:#4a4a4a;text-decoration:underline}.button.is-text.is-focused,.button.is-text.is-hovered,.button.is-text:focus,.button.is-text:hover{background-color:#f5f5f5;color:#363636}.button.is-text.is-active,.button.is-text:active{background-color:#e8e8e8;color:#363636}.button.is-text[disabled],fieldset[disabled] .button.is-text{background-color:transparent;border-color:transparent;box-shadow:none}.button.is-ghost{background:0 0;border-color:transparent;color:#485fc7;text-decoration:none}.button.is-ghost.is-hovered,.button.is-ghost:hover{color:#485fc7;text-decoration:underline}.button.is-white{background-color:#fff;border-color:transparent;color:#0a0a0a}.button.is-white.is-hovered,.button.is-white:hover{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.button.is-white.is-focused,.button.is-white:focus{border-color:transparent;color:#0a0a0a}.button.is-white.is-focused:not(:active),.button.is-white:focus:not(:active){box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.button.is-white.is-active,.button.is-white:active{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.button.is-white[disabled],fieldset[disabled] .button.is-white{background-color:#fff;border-color:transparent;box-shadow:none}.button.is-white.is-inverted{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted.is-hovered,.button.is-white.is-inverted:hover{background-color:#000}.button.is-white.is-inverted[disabled],fieldset[disabled] .button.is-white.is-inverted{background-color:#0a0a0a;border-color:transparent;box-shadow:none;color:#fff}.button.is-white.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-white.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-white.is-outlined.is-focused,.button.is-white.is-outlined.is-hovered,.button.is-white.is-outlined:focus,.button.is-white.is-outlined:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.button.is-white.is-outlined.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-white.is-outlined.is-loading.is-focused::after,.button.is-white.is-outlined.is-loading.is-hovered::after,.button.is-white.is-outlined.is-loading:focus::after,.button.is-white.is-outlined.is-loading:hover::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-white.is-outlined[disabled],fieldset[disabled] .button.is-white.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-white.is-inverted.is-outlined.is-focused,.button.is-white.is-inverted.is-outlined.is-hovered,.button.is-white.is-inverted.is-outlined:focus,.button.is-white.is-inverted.is-outlined:hover{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-white.is-inverted.is-outlined.is-loading:focus::after,.button.is-white.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-white.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black{background-color:#0a0a0a;border-color:transparent;color:#fff}.button.is-black.is-hovered,.button.is-black:hover{background-color:#040404;border-color:transparent;color:#fff}.button.is-black.is-focused,.button.is-black:focus{border-color:transparent;color:#fff}.button.is-black.is-focused:not(:active),.button.is-black:focus:not(:active){box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.button.is-black.is-active,.button.is-black:active{background-color:#000;border-color:transparent;color:#fff}.button.is-black[disabled],fieldset[disabled] .button.is-black{background-color:#0a0a0a;border-color:transparent;box-shadow:none}.button.is-black.is-inverted{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted.is-hovered,.button.is-black.is-inverted:hover{background-color:#f2f2f2}.button.is-black.is-inverted[disabled],fieldset[disabled] .button.is-black.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#0a0a0a}.button.is-black.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-black.is-outlined.is-focused,.button.is-black.is-outlined.is-hovered,.button.is-black.is-outlined:focus,.button.is-black.is-outlined:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.button.is-black.is-outlined.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-black.is-outlined.is-loading.is-focused::after,.button.is-black.is-outlined.is-loading.is-hovered::after,.button.is-black.is-outlined.is-loading:focus::after,.button.is-black.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-black.is-outlined[disabled],fieldset[disabled] .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-black.is-inverted.is-outlined.is-focused,.button.is-black.is-inverted.is-outlined.is-hovered,.button.is-black.is-inverted.is-outlined:focus,.button.is-black.is-inverted.is-outlined:hover{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-black.is-inverted.is-outlined.is-loading:focus::after,.button.is-black.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-black.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-light{background-color:#f5f5f5;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light.is-hovered,.button.is-light:hover{background-color:#eee;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light.is-focused,.button.is-light:focus{border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light.is-focused:not(:active),.button.is-light:focus:not(:active){box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.button.is-light.is-active,.button.is-light:active{background-color:#e8e8e8;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light[disabled],fieldset[disabled] .button.is-light{background-color:#f5f5f5;border-color:transparent;box-shadow:none}.button.is-light.is-inverted{background-color:rgba(0,0,0,.7);color:#f5f5f5}.button.is-light.is-inverted.is-hovered,.button.is-light.is-inverted:hover{background-color:rgba(0,0,0,.7)}.button.is-light.is-inverted[disabled],fieldset[disabled] .button.is-light.is-inverted{background-color:rgba(0,0,0,.7);border-color:transparent;box-shadow:none;color:#f5f5f5}.button.is-light.is-loading::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;color:#f5f5f5}.button.is-light.is-outlined.is-focused,.button.is-light.is-outlined.is-hovered,.button.is-light.is-outlined:focus,.button.is-light.is-outlined:hover{background-color:#f5f5f5;border-color:#f5f5f5;color:rgba(0,0,0,.7)}.button.is-light.is-outlined.is-loading::after{border-color:transparent transparent #f5f5f5 #f5f5f5!important}.button.is-light.is-outlined.is-loading.is-focused::after,.button.is-light.is-outlined.is-loading.is-hovered::after,.button.is-light.is-outlined.is-loading:focus::after,.button.is-light.is-outlined.is-loading:hover::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-light.is-outlined[disabled],fieldset[disabled] .button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;box-shadow:none;color:#f5f5f5}.button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);color:rgba(0,0,0,.7)}.button.is-light.is-inverted.is-outlined.is-focused,.button.is-light.is-inverted.is-outlined.is-hovered,.button.is-light.is-inverted.is-outlined:focus,.button.is-light.is-inverted.is-outlined:hover{background-color:rgba(0,0,0,.7);color:#f5f5f5}.button.is-light.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-light.is-inverted.is-outlined.is-loading:focus::after,.button.is-light.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #f5f5f5 #f5f5f5!important}.button.is-light.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);box-shadow:none;color:rgba(0,0,0,.7)}.button.is-dark{background-color:#363636;border-color:transparent;color:#fff}.button.is-dark.is-hovered,.button.is-dark:hover{background-color:#2f2f2f;border-color:transparent;color:#fff}.button.is-dark.is-focused,.button.is-dark:focus{border-color:transparent;color:#fff}.button.is-dark.is-focused:not(:active),.button.is-dark:focus:not(:active){box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.button.is-dark.is-active,.button.is-dark:active{background-color:#292929;border-color:transparent;color:#fff}.button.is-dark[disabled],fieldset[disabled] .button.is-dark{background-color:#363636;border-color:transparent;box-shadow:none}.button.is-dark.is-inverted{background-color:#fff;color:#363636}.button.is-dark.is-inverted.is-hovered,.button.is-dark.is-inverted:hover{background-color:#f2f2f2}.button.is-dark.is-inverted[disabled],fieldset[disabled] .button.is-dark.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#363636}.button.is-dark.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-dark.is-outlined{background-color:transparent;border-color:#363636;color:#363636}.button.is-dark.is-outlined.is-focused,.button.is-dark.is-outlined.is-hovered,.button.is-dark.is-outlined:focus,.button.is-dark.is-outlined:hover{background-color:#363636;border-color:#363636;color:#fff}.button.is-dark.is-outlined.is-loading::after{border-color:transparent transparent #363636 #363636!important}.button.is-dark.is-outlined.is-loading.is-focused::after,.button.is-dark.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-outlined.is-loading:focus::after,.button.is-dark.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-dark.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-outlined{background-color:transparent;border-color:#363636;box-shadow:none;color:#363636}.button.is-dark.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-dark.is-inverted.is-outlined.is-focused,.button.is-dark.is-inverted.is-outlined.is-hovered,.button.is-dark.is-inverted.is-outlined:focus,.button.is-dark.is-inverted.is-outlined:hover{background-color:#fff;color:#363636}.button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-inverted.is-outlined.is-loading:focus::after,.button.is-dark.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #363636 #363636!important}.button.is-dark.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-primary{background-color:#00d1b2;border-color:transparent;color:#fff}.button.is-primary.is-hovered,.button.is-primary:hover{background-color:#00c4a7;border-color:transparent;color:#fff}.button.is-primary.is-focused,.button.is-primary:focus{border-color:transparent;color:#fff}.button.is-primary.is-focused:not(:active),.button.is-primary:focus:not(:active){box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.button.is-primary.is-active,.button.is-primary:active{background-color:#00b89c;border-color:transparent;color:#fff}.button.is-primary[disabled],fieldset[disabled] .button.is-primary{background-color:#00d1b2;border-color:transparent;box-shadow:none}.button.is-primary.is-inverted{background-color:#fff;color:#00d1b2}.button.is-primary.is-inverted.is-hovered,.button.is-primary.is-inverted:hover{background-color:#f2f2f2}.button.is-primary.is-inverted[disabled],fieldset[disabled] .button.is-primary.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#00d1b2}.button.is-primary.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-primary.is-outlined{background-color:transparent;border-color:#00d1b2;color:#00d1b2}.button.is-primary.is-outlined.is-focused,.button.is-primary.is-outlined.is-hovered,.button.is-primary.is-outlined:focus,.button.is-primary.is-outlined:hover{background-color:#00d1b2;border-color:#00d1b2;color:#fff}.button.is-primary.is-outlined.is-loading::after{border-color:transparent transparent #00d1b2 #00d1b2!important}.button.is-primary.is-outlined.is-loading.is-focused::after,.button.is-primary.is-outlined.is-loading.is-hovered::after,.button.is-primary.is-outlined.is-loading:focus::after,.button.is-primary.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-primary.is-outlined[disabled],fieldset[disabled] .button.is-primary.is-outlined{background-color:transparent;border-color:#00d1b2;box-shadow:none;color:#00d1b2}.button.is-primary.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-primary.is-inverted.is-outlined.is-focused,.button.is-primary.is-inverted.is-outlined.is-hovered,.button.is-primary.is-inverted.is-outlined:focus,.button.is-primary.is-inverted.is-outlined:hover{background-color:#fff;color:#00d1b2}.button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-primary.is-inverted.is-outlined.is-loading:focus::after,.button.is-primary.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #00d1b2 #00d1b2!important}.button.is-primary.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-primary.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-primary.is-light{background-color:#ebfffc;color:#00947e}.button.is-primary.is-light.is-hovered,.button.is-primary.is-light:hover{background-color:#defffa;border-color:transparent;color:#00947e}.button.is-primary.is-light.is-active,.button.is-primary.is-light:active{background-color:#d1fff8;border-color:transparent;color:#00947e}.button.is-link{background-color:#485fc7;border-color:transparent;color:#fff}.button.is-link.is-hovered,.button.is-link:hover{background-color:#3e56c4;border-color:transparent;color:#fff}.button.is-link.is-focused,.button.is-link:focus{border-color:transparent;color:#fff}.button.is-link.is-focused:not(:active),.button.is-link:focus:not(:active){box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.button.is-link.is-active,.button.is-link:active{background-color:#3a51bb;border-color:transparent;color:#fff}.button.is-link[disabled],fieldset[disabled] .button.is-link{background-color:#485fc7;border-color:transparent;box-shadow:none}.button.is-link.is-inverted{background-color:#fff;color:#485fc7}.button.is-link.is-inverted.is-hovered,.button.is-link.is-inverted:hover{background-color:#f2f2f2}.button.is-link.is-inverted[disabled],fieldset[disabled] .button.is-link.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#485fc7}.button.is-link.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-link.is-outlined{background-color:transparent;border-color:#485fc7;color:#485fc7}.button.is-link.is-outlined.is-focused,.button.is-link.is-outlined.is-hovered,.button.is-link.is-outlined:focus,.button.is-link.is-outlined:hover{background-color:#485fc7;border-color:#485fc7;color:#fff}.button.is-link.is-outlined.is-loading::after{border-color:transparent transparent #485fc7 #485fc7!important}.button.is-link.is-outlined.is-loading.is-focused::after,.button.is-link.is-outlined.is-loading.is-hovered::after,.button.is-link.is-outlined.is-loading:focus::after,.button.is-link.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-link.is-outlined[disabled],fieldset[disabled] .button.is-link.is-outlined{background-color:transparent;border-color:#485fc7;box-shadow:none;color:#485fc7}.button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-link.is-inverted.is-outlined.is-focused,.button.is-link.is-inverted.is-outlined.is-hovered,.button.is-link.is-inverted.is-outlined:focus,.button.is-link.is-inverted.is-outlined:hover{background-color:#fff;color:#485fc7}.button.is-link.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-link.is-inverted.is-outlined.is-loading:focus::after,.button.is-link.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #485fc7 #485fc7!important}.button.is-link.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-link.is-light{background-color:#eff1fa;color:#3850b7}.button.is-link.is-light.is-hovered,.button.is-link.is-light:hover{background-color:#e6e9f7;border-color:transparent;color:#3850b7}.button.is-link.is-light.is-active,.button.is-link.is-light:active{background-color:#dce0f4;border-color:transparent;color:#3850b7}.button.is-info{background-color:#3e8ed0;border-color:transparent;color:#fff}.button.is-info.is-hovered,.button.is-info:hover{background-color:#3488ce;border-color:transparent;color:#fff}.button.is-info.is-focused,.button.is-info:focus{border-color:transparent;color:#fff}.button.is-info.is-focused:not(:active),.button.is-info:focus:not(:active){box-shadow:0 0 0 .125em rgba(62,142,208,.25)}.button.is-info.is-active,.button.is-info:active{background-color:#3082c5;border-color:transparent;color:#fff}.button.is-info[disabled],fieldset[disabled] .button.is-info{background-color:#3e8ed0;border-color:transparent;box-shadow:none}.button.is-info.is-inverted{background-color:#fff;color:#3e8ed0}.button.is-info.is-inverted.is-hovered,.button.is-info.is-inverted:hover{background-color:#f2f2f2}.button.is-info.is-inverted[disabled],fieldset[disabled] .button.is-info.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#3e8ed0}.button.is-info.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-info.is-outlined{background-color:transparent;border-color:#3e8ed0;color:#3e8ed0}.button.is-info.is-outlined.is-focused,.button.is-info.is-outlined.is-hovered,.button.is-info.is-outlined:focus,.button.is-info.is-outlined:hover{background-color:#3e8ed0;border-color:#3e8ed0;color:#fff}.button.is-info.is-outlined.is-loading::after{border-color:transparent transparent #3e8ed0 #3e8ed0!important}.button.is-info.is-outlined.is-loading.is-focused::after,.button.is-info.is-outlined.is-loading.is-hovered::after,.button.is-info.is-outlined.is-loading:focus::after,.button.is-info.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-info.is-outlined[disabled],fieldset[disabled] .button.is-info.is-outlined{background-color:transparent;border-color:#3e8ed0;box-shadow:none;color:#3e8ed0}.button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-info.is-inverted.is-outlined.is-focused,.button.is-info.is-inverted.is-outlined.is-hovered,.button.is-info.is-inverted.is-outlined:focus,.button.is-info.is-inverted.is-outlined:hover{background-color:#fff;color:#3e8ed0}.button.is-info.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-info.is-inverted.is-outlined.is-loading:focus::after,.button.is-info.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #3e8ed0 #3e8ed0!important}.button.is-info.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-info.is-light{background-color:#eff5fb;color:#296fa8}.button.is-info.is-light.is-hovered,.button.is-info.is-light:hover{background-color:#e4eff9;border-color:transparent;color:#296fa8}.button.is-info.is-light.is-active,.button.is-info.is-light:active{background-color:#dae9f6;border-color:transparent;color:#296fa8}.button.is-success{background-color:#48c78e;border-color:transparent;color:#fff}.button.is-success.is-hovered,.button.is-success:hover{background-color:#3ec487;border-color:transparent;color:#fff}.button.is-success.is-focused,.button.is-success:focus{border-color:transparent;color:#fff}.button.is-success.is-focused:not(:active),.button.is-success:focus:not(:active){box-shadow:0 0 0 .125em rgba(72,199,142,.25)}.button.is-success.is-active,.button.is-success:active{background-color:#3abb81;border-color:transparent;color:#fff}.button.is-success[disabled],fieldset[disabled] .button.is-success{background-color:#48c78e;border-color:transparent;box-shadow:none}.button.is-success.is-inverted{background-color:#fff;color:#48c78e}.button.is-success.is-inverted.is-hovered,.button.is-success.is-inverted:hover{background-color:#f2f2f2}.button.is-success.is-inverted[disabled],fieldset[disabled] .button.is-success.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#48c78e}.button.is-success.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-success.is-outlined{background-color:transparent;border-color:#48c78e;color:#48c78e}.button.is-success.is-outlined.is-focused,.button.is-success.is-outlined.is-hovered,.button.is-success.is-outlined:focus,.button.is-success.is-outlined:hover{background-color:#48c78e;border-color:#48c78e;color:#fff}.button.is-success.is-outlined.is-loading::after{border-color:transparent transparent #48c78e #48c78e!important}.button.is-success.is-outlined.is-loading.is-focused::after,.button.is-success.is-outlined.is-loading.is-hovered::after,.button.is-success.is-outlined.is-loading:focus::after,.button.is-success.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-success.is-outlined[disabled],fieldset[disabled] .button.is-success.is-outlined{background-color:transparent;border-color:#48c78e;box-shadow:none;color:#48c78e}.button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-success.is-inverted.is-outlined.is-focused,.button.is-success.is-inverted.is-outlined.is-hovered,.button.is-success.is-inverted.is-outlined:focus,.button.is-success.is-inverted.is-outlined:hover{background-color:#fff;color:#48c78e}.button.is-success.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-success.is-inverted.is-outlined.is-loading:focus::after,.button.is-success.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #48c78e #48c78e!important}.button.is-success.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-success.is-light{background-color:#effaf5;color:#257953}.button.is-success.is-light.is-hovered,.button.is-success.is-light:hover{background-color:#e6f7ef;border-color:transparent;color:#257953}.button.is-success.is-light.is-active,.button.is-success.is-light:active{background-color:#dcf4e9;border-color:transparent;color:#257953}.button.is-warning{background-color:#ffe08a;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-hovered,.button.is-warning:hover{background-color:#ffdc7d;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-focused,.button.is-warning:focus{border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-focused:not(:active),.button.is-warning:focus:not(:active){box-shadow:0 0 0 .125em rgba(255,224,138,.25)}.button.is-warning.is-active,.button.is-warning:active{background-color:#ffd970;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning[disabled],fieldset[disabled] .button.is-warning{background-color:#ffe08a;border-color:transparent;box-shadow:none}.button.is-warning.is-inverted{background-color:rgba(0,0,0,.7);color:#ffe08a}.button.is-warning.is-inverted.is-hovered,.button.is-warning.is-inverted:hover{background-color:rgba(0,0,0,.7)}.button.is-warning.is-inverted[disabled],fieldset[disabled] .button.is-warning.is-inverted{background-color:rgba(0,0,0,.7);border-color:transparent;box-shadow:none;color:#ffe08a}.button.is-warning.is-loading::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-warning.is-outlined{background-color:transparent;border-color:#ffe08a;color:#ffe08a}.button.is-warning.is-outlined.is-focused,.button.is-warning.is-outlined.is-hovered,.button.is-warning.is-outlined:focus,.button.is-warning.is-outlined:hover{background-color:#ffe08a;border-color:#ffe08a;color:rgba(0,0,0,.7)}.button.is-warning.is-outlined.is-loading::after{border-color:transparent transparent #ffe08a #ffe08a!important}.button.is-warning.is-outlined.is-loading.is-focused::after,.button.is-warning.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-outlined.is-loading:focus::after,.button.is-warning.is-outlined.is-loading:hover::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-warning.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-outlined{background-color:transparent;border-color:#ffe08a;box-shadow:none;color:#ffe08a}.button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);color:rgba(0,0,0,.7)}.button.is-warning.is-inverted.is-outlined.is-focused,.button.is-warning.is-inverted.is-outlined.is-hovered,.button.is-warning.is-inverted.is-outlined:focus,.button.is-warning.is-inverted.is-outlined:hover{background-color:rgba(0,0,0,.7);color:#ffe08a}.button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-inverted.is-outlined.is-loading:focus::after,.button.is-warning.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #ffe08a #ffe08a!important}.button.is-warning.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);box-shadow:none;color:rgba(0,0,0,.7)}.button.is-warning.is-light{background-color:#fffaeb;color:#946c00}.button.is-warning.is-light.is-hovered,.button.is-warning.is-light:hover{background-color:#fff6de;border-color:transparent;color:#946c00}.button.is-warning.is-light.is-active,.button.is-warning.is-light:active{background-color:#fff3d1;border-color:transparent;color:#946c00}.button.is-danger{background-color:#f14668;border-color:transparent;color:#fff}.button.is-danger.is-hovered,.button.is-danger:hover{background-color:#f03a5f;border-color:transparent;color:#fff}.button.is-danger.is-focused,.button.is-danger:focus{border-color:transparent;color:#fff}.button.is-danger.is-focused:not(:active),.button.is-danger:focus:not(:active){box-shadow:0 0 0 .125em rgba(241,70,104,.25)}.button.is-danger.is-active,.button.is-danger:active{background-color:#ef2e55;border-color:transparent;color:#fff}.button.is-danger[disabled],fieldset[disabled] .button.is-danger{background-color:#f14668;border-color:transparent;box-shadow:none}.button.is-danger.is-inverted{background-color:#fff;color:#f14668}.button.is-danger.is-inverted.is-hovered,.button.is-danger.is-inverted:hover{background-color:#f2f2f2}.button.is-danger.is-inverted[disabled],fieldset[disabled] .button.is-danger.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#f14668}.button.is-danger.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-danger.is-outlined{background-color:transparent;border-color:#f14668;color:#f14668}.button.is-danger.is-outlined.is-focused,.button.is-danger.is-outlined.is-hovered,.button.is-danger.is-outlined:focus,.button.is-danger.is-outlined:hover{background-color:#f14668;border-color:#f14668;color:#fff}.button.is-danger.is-outlined.is-loading::after{border-color:transparent transparent #f14668 #f14668!important}.button.is-danger.is-outlined.is-loading.is-focused::after,.button.is-danger.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-outlined.is-loading:focus::after,.button.is-danger.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-danger.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-outlined{background-color:transparent;border-color:#f14668;box-shadow:none;color:#f14668}.button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-danger.is-inverted.is-outlined.is-focused,.button.is-danger.is-inverted.is-outlined.is-hovered,.button.is-danger.is-inverted.is-outlined:focus,.button.is-danger.is-inverted.is-outlined:hover{background-color:#fff;color:#f14668}.button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-inverted.is-outlined.is-loading:focus::after,.button.is-danger.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #f14668 #f14668!important}.button.is-danger.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-danger.is-light{background-color:#feecf0;color:#cc0f35}.button.is-danger.is-light.is-hovered,.button.is-danger.is-light:hover{background-color:#fde0e6;border-color:transparent;color:#cc0f35}.button.is-danger.is-light.is-active,.button.is-danger.is-light:active{background-color:#fcd4dc;border-color:transparent;color:#cc0f35}.button.is-small{font-size:.75rem}.button.is-small:not(.is-rounded){border-radius:2px}.button.is-normal{font-size:1rem}.button.is-medium{font-size:1.25rem}.button.is-large{font-size:1.5rem}.button[disabled],fieldset[disabled] .button{background-color:#fff;border-color:#dbdbdb;box-shadow:none;opacity:.5}.button.is-fullwidth{display:flex;width:100%}.button.is-loading{color:transparent!important;pointer-events:none}.button.is-loading::after{position:absolute;left:calc(50% - (1em * .5));top:calc(50% - (1em * .5));position:absolute!important}.button.is-static{background-color:#f5f5f5;border-color:#dbdbdb;color:#7a7a7a;box-shadow:none;pointer-events:none}.button.is-rounded{border-radius:9999px;padding-left:calc(1em + .25em);padding-right:calc(1em + .25em)}.buttons{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.buttons .button{margin-bottom:.5rem}.buttons .button:not(:last-child):not(.is-fullwidth){margin-left:.5rem}.buttons:last-child{margin-bottom:-.5rem}.buttons:not(:last-child){margin-bottom:1rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large){font-size:.75rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded){border-radius:2px}.buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large){font-size:1.25rem}.buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium){font-size:1.5rem}.buttons.has-addons .button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.buttons.has-addons .button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-left:-1px}.buttons.has-addons .button:last-child{margin-left:0}.buttons.has-addons .button.is-hovered,.buttons.has-addons .button:hover{z-index:2}.buttons.has-addons .button.is-active,.buttons.has-addons .button.is-focused,.buttons.has-addons .button.is-selected,.buttons.has-addons .button:active,.buttons.has-addons .button:focus{z-index:3}.buttons.has-addons .button.is-active:hover,.buttons.has-addons .button.is-focused:hover,.buttons.has-addons .button.is-selected:hover,.buttons.has-addons .button:active:hover,.buttons.has-addons .button:focus:hover{z-index:4}.buttons.has-addons .button.is-expanded{flex-grow:1;flex-shrink:1}.buttons.is-centered{justify-content:center}.buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth){margin-left:.25rem;margin-right:.25rem}.buttons.is-right{justify-content:flex-end}.buttons.is-right:not(.has-addons) .button:not(.is-fullwidth){margin-left:.25rem;margin-right:.25rem}.container{flex-grow:1;margin:0 auto;position:relative;width:auto}.container.is-fluid{max-width:none!important;padding-left:32px;padding-right:32px;width:100%}@media screen and (min-width:1024px){.container{max-width:960px}}@media screen and (max-width:1215px){.container.is-widescreen:not(.is-max-desktop){max-width:1152px}}@media screen and (max-width:1407px){.container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}@media screen and (min-width:1216px){.container:not(.is-max-desktop){max-width:1152px}}@media screen and (min-width:1408px){.container:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}.content li+li{margin-top:.25em}.content blockquote:not(:last-child),.content dl:not(:last-child),.content ol:not(:last-child),.content p:not(:last-child),.content pre:not(:last-child),.content table:not(:last-child),.content ul:not(:last-child){margin-bottom:1em}.content h1,.content h2,.content h3,.content h4,.content h5,.content h6{color:#363636;font-weight:600;line-height:1.125}.content h1{font-size:2em;margin-bottom:.5em}.content h1:not(:first-child){margin-top:1em}.content h2{font-size:1.75em;margin-bottom:.5714em}.content h2:not(:first-child){margin-top:1.1428em}.content h3{font-size:1.5em;margin-bottom:.6666em}.content h3:not(:first-child){margin-top:1.3333em}.content h4{font-size:1.25em;margin-bottom:.8em}.content h5{font-size:1.125em;margin-bottom:.8888em}.content h6{font-size:1em;margin-bottom:1em}.content blockquote{background-color:#f5f5f5;border-right:5px solid #dbdbdb;padding:1.25em 1.5em}.content ol{list-style-position:outside;margin-right:2em;margin-top:1em}.content ol:not([type]){list-style-type:decimal}.content ol:not([type]).is-lower-alpha{list-style-type:lower-alpha}.content ol:not([type]).is-lower-roman{list-style-type:lower-roman}.content ol:not([type]).is-upper-alpha{list-style-type:upper-alpha}.content ol:not([type]).is-upper-roman{list-style-type:upper-roman}.content ul{list-style:disc outside;margin-right:2em;margin-top:1em}.content ul ul{list-style-type:circle;margin-top:.5em}.content ul ul ul{list-style-type:square}.content dd{margin-right:2em}.content figure{margin-left:2em;margin-right:2em;text-align:center}.content figure:not(:first-child){margin-top:2em}.content figure:not(:last-child){margin-bottom:2em}.content figure img{display:inline-block}.content figure figcaption{font-style:italic}.content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:1.25em 1.5em;white-space:pre;word-wrap:normal}.content sub,.content sup{font-size:75%}.content table{width:100%}.content table td,.content table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:.5em .75em;vertical-align:top}.content table th{color:#363636}.content table th:not([align]){text-align:inherit}.content table thead td,.content table thead th{border-width:0 0 2px;color:#363636}.content table tfoot td,.content table tfoot th{border-width:2px 0 0;color:#363636}.content table tbody tr:last-child td,.content table tbody tr:last-child th{border-bottom-width:0}.content .tabs li+li{margin-top:0}.content.is-small{font-size:.75rem}.content.is-normal{font-size:1rem}.content.is-medium{font-size:1.25rem}.content.is-large{font-size:1.5rem}.icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}.icon.is-small{height:1rem;width:1rem}.icon.is-medium{height:2rem;width:2rem}.icon.is-large{height:3rem;width:3rem}.icon-text{align-items:flex-start;color:inherit;display:inline-flex;flex-wrap:wrap;line-height:1.5rem;vertical-align:top}.icon-text .icon{flex-grow:0;flex-shrink:0}.icon-text .icon:not(:last-child){margin-left:.25em}.icon-text .icon:not(:first-child){margin-right:.25em}div.icon-text{display:flex}.image{display:block;position:relative}.image img{display:block;height:auto;width:100%}.image img.is-rounded{border-radius:9999px}.image.is-fullwidth{width:100%}.image.is-16by9 .has-ratio,.image.is-16by9 img,.image.is-1by1 .has-ratio,.image.is-1by1 img,.image.is-1by2 .has-ratio,.image.is-1by2 img,.image.is-1by3 .has-ratio,.image.is-1by3 img,.image.is-2by1 .has-ratio,.image.is-2by1 img,.image.is-2by3 .has-ratio,.image.is-2by3 img,.image.is-3by1 .has-ratio,.image.is-3by1 img,.image.is-3by2 .has-ratio,.image.is-3by2 img,.image.is-3by4 .has-ratio,.image.is-3by4 img,.image.is-3by5 .has-ratio,.image.is-3by5 img,.image.is-4by3 .has-ratio,.image.is-4by3 img,.image.is-4by5 .has-ratio,.image.is-4by5 img,.image.is-5by3 .has-ratio,.image.is-5by3 img,.image.is-5by4 .has-ratio,.image.is-5by4 img,.image.is-9by16 .has-ratio,.image.is-9by16 img,.image.is-square .has-ratio,.image.is-square img{height:100%;width:100%}.image.is-1by1,.image.is-square{padding-top:100%}.image.is-5by4{padding-top:80%}.image.is-4by3{padding-top:75%}.image.is-3by2{padding-top:66.6666%}.image.is-5by3{padding-top:60%}.image.is-16by9{padding-top:56.25%}.image.is-2by1{padding-top:50%}.image.is-3by1{padding-top:33.3333%}.image.is-4by5{padding-top:125%}.image.is-3by4{padding-top:133.3333%}.image.is-2by3{padding-top:150%}.image.is-3by5{padding-top:166.6666%}.image.is-9by16{padding-top:177.7777%}.image.is-1by2{padding-top:200%}.image.is-1by3{padding-top:300%}.image.is-16x16{height:16px;width:16px}.image.is-24x24{height:24px;width:24px}.image.is-32x32{height:32px;width:32px}.image.is-48x48{height:48px;width:48px}.image.is-64x64{height:64px;width:64px}.image.is-96x96{height:96px;width:96px}.image.is-128x128{height:128px;width:128px}.notification{background-color:#f5f5f5;border-radius:4px;position:relative;padding:1.25rem 1.5rem 1.25rem 2.5rem}.notification a:not(.button):not(.dropdown-item){color:currentColor;text-decoration:underline}.notification strong{color:currentColor}.notification code,.notification pre{background:#fff}.notification pre code{background:0 0}.notification>.delete{left:.5rem;position:absolute;top:.5rem}.notification .content,.notification .subtitle,.notification .title{color:currentColor}.notification.is-white{background-color:#fff;color:#0a0a0a}.notification.is-black{background-color:#0a0a0a;color:#fff}.notification.is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.notification.is-dark{background-color:#363636;color:#fff}.notification.is-primary{background-color:#00d1b2;color:#fff}.notification.is-primary.is-light{background-color:#ebfffc;color:#00947e}.notification.is-link{background-color:#485fc7;color:#fff}.notification.is-link.is-light{background-color:#eff1fa;color:#3850b7}.notification.is-info{background-color:#3e8ed0;color:#fff}.notification.is-info.is-light{background-color:#eff5fb;color:#296fa8}.notification.is-success{background-color:#48c78e;color:#fff}.notification.is-success.is-light{background-color:#effaf5;color:#257953}.notification.is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.notification.is-warning.is-light{background-color:#fffaeb;color:#946c00}.notification.is-danger{background-color:#f14668;color:#fff}.notification.is-danger.is-light{background-color:#feecf0;color:#cc0f35}.progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:9999px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}.progress::-webkit-progress-bar{background-color:#ededed}.progress::-webkit-progress-value{background-color:#4a4a4a}.progress::-moz-progress-bar{background-color:#4a4a4a}.progress::-ms-fill{background-color:#4a4a4a;border:none}.progress.is-white::-webkit-progress-value{background-color:#fff}.progress.is-white::-moz-progress-bar{background-color:#fff}.progress.is-white::-ms-fill{background-color:#fff}.progress.is-white:indeterminate{background-image:linear-gradient(to right,#fff 30%,#ededed 30%)}.progress.is-black::-webkit-progress-value{background-color:#0a0a0a}.progress.is-black::-moz-progress-bar{background-color:#0a0a0a}.progress.is-black::-ms-fill{background-color:#0a0a0a}.progress.is-black:indeterminate{background-image:linear-gradient(to right,#0a0a0a 30%,#ededed 30%)}.progress.is-light::-webkit-progress-value{background-color:#f5f5f5}.progress.is-light::-moz-progress-bar{background-color:#f5f5f5}.progress.is-light::-ms-fill{background-color:#f5f5f5}.progress.is-light:indeterminate{background-image:linear-gradient(to right,#f5f5f5 30%,#ededed 30%)}.progress.is-dark::-webkit-progress-value{background-color:#363636}.progress.is-dark::-moz-progress-bar{background-color:#363636}.progress.is-dark::-ms-fill{background-color:#363636}.progress.is-dark:indeterminate{background-image:linear-gradient(to right,#363636 30%,#ededed 30%)}.progress.is-primary::-webkit-progress-value{background-color:#00d1b2}.progress.is-primary::-moz-progress-bar{background-color:#00d1b2}.progress.is-primary::-ms-fill{background-color:#00d1b2}.progress.is-primary:indeterminate{background-image:linear-gradient(to right,#00d1b2 30%,#ededed 30%)}.progress.is-link::-webkit-progress-value{background-color:#485fc7}.progress.is-link::-moz-progress-bar{background-color:#485fc7}.progress.is-link::-ms-fill{background-color:#485fc7}.progress.is-link:indeterminate{background-image:linear-gradient(to right,#485fc7 30%,#ededed 30%)}.progress.is-info::-webkit-progress-value{background-color:#3e8ed0}.progress.is-info::-moz-progress-bar{background-color:#3e8ed0}.progress.is-info::-ms-fill{background-color:#3e8ed0}.progress.is-info:indeterminate{background-image:linear-gradient(to right,#3e8ed0 30%,#ededed 30%)}.progress.is-success::-webkit-progress-value{background-color:#48c78e}.progress.is-success::-moz-progress-bar{background-color:#48c78e}.progress.is-success::-ms-fill{background-color:#48c78e}.progress.is-success:indeterminate{background-image:linear-gradient(to right,#48c78e 30%,#ededed 30%)}.progress.is-warning::-webkit-progress-value{background-color:#ffe08a}.progress.is-warning::-moz-progress-bar{background-color:#ffe08a}.progress.is-warning::-ms-fill{background-color:#ffe08a}.progress.is-warning:indeterminate{background-image:linear-gradient(to right,#ffe08a 30%,#ededed 30%)}.progress.is-danger::-webkit-progress-value{background-color:#f14668}.progress.is-danger::-moz-progress-bar{background-color:#f14668}.progress.is-danger::-ms-fill{background-color:#f14668}.progress.is-danger:indeterminate{background-image:linear-gradient(to right,#f14668 30%,#ededed 30%)}.progress:indeterminate{-webkit-animation-duration:1.5s;animation-duration:1.5s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:moveIndeterminate;animation-name:moveIndeterminate;-webkit-animation-timing-function:linear;animation-timing-function:linear;background-color:#ededed;background-image:linear-gradient(to right,#4a4a4a 30%,#ededed 30%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}.progress:indeterminate::-webkit-progress-bar{background-color:transparent}.progress:indeterminate::-moz-progress-bar{background-color:transparent}.progress:indeterminate::-ms-fill{animation-name:none}.progress.is-small{height:.75rem}.progress.is-medium{height:1.25rem}.progress.is-large{height:1.5rem}@-webkit-keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}@keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}.table{background-color:#fff;color:#363636}.table td,.table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:.5em .75em;vertical-align:top}.table td.is-white,.table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}.table td.is-black,.table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.table td.is-light,.table th.is-light{background-color:#f5f5f5;border-color:#f5f5f5;color:rgba(0,0,0,.7)}.table td.is-dark,.table th.is-dark{background-color:#363636;border-color:#363636;color:#fff}.table td.is-primary,.table th.is-primary{background-color:#00d1b2;border-color:#00d1b2;color:#fff}.table td.is-link,.table th.is-link{background-color:#485fc7;border-color:#485fc7;color:#fff}.table td.is-info,.table th.is-info{background-color:#3e8ed0;border-color:#3e8ed0;color:#fff}.table td.is-success,.table th.is-success{background-color:#48c78e;border-color:#48c78e;color:#fff}.table td.is-warning,.table th.is-warning{background-color:#ffe08a;border-color:#ffe08a;color:rgba(0,0,0,.7)}.table td.is-danger,.table th.is-danger{background-color:#f14668;border-color:#f14668;color:#fff}.table td.is-narrow,.table th.is-narrow{white-space:nowrap;width:1%}.table td.is-selected,.table th.is-selected{background-color:#00d1b2;color:#fff}.table td.is-selected a,.table td.is-selected strong,.table th.is-selected a,.table th.is-selected strong{color:currentColor}.table td.is-vcentered,.table th.is-vcentered{vertical-align:middle}.table th{color:#363636}.table th:not([align]){text-align:inherit}.table tr.is-selected{background-color:#00d1b2;color:#fff}.table tr.is-selected a,.table tr.is-selected strong{color:currentColor}.table tr.is-selected td,.table tr.is-selected th{border-color:#fff;color:currentColor}.table thead{background-color:transparent}.table thead td,.table thead th{border-width:0 0 2px;color:#363636}.table tfoot{background-color:transparent}.table tfoot td,.table tfoot th{border-width:2px 0 0;color:#363636}.table tbody{background-color:transparent}.table tbody tr:last-child td,.table tbody tr:last-child th{border-bottom-width:0}.table.is-bordered td,.table.is-bordered th{border-width:1px}.table.is-bordered tr:last-child td,.table.is-bordered tr:last-child th{border-bottom-width:1px}.table.is-fullwidth{width:100%}.table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even){background-color:#f5f5f5}.table.is-narrow td,.table.is-narrow th{padding:.25em .5em}.table.is-striped tbody tr:not(.is-selected):nth-child(even){background-color:#fafafa}.table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}.tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.tags .tag{margin-bottom:.5rem}.tags .tag:not(:last-child){margin-left:.5rem}.tags:last-child{margin-bottom:-.5rem}.tags:not(:last-child){margin-bottom:1rem}.tags.are-medium .tag:not(.is-normal):not(.is-large){font-size:1rem}.tags.are-large .tag:not(.is-normal):not(.is-medium){font-size:1.25rem}.tags.is-centered{justify-content:center}.tags.is-centered .tag{margin-right:.25rem;margin-left:.25rem}.tags.is-right{justify-content:flex-end}.tags.is-right .tag:not(:first-child){margin-left:.5rem}.tags.is-right .tag:not(:last-child){margin-right:0}.tags.has-addons .tag{margin-left:0}.tags.has-addons .tag:not(:first-child){margin-right:0;border-top-right-radius:0;border-bottom-right-radius:0}.tags.has-addons .tag:not(:last-child){border-top-left-radius:0;border-bottom-left-radius:0}.tag:not(body){align-items:center;background-color:#f5f5f5;border-radius:4px;color:#4a4a4a;display:inline-flex;font-size:.75rem;height:2em;justify-content:center;line-height:1.5;padding-left:.75em;padding-right:.75em;white-space:nowrap}.tag:not(body) .delete{margin-right:.25rem;margin-left:-.375rem}.tag:not(body).is-white{background-color:#fff;color:#0a0a0a}.tag:not(body).is-black{background-color:#0a0a0a;color:#fff}.tag:not(body).is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.tag:not(body).is-dark{background-color:#363636;color:#fff}.tag:not(body).is-primary{background-color:#00d1b2;color:#fff}.tag:not(body).is-primary.is-light{background-color:#ebfffc;color:#00947e}.tag:not(body).is-link{background-color:#485fc7;color:#fff}.tag:not(body).is-link.is-light{background-color:#eff1fa;color:#3850b7}.tag:not(body).is-info{background-color:#3e8ed0;color:#fff}.tag:not(body).is-info.is-light{background-color:#eff5fb;color:#296fa8}.tag:not(body).is-success{background-color:#48c78e;color:#fff}.tag:not(body).is-success.is-light{background-color:#effaf5;color:#257953}.tag:not(body).is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.tag:not(body).is-warning.is-light{background-color:#fffaeb;color:#946c00}.tag:not(body).is-danger{background-color:#f14668;color:#fff}.tag:not(body).is-danger.is-light{background-color:#feecf0;color:#cc0f35}.tag:not(body).is-normal{font-size:.75rem}.tag:not(body).is-medium{font-size:1rem}.tag:not(body).is-large{font-size:1.25rem}.tag:not(body) .icon:first-child:not(:last-child){margin-right:-.375em;margin-left:.1875em}.tag:not(body) .icon:last-child:not(:first-child){margin-right:.1875em;margin-left:-.375em}.tag:not(body) .icon:first-child:last-child{margin-right:-.375em;margin-left:-.375em}.tag:not(body).is-delete{margin-right:1px;padding:0;position:relative;width:2em}.tag:not(body).is-delete::after,.tag:not(body).is-delete::before{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.tag:not(body).is-delete::before{height:1px;width:50%}.tag:not(body).is-delete::after{height:50%;width:1px}.tag:not(body).is-delete:focus,.tag:not(body).is-delete:hover{background-color:#e8e8e8}.tag:not(body).is-delete:active{background-color:#dbdbdb}.tag:not(body).is-rounded{border-radius:9999px}a.tag:hover{text-decoration:underline}.subtitle,.title{word-break:break-word}.subtitle em,.subtitle span,.title em,.title span{font-weight:inherit}.subtitle sub,.title sub{font-size:.75em}.subtitle sup,.title sup{font-size:.75em}.subtitle .tag,.title .tag{vertical-align:middle}.title{color:#363636;font-size:2rem;font-weight:600;line-height:1.125}.title strong{color:inherit;font-weight:inherit}.title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}.title.is-1{font-size:3rem}.title.is-2{font-size:2.5rem}.title.is-3{font-size:2rem}.title.is-4{font-size:1.5rem}.title.is-5{font-size:1.25rem}.title.is-6{font-size:1rem}.title.is-7{font-size:.75rem}.subtitle{color:#4a4a4a;font-size:1.25rem;font-weight:400;line-height:1.25}.subtitle strong{color:#363636;font-weight:600}.subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}.subtitle.is-1{font-size:3rem}.subtitle.is-2{font-size:2.5rem}.subtitle.is-3{font-size:2rem}.subtitle.is-4{font-size:1.5rem}.subtitle.is-5{font-size:1.25rem}.subtitle.is-6{font-size:1rem}.subtitle.is-7{font-size:.75rem}.heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}.number{align-items:center;background-color:#f5f5f5;border-radius:9999px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:.25rem .5rem;text-align:center;vertical-align:top}.input,.select select,.textarea{background-color:#fff;border-color:#dbdbdb;border-radius:4px;color:#363636}.input::-moz-placeholder,.select select::-moz-placeholder,.textarea::-moz-placeholder{color:rgba(54,54,54,.3)}.input::-webkit-input-placeholder,.select select::-webkit-input-placeholder,.textarea::-webkit-input-placeholder{color:rgba(54,54,54,.3)}.input:-moz-placeholder,.select select:-moz-placeholder,.textarea:-moz-placeholder{color:rgba(54,54,54,.3)}.input:-ms-input-placeholder,.select select:-ms-input-placeholder,.textarea:-ms-input-placeholder{color:rgba(54,54,54,.3)}.input:hover,.is-hovered.input,.is-hovered.textarea,.select select.is-hovered,.select select:hover,.textarea:hover{border-color:#b5b5b5}.input:active,.input:focus,.is-active.input,.is-active.textarea,.is-focused.input,.is-focused.textarea,.select select.is-active,.select select.is-focused,.select select:active,.select select:focus,.textarea:active,.textarea:focus{border-color:#485fc7;box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.input[disabled],.select fieldset[disabled] select,.select select[disabled],.textarea[disabled],fieldset[disabled] .input,fieldset[disabled] .select select,fieldset[disabled] .textarea{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none;color:#7a7a7a}.input[disabled]::-moz-placeholder,.select fieldset[disabled] select::-moz-placeholder,.select select[disabled]::-moz-placeholder,.textarea[disabled]::-moz-placeholder,fieldset[disabled] .input::-moz-placeholder,fieldset[disabled] .select select::-moz-placeholder,fieldset[disabled] .textarea::-moz-placeholder{color:rgba(122,122,122,.3)}.input[disabled]::-webkit-input-placeholder,.select fieldset[disabled] select::-webkit-input-placeholder,.select select[disabled]::-webkit-input-placeholder,.textarea[disabled]::-webkit-input-placeholder,fieldset[disabled] .input::-webkit-input-placeholder,fieldset[disabled] .select select::-webkit-input-placeholder,fieldset[disabled] .textarea::-webkit-input-placeholder{color:rgba(122,122,122,.3)}.input[disabled]:-moz-placeholder,.select fieldset[disabled] select:-moz-placeholder,.select select[disabled]:-moz-placeholder,.textarea[disabled]:-moz-placeholder,fieldset[disabled] .input:-moz-placeholder,fieldset[disabled] .select select:-moz-placeholder,fieldset[disabled] .textarea:-moz-placeholder{color:rgba(122,122,122,.3)}.input[disabled]:-ms-input-placeholder,.select fieldset[disabled] select:-ms-input-placeholder,.select select[disabled]:-ms-input-placeholder,.textarea[disabled]:-ms-input-placeholder,fieldset[disabled] .input:-ms-input-placeholder,fieldset[disabled] .select select:-ms-input-placeholder,fieldset[disabled] .textarea:-ms-input-placeholder{color:rgba(122,122,122,.3)}.input,.textarea{box-shadow:inset 0 .0625em .125em rgba(10,10,10,.05);max-width:100%;width:100%}.input[readonly],.textarea[readonly]{box-shadow:none}.is-white.input,.is-white.textarea{border-color:#fff}.is-white.input:active,.is-white.input:focus,.is-white.is-active.input,.is-white.is-active.textarea,.is-white.is-focused.input,.is-white.is-focused.textarea,.is-white.textarea:active,.is-white.textarea:focus{box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.is-black.input,.is-black.textarea{border-color:#0a0a0a}.is-black.input:active,.is-black.input:focus,.is-black.is-active.input,.is-black.is-active.textarea,.is-black.is-focused.input,.is-black.is-focused.textarea,.is-black.textarea:active,.is-black.textarea:focus{box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.is-light.input,.is-light.textarea{border-color:#f5f5f5}.is-light.input:active,.is-light.input:focus,.is-light.is-active.input,.is-light.is-active.textarea,.is-light.is-focused.input,.is-light.is-focused.textarea,.is-light.textarea:active,.is-light.textarea:focus{box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.is-dark.input,.is-dark.textarea{border-color:#363636}.is-dark.input:active,.is-dark.input:focus,.is-dark.is-active.input,.is-dark.is-active.textarea,.is-dark.is-focused.input,.is-dark.is-focused.textarea,.is-dark.textarea:active,.is-dark.textarea:focus{box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.is-primary.input,.is-primary.textarea{border-color:#00d1b2}.is-primary.input:active,.is-primary.input:focus,.is-primary.is-active.input,.is-primary.is-active.textarea,.is-primary.is-focused.input,.is-primary.is-focused.textarea,.is-primary.textarea:active,.is-primary.textarea:focus{box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.is-link.input,.is-link.textarea{border-color:#485fc7}.is-link.input:active,.is-link.input:focus,.is-link.is-active.input,.is-link.is-active.textarea,.is-link.is-focused.input,.is-link.is-focused.textarea,.is-link.textarea:active,.is-link.textarea:focus{box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.is-info.input,.is-info.textarea{border-color:#3e8ed0}.is-info.input:active,.is-info.input:focus,.is-info.is-active.input,.is-info.is-active.textarea,.is-info.is-focused.input,.is-info.is-focused.textarea,.is-info.textarea:active,.is-info.textarea:focus{box-shadow:0 0 0 .125em rgba(62,142,208,.25)}.is-success.input,.is-success.textarea{border-color:#48c78e}.is-success.input:active,.is-success.input:focus,.is-success.is-active.input,.is-success.is-active.textarea,.is-success.is-focused.input,.is-success.is-focused.textarea,.is-success.textarea:active,.is-success.textarea:focus{box-shadow:0 0 0 .125em rgba(72,199,142,.25)}.is-warning.input,.is-warning.textarea{border-color:#ffe08a}.is-warning.input:active,.is-warning.input:focus,.is-warning.is-active.input,.is-warning.is-active.textarea,.is-warning.is-focused.input,.is-warning.is-focused.textarea,.is-warning.textarea:active,.is-warning.textarea:focus{box-shadow:0 0 0 .125em rgba(255,224,138,.25)}.is-danger.input,.is-danger.textarea{border-color:#f14668}.is-danger.input:active,.is-danger.input:focus,.is-danger.is-active.input,.is-danger.is-active.textarea,.is-danger.is-focused.input,.is-danger.is-focused.textarea,.is-danger.textarea:active,.is-danger.textarea:focus{box-shadow:0 0 0 .125em rgba(241,70,104,.25)}.is-small.input,.is-small.textarea{border-radius:2px;font-size:.75rem}.is-medium.input,.is-medium.textarea{font-size:1.25rem}.is-large.input,.is-large.textarea{font-size:1.5rem}.is-fullwidth.input,.is-fullwidth.textarea{display:block;width:100%}.is-inline.input,.is-inline.textarea{display:inline;width:auto}.input.is-rounded{border-radius:9999px;padding-left:calc(calc(.75em - 1px) + .375em);padding-right:calc(calc(.75em - 1px) + .375em)}.input.is-static{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}.textarea{display:block;max-width:100%;min-width:100%;padding:calc(.75em - 1px);resize:vertical}.textarea:not([rows]){max-height:40em;min-height:8em}.textarea[rows]{height:initial}.textarea.has-fixed-size{resize:none}.checkbox,.radio{cursor:pointer;display:inline-block;line-height:1.25;position:relative}.checkbox input,.radio input{cursor:pointer}.checkbox:hover,.radio:hover{color:#363636}.checkbox input[disabled],.checkbox[disabled],.radio input[disabled],.radio[disabled],fieldset[disabled] .checkbox,fieldset[disabled] .radio{color:#7a7a7a;cursor:not-allowed}.radio+.radio{margin-right:.5em}.select{display:inline-block;max-width:100%;position:relative;vertical-align:top}.select:not(.is-multiple){height:2.5em}.select:not(.is-multiple):not(.is-loading)::after{border-color:#485fc7;left:1.125em;z-index:4}.select.is-rounded select{border-radius:9999px;padding-right:1em}.select select{cursor:pointer;display:block;font-size:1em;max-width:100%;outline:0}.select select::-ms-expand{display:none}.select select[disabled]:hover,fieldset[disabled] .select select:hover{border-color:#f5f5f5}.select select:not([multiple]){padding-left:2.5em}.select select[multiple]{height:auto;padding:0}.select select[multiple] option{padding:.5em 1em}.select:not(.is-multiple):not(.is-loading):hover::after{border-color:#363636}.select.is-white:not(:hover)::after{border-color:#fff}.select.is-white select{border-color:#fff}.select.is-white select.is-hovered,.select.is-white select:hover{border-color:#f2f2f2}.select.is-white select.is-active,.select.is-white select.is-focused,.select.is-white select:active,.select.is-white select:focus{box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.select.is-black:not(:hover)::after{border-color:#0a0a0a}.select.is-black select{border-color:#0a0a0a}.select.is-black select.is-hovered,.select.is-black select:hover{border-color:#000}.select.is-black select.is-active,.select.is-black select.is-focused,.select.is-black select:active,.select.is-black select:focus{box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.select.is-light:not(:hover)::after{border-color:#f5f5f5}.select.is-light select{border-color:#f5f5f5}.select.is-light select.is-hovered,.select.is-light select:hover{border-color:#e8e8e8}.select.is-light select.is-active,.select.is-light select.is-focused,.select.is-light select:active,.select.is-light select:focus{box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.select.is-dark:not(:hover)::after{border-color:#363636}.select.is-dark select{border-color:#363636}.select.is-dark select.is-hovered,.select.is-dark select:hover{border-color:#292929}.select.is-dark select.is-active,.select.is-dark select.is-focused,.select.is-dark select:active,.select.is-dark select:focus{box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.select.is-primary:not(:hover)::after{border-color:#00d1b2}.select.is-primary select{border-color:#00d1b2}.select.is-primary select.is-hovered,.select.is-primary select:hover{border-color:#00b89c}.select.is-primary select.is-active,.select.is-primary select.is-focused,.select.is-primary select:active,.select.is-primary select:focus{box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.select.is-link:not(:hover)::after{border-color:#485fc7}.select.is-link select{border-color:#485fc7}.select.is-link select.is-hovered,.select.is-link select:hover{border-color:#3a51bb}.select.is-link select.is-active,.select.is-link select.is-focused,.select.is-link select:active,.select.is-link select:focus{box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.select.is-info:not(:hover)::after{border-color:#3e8ed0}.select.is-info select{border-color:#3e8ed0}.select.is-info select.is-hovered,.select.is-info select:hover{border-color:#3082c5}.select.is-info select.is-active,.select.is-info select.is-focused,.select.is-info select:active,.select.is-info select:focus{box-shadow:0 0 0 .125em rgba(62,142,208,.25)}.select.is-success:not(:hover)::after{border-color:#48c78e}.select.is-success select{border-color:#48c78e}.select.is-success select.is-hovered,.select.is-success select:hover{border-color:#3abb81}.select.is-success select.is-active,.select.is-success select.is-focused,.select.is-success select:active,.select.is-success select:focus{box-shadow:0 0 0 .125em rgba(72,199,142,.25)}.select.is-warning:not(:hover)::after{border-color:#ffe08a}.select.is-warning select{border-color:#ffe08a}.select.is-warning select.is-hovered,.select.is-warning select:hover{border-color:#ffd970}.select.is-warning select.is-active,.select.is-warning select.is-focused,.select.is-warning select:active,.select.is-warning select:focus{box-shadow:0 0 0 .125em rgba(255,224,138,.25)}.select.is-danger:not(:hover)::after{border-color:#f14668}.select.is-danger select{border-color:#f14668}.select.is-danger select.is-hovered,.select.is-danger select:hover{border-color:#ef2e55}.select.is-danger select.is-active,.select.is-danger select.is-focused,.select.is-danger select:active,.select.is-danger select:focus{box-shadow:0 0 0 .125em rgba(241,70,104,.25)}.select.is-small{border-radius:2px;font-size:.75rem}.select.is-medium{font-size:1.25rem}.select.is-large{font-size:1.5rem}.select.is-disabled::after{border-color:#7a7a7a}.select.is-fullwidth{width:100%}.select.is-fullwidth select{width:100%}.select.is-loading::after{margin-top:0;position:absolute;left:.625em;top:.625em;transform:none}.select.is-loading.is-small:after{font-size:.75rem}.select.is-loading.is-medium:after{font-size:1.25rem}.select.is-loading.is-large:after{font-size:1.5rem}.file{align-items:stretch;display:flex;justify-content:flex-start;position:relative}.file.is-white .file-cta{background-color:#fff;border-color:transparent;color:#0a0a0a}.file.is-white.is-hovered .file-cta,.file.is-white:hover .file-cta{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.file.is-white.is-focused .file-cta,.file.is-white:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(255,255,255,.25);color:#0a0a0a}.file.is-white.is-active .file-cta,.file.is-white:active .file-cta{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.file.is-black .file-cta{background-color:#0a0a0a;border-color:transparent;color:#fff}.file.is-black.is-hovered .file-cta,.file.is-black:hover .file-cta{background-color:#040404;border-color:transparent;color:#fff}.file.is-black.is-focused .file-cta,.file.is-black:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(10,10,10,.25);color:#fff}.file.is-black.is-active .file-cta,.file.is-black:active .file-cta{background-color:#000;border-color:transparent;color:#fff}.file.is-light .file-cta{background-color:#f5f5f5;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-light.is-hovered .file-cta,.file.is-light:hover .file-cta{background-color:#eee;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-light.is-focused .file-cta,.file.is-light:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(245,245,245,.25);color:rgba(0,0,0,.7)}.file.is-light.is-active .file-cta,.file.is-light:active .file-cta{background-color:#e8e8e8;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-dark .file-cta{background-color:#363636;border-color:transparent;color:#fff}.file.is-dark.is-hovered .file-cta,.file.is-dark:hover .file-cta{background-color:#2f2f2f;border-color:transparent;color:#fff}.file.is-dark.is-focused .file-cta,.file.is-dark:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(54,54,54,.25);color:#fff}.file.is-dark.is-active .file-cta,.file.is-dark:active .file-cta{background-color:#292929;border-color:transparent;color:#fff}.file.is-primary .file-cta{background-color:#00d1b2;border-color:transparent;color:#fff}.file.is-primary.is-hovered .file-cta,.file.is-primary:hover .file-cta{background-color:#00c4a7;border-color:transparent;color:#fff}.file.is-primary.is-focused .file-cta,.file.is-primary:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(0,209,178,.25);color:#fff}.file.is-primary.is-active .file-cta,.file.is-primary:active .file-cta{background-color:#00b89c;border-color:transparent;color:#fff}.file.is-link .file-cta{background-color:#485fc7;border-color:transparent;color:#fff}.file.is-link.is-hovered .file-cta,.file.is-link:hover .file-cta{background-color:#3e56c4;border-color:transparent;color:#fff}.file.is-link.is-focused .file-cta,.file.is-link:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(72,95,199,.25);color:#fff}.file.is-link.is-active .file-cta,.file.is-link:active .file-cta{background-color:#3a51bb;border-color:transparent;color:#fff}.file.is-info .file-cta{background-color:#3e8ed0;border-color:transparent;color:#fff}.file.is-info.is-hovered .file-cta,.file.is-info:hover .file-cta{background-color:#3488ce;border-color:transparent;color:#fff}.file.is-info.is-focused .file-cta,.file.is-info:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(62,142,208,.25);color:#fff}.file.is-info.is-active .file-cta,.file.is-info:active .file-cta{background-color:#3082c5;border-color:transparent;color:#fff}.file.is-success .file-cta{background-color:#48c78e;border-color:transparent;color:#fff}.file.is-success.is-hovered .file-cta,.file.is-success:hover .file-cta{background-color:#3ec487;border-color:transparent;color:#fff}.file.is-success.is-focused .file-cta,.file.is-success:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(72,199,142,.25);color:#fff}.file.is-success.is-active .file-cta,.file.is-success:active .file-cta{background-color:#3abb81;border-color:transparent;color:#fff}.file.is-warning .file-cta{background-color:#ffe08a;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-warning.is-hovered .file-cta,.file.is-warning:hover .file-cta{background-color:#ffdc7d;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-warning.is-focused .file-cta,.file.is-warning:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(255,224,138,.25);color:rgba(0,0,0,.7)}.file.is-warning.is-active .file-cta,.file.is-warning:active .file-cta{background-color:#ffd970;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-danger .file-cta{background-color:#f14668;border-color:transparent;color:#fff}.file.is-danger.is-hovered .file-cta,.file.is-danger:hover .file-cta{background-color:#f03a5f;border-color:transparent;color:#fff}.file.is-danger.is-focused .file-cta,.file.is-danger:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(241,70,104,.25);color:#fff}.file.is-danger.is-active .file-cta,.file.is-danger:active .file-cta{background-color:#ef2e55;border-color:transparent;color:#fff}.file.is-small{font-size:.75rem}.file.is-normal{font-size:1rem}.file.is-medium{font-size:1.25rem}.file.is-medium .file-icon .fa{font-size:21px}.file.is-large{font-size:1.5rem}.file.is-large .file-icon .fa{font-size:28px}.file.has-name .file-cta{border-bottom-right-radius:0;border-top-right-radius:0}.file.has-name .file-name{border-bottom-left-radius:0;border-top-left-radius:0}.file.has-name.is-empty .file-cta{border-radius:4px}.file.has-name.is-empty .file-name{display:none}.file.is-boxed .file-label{flex-direction:column}.file.is-boxed .file-cta{flex-direction:column;height:auto;padding:1em 3em}.file.is-boxed .file-name{border-width:0 1px 1px}.file.is-boxed .file-icon{height:1.5em;width:1.5em}.file.is-boxed .file-icon .fa{font-size:21px}.file.is-boxed.is-small .file-icon .fa{font-size:14px}.file.is-boxed.is-medium .file-icon .fa{font-size:28px}.file.is-boxed.is-large .file-icon .fa{font-size:35px}.file.is-boxed.has-name .file-cta{border-radius:4px 4px 0 0}.file.is-boxed.has-name .file-name{border-radius:0 0 4px 4px;border-width:0 1px 1px}.file.is-centered{justify-content:center}.file.is-fullwidth .file-label{width:100%}.file.is-fullwidth .file-name{flex-grow:1;max-width:none}.file.is-right{justify-content:flex-end}.file.is-right .file-cta{border-radius:0 4px 4px 0}.file.is-right .file-name{border-radius:4px 0 0 4px;border-width:1px 0 1px 1px;order:-1}.file-label{align-items:stretch;display:flex;cursor:pointer;justify-content:flex-start;overflow:hidden;position:relative}.file-label:hover .file-cta{background-color:#eee;color:#363636}.file-label:hover .file-name{border-color:#d5d5d5}.file-label:active .file-cta{background-color:#e8e8e8;color:#363636}.file-label:active .file-name{border-color:#cfcfcf}.file-input{height:100%;left:0;opacity:0;outline:0;position:absolute;top:0;width:100%}.file-cta,.file-name{border-color:#dbdbdb;border-radius:4px;font-size:1em;padding-left:1em;padding-right:1em;white-space:nowrap}.file-cta{background-color:#f5f5f5;color:#4a4a4a}.file-name{border-color:#dbdbdb;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:inherit;text-overflow:ellipsis}.file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-left:.5em;width:1em}.file-icon .fa{font-size:14px}.label{color:#363636;display:block;font-size:1rem;font-weight:700}.label:not(:last-child){margin-bottom:.5em}.label.is-small{font-size:.75rem}.label.is-medium{font-size:1.25rem}.label.is-large{font-size:1.5rem}.help{display:block;font-size:.75rem;margin-top:.25rem}.help.is-white{color:#fff}.help.is-black{color:#0a0a0a}.help.is-light{color:#f5f5f5}.help.is-dark{color:#363636}.help.is-primary{color:#00d1b2}.help.is-link{color:#485fc7}.help.is-info{color:#3e8ed0}.help.is-success{color:#48c78e}.help.is-warning{color:#ffe08a}.help.is-danger{color:#f14668}.field:not(:last-child){margin-bottom:.75rem}.field.has-addons{display:flex;justify-content:flex-start}.field.has-addons .control:not(:last-child){margin-left:-1px}.field.has-addons .control:not(:first-child):not(:last-child) .button,.field.has-addons .control:not(:first-child):not(:last-child) .input,.field.has-addons .control:not(:first-child):not(:last-child) .select select{border-radius:0}.field.has-addons .control:first-child:not(:only-child) .button,.field.has-addons .control:first-child:not(:only-child) .input,.field.has-addons .control:first-child:not(:only-child) .select select{border-bottom-left-radius:0;border-top-left-radius:0}.field.has-addons .control:last-child:not(:only-child) .button,.field.has-addons .control:last-child:not(:only-child) .input,.field.has-addons .control:last-child:not(:only-child) .select select{border-bottom-right-radius:0;border-top-right-radius:0}.field.has-addons .control .button:not([disabled]).is-hovered,.field.has-addons .control .button:not([disabled]):hover,.field.has-addons .control .input:not([disabled]).is-hovered,.field.has-addons .control .input:not([disabled]):hover,.field.has-addons .control .select select:not([disabled]).is-hovered,.field.has-addons .control .select select:not([disabled]):hover{z-index:2}.field.has-addons .control .button:not([disabled]).is-active,.field.has-addons .control .button:not([disabled]).is-focused,.field.has-addons .control .button:not([disabled]):active,.field.has-addons .control .button:not([disabled]):focus,.field.has-addons .control .input:not([disabled]).is-active,.field.has-addons .control .input:not([disabled]).is-focused,.field.has-addons .control .input:not([disabled]):active,.field.has-addons .control .input:not([disabled]):focus,.field.has-addons .control .select select:not([disabled]).is-active,.field.has-addons .control .select select:not([disabled]).is-focused,.field.has-addons .control .select select:not([disabled]):active,.field.has-addons .control .select select:not([disabled]):focus{z-index:3}.field.has-addons .control .button:not([disabled]).is-active:hover,.field.has-addons .control .button:not([disabled]).is-focused:hover,.field.has-addons .control .button:not([disabled]):active:hover,.field.has-addons .control .button:not([disabled]):focus:hover,.field.has-addons .control .input:not([disabled]).is-active:hover,.field.has-addons .control .input:not([disabled]).is-focused:hover,.field.has-addons .control .input:not([disabled]):active:hover,.field.has-addons .control .input:not([disabled]):focus:hover,.field.has-addons .control .select select:not([disabled]).is-active:hover,.field.has-addons .control .select select:not([disabled]).is-focused:hover,.field.has-addons .control .select select:not([disabled]):active:hover,.field.has-addons .control .select select:not([disabled]):focus:hover{z-index:4}.field.has-addons .control.is-expanded{flex-grow:1;flex-shrink:1}.field.has-addons.has-addons-centered{justify-content:center}.field.has-addons.has-addons-right{justify-content:flex-end}.field.has-addons.has-addons-fullwidth .control{flex-grow:1;flex-shrink:0}.field.is-grouped{display:flex;justify-content:flex-start}.field.is-grouped>.control{flex-shrink:0}.field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-left:.75rem}.field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}.field.is-grouped.is-grouped-centered{justify-content:center}.field.is-grouped.is-grouped-right{justify-content:flex-end}.field.is-grouped.is-grouped-multiline{flex-wrap:wrap}.field.is-grouped.is-grouped-multiline>.control:last-child,.field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:.75rem}.field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-.75rem}.field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width:769px),print{.field.is-horizontal{display:flex}}.field-label .label{font-size:inherit}@media screen and (max-width:768px){.field-label{margin-bottom:.5rem}}@media screen and (min-width:769px),print{.field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-left:1.5rem;text-align:right}.field-label.is-small{font-size:.75rem;padding-top:.375em}.field-label.is-normal{padding-top:.375em}.field-label.is-medium{font-size:1.25rem;padding-top:.375em}.field-label.is-large{font-size:1.5rem;padding-top:.375em}}.field-body .field .field{margin-bottom:0}@media screen and (min-width:769px),print{.field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}.field-body .field{margin-bottom:0}.field-body>.field{flex-shrink:1}.field-body>.field:not(.is-narrow){flex-grow:1}.field-body>.field:not(:last-child){margin-left:.75rem}}.control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:inherit}.control.has-icons-left .input:focus~.icon,.control.has-icons-left .select:focus~.icon,.control.has-icons-right .input:focus~.icon,.control.has-icons-right .select:focus~.icon{color:#4a4a4a}.control.has-icons-left .input.is-small~.icon,.control.has-icons-left .select.is-small~.icon,.control.has-icons-right .input.is-small~.icon,.control.has-icons-right .select.is-small~.icon{font-size:.75rem}.control.has-icons-left .input.is-medium~.icon,.control.has-icons-left .select.is-medium~.icon,.control.has-icons-right .input.is-medium~.icon,.control.has-icons-right .select.is-medium~.icon{font-size:1.25rem}.control.has-icons-left .input.is-large~.icon,.control.has-icons-left .select.is-large~.icon,.control.has-icons-right .input.is-large~.icon,.control.has-icons-right .select.is-large~.icon{font-size:1.5rem}.control.has-icons-left .icon,.control.has-icons-right .icon{color:#dbdbdb;height:2.5em;pointer-events:none;position:absolute;top:0;width:2.5em;z-index:4}.control.has-icons-left .input,.control.has-icons-left .select select{padding-left:2.5em}.control.has-icons-left .icon.is-left{left:0}.control.has-icons-right .input,.control.has-icons-right .select select{padding-right:2.5em}.control.has-icons-right .icon.is-right{right:0}.control.is-loading::after{position:absolute!important;left:.625em;top:.625em;z-index:4}.control.is-loading.is-small:after{font-size:.75rem}.control.is-loading.is-medium:after{font-size:1.25rem}.control.is-loading.is-large:after{font-size:1.5rem}.breadcrumb{font-size:1rem;white-space:nowrap}.breadcrumb a{align-items:center;color:#485fc7;display:flex;justify-content:center;padding:0 .75em}.breadcrumb a:hover{color:#363636}.breadcrumb li{align-items:center;display:flex}.breadcrumb li:first-child a{padding-right:0}.breadcrumb li.is-active a{color:#363636;cursor:default;pointer-events:none}.breadcrumb li+li::before{color:#b5b5b5;content:"\0002f"}.breadcrumb ol,.breadcrumb ul{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}.breadcrumb .icon:first-child{margin-left:.5em}.breadcrumb .icon:last-child{margin-right:.5em}.breadcrumb.is-centered ol,.breadcrumb.is-centered ul{justify-content:center}.breadcrumb.is-right ol,.breadcrumb.is-right ul{justify-content:flex-end}.breadcrumb.is-small{font-size:.75rem}.breadcrumb.is-medium{font-size:1.25rem}.breadcrumb.is-large{font-size:1.5rem}.breadcrumb.has-arrow-separator li+li::before{content:"\02192"}.breadcrumb.has-bullet-separator li+li::before{content:"\02022"}.breadcrumb.has-dot-separator li+li::before{content:"\000b7"}.breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}.card{background-color:#fff;border-radius:.25rem;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);color:#4a4a4a;max-width:100%;position:relative}.card-content:first-child,.card-footer:first-child,.card-header:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-content:last-child,.card-footer:last-child,.card-header:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-header{background-color:transparent;align-items:stretch;box-shadow:0 .125em .25em rgba(10,10,10,.1);display:flex}.card-header-title{align-items:center;color:#363636;display:flex;flex-grow:1;font-weight:700;padding:.75rem 1rem}.card-header-title.is-centered{justify-content:center}.card-header-icon{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:0 0;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0;align-items:center;cursor:pointer;display:flex;justify-content:center;padding:.75rem 1rem}.card-image{display:block;position:relative}.card-image:first-child img{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-image:last-child img{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-content{background-color:transparent;padding:1.5rem}.card-footer{background-color:transparent;border-top:1px solid #ededed;align-items:stretch;display:flex}.card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:.75rem}.card-footer-item:not(:last-child){border-left:1px solid #ededed}.card .media:not(:last-child){margin-bottom:1.5rem}.dropdown{display:inline-flex;position:relative;vertical-align:top}.dropdown.is-active .dropdown-menu,.dropdown.is-hoverable:hover .dropdown-menu{display:block}.dropdown.is-right .dropdown-menu{left:auto;right:0}.dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}.dropdown-menu{display:none;right:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}.dropdown-content{background-color:#fff;border-radius:4px;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);padding-bottom:.5rem;padding-top:.5rem}.dropdown-item{color:#4a4a4a;display:block;font-size:.875rem;line-height:1.5;padding:.375rem 1rem;position:relative}a.dropdown-item,button.dropdown-item{padding-left:3rem;text-align:inherit;white-space:nowrap;width:100%}a.dropdown-item:hover,button.dropdown-item:hover{background-color:#f5f5f5;color:#0a0a0a}a.dropdown-item.is-active,button.dropdown-item.is-active{background-color:#485fc7;color:#fff}.dropdown-divider{background-color:#ededed;border:none;display:block;height:1px;margin:.5rem 0}.level{align-items:center;justify-content:space-between}.level code{border-radius:4px}.level img{display:inline-block;vertical-align:top}.level.is-mobile{display:flex}.level.is-mobile .level-left,.level.is-mobile .level-right{display:flex}.level.is-mobile .level-left+.level-right{margin-top:0}.level.is-mobile .level-item:not(:last-child){margin-bottom:0;margin-left:.75rem}.level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width:769px),print{.level{display:flex}.level>.level-item:not(.is-narrow){flex-grow:1}}.level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}.level-item .subtitle,.level-item .title{margin-bottom:0}@media screen and (max-width:768px){.level-item:not(:last-child){margin-bottom:.75rem}}.level-left,.level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.level-left .level-item.is-flexible,.level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width:769px),print{.level-left .level-item:not(:last-child),.level-right .level-item:not(:last-child){margin-left:.75rem}}.level-left{align-items:center;justify-content:flex-start}@media screen and (max-width:768px){.level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width:769px),print{.level-left{display:flex}}.level-right{align-items:center;justify-content:flex-end}@media screen and (min-width:769px),print{.level-right{display:flex}}.media{align-items:flex-start;display:flex;text-align:inherit}.media .content:not(:last-child){margin-bottom:.75rem}.media .media{border-top:1px solid rgba(219,219,219,.5);display:flex;padding-top:.75rem}.media .media .content:not(:last-child),.media .media .control:not(:last-child){margin-bottom:.5rem}.media .media .media{padding-top:.5rem}.media .media .media+.media{margin-top:.5rem}.media+.media{border-top:1px solid rgba(219,219,219,.5);margin-top:1rem;padding-top:1rem}.media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}.media-left,.media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.media-left{margin-left:1rem}.media-right{margin-right:1rem}.media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:inherit}@media screen and (max-width:768px){.media-content{overflow-x:auto}}.menu{font-size:1rem}.menu.is-small{font-size:.75rem}.menu.is-medium{font-size:1.25rem}.menu.is-large{font-size:1.5rem}.menu-list{line-height:1.25}.menu-list a{border-radius:2px;color:#4a4a4a;display:block;padding:.5em .75em}.menu-list a:hover{background-color:#f5f5f5;color:#363636}.menu-list a.is-active{background-color:#485fc7;color:#fff}.menu-list li ul{border-right:1px solid #dbdbdb;margin:.75em;padding-right:.75em}.menu-label{color:#7a7a7a;font-size:.75em;letter-spacing:.1em;text-transform:uppercase}.menu-label:not(:first-child){margin-top:1em}.menu-label:not(:last-child){margin-bottom:1em}.message{background-color:#f5f5f5;border-radius:4px;font-size:1rem}.message strong{color:currentColor}.message a:not(.button):not(.tag):not(.dropdown-item){color:currentColor;text-decoration:underline}.message.is-small{font-size:.75rem}.message.is-medium{font-size:1.25rem}.message.is-large{font-size:1.5rem}.message.is-white{background-color:#fff}.message.is-white .message-header{background-color:#fff;color:#0a0a0a}.message.is-white .message-body{border-color:#fff}.message.is-black{background-color:#fafafa}.message.is-black .message-header{background-color:#0a0a0a;color:#fff}.message.is-black .message-body{border-color:#0a0a0a}.message.is-light{background-color:#fafafa}.message.is-light .message-header{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.message.is-light .message-body{border-color:#f5f5f5}.message.is-dark{background-color:#fafafa}.message.is-dark .message-header{background-color:#363636;color:#fff}.message.is-dark .message-body{border-color:#363636}.message.is-primary{background-color:#ebfffc}.message.is-primary .message-header{background-color:#00d1b2;color:#fff}.message.is-primary .message-body{border-color:#00d1b2;color:#00947e}.message.is-link{background-color:#eff1fa}.message.is-link .message-header{background-color:#485fc7;color:#fff}.message.is-link .message-body{border-color:#485fc7;color:#3850b7}.message.is-info{background-color:#eff5fb}.message.is-info .message-header{background-color:#3e8ed0;color:#fff}.message.is-info .message-body{border-color:#3e8ed0;color:#296fa8}.message.is-success{background-color:#effaf5}.message.is-success .message-header{background-color:#48c78e;color:#fff}.message.is-success .message-body{border-color:#48c78e;color:#257953}.message.is-warning{background-color:#fffaeb}.message.is-warning .message-header{background-color:#ffe08a;color:rgba(0,0,0,.7)}.message.is-warning .message-body{border-color:#ffe08a;color:#946c00}.message.is-danger{background-color:#feecf0}.message.is-danger .message-header{background-color:#f14668;color:#fff}.message.is-danger .message-body{border-color:#f14668;color:#cc0f35}.message-header{align-items:center;background-color:#4a4a4a;border-radius:4px 4px 0 0;color:#fff;display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:.75em 1em;position:relative}.message-header .delete{flex-grow:0;flex-shrink:0;margin-right:.75em}.message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}.message-body{border-color:#dbdbdb;border-radius:4px;border-style:solid;border-width:0 0 0 4px;color:#4a4a4a;padding:1.25em 1.5em}.message-body code,.message-body pre{background-color:#fff}.message-body pre code{background-color:transparent}.modal{align-items:center;display:none;flex-direction:column;justify-content:center;overflow:hidden;position:fixed;z-index:40}.modal.is-active{display:flex}.modal-background{background-color:rgba(10,10,10,.86)}.modal-card,.modal-content{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width:769px){.modal-card,.modal-content{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}.modal-close{background:0 0;height:40px;position:fixed;left:20px;top:20px;width:40px}.modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden;-ms-overflow-y:visible}.modal-card-foot,.modal-card-head{align-items:center;background-color:#f5f5f5;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}.modal-card-head{border-bottom:1px solid #dbdbdb;border-top-left-radius:6px;border-top-right-radius:6px}.modal-card-title{color:#363636;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}.modal-card-foot{border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:1px solid #dbdbdb}.modal-card-foot .button:not(:last-child){margin-left:.5em}.modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}.navbar{background-color:#fff;min-height:3.25rem;position:relative;z-index:30}.navbar.is-white{background-color:#fff;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link,.navbar.is-white .navbar-brand>.navbar-item{color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link.is-active,.navbar.is-white .navbar-brand .navbar-link:focus,.navbar.is-white .navbar-brand .navbar-link:hover,.navbar.is-white .navbar-brand>a.navbar-item.is-active,.navbar.is-white .navbar-brand>a.navbar-item:focus,.navbar.is-white .navbar-brand>a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-burger{color:#0a0a0a}@media screen and (min-width:1024px){.navbar.is-white .navbar-end .navbar-link,.navbar.is-white .navbar-end>.navbar-item,.navbar.is-white .navbar-start .navbar-link,.navbar.is-white .navbar-start>.navbar-item{color:#0a0a0a}.navbar.is-white .navbar-end .navbar-link.is-active,.navbar.is-white .navbar-end .navbar-link:focus,.navbar.is-white .navbar-end .navbar-link:hover,.navbar.is-white .navbar-end>a.navbar-item.is-active,.navbar.is-white .navbar-end>a.navbar-item:focus,.navbar.is-white .navbar-end>a.navbar-item:hover,.navbar.is-white .navbar-start .navbar-link.is-active,.navbar.is-white .navbar-start .navbar-link:focus,.navbar.is-white .navbar-start .navbar-link:hover,.navbar.is-white .navbar-start>a.navbar-item.is-active,.navbar.is-white .navbar-start>a.navbar-item:focus,.navbar.is-white .navbar-start>a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-end .navbar-link::after,.navbar.is-white .navbar-start .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-white .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-white .navbar-item.has-dropdown:hover .navbar-link{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}.navbar.is-black{background-color:#0a0a0a;color:#fff}.navbar.is-black .navbar-brand .navbar-link,.navbar.is-black .navbar-brand>.navbar-item{color:#fff}.navbar.is-black .navbar-brand .navbar-link.is-active,.navbar.is-black .navbar-brand .navbar-link:focus,.navbar.is-black .navbar-brand .navbar-link:hover,.navbar.is-black .navbar-brand>a.navbar-item.is-active,.navbar.is-black .navbar-brand>a.navbar-item:focus,.navbar.is-black .navbar-brand>a.navbar-item:hover{background-color:#000;color:#fff}.navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-black .navbar-end .navbar-link,.navbar.is-black .navbar-end>.navbar-item,.navbar.is-black .navbar-start .navbar-link,.navbar.is-black .navbar-start>.navbar-item{color:#fff}.navbar.is-black .navbar-end .navbar-link.is-active,.navbar.is-black .navbar-end .navbar-link:focus,.navbar.is-black .navbar-end .navbar-link:hover,.navbar.is-black .navbar-end>a.navbar-item.is-active,.navbar.is-black .navbar-end>a.navbar-item:focus,.navbar.is-black .navbar-end>a.navbar-item:hover,.navbar.is-black .navbar-start .navbar-link.is-active,.navbar.is-black .navbar-start .navbar-link:focus,.navbar.is-black .navbar-start .navbar-link:hover,.navbar.is-black .navbar-start>a.navbar-item.is-active,.navbar.is-black .navbar-start>a.navbar-item:focus,.navbar.is-black .navbar-start>a.navbar-item:hover{background-color:#000;color:#fff}.navbar.is-black .navbar-end .navbar-link::after,.navbar.is-black .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-black .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-black .navbar-item.has-dropdown:hover .navbar-link{background-color:#000;color:#fff}.navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}.navbar.is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-brand .navbar-link,.navbar.is-light .navbar-brand>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-light .navbar-brand .navbar-link.is-active,.navbar.is-light .navbar-brand .navbar-link:focus,.navbar.is-light .navbar-brand .navbar-link:hover,.navbar.is-light .navbar-brand>a.navbar-item.is-active,.navbar.is-light .navbar-brand>a.navbar-item:focus,.navbar.is-light .navbar-brand>a.navbar-item:hover{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-light .navbar-burger{color:rgba(0,0,0,.7)}@media screen and (min-width:1024px){.navbar.is-light .navbar-end .navbar-link,.navbar.is-light .navbar-end>.navbar-item,.navbar.is-light .navbar-start .navbar-link,.navbar.is-light .navbar-start>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-light .navbar-end .navbar-link.is-active,.navbar.is-light .navbar-end .navbar-link:focus,.navbar.is-light .navbar-end .navbar-link:hover,.navbar.is-light .navbar-end>a.navbar-item.is-active,.navbar.is-light .navbar-end>a.navbar-item:focus,.navbar.is-light .navbar-end>a.navbar-item:hover,.navbar.is-light .navbar-start .navbar-link.is-active,.navbar.is-light .navbar-start .navbar-link:focus,.navbar.is-light .navbar-start .navbar-link:hover,.navbar.is-light .navbar-start>a.navbar-item.is-active,.navbar.is-light .navbar-start>a.navbar-item:focus,.navbar.is-light .navbar-start>a.navbar-item:hover{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-end .navbar-link::after,.navbar.is-light .navbar-start .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-light .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-light .navbar-item.has-dropdown:hover .navbar-link{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:rgba(0,0,0,.7)}}.navbar.is-dark{background-color:#363636;color:#fff}.navbar.is-dark .navbar-brand .navbar-link,.navbar.is-dark .navbar-brand>.navbar-item{color:#fff}.navbar.is-dark .navbar-brand .navbar-link.is-active,.navbar.is-dark .navbar-brand .navbar-link:focus,.navbar.is-dark .navbar-brand .navbar-link:hover,.navbar.is-dark .navbar-brand>a.navbar-item.is-active,.navbar.is-dark .navbar-brand>a.navbar-item:focus,.navbar.is-dark .navbar-brand>a.navbar-item:hover{background-color:#292929;color:#fff}.navbar.is-dark .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-dark .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-dark .navbar-end .navbar-link,.navbar.is-dark .navbar-end>.navbar-item,.navbar.is-dark .navbar-start .navbar-link,.navbar.is-dark .navbar-start>.navbar-item{color:#fff}.navbar.is-dark .navbar-end .navbar-link.is-active,.navbar.is-dark .navbar-end .navbar-link:focus,.navbar.is-dark .navbar-end .navbar-link:hover,.navbar.is-dark .navbar-end>a.navbar-item.is-active,.navbar.is-dark .navbar-end>a.navbar-item:focus,.navbar.is-dark .navbar-end>a.navbar-item:hover,.navbar.is-dark .navbar-start .navbar-link.is-active,.navbar.is-dark .navbar-start .navbar-link:focus,.navbar.is-dark .navbar-start .navbar-link:hover,.navbar.is-dark .navbar-start>a.navbar-item.is-active,.navbar.is-dark .navbar-start>a.navbar-item:focus,.navbar.is-dark .navbar-start>a.navbar-item:hover{background-color:#292929;color:#fff}.navbar.is-dark .navbar-end .navbar-link::after,.navbar.is-dark .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link{background-color:#292929;color:#fff}.navbar.is-dark .navbar-dropdown a.navbar-item.is-active{background-color:#363636;color:#fff}}.navbar.is-primary{background-color:#00d1b2;color:#fff}.navbar.is-primary .navbar-brand .navbar-link,.navbar.is-primary .navbar-brand>.navbar-item{color:#fff}.navbar.is-primary .navbar-brand .navbar-link.is-active,.navbar.is-primary .navbar-brand .navbar-link:focus,.navbar.is-primary .navbar-brand .navbar-link:hover,.navbar.is-primary .navbar-brand>a.navbar-item.is-active,.navbar.is-primary .navbar-brand>a.navbar-item:focus,.navbar.is-primary .navbar-brand>a.navbar-item:hover{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-primary .navbar-end .navbar-link,.navbar.is-primary .navbar-end>.navbar-item,.navbar.is-primary .navbar-start .navbar-link,.navbar.is-primary .navbar-start>.navbar-item{color:#fff}.navbar.is-primary .navbar-end .navbar-link.is-active,.navbar.is-primary .navbar-end .navbar-link:focus,.navbar.is-primary .navbar-end .navbar-link:hover,.navbar.is-primary .navbar-end>a.navbar-item.is-active,.navbar.is-primary .navbar-end>a.navbar-item:focus,.navbar.is-primary .navbar-end>a.navbar-item:hover,.navbar.is-primary .navbar-start .navbar-link.is-active,.navbar.is-primary .navbar-start .navbar-link:focus,.navbar.is-primary .navbar-start .navbar-link:hover,.navbar.is-primary .navbar-start>a.navbar-item.is-active,.navbar.is-primary .navbar-start>a.navbar-item:focus,.navbar.is-primary .navbar-start>a.navbar-item:hover{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-end .navbar-link::after,.navbar.is-primary .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-dropdown a.navbar-item.is-active{background-color:#00d1b2;color:#fff}}.navbar.is-link{background-color:#485fc7;color:#fff}.navbar.is-link .navbar-brand .navbar-link,.navbar.is-link .navbar-brand>.navbar-item{color:#fff}.navbar.is-link .navbar-brand .navbar-link.is-active,.navbar.is-link .navbar-brand .navbar-link:focus,.navbar.is-link .navbar-brand .navbar-link:hover,.navbar.is-link .navbar-brand>a.navbar-item.is-active,.navbar.is-link .navbar-brand>a.navbar-item:focus,.navbar.is-link .navbar-brand>a.navbar-item:hover{background-color:#3a51bb;color:#fff}.navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-link .navbar-end .navbar-link,.navbar.is-link .navbar-end>.navbar-item,.navbar.is-link .navbar-start .navbar-link,.navbar.is-link .navbar-start>.navbar-item{color:#fff}.navbar.is-link .navbar-end .navbar-link.is-active,.navbar.is-link .navbar-end .navbar-link:focus,.navbar.is-link .navbar-end .navbar-link:hover,.navbar.is-link .navbar-end>a.navbar-item.is-active,.navbar.is-link .navbar-end>a.navbar-item:focus,.navbar.is-link .navbar-end>a.navbar-item:hover,.navbar.is-link .navbar-start .navbar-link.is-active,.navbar.is-link .navbar-start .navbar-link:focus,.navbar.is-link .navbar-start .navbar-link:hover,.navbar.is-link .navbar-start>a.navbar-item.is-active,.navbar.is-link .navbar-start>a.navbar-item:focus,.navbar.is-link .navbar-start>a.navbar-item:hover{background-color:#3a51bb;color:#fff}.navbar.is-link .navbar-end .navbar-link::after,.navbar.is-link .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-link .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-link .navbar-item.has-dropdown:hover .navbar-link{background-color:#3a51bb;color:#fff}.navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#485fc7;color:#fff}}.navbar.is-info{background-color:#3e8ed0;color:#fff}.navbar.is-info .navbar-brand .navbar-link,.navbar.is-info .navbar-brand>.navbar-item{color:#fff}.navbar.is-info .navbar-brand .navbar-link.is-active,.navbar.is-info .navbar-brand .navbar-link:focus,.navbar.is-info .navbar-brand .navbar-link:hover,.navbar.is-info .navbar-brand>a.navbar-item.is-active,.navbar.is-info .navbar-brand>a.navbar-item:focus,.navbar.is-info .navbar-brand>a.navbar-item:hover{background-color:#3082c5;color:#fff}.navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-info .navbar-end .navbar-link,.navbar.is-info .navbar-end>.navbar-item,.navbar.is-info .navbar-start .navbar-link,.navbar.is-info .navbar-start>.navbar-item{color:#fff}.navbar.is-info .navbar-end .navbar-link.is-active,.navbar.is-info .navbar-end .navbar-link:focus,.navbar.is-info .navbar-end .navbar-link:hover,.navbar.is-info .navbar-end>a.navbar-item.is-active,.navbar.is-info .navbar-end>a.navbar-item:focus,.navbar.is-info .navbar-end>a.navbar-item:hover,.navbar.is-info .navbar-start .navbar-link.is-active,.navbar.is-info .navbar-start .navbar-link:focus,.navbar.is-info .navbar-start .navbar-link:hover,.navbar.is-info .navbar-start>a.navbar-item.is-active,.navbar.is-info .navbar-start>a.navbar-item:focus,.navbar.is-info .navbar-start>a.navbar-item:hover{background-color:#3082c5;color:#fff}.navbar.is-info .navbar-end .navbar-link::after,.navbar.is-info .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-info .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-info .navbar-item.has-dropdown:hover .navbar-link{background-color:#3082c5;color:#fff}.navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#3e8ed0;color:#fff}}.navbar.is-success{background-color:#48c78e;color:#fff}.navbar.is-success .navbar-brand .navbar-link,.navbar.is-success .navbar-brand>.navbar-item{color:#fff}.navbar.is-success .navbar-brand .navbar-link.is-active,.navbar.is-success .navbar-brand .navbar-link:focus,.navbar.is-success .navbar-brand .navbar-link:hover,.navbar.is-success .navbar-brand>a.navbar-item.is-active,.navbar.is-success .navbar-brand>a.navbar-item:focus,.navbar.is-success .navbar-brand>a.navbar-item:hover{background-color:#3abb81;color:#fff}.navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-success .navbar-end .navbar-link,.navbar.is-success .navbar-end>.navbar-item,.navbar.is-success .navbar-start .navbar-link,.navbar.is-success .navbar-start>.navbar-item{color:#fff}.navbar.is-success .navbar-end .navbar-link.is-active,.navbar.is-success .navbar-end .navbar-link:focus,.navbar.is-success .navbar-end .navbar-link:hover,.navbar.is-success .navbar-end>a.navbar-item.is-active,.navbar.is-success .navbar-end>a.navbar-item:focus,.navbar.is-success .navbar-end>a.navbar-item:hover,.navbar.is-success .navbar-start .navbar-link.is-active,.navbar.is-success .navbar-start .navbar-link:focus,.navbar.is-success .navbar-start .navbar-link:hover,.navbar.is-success .navbar-start>a.navbar-item.is-active,.navbar.is-success .navbar-start>a.navbar-item:focus,.navbar.is-success .navbar-start>a.navbar-item:hover{background-color:#3abb81;color:#fff}.navbar.is-success .navbar-end .navbar-link::after,.navbar.is-success .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-success .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-success .navbar-item.has-dropdown:hover .navbar-link{background-color:#3abb81;color:#fff}.navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#48c78e;color:#fff}}.navbar.is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link,.navbar.is-warning .navbar-brand>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link.is-active,.navbar.is-warning .navbar-brand .navbar-link:focus,.navbar.is-warning .navbar-brand .navbar-link:hover,.navbar.is-warning .navbar-brand>a.navbar-item.is-active,.navbar.is-warning .navbar-brand>a.navbar-item:focus,.navbar.is-warning .navbar-brand>a.navbar-item:hover{background-color:#ffd970;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-burger{color:rgba(0,0,0,.7)}@media screen and (min-width:1024px){.navbar.is-warning .navbar-end .navbar-link,.navbar.is-warning .navbar-end>.navbar-item,.navbar.is-warning .navbar-start .navbar-link,.navbar.is-warning .navbar-start>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-end .navbar-link.is-active,.navbar.is-warning .navbar-end .navbar-link:focus,.navbar.is-warning .navbar-end .navbar-link:hover,.navbar.is-warning .navbar-end>a.navbar-item.is-active,.navbar.is-warning .navbar-end>a.navbar-item:focus,.navbar.is-warning .navbar-end>a.navbar-item:hover,.navbar.is-warning .navbar-start .navbar-link.is-active,.navbar.is-warning .navbar-start .navbar-link:focus,.navbar.is-warning .navbar-start .navbar-link:hover,.navbar.is-warning .navbar-start>a.navbar-item.is-active,.navbar.is-warning .navbar-start>a.navbar-item:focus,.navbar.is-warning .navbar-start>a.navbar-item:hover{background-color:#ffd970;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-end .navbar-link::after,.navbar.is-warning .navbar-start .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link{background-color:#ffd970;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ffe08a;color:rgba(0,0,0,.7)}}.navbar.is-danger{background-color:#f14668;color:#fff}.navbar.is-danger .navbar-brand .navbar-link,.navbar.is-danger .navbar-brand>.navbar-item{color:#fff}.navbar.is-danger .navbar-brand .navbar-link.is-active,.navbar.is-danger .navbar-brand .navbar-link:focus,.navbar.is-danger .navbar-brand .navbar-link:hover,.navbar.is-danger .navbar-brand>a.navbar-item.is-active,.navbar.is-danger .navbar-brand>a.navbar-item:focus,.navbar.is-danger .navbar-brand>a.navbar-item:hover{background-color:#ef2e55;color:#fff}.navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-danger .navbar-end .navbar-link,.navbar.is-danger .navbar-end>.navbar-item,.navbar.is-danger .navbar-start .navbar-link,.navbar.is-danger .navbar-start>.navbar-item{color:#fff}.navbar.is-danger .navbar-end .navbar-link.is-active,.navbar.is-danger .navbar-end .navbar-link:focus,.navbar.is-danger .navbar-end .navbar-link:hover,.navbar.is-danger .navbar-end>a.navbar-item.is-active,.navbar.is-danger .navbar-end>a.navbar-item:focus,.navbar.is-danger .navbar-end>a.navbar-item:hover,.navbar.is-danger .navbar-start .navbar-link.is-active,.navbar.is-danger .navbar-start .navbar-link:focus,.navbar.is-danger .navbar-start .navbar-link:hover,.navbar.is-danger .navbar-start>a.navbar-item.is-active,.navbar.is-danger .navbar-start>a.navbar-item:focus,.navbar.is-danger .navbar-start>a.navbar-item:hover{background-color:#ef2e55;color:#fff}.navbar.is-danger .navbar-end .navbar-link::after,.navbar.is-danger .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link{background-color:#ef2e55;color:#fff}.navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#f14668;color:#fff}}.navbar>.container{align-items:stretch;display:flex;min-height:3.25rem;width:100%}.navbar.has-shadow{box-shadow:0 2px 0 0 #f5f5f5}.navbar.is-fixed-bottom,.navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom{bottom:0}.navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #f5f5f5}.navbar.is-fixed-top{top:0}body.has-navbar-fixed-top,html.has-navbar-fixed-top{padding-top:3.25rem}body.has-navbar-fixed-bottom,html.has-navbar-fixed-bottom{padding-bottom:3.25rem}.navbar-brand,.navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:3.25rem}.navbar-brand a.navbar-item:focus,.navbar-brand a.navbar-item:hover{background-color:transparent}.navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}.navbar-burger{color:#4a4a4a;cursor:pointer;display:block;height:3.25rem;position:relative;width:3.25rem;margin-right:auto}.navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;transform-origin:center;transition-duration:86ms;transition-property:background-color,opacity,transform;transition-timing-function:ease-out;width:16px}.navbar-burger span:nth-child(1){top:calc(50% - 6px)}.navbar-burger span:nth-child(2){top:calc(50% - 1px)}.navbar-burger span:nth-child(3){top:calc(50% + 4px)}.navbar-burger:hover{background-color:rgba(0,0,0,.05)}.navbar-burger.is-active span:nth-child(1){transform:translateY(5px) rotate(45deg)}.navbar-burger.is-active span:nth-child(2){opacity:0}.navbar-burger.is-active span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}.navbar-menu{display:none}.navbar-item,.navbar-link{color:#4a4a4a;display:block;line-height:1.5;padding:.5rem .75rem;position:relative}.navbar-item .icon:only-child,.navbar-link .icon:only-child{margin-left:-.25rem;margin-right:-.25rem}.navbar-link,a.navbar-item{cursor:pointer}.navbar-link.is-active,.navbar-link:focus,.navbar-link:focus-within,.navbar-link:hover,a.navbar-item.is-active,a.navbar-item:focus,a.navbar-item:focus-within,a.navbar-item:hover{background-color:#fafafa;color:#485fc7}.navbar-item{flex-grow:0;flex-shrink:0}.navbar-item img{max-height:1.75rem}.navbar-item.has-dropdown{padding:0}.navbar-item.is-expanded{flex-grow:1;flex-shrink:1}.navbar-item.is-tab{border-bottom:1px solid transparent;min-height:3.25rem;padding-bottom:calc(.5rem - 1px)}.navbar-item.is-tab:focus,.navbar-item.is-tab:hover{background-color:transparent;border-bottom-color:#485fc7}.navbar-item.is-tab.is-active{background-color:transparent;border-bottom-color:#485fc7;border-bottom-style:solid;border-bottom-width:3px;color:#485fc7;padding-bottom:calc(.5rem - 3px)}.navbar-content{flex-grow:1;flex-shrink:1}.navbar-link:not(.is-arrowless){padding-left:2.5em}.navbar-link:not(.is-arrowless)::after{border-color:#485fc7;margin-top:-.375em;left:1.125em}.navbar-dropdown{font-size:.875rem;padding-bottom:.5rem;padding-top:.5rem}.navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}.navbar-divider{background-color:#f5f5f5;border:none;display:none;height:2px;margin:.5rem 0}@media screen and (max-width:1023px){.navbar>.container{display:block}.navbar-brand .navbar-item,.navbar-tabs .navbar-item{align-items:center;display:flex}.navbar-link::after{display:none}.navbar-menu{background-color:#fff;box-shadow:0 8px 16px rgba(10,10,10,.1);padding:.5rem 0}.navbar-menu.is-active{display:block}.navbar.is-fixed-bottom-touch,.navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-touch{bottom:0}.navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,.1)}.navbar.is-fixed-top-touch{top:0}.navbar.is-fixed-top .navbar-menu,.navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 3.25rem);overflow:auto}body.has-navbar-fixed-top-touch,html.has-navbar-fixed-top-touch{padding-top:3.25rem}body.has-navbar-fixed-bottom-touch,html.has-navbar-fixed-bottom-touch{padding-bottom:3.25rem}}@media screen and (min-width:1024px){.navbar,.navbar-end,.navbar-menu,.navbar-start{align-items:stretch;display:flex}.navbar{min-height:3.25rem}.navbar.is-spaced{padding:1rem 2rem}.navbar.is-spaced .navbar-end,.navbar.is-spaced .navbar-start{align-items:center}.navbar.is-spaced .navbar-link,.navbar.is-spaced a.navbar-item{border-radius:4px}.navbar.is-transparent .navbar-link.is-active,.navbar.is-transparent .navbar-link:focus,.navbar.is-transparent .navbar-link:hover,.navbar.is-transparent a.navbar-item.is-active,.navbar.is-transparent a.navbar-item:focus,.navbar.is-transparent a.navbar-item:hover{background-color:transparent!important}.navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent!important}.navbar.is-transparent .navbar-dropdown a.navbar-item:focus,.navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#485fc7}.navbar-burger{display:none}.navbar-item,.navbar-link{align-items:center;display:flex}.navbar-item.has-dropdown{align-items:stretch}.navbar-item.has-dropdown-up .navbar-link::after{transform:rotate(135deg) translate(.25em,-.25em)}.navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:2px solid #dbdbdb;border-radius:6px 6px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,.1);top:auto}.navbar-item.is-active .navbar-dropdown,.navbar-item.is-hoverable:focus .navbar-dropdown,.navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar-item.is-active .navbar-dropdown.is-boxed,.navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed,.navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed,.navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-active .navbar-dropdown,.navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown,.navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown{opacity:1;pointer-events:auto;transform:translateY(0)}.navbar-menu{flex-grow:1;flex-shrink:0}.navbar-start{justify-content:flex-start;margin-left:auto}.navbar-end{justify-content:flex-end;margin-right:auto}.navbar-dropdown{background-color:#fff;border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:2px solid #dbdbdb;box-shadow:0 8px 8px rgba(10,10,10,.1);display:none;font-size:.875rem;right:0;min-width:100%;position:absolute;top:100%;z-index:20}.navbar-dropdown .navbar-item{padding:.375rem 1rem;white-space:nowrap}.navbar-dropdown a.navbar-item{padding-left:3rem}.navbar-dropdown a.navbar-item:focus,.navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#485fc7}.navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-dropdown{border-radius:6px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));transform:translateY(-5px);transition-duration:86ms;transition-property:opacity,transform}.navbar-dropdown.is-right{left:auto;right:0}.navbar-divider{display:block}.container>.navbar .navbar-brand,.navbar>.container .navbar-brand{margin-right:-.75rem}.container>.navbar .navbar-menu,.navbar>.container .navbar-menu{margin-left:-.75rem}.navbar.is-fixed-bottom-desktop,.navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-desktop{bottom:0}.navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,.1)}.navbar.is-fixed-top-desktop{top:0}body.has-navbar-fixed-top-desktop,html.has-navbar-fixed-top-desktop{padding-top:3.25rem}body.has-navbar-fixed-bottom-desktop,html.has-navbar-fixed-bottom-desktop{padding-bottom:3.25rem}body.has-spaced-navbar-fixed-top,html.has-spaced-navbar-fixed-top{padding-top:5.25rem}body.has-spaced-navbar-fixed-bottom,html.has-spaced-navbar-fixed-bottom{padding-bottom:5.25rem}.navbar-link.is-active,a.navbar-item.is-active{color:#0a0a0a}.navbar-link.is-active:not(:focus):not(:hover),a.navbar-item.is-active:not(:focus):not(:hover){background-color:transparent}.navbar-item.has-dropdown.is-active .navbar-link,.navbar-item.has-dropdown:focus .navbar-link,.navbar-item.has-dropdown:hover .navbar-link{background-color:#fafafa}}.hero.is-fullheight-with-navbar{min-height:calc(100vh - 3.25rem)}.pagination{font-size:1rem;margin:-.25rem}.pagination.is-small{font-size:.75rem}.pagination.is-medium{font-size:1.25rem}.pagination.is-large{font-size:1.5rem}.pagination.is-rounded .pagination-next,.pagination.is-rounded .pagination-previous{padding-left:1em;padding-right:1em;border-radius:9999px}.pagination.is-rounded .pagination-link{border-radius:9999px}.pagination,.pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous{font-size:1em;justify-content:center;margin:.25rem;padding-left:.5em;padding-right:.5em;text-align:center}.pagination-link,.pagination-next,.pagination-previous{border-color:#dbdbdb;color:#363636;min-width:2.5em}.pagination-link:hover,.pagination-next:hover,.pagination-previous:hover{border-color:#b5b5b5;color:#363636}.pagination-link:focus,.pagination-next:focus,.pagination-previous:focus{border-color:#485fc7}.pagination-link:active,.pagination-next:active,.pagination-previous:active{box-shadow:inset 0 1px 2px rgba(10,10,10,.2)}.pagination-link[disabled],.pagination-next[disabled],.pagination-previous[disabled]{background-color:#dbdbdb;border-color:#dbdbdb;box-shadow:none;color:#7a7a7a;opacity:.5}.pagination-next,.pagination-previous{padding-left:.75em;padding-right:.75em;white-space:nowrap}.pagination-link.is-current{background-color:#485fc7;border-color:#485fc7;color:#fff}.pagination-ellipsis{color:#b5b5b5;pointer-events:none}.pagination-list{flex-wrap:wrap}.pagination-list li{list-style:none}@media screen and (max-width:768px){.pagination{flex-wrap:wrap}.pagination-next,.pagination-previous{flex-grow:1;flex-shrink:1}.pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width:769px),print{.pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous{margin-bottom:0;margin-top:0}.pagination-previous{order:2}.pagination-next{order:3}.pagination{justify-content:space-between;margin-bottom:0;margin-top:0}.pagination.is-centered .pagination-previous{order:1}.pagination.is-centered .pagination-list{justify-content:center;order:2}.pagination.is-centered .pagination-next{order:3}.pagination.is-right .pagination-previous{order:1}.pagination.is-right .pagination-next{order:2}.pagination.is-right .pagination-list{justify-content:flex-end;order:3}}.panel{border-radius:6px;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);font-size:1rem}.panel:not(:last-child){margin-bottom:1.5rem}.panel.is-white .panel-heading{background-color:#fff;color:#0a0a0a}.panel.is-white .panel-tabs a.is-active{border-bottom-color:#fff}.panel.is-white .panel-block.is-active .panel-icon{color:#fff}.panel.is-black .panel-heading{background-color:#0a0a0a;color:#fff}.panel.is-black .panel-tabs a.is-active{border-bottom-color:#0a0a0a}.panel.is-black .panel-block.is-active .panel-icon{color:#0a0a0a}.panel.is-light .panel-heading{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.panel.is-light .panel-tabs a.is-active{border-bottom-color:#f5f5f5}.panel.is-light .panel-block.is-active .panel-icon{color:#f5f5f5}.panel.is-dark .panel-heading{background-color:#363636;color:#fff}.panel.is-dark .panel-tabs a.is-active{border-bottom-color:#363636}.panel.is-dark .panel-block.is-active .panel-icon{color:#363636}.panel.is-primary .panel-heading{background-color:#00d1b2;color:#fff}.panel.is-primary .panel-tabs a.is-active{border-bottom-color:#00d1b2}.panel.is-primary .panel-block.is-active .panel-icon{color:#00d1b2}.panel.is-link .panel-heading{background-color:#485fc7;color:#fff}.panel.is-link .panel-tabs a.is-active{border-bottom-color:#485fc7}.panel.is-link .panel-block.is-active .panel-icon{color:#485fc7}.panel.is-info .panel-heading{background-color:#3e8ed0;color:#fff}.panel.is-info .panel-tabs a.is-active{border-bottom-color:#3e8ed0}.panel.is-info .panel-block.is-active .panel-icon{color:#3e8ed0}.panel.is-success .panel-heading{background-color:#48c78e;color:#fff}.panel.is-success .panel-tabs a.is-active{border-bottom-color:#48c78e}.panel.is-success .panel-block.is-active .panel-icon{color:#48c78e}.panel.is-warning .panel-heading{background-color:#ffe08a;color:rgba(0,0,0,.7)}.panel.is-warning .panel-tabs a.is-active{border-bottom-color:#ffe08a}.panel.is-warning .panel-block.is-active .panel-icon{color:#ffe08a}.panel.is-danger .panel-heading{background-color:#f14668;color:#fff}.panel.is-danger .panel-tabs a.is-active{border-bottom-color:#f14668}.panel.is-danger .panel-block.is-active .panel-icon{color:#f14668}.panel-block:not(:last-child),.panel-tabs:not(:last-child){border-bottom:1px solid #ededed}.panel-heading{background-color:#ededed;border-radius:6px 6px 0 0;color:#363636;font-size:1.25em;font-weight:700;line-height:1.25;padding:.75em 1em}.panel-tabs{align-items:flex-end;display:flex;font-size:.875em;justify-content:center}.panel-tabs a{border-bottom:1px solid #dbdbdb;margin-bottom:-1px;padding:.5em}.panel-tabs a.is-active{border-bottom-color:#4a4a4a;color:#363636}.panel-list a{color:#4a4a4a}.panel-list a:hover{color:#485fc7}.panel-block{align-items:center;color:#363636;display:flex;justify-content:flex-start;padding:.5em .75em}.panel-block input[type=checkbox]{margin-left:.75em}.panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}.panel-block.is-wrapped{flex-wrap:wrap}.panel-block.is-active{border-left-color:#485fc7;color:#363636}.panel-block.is-active .panel-icon{color:#485fc7}.panel-block:last-child{border-bottom-left-radius:6px;border-bottom-right-radius:6px}a.panel-block,label.panel-block{cursor:pointer}a.panel-block:hover,label.panel-block:hover{background-color:#f5f5f5}.panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#7a7a7a;margin-left:.75em}.panel-icon .fa{font-size:inherit;line-height:inherit}.tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:1rem;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}.tabs a{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;color:#4a4a4a;display:flex;justify-content:center;margin-bottom:-1px;padding:.5em 1em;vertical-align:top}.tabs a:hover{border-bottom-color:#363636;color:#363636}.tabs li{display:block}.tabs li.is-active a{border-bottom-color:#485fc7;color:#485fc7}.tabs ul{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}.tabs ul.is-left{padding-right:.75em}.tabs ul.is-center{flex:none;justify-content:center;padding-left:.75em;padding-right:.75em}.tabs ul.is-right{justify-content:flex-end;padding-left:.75em}.tabs .icon:first-child{margin-left:.5em}.tabs .icon:last-child{margin-right:.5em}.tabs.is-centered ul{justify-content:center}.tabs.is-right ul{justify-content:flex-end}.tabs.is-boxed a{border:1px solid transparent;border-radius:0 0 4px 4px}.tabs.is-boxed a:hover{background-color:#f5f5f5;border-bottom-color:#dbdbdb}.tabs.is-boxed li.is-active a{background-color:#fff;border-color:#dbdbdb;border-bottom-color:transparent!important}.tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}.tabs.is-toggle a{border-color:#dbdbdb;border-style:solid;border-width:1px;margin-bottom:0;position:relative}.tabs.is-toggle a:hover{background-color:#f5f5f5;border-color:#b5b5b5;z-index:2}.tabs.is-toggle li+li{margin-right:-1px}.tabs.is-toggle li:first-child a{border-top-right-radius:4px;border-bottom-right-radius:4px}.tabs.is-toggle li:last-child a{border-top-left-radius:4px;border-bottom-left-radius:4px}.tabs.is-toggle li.is-active a{background-color:#485fc7;border-color:#485fc7;color:#fff;z-index:1}.tabs.is-toggle ul{border-bottom:none}.tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-right-radius:9999px;border-top-right-radius:9999px;padding-right:1.25em}.tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-left-radius:9999px;border-top-left-radius:9999px;padding-left:1.25em}.tabs.is-small{font-size:.75rem}.tabs.is-medium{font-size:1.25rem}.tabs.is-large{font-size:1.5rem}.column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>.column.is-narrow{flex:none;width:unset}.columns.is-mobile>.column.is-full{flex:none;width:100%}.columns.is-mobile>.column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>.column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>.column.is-half{flex:none;width:50%}.columns.is-mobile>.column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>.column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>.column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>.column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>.column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>.column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>.column.is-offset-three-quarters{margin-right:75%}.columns.is-mobile>.column.is-offset-two-thirds{margin-right:66.6666%}.columns.is-mobile>.column.is-offset-half{margin-right:50%}.columns.is-mobile>.column.is-offset-one-third{margin-right:33.3333%}.columns.is-mobile>.column.is-offset-one-quarter{margin-right:25%}.columns.is-mobile>.column.is-offset-one-fifth{margin-right:20%}.columns.is-mobile>.column.is-offset-two-fifths{margin-right:40%}.columns.is-mobile>.column.is-offset-three-fifths{margin-right:60%}.columns.is-mobile>.column.is-offset-four-fifths{margin-right:80%}.columns.is-mobile>.column.is-0{flex:none;width:0%}.columns.is-mobile>.column.is-offset-0{margin-right:0}.columns.is-mobile>.column.is-1{flex:none;width:8.33333%}.columns.is-mobile>.column.is-offset-1{margin-right:8.33333%}.columns.is-mobile>.column.is-2{flex:none;width:16.66667%}.columns.is-mobile>.column.is-offset-2{margin-right:16.66667%}.columns.is-mobile>.column.is-3{flex:none;width:25%}.columns.is-mobile>.column.is-offset-3{margin-right:25%}.columns.is-mobile>.column.is-4{flex:none;width:33.33333%}.columns.is-mobile>.column.is-offset-4{margin-right:33.33333%}.columns.is-mobile>.column.is-5{flex:none;width:41.66667%}.columns.is-mobile>.column.is-offset-5{margin-right:41.66667%}.columns.is-mobile>.column.is-6{flex:none;width:50%}.columns.is-mobile>.column.is-offset-6{margin-right:50%}.columns.is-mobile>.column.is-7{flex:none;width:58.33333%}.columns.is-mobile>.column.is-offset-7{margin-right:58.33333%}.columns.is-mobile>.column.is-8{flex:none;width:66.66667%}.columns.is-mobile>.column.is-offset-8{margin-right:66.66667%}.columns.is-mobile>.column.is-9{flex:none;width:75%}.columns.is-mobile>.column.is-offset-9{margin-right:75%}.columns.is-mobile>.column.is-10{flex:none;width:83.33333%}.columns.is-mobile>.column.is-offset-10{margin-right:83.33333%}.columns.is-mobile>.column.is-11{flex:none;width:91.66667%}.columns.is-mobile>.column.is-offset-11{margin-right:91.66667%}.columns.is-mobile>.column.is-12{flex:none;width:100%}.columns.is-mobile>.column.is-offset-12{margin-right:100%}@media screen and (max-width:768px){.column.is-narrow-mobile{flex:none;width:unset}.column.is-full-mobile{flex:none;width:100%}.column.is-three-quarters-mobile{flex:none;width:75%}.column.is-two-thirds-mobile{flex:none;width:66.6666%}.column.is-half-mobile{flex:none;width:50%}.column.is-one-third-mobile{flex:none;width:33.3333%}.column.is-one-quarter-mobile{flex:none;width:25%}.column.is-one-fifth-mobile{flex:none;width:20%}.column.is-two-fifths-mobile{flex:none;width:40%}.column.is-three-fifths-mobile{flex:none;width:60%}.column.is-four-fifths-mobile{flex:none;width:80%}.column.is-offset-three-quarters-mobile{margin-right:75%}.column.is-offset-two-thirds-mobile{margin-right:66.6666%}.column.is-offset-half-mobile{margin-right:50%}.column.is-offset-one-third-mobile{margin-right:33.3333%}.column.is-offset-one-quarter-mobile{margin-right:25%}.column.is-offset-one-fifth-mobile{margin-right:20%}.column.is-offset-two-fifths-mobile{margin-right:40%}.column.is-offset-three-fifths-mobile{margin-right:60%}.column.is-offset-four-fifths-mobile{margin-right:80%}.column.is-0-mobile{flex:none;width:0%}.column.is-offset-0-mobile{margin-right:0}.column.is-1-mobile{flex:none;width:8.33333%}.column.is-offset-1-mobile{margin-right:8.33333%}.column.is-2-mobile{flex:none;width:16.66667%}.column.is-offset-2-mobile{margin-right:16.66667%}.column.is-3-mobile{flex:none;width:25%}.column.is-offset-3-mobile{margin-right:25%}.column.is-4-mobile{flex:none;width:33.33333%}.column.is-offset-4-mobile{margin-right:33.33333%}.column.is-5-mobile{flex:none;width:41.66667%}.column.is-offset-5-mobile{margin-right:41.66667%}.column.is-6-mobile{flex:none;width:50%}.column.is-offset-6-mobile{margin-right:50%}.column.is-7-mobile{flex:none;width:58.33333%}.column.is-offset-7-mobile{margin-right:58.33333%}.column.is-8-mobile{flex:none;width:66.66667%}.column.is-offset-8-mobile{margin-right:66.66667%}.column.is-9-mobile{flex:none;width:75%}.column.is-offset-9-mobile{margin-right:75%}.column.is-10-mobile{flex:none;width:83.33333%}.column.is-offset-10-mobile{margin-right:83.33333%}.column.is-11-mobile{flex:none;width:91.66667%}.column.is-offset-11-mobile{margin-right:91.66667%}.column.is-12-mobile{flex:none;width:100%}.column.is-offset-12-mobile{margin-right:100%}}@media screen and (min-width:769px),print{.column.is-narrow,.column.is-narrow-tablet{flex:none;width:unset}.column.is-full,.column.is-full-tablet{flex:none;width:100%}.column.is-three-quarters,.column.is-three-quarters-tablet{flex:none;width:75%}.column.is-two-thirds,.column.is-two-thirds-tablet{flex:none;width:66.6666%}.column.is-half,.column.is-half-tablet{flex:none;width:50%}.column.is-one-third,.column.is-one-third-tablet{flex:none;width:33.3333%}.column.is-one-quarter,.column.is-one-quarter-tablet{flex:none;width:25%}.column.is-one-fifth,.column.is-one-fifth-tablet{flex:none;width:20%}.column.is-two-fifths,.column.is-two-fifths-tablet{flex:none;width:40%}.column.is-three-fifths,.column.is-three-fifths-tablet{flex:none;width:60%}.column.is-four-fifths,.column.is-four-fifths-tablet{flex:none;width:80%}.column.is-offset-three-quarters,.column.is-offset-three-quarters-tablet{margin-right:75%}.column.is-offset-two-thirds,.column.is-offset-two-thirds-tablet{margin-right:66.6666%}.column.is-offset-half,.column.is-offset-half-tablet{margin-right:50%}.column.is-offset-one-third,.column.is-offset-one-third-tablet{margin-right:33.3333%}.column.is-offset-one-quarter,.column.is-offset-one-quarter-tablet{margin-right:25%}.column.is-offset-one-fifth,.column.is-offset-one-fifth-tablet{margin-right:20%}.column.is-offset-two-fifths,.column.is-offset-two-fifths-tablet{margin-right:40%}.column.is-offset-three-fifths,.column.is-offset-three-fifths-tablet{margin-right:60%}.column.is-offset-four-fifths,.column.is-offset-four-fifths-tablet{margin-right:80%}.column.is-0,.column.is-0-tablet{flex:none;width:0%}.column.is-offset-0,.column.is-offset-0-tablet{margin-right:0}.column.is-1,.column.is-1-tablet{flex:none;width:8.33333%}.column.is-offset-1,.column.is-offset-1-tablet{margin-right:8.33333%}.column.is-2,.column.is-2-tablet{flex:none;width:16.66667%}.column.is-offset-2,.column.is-offset-2-tablet{margin-right:16.66667%}.column.is-3,.column.is-3-tablet{flex:none;width:25%}.column.is-offset-3,.column.is-offset-3-tablet{margin-right:25%}.column.is-4,.column.is-4-tablet{flex:none;width:33.33333%}.column.is-offset-4,.column.is-offset-4-tablet{margin-right:33.33333%}.column.is-5,.column.is-5-tablet{flex:none;width:41.66667%}.column.is-offset-5,.column.is-offset-5-tablet{margin-right:41.66667%}.column.is-6,.column.is-6-tablet{flex:none;width:50%}.column.is-offset-6,.column.is-offset-6-tablet{margin-right:50%}.column.is-7,.column.is-7-tablet{flex:none;width:58.33333%}.column.is-offset-7,.column.is-offset-7-tablet{margin-right:58.33333%}.column.is-8,.column.is-8-tablet{flex:none;width:66.66667%}.column.is-offset-8,.column.is-offset-8-tablet{margin-right:66.66667%}.column.is-9,.column.is-9-tablet{flex:none;width:75%}.column.is-offset-9,.column.is-offset-9-tablet{margin-right:75%}.column.is-10,.column.is-10-tablet{flex:none;width:83.33333%}.column.is-offset-10,.column.is-offset-10-tablet{margin-right:83.33333%}.column.is-11,.column.is-11-tablet{flex:none;width:91.66667%}.column.is-offset-11,.column.is-offset-11-tablet{margin-right:91.66667%}.column.is-12,.column.is-12-tablet{flex:none;width:100%}.column.is-offset-12,.column.is-offset-12-tablet{margin-right:100%}}@media screen and (max-width:1023px){.column.is-narrow-touch{flex:none;width:unset}.column.is-full-touch{flex:none;width:100%}.column.is-three-quarters-touch{flex:none;width:75%}.column.is-two-thirds-touch{flex:none;width:66.6666%}.column.is-half-touch{flex:none;width:50%}.column.is-one-third-touch{flex:none;width:33.3333%}.column.is-one-quarter-touch{flex:none;width:25%}.column.is-one-fifth-touch{flex:none;width:20%}.column.is-two-fifths-touch{flex:none;width:40%}.column.is-three-fifths-touch{flex:none;width:60%}.column.is-four-fifths-touch{flex:none;width:80%}.column.is-offset-three-quarters-touch{margin-right:75%}.column.is-offset-two-thirds-touch{margin-right:66.6666%}.column.is-offset-half-touch{margin-right:50%}.column.is-offset-one-third-touch{margin-right:33.3333%}.column.is-offset-one-quarter-touch{margin-right:25%}.column.is-offset-one-fifth-touch{margin-right:20%}.column.is-offset-two-fifths-touch{margin-right:40%}.column.is-offset-three-fifths-touch{margin-right:60%}.column.is-offset-four-fifths-touch{margin-right:80%}.column.is-0-touch{flex:none;width:0%}.column.is-offset-0-touch{margin-right:0}.column.is-1-touch{flex:none;width:8.33333%}.column.is-offset-1-touch{margin-right:8.33333%}.column.is-2-touch{flex:none;width:16.66667%}.column.is-offset-2-touch{margin-right:16.66667%}.column.is-3-touch{flex:none;width:25%}.column.is-offset-3-touch{margin-right:25%}.column.is-4-touch{flex:none;width:33.33333%}.column.is-offset-4-touch{margin-right:33.33333%}.column.is-5-touch{flex:none;width:41.66667%}.column.is-offset-5-touch{margin-right:41.66667%}.column.is-6-touch{flex:none;width:50%}.column.is-offset-6-touch{margin-right:50%}.column.is-7-touch{flex:none;width:58.33333%}.column.is-offset-7-touch{margin-right:58.33333%}.column.is-8-touch{flex:none;width:66.66667%}.column.is-offset-8-touch{margin-right:66.66667%}.column.is-9-touch{flex:none;width:75%}.column.is-offset-9-touch{margin-right:75%}.column.is-10-touch{flex:none;width:83.33333%}.column.is-offset-10-touch{margin-right:83.33333%}.column.is-11-touch{flex:none;width:91.66667%}.column.is-offset-11-touch{margin-right:91.66667%}.column.is-12-touch{flex:none;width:100%}.column.is-offset-12-touch{margin-right:100%}}@media screen and (min-width:1024px){.column.is-narrow-desktop{flex:none;width:unset}.column.is-full-desktop{flex:none;width:100%}.column.is-three-quarters-desktop{flex:none;width:75%}.column.is-two-thirds-desktop{flex:none;width:66.6666%}.column.is-half-desktop{flex:none;width:50%}.column.is-one-third-desktop{flex:none;width:33.3333%}.column.is-one-quarter-desktop{flex:none;width:25%}.column.is-one-fifth-desktop{flex:none;width:20%}.column.is-two-fifths-desktop{flex:none;width:40%}.column.is-three-fifths-desktop{flex:none;width:60%}.column.is-four-fifths-desktop{flex:none;width:80%}.column.is-offset-three-quarters-desktop{margin-right:75%}.column.is-offset-two-thirds-desktop{margin-right:66.6666%}.column.is-offset-half-desktop{margin-right:50%}.column.is-offset-one-third-desktop{margin-right:33.3333%}.column.is-offset-one-quarter-desktop{margin-right:25%}.column.is-offset-one-fifth-desktop{margin-right:20%}.column.is-offset-two-fifths-desktop{margin-right:40%}.column.is-offset-three-fifths-desktop{margin-right:60%}.column.is-offset-four-fifths-desktop{margin-right:80%}.column.is-0-desktop{flex:none;width:0%}.column.is-offset-0-desktop{margin-right:0}.column.is-1-desktop{flex:none;width:8.33333%}.column.is-offset-1-desktop{margin-right:8.33333%}.column.is-2-desktop{flex:none;width:16.66667%}.column.is-offset-2-desktop{margin-right:16.66667%}.column.is-3-desktop{flex:none;width:25%}.column.is-offset-3-desktop{margin-right:25%}.column.is-4-desktop{flex:none;width:33.33333%}.column.is-offset-4-desktop{margin-right:33.33333%}.column.is-5-desktop{flex:none;width:41.66667%}.column.is-offset-5-desktop{margin-right:41.66667%}.column.is-6-desktop{flex:none;width:50%}.column.is-offset-6-desktop{margin-right:50%}.column.is-7-desktop{flex:none;width:58.33333%}.column.is-offset-7-desktop{margin-right:58.33333%}.column.is-8-desktop{flex:none;width:66.66667%}.column.is-offset-8-desktop{margin-right:66.66667%}.column.is-9-desktop{flex:none;width:75%}.column.is-offset-9-desktop{margin-right:75%}.column.is-10-desktop{flex:none;width:83.33333%}.column.is-offset-10-desktop{margin-right:83.33333%}.column.is-11-desktop{flex:none;width:91.66667%}.column.is-offset-11-desktop{margin-right:91.66667%}.column.is-12-desktop{flex:none;width:100%}.column.is-offset-12-desktop{margin-right:100%}}@media screen and (min-width:1216px){.column.is-narrow-widescreen{flex:none;width:unset}.column.is-full-widescreen{flex:none;width:100%}.column.is-three-quarters-widescreen{flex:none;width:75%}.column.is-two-thirds-widescreen{flex:none;width:66.6666%}.column.is-half-widescreen{flex:none;width:50%}.column.is-one-third-widescreen{flex:none;width:33.3333%}.column.is-one-quarter-widescreen{flex:none;width:25%}.column.is-one-fifth-widescreen{flex:none;width:20%}.column.is-two-fifths-widescreen{flex:none;width:40%}.column.is-three-fifths-widescreen{flex:none;width:60%}.column.is-four-fifths-widescreen{flex:none;width:80%}.column.is-offset-three-quarters-widescreen{margin-right:75%}.column.is-offset-two-thirds-widescreen{margin-right:66.6666%}.column.is-offset-half-widescreen{margin-right:50%}.column.is-offset-one-third-widescreen{margin-right:33.3333%}.column.is-offset-one-quarter-widescreen{margin-right:25%}.column.is-offset-one-fifth-widescreen{margin-right:20%}.column.is-offset-two-fifths-widescreen{margin-right:40%}.column.is-offset-three-fifths-widescreen{margin-right:60%}.column.is-offset-four-fifths-widescreen{margin-right:80%}.column.is-0-widescreen{flex:none;width:0%}.column.is-offset-0-widescreen{margin-right:0}.column.is-1-widescreen{flex:none;width:8.33333%}.column.is-offset-1-widescreen{margin-right:8.33333%}.column.is-2-widescreen{flex:none;width:16.66667%}.column.is-offset-2-widescreen{margin-right:16.66667%}.column.is-3-widescreen{flex:none;width:25%}.column.is-offset-3-widescreen{margin-right:25%}.column.is-4-widescreen{flex:none;width:33.33333%}.column.is-offset-4-widescreen{margin-right:33.33333%}.column.is-5-widescreen{flex:none;width:41.66667%}.column.is-offset-5-widescreen{margin-right:41.66667%}.column.is-6-widescreen{flex:none;width:50%}.column.is-offset-6-widescreen{margin-right:50%}.column.is-7-widescreen{flex:none;width:58.33333%}.column.is-offset-7-widescreen{margin-right:58.33333%}.column.is-8-widescreen{flex:none;width:66.66667%}.column.is-offset-8-widescreen{margin-right:66.66667%}.column.is-9-widescreen{flex:none;width:75%}.column.is-offset-9-widescreen{margin-right:75%}.column.is-10-widescreen{flex:none;width:83.33333%}.column.is-offset-10-widescreen{margin-right:83.33333%}.column.is-11-widescreen{flex:none;width:91.66667%}.column.is-offset-11-widescreen{margin-right:91.66667%}.column.is-12-widescreen{flex:none;width:100%}.column.is-offset-12-widescreen{margin-right:100%}}@media screen and (min-width:1408px){.column.is-narrow-fullhd{flex:none;width:unset}.column.is-full-fullhd{flex:none;width:100%}.column.is-three-quarters-fullhd{flex:none;width:75%}.column.is-two-thirds-fullhd{flex:none;width:66.6666%}.column.is-half-fullhd{flex:none;width:50%}.column.is-one-third-fullhd{flex:none;width:33.3333%}.column.is-one-quarter-fullhd{flex:none;width:25%}.column.is-one-fifth-fullhd{flex:none;width:20%}.column.is-two-fifths-fullhd{flex:none;width:40%}.column.is-three-fifths-fullhd{flex:none;width:60%}.column.is-four-fifths-fullhd{flex:none;width:80%}.column.is-offset-three-quarters-fullhd{margin-right:75%}.column.is-offset-two-thirds-fullhd{margin-right:66.6666%}.column.is-offset-half-fullhd{margin-right:50%}.column.is-offset-one-third-fullhd{margin-right:33.3333%}.column.is-offset-one-quarter-fullhd{margin-right:25%}.column.is-offset-one-fifth-fullhd{margin-right:20%}.column.is-offset-two-fifths-fullhd{margin-right:40%}.column.is-offset-three-fifths-fullhd{margin-right:60%}.column.is-offset-four-fifths-fullhd{margin-right:80%}.column.is-0-fullhd{flex:none;width:0%}.column.is-offset-0-fullhd{margin-right:0}.column.is-1-fullhd{flex:none;width:8.33333%}.column.is-offset-1-fullhd{margin-right:8.33333%}.column.is-2-fullhd{flex:none;width:16.66667%}.column.is-offset-2-fullhd{margin-right:16.66667%}.column.is-3-fullhd{flex:none;width:25%}.column.is-offset-3-fullhd{margin-right:25%}.column.is-4-fullhd{flex:none;width:33.33333%}.column.is-offset-4-fullhd{margin-right:33.33333%}.column.is-5-fullhd{flex:none;width:41.66667%}.column.is-offset-5-fullhd{margin-right:41.66667%}.column.is-6-fullhd{flex:none;width:50%}.column.is-offset-6-fullhd{margin-right:50%}.column.is-7-fullhd{flex:none;width:58.33333%}.column.is-offset-7-fullhd{margin-right:58.33333%}.column.is-8-fullhd{flex:none;width:66.66667%}.column.is-offset-8-fullhd{margin-right:66.66667%}.column.is-9-fullhd{flex:none;width:75%}.column.is-offset-9-fullhd{margin-right:75%}.column.is-10-fullhd{flex:none;width:83.33333%}.column.is-offset-10-fullhd{margin-right:83.33333%}.column.is-11-fullhd{flex:none;width:91.66667%}.column.is-offset-11-fullhd{margin-right:91.66667%}.column.is-12-fullhd{flex:none;width:100%}.column.is-offset-12-fullhd{margin-right:100%}}.columns{margin-right:-.75rem;margin-left:-.75rem;margin-top:-.75rem}.columns:last-child{margin-bottom:-.75rem}.columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}.columns.is-centered{justify-content:center}.columns.is-gapless{margin-right:0;margin-left:0;margin-top:0}.columns.is-gapless>.column{margin:0;padding:0!important}.columns.is-gapless:not(:last-child){margin-bottom:1.5rem}.columns.is-gapless:last-child{margin-bottom:0}.columns.is-mobile{display:flex}.columns.is-multiline{flex-wrap:wrap}.columns.is-vcentered{align-items:center}@media screen and (min-width:769px),print{.columns:not(.is-desktop){display:flex}}@media screen and (min-width:1024px){.columns.is-desktop{display:flex}}.columns.is-variable{--columnGap:0.75rem;margin-right:calc(-1 * var(--columnGap));margin-left:calc(-1 * var(--columnGap))}.columns.is-variable>.column{padding-left:var(--columnGap);padding-right:var(--columnGap)}.columns.is-variable.is-0{--columnGap:0rem}@media screen and (max-width:768px){.columns.is-variable.is-0-mobile{--columnGap:0rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-0-tablet{--columnGap:0rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-0-tablet-only{--columnGap:0rem}}@media screen and (max-width:1023px){.columns.is-variable.is-0-touch{--columnGap:0rem}}@media screen and (min-width:1024px){.columns.is-variable.is-0-desktop{--columnGap:0rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-0-desktop-only{--columnGap:0rem}}@media screen and (min-width:1216px){.columns.is-variable.is-0-widescreen{--columnGap:0rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-0-widescreen-only{--columnGap:0rem}}@media screen and (min-width:1408px){.columns.is-variable.is-0-fullhd{--columnGap:0rem}}.columns.is-variable.is-1{--columnGap:0.25rem}@media screen and (max-width:768px){.columns.is-variable.is-1-mobile{--columnGap:0.25rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-1-tablet{--columnGap:0.25rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-1-tablet-only{--columnGap:0.25rem}}@media screen and (max-width:1023px){.columns.is-variable.is-1-touch{--columnGap:0.25rem}}@media screen and (min-width:1024px){.columns.is-variable.is-1-desktop{--columnGap:0.25rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-1-desktop-only{--columnGap:0.25rem}}@media screen and (min-width:1216px){.columns.is-variable.is-1-widescreen{--columnGap:0.25rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-1-widescreen-only{--columnGap:0.25rem}}@media screen and (min-width:1408px){.columns.is-variable.is-1-fullhd{--columnGap:0.25rem}}.columns.is-variable.is-2{--columnGap:0.5rem}@media screen and (max-width:768px){.columns.is-variable.is-2-mobile{--columnGap:0.5rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-2-tablet{--columnGap:0.5rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-2-tablet-only{--columnGap:0.5rem}}@media screen and (max-width:1023px){.columns.is-variable.is-2-touch{--columnGap:0.5rem}}@media screen and (min-width:1024px){.columns.is-variable.is-2-desktop{--columnGap:0.5rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-2-desktop-only{--columnGap:0.5rem}}@media screen and (min-width:1216px){.columns.is-variable.is-2-widescreen{--columnGap:0.5rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-2-widescreen-only{--columnGap:0.5rem}}@media screen and (min-width:1408px){.columns.is-variable.is-2-fullhd{--columnGap:0.5rem}}.columns.is-variable.is-3{--columnGap:0.75rem}@media screen and (max-width:768px){.columns.is-variable.is-3-mobile{--columnGap:0.75rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-3-tablet{--columnGap:0.75rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-3-tablet-only{--columnGap:0.75rem}}@media screen and (max-width:1023px){.columns.is-variable.is-3-touch{--columnGap:0.75rem}}@media screen and (min-width:1024px){.columns.is-variable.is-3-desktop{--columnGap:0.75rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-3-desktop-only{--columnGap:0.75rem}}@media screen and (min-width:1216px){.columns.is-variable.is-3-widescreen{--columnGap:0.75rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-3-widescreen-only{--columnGap:0.75rem}}@media screen and (min-width:1408px){.columns.is-variable.is-3-fullhd{--columnGap:0.75rem}}.columns.is-variable.is-4{--columnGap:1rem}@media screen and (max-width:768px){.columns.is-variable.is-4-mobile{--columnGap:1rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-4-tablet{--columnGap:1rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-4-tablet-only{--columnGap:1rem}}@media screen and (max-width:1023px){.columns.is-variable.is-4-touch{--columnGap:1rem}}@media screen and (min-width:1024px){.columns.is-variable.is-4-desktop{--columnGap:1rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-4-desktop-only{--columnGap:1rem}}@media screen and (min-width:1216px){.columns.is-variable.is-4-widescreen{--columnGap:1rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-4-widescreen-only{--columnGap:1rem}}@media screen and (min-width:1408px){.columns.is-variable.is-4-fullhd{--columnGap:1rem}}.columns.is-variable.is-5{--columnGap:1.25rem}@media screen and (max-width:768px){.columns.is-variable.is-5-mobile{--columnGap:1.25rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-5-tablet{--columnGap:1.25rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-5-tablet-only{--columnGap:1.25rem}}@media screen and (max-width:1023px){.columns.is-variable.is-5-touch{--columnGap:1.25rem}}@media screen and (min-width:1024px){.columns.is-variable.is-5-desktop{--columnGap:1.25rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-5-desktop-only{--columnGap:1.25rem}}@media screen and (min-width:1216px){.columns.is-variable.is-5-widescreen{--columnGap:1.25rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-5-widescreen-only{--columnGap:1.25rem}}@media screen and (min-width:1408px){.columns.is-variable.is-5-fullhd{--columnGap:1.25rem}}.columns.is-variable.is-6{--columnGap:1.5rem}@media screen and (max-width:768px){.columns.is-variable.is-6-mobile{--columnGap:1.5rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-6-tablet{--columnGap:1.5rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-6-tablet-only{--columnGap:1.5rem}}@media screen and (max-width:1023px){.columns.is-variable.is-6-touch{--columnGap:1.5rem}}@media screen and (min-width:1024px){.columns.is-variable.is-6-desktop{--columnGap:1.5rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-6-desktop-only{--columnGap:1.5rem}}@media screen and (min-width:1216px){.columns.is-variable.is-6-widescreen{--columnGap:1.5rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-6-widescreen-only{--columnGap:1.5rem}}@media screen and (min-width:1408px){.columns.is-variable.is-6-fullhd{--columnGap:1.5rem}}.columns.is-variable.is-7{--columnGap:1.75rem}@media screen and (max-width:768px){.columns.is-variable.is-7-mobile{--columnGap:1.75rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-7-tablet{--columnGap:1.75rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-7-tablet-only{--columnGap:1.75rem}}@media screen and (max-width:1023px){.columns.is-variable.is-7-touch{--columnGap:1.75rem}}@media screen and (min-width:1024px){.columns.is-variable.is-7-desktop{--columnGap:1.75rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-7-desktop-only{--columnGap:1.75rem}}@media screen and (min-width:1216px){.columns.is-variable.is-7-widescreen{--columnGap:1.75rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-7-widescreen-only{--columnGap:1.75rem}}@media screen and (min-width:1408px){.columns.is-variable.is-7-fullhd{--columnGap:1.75rem}}.columns.is-variable.is-8{--columnGap:2rem}@media screen and (max-width:768px){.columns.is-variable.is-8-mobile{--columnGap:2rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-8-tablet{--columnGap:2rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-8-tablet-only{--columnGap:2rem}}@media screen and (max-width:1023px){.columns.is-variable.is-8-touch{--columnGap:2rem}}@media screen and (min-width:1024px){.columns.is-variable.is-8-desktop{--columnGap:2rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-8-desktop-only{--columnGap:2rem}}@media screen and (min-width:1216px){.columns.is-variable.is-8-widescreen{--columnGap:2rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-8-widescreen-only{--columnGap:2rem}}@media screen and (min-width:1408px){.columns.is-variable.is-8-fullhd{--columnGap:2rem}}.tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:-webkit-min-content;min-height:-moz-min-content;min-height:min-content}.tile.is-ancestor{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.tile.is-ancestor:last-child{margin-bottom:-.75rem}.tile.is-ancestor:not(:last-child){margin-bottom:.75rem}.tile.is-child{margin:0!important}.tile.is-parent{padding:.75rem}.tile.is-vertical{flex-direction:column}.tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem!important}@media screen and (min-width:769px),print{.tile:not(.is-child){display:flex}.tile.is-1{flex:none;width:8.33333%}.tile.is-2{flex:none;width:16.66667%}.tile.is-3{flex:none;width:25%}.tile.is-4{flex:none;width:33.33333%}.tile.is-5{flex:none;width:41.66667%}.tile.is-6{flex:none;width:50%}.tile.is-7{flex:none;width:58.33333%}.tile.is-8{flex:none;width:66.66667%}.tile.is-9{flex:none;width:75%}.tile.is-10{flex:none;width:83.33333%}.tile.is-11{flex:none;width:91.66667%}.tile.is-12{flex:none;width:100%}}.has-text-white{color:#fff!important}a.has-text-white:focus,a.has-text-white:hover{color:#e6e6e6!important}.has-background-white{background-color:#fff!important}.has-text-black{color:#0a0a0a!important}a.has-text-black:focus,a.has-text-black:hover{color:#000!important}.has-background-black{background-color:#0a0a0a!important}.has-text-light{color:#f5f5f5!important}a.has-text-light:focus,a.has-text-light:hover{color:#dbdbdb!important}.has-background-light{background-color:#f5f5f5!important}.has-text-dark{color:#363636!important}a.has-text-dark:focus,a.has-text-dark:hover{color:#1c1c1c!important}.has-background-dark{background-color:#363636!important}.has-text-primary{color:#00d1b2!important}a.has-text-primary:focus,a.has-text-primary:hover{color:#009e86!important}.has-background-primary{background-color:#00d1b2!important}.has-text-primary-light{color:#ebfffc!important}a.has-text-primary-light:focus,a.has-text-primary-light:hover{color:#b8fff4!important}.has-background-primary-light{background-color:#ebfffc!important}.has-text-primary-dark{color:#00947e!important}a.has-text-primary-dark:focus,a.has-text-primary-dark:hover{color:#00c7a9!important}.has-background-primary-dark{background-color:#00947e!important}.has-text-link{color:#485fc7!important}a.has-text-link:focus,a.has-text-link:hover{color:#3449a8!important}.has-background-link{background-color:#485fc7!important}.has-text-link-light{color:#eff1fa!important}a.has-text-link-light:focus,a.has-text-link-light:hover{color:#c8cfee!important}.has-background-link-light{background-color:#eff1fa!important}.has-text-link-dark{color:#3850b7!important}a.has-text-link-dark:focus,a.has-text-link-dark:hover{color:#576dcb!important}.has-background-link-dark{background-color:#3850b7!important}.has-text-info{color:#3e8ed0!important}a.has-text-info:focus,a.has-text-info:hover{color:#2b74b1!important}.has-background-info{background-color:#3e8ed0!important}.has-text-info-light{color:#eff5fb!important}a.has-text-info-light:focus,a.has-text-info-light:hover{color:#c6ddf1!important}.has-background-info-light{background-color:#eff5fb!important}.has-text-info-dark{color:#296fa8!important}a.has-text-info-dark:focus,a.has-text-info-dark:hover{color:#368ace!important}.has-background-info-dark{background-color:#296fa8!important}.has-text-success{color:#48c78e!important}a.has-text-success:focus,a.has-text-success:hover{color:#34a873!important}.has-background-success{background-color:#48c78e!important}.has-text-success-light{color:#effaf5!important}a.has-text-success-light:focus,a.has-text-success-light:hover{color:#c8eedd!important}.has-background-success-light{background-color:#effaf5!important}.has-text-success-dark{color:#257953!important}a.has-text-success-dark:focus,a.has-text-success-dark:hover{color:#31a06e!important}.has-background-success-dark{background-color:#257953!important}.has-text-warning{color:#ffe08a!important}a.has-text-warning:focus,a.has-text-warning:hover{color:#ffd257!important}.has-background-warning{background-color:#ffe08a!important}.has-text-warning-light{color:#fffaeb!important}a.has-text-warning-light:focus,a.has-text-warning-light:hover{color:#ffecb8!important}.has-background-warning-light{background-color:#fffaeb!important}.has-text-warning-dark{color:#946c00!important}a.has-text-warning-dark:focus,a.has-text-warning-dark:hover{color:#c79200!important}.has-background-warning-dark{background-color:#946c00!important}.has-text-danger{color:#f14668!important}a.has-text-danger:focus,a.has-text-danger:hover{color:#ee1742!important}.has-background-danger{background-color:#f14668!important}.has-text-danger-light{color:#feecf0!important}a.has-text-danger-light:focus,a.has-text-danger-light:hover{color:#fabdc9!important}.has-background-danger-light{background-color:#feecf0!important}.has-text-danger-dark{color:#cc0f35!important}a.has-text-danger-dark:focus,a.has-text-danger-dark:hover{color:#ee2049!important}.has-background-danger-dark{background-color:#cc0f35!important}.has-text-black-bis{color:#121212!important}.has-background-black-bis{background-color:#121212!important}.has-text-black-ter{color:#242424!important}.has-background-black-ter{background-color:#242424!important}.has-text-grey-darker{color:#363636!important}.has-background-grey-darker{background-color:#363636!important}.has-text-grey-dark{color:#4a4a4a!important}.has-background-grey-dark{background-color:#4a4a4a!important}.has-text-grey{color:#7a7a7a!important}.has-background-grey{background-color:#7a7a7a!important}.has-text-grey-light{color:#b5b5b5!important}.has-background-grey-light{background-color:#b5b5b5!important}.has-text-grey-lighter{color:#dbdbdb!important}.has-background-grey-lighter{background-color:#dbdbdb!important}.has-text-white-ter{color:#f5f5f5!important}.has-background-white-ter{background-color:#f5f5f5!important}.has-text-white-bis{color:#fafafa!important}.has-background-white-bis{background-color:#fafafa!important}.is-flex-direction-row{flex-direction:row!important}.is-flex-direction-row-reverse{flex-direction:row-reverse!important}.is-flex-direction-column{flex-direction:column!important}.is-flex-direction-column-reverse{flex-direction:column-reverse!important}.is-flex-wrap-nowrap{flex-wrap:nowrap!important}.is-flex-wrap-wrap{flex-wrap:wrap!important}.is-flex-wrap-wrap-reverse{flex-wrap:wrap-reverse!important}.is-justify-content-flex-start{justify-content:flex-start!important}.is-justify-content-flex-end{justify-content:flex-end!important}.is-justify-content-center{justify-content:center!important}.is-justify-content-space-between{justify-content:space-between!important}.is-justify-content-space-around{justify-content:space-around!important}.is-justify-content-space-evenly{justify-content:space-evenly!important}.is-justify-content-start{justify-content:start!important}.is-justify-content-end{justify-content:end!important}.is-justify-content-left{justify-content:left!important}.is-justify-content-right{justify-content:right!important}.is-align-content-flex-start{align-content:flex-start!important}.is-align-content-flex-end{align-content:flex-end!important}.is-align-content-center{align-content:center!important}.is-align-content-space-between{align-content:space-between!important}.is-align-content-space-around{align-content:space-around!important}.is-align-content-space-evenly{align-content:space-evenly!important}.is-align-content-stretch{align-content:stretch!important}.is-align-content-start{align-content:start!important}.is-align-content-end{align-content:end!important}.is-align-content-baseline{align-content:baseline!important}.is-align-items-stretch{align-items:stretch!important}.is-align-items-flex-start{align-items:flex-start!important}.is-align-items-flex-end{align-items:flex-end!important}.is-align-items-center{align-items:center!important}.is-align-items-baseline{align-items:baseline!important}.is-align-items-start{align-items:start!important}.is-align-items-end{align-items:end!important}.is-align-items-self-start{align-items:self-start!important}.is-align-items-self-end{align-items:self-end!important}.is-align-self-auto{align-self:auto!important}.is-align-self-flex-start{align-self:flex-start!important}.is-align-self-flex-end{align-self:flex-end!important}.is-align-self-center{align-self:center!important}.is-align-self-baseline{align-self:baseline!important}.is-align-self-stretch{align-self:stretch!important}.is-flex-grow-0{flex-grow:0!important}.is-flex-grow-1{flex-grow:1!important}.is-flex-grow-2{flex-grow:2!important}.is-flex-grow-3{flex-grow:3!important}.is-flex-grow-4{flex-grow:4!important}.is-flex-grow-5{flex-grow:5!important}.is-flex-shrink-0{flex-shrink:0!important}.is-flex-shrink-1{flex-shrink:1!important}.is-flex-shrink-2{flex-shrink:2!important}.is-flex-shrink-3{flex-shrink:3!important}.is-flex-shrink-4{flex-shrink:4!important}.is-flex-shrink-5{flex-shrink:5!important}.is-clearfix::after{clear:both;content:" ";display:table}.is-pulled-left{float:left!important}.is-pulled-right{float:right!important}.is-radiusless{border-radius:0!important}.is-shadowless{box-shadow:none!important}.is-clickable{cursor:pointer!important;pointer-events:all!important}.is-clipped{overflow:hidden!important}.is-relative{position:relative!important}.is-marginless{margin:0!important}.is-paddingless{padding:0!important}.m-0{margin:0!important}.mt-0{margin-top:0!important}.mr-0{margin-right:0!important}.mb-0{margin-bottom:0!important}.ml-0{margin-left:0!important}.mx-0{margin-left:0!important;margin-right:0!important}.my-0{margin-top:0!important;margin-bottom:0!important}.m-1{margin:.25rem!important}.mt-1{margin-top:.25rem!important}.mr-1{margin-right:.25rem!important}.mb-1{margin-bottom:.25rem!important}.ml-1{margin-left:.25rem!important}.mx-1{margin-left:.25rem!important;margin-right:.25rem!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-2{margin:.5rem!important}.mt-2{margin-top:.5rem!important}.mr-2{margin-right:.5rem!important}.mb-2{margin-bottom:.5rem!important}.ml-2{margin-left:.5rem!important}.mx-2{margin-left:.5rem!important;margin-right:.5rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-3{margin:.75rem!important}.mt-3{margin-top:.75rem!important}.mr-3{margin-right:.75rem!important}.mb-3{margin-bottom:.75rem!important}.ml-3{margin-left:.75rem!important}.mx-3{margin-left:.75rem!important;margin-right:.75rem!important}.my-3{margin-top:.75rem!important;margin-bottom:.75rem!important}.m-4{margin:1rem!important}.mt-4{margin-top:1rem!important}.mr-4{margin-right:1rem!important}.mb-4{margin-bottom:1rem!important}.ml-4{margin-left:1rem!important}.mx-4{margin-left:1rem!important;margin-right:1rem!important}.my-4{margin-top:1rem!important;margin-bottom:1rem!important}.m-5{margin:1.5rem!important}.mt-5{margin-top:1.5rem!important}.mr-5{margin-right:1.5rem!important}.mb-5{margin-bottom:1.5rem!important}.ml-5{margin-left:1.5rem!important}.mx-5{margin-left:1.5rem!important;margin-right:1.5rem!important}.my-5{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-6{margin:3rem!important}.mt-6{margin-top:3rem!important}.mr-6{margin-right:3rem!important}.mb-6{margin-bottom:3rem!important}.ml-6{margin-left:3rem!important}.mx-6{margin-left:3rem!important;margin-right:3rem!important}.my-6{margin-top:3rem!important;margin-bottom:3rem!important}.m-auto{margin:auto!important}.mt-auto{margin-top:auto!important}.mr-auto{margin-right:auto!important}.mb-auto{margin-bottom:auto!important}.ml-auto{margin-left:auto!important}.mx-auto{margin-left:auto!important;margin-right:auto!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.p-0{padding:0!important}.pt-0{padding-top:0!important}.pr-0{padding-right:0!important}.pb-0{padding-bottom:0!important}.pl-0{padding-left:0!important}.px-0{padding-left:0!important;padding-right:0!important}.py-0{padding-top:0!important;padding-bottom:0!important}.p-1{padding:.25rem!important}.pt-1{padding-top:.25rem!important}.pr-1{padding-right:.25rem!important}.pb-1{padding-bottom:.25rem!important}.pl-1{padding-left:.25rem!important}.px-1{padding-left:.25rem!important;padding-right:.25rem!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-2{padding:.5rem!important}.pt-2{padding-top:.5rem!important}.pr-2{padding-right:.5rem!important}.pb-2{padding-bottom:.5rem!important}.pl-2{padding-left:.5rem!important}.px-2{padding-left:.5rem!important;padding-right:.5rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-3{padding:.75rem!important}.pt-3{padding-top:.75rem!important}.pr-3{padding-right:.75rem!important}.pb-3{padding-bottom:.75rem!important}.pl-3{padding-left:.75rem!important}.px-3{padding-left:.75rem!important;padding-right:.75rem!important}.py-3{padding-top:.75rem!important;padding-bottom:.75rem!important}.p-4{padding:1rem!important}.pt-4{padding-top:1rem!important}.pr-4{padding-right:1rem!important}.pb-4{padding-bottom:1rem!important}.pl-4{padding-left:1rem!important}.px-4{padding-left:1rem!important;padding-right:1rem!important}.py-4{padding-top:1rem!important;padding-bottom:1rem!important}.p-5{padding:1.5rem!important}.pt-5{padding-top:1.5rem!important}.pr-5{padding-right:1.5rem!important}.pb-5{padding-bottom:1.5rem!important}.pl-5{padding-left:1.5rem!important}.px-5{padding-left:1.5rem!important;padding-right:1.5rem!important}.py-5{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-6{padding:3rem!important}.pt-6{padding-top:3rem!important}.pr-6{padding-right:3rem!important}.pb-6{padding-bottom:3rem!important}.pl-6{padding-left:3rem!important}.px-6{padding-left:3rem!important;padding-right:3rem!important}.py-6{padding-top:3rem!important;padding-bottom:3rem!important}.p-auto{padding:auto!important}.pt-auto{padding-top:auto!important}.pr-auto{padding-right:auto!important}.pb-auto{padding-bottom:auto!important}.pl-auto{padding-left:auto!important}.px-auto{padding-left:auto!important;padding-right:auto!important}.py-auto{padding-top:auto!important;padding-bottom:auto!important}.is-size-1{font-size:3rem!important}.is-size-2{font-size:2.5rem!important}.is-size-3{font-size:2rem!important}.is-size-4{font-size:1.5rem!important}.is-size-5{font-size:1.25rem!important}.is-size-6{font-size:1rem!important}.is-size-7{font-size:.75rem!important}@media screen and (max-width:768px){.is-size-1-mobile{font-size:3rem!important}.is-size-2-mobile{font-size:2.5rem!important}.is-size-3-mobile{font-size:2rem!important}.is-size-4-mobile{font-size:1.5rem!important}.is-size-5-mobile{font-size:1.25rem!important}.is-size-6-mobile{font-size:1rem!important}.is-size-7-mobile{font-size:.75rem!important}}@media screen and (min-width:769px),print{.is-size-1-tablet{font-size:3rem!important}.is-size-2-tablet{font-size:2.5rem!important}.is-size-3-tablet{font-size:2rem!important}.is-size-4-tablet{font-size:1.5rem!important}.is-size-5-tablet{font-size:1.25rem!important}.is-size-6-tablet{font-size:1rem!important}.is-size-7-tablet{font-size:.75rem!important}}@media screen and (max-width:1023px){.is-size-1-touch{font-size:3rem!important}.is-size-2-touch{font-size:2.5rem!important}.is-size-3-touch{font-size:2rem!important}.is-size-4-touch{font-size:1.5rem!important}.is-size-5-touch{font-size:1.25rem!important}.is-size-6-touch{font-size:1rem!important}.is-size-7-touch{font-size:.75rem!important}}@media screen and (min-width:1024px){.is-size-1-desktop{font-size:3rem!important}.is-size-2-desktop{font-size:2.5rem!important}.is-size-3-desktop{font-size:2rem!important}.is-size-4-desktop{font-size:1.5rem!important}.is-size-5-desktop{font-size:1.25rem!important}.is-size-6-desktop{font-size:1rem!important}.is-size-7-desktop{font-size:.75rem!important}}@media screen and (min-width:1216px){.is-size-1-widescreen{font-size:3rem!important}.is-size-2-widescreen{font-size:2.5rem!important}.is-size-3-widescreen{font-size:2rem!important}.is-size-4-widescreen{font-size:1.5rem!important}.is-size-5-widescreen{font-size:1.25rem!important}.is-size-6-widescreen{font-size:1rem!important}.is-size-7-widescreen{font-size:.75rem!important}}@media screen and (min-width:1408px){.is-size-1-fullhd{font-size:3rem!important}.is-size-2-fullhd{font-size:2.5rem!important}.is-size-3-fullhd{font-size:2rem!important}.is-size-4-fullhd{font-size:1.5rem!important}.is-size-5-fullhd{font-size:1.25rem!important}.is-size-6-fullhd{font-size:1rem!important}.is-size-7-fullhd{font-size:.75rem!important}}.has-text-centered{text-align:center!important}.has-text-justified{text-align:justify!important}.has-text-left{text-align:left!important}.has-text-right{text-align:right!important}@media screen and (max-width:768px){.has-text-centered-mobile{text-align:center!important}}@media screen and (min-width:769px),print{.has-text-centered-tablet{text-align:center!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-centered-tablet-only{text-align:center!important}}@media screen and (max-width:1023px){.has-text-centered-touch{text-align:center!important}}@media screen and (min-width:1024px){.has-text-centered-desktop{text-align:center!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-centered-desktop-only{text-align:center!important}}@media screen and (min-width:1216px){.has-text-centered-widescreen{text-align:center!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-centered-widescreen-only{text-align:center!important}}@media screen and (min-width:1408px){.has-text-centered-fullhd{text-align:center!important}}@media screen and (max-width:768px){.has-text-justified-mobile{text-align:justify!important}}@media screen and (min-width:769px),print{.has-text-justified-tablet{text-align:justify!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-justified-tablet-only{text-align:justify!important}}@media screen and (max-width:1023px){.has-text-justified-touch{text-align:justify!important}}@media screen and (min-width:1024px){.has-text-justified-desktop{text-align:justify!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-justified-desktop-only{text-align:justify!important}}@media screen and (min-width:1216px){.has-text-justified-widescreen{text-align:justify!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-justified-widescreen-only{text-align:justify!important}}@media screen and (min-width:1408px){.has-text-justified-fullhd{text-align:justify!important}}@media screen and (max-width:768px){.has-text-left-mobile{text-align:left!important}}@media screen and (min-width:769px),print{.has-text-left-tablet{text-align:left!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-left-tablet-only{text-align:left!important}}@media screen and (max-width:1023px){.has-text-left-touch{text-align:left!important}}@media screen and (min-width:1024px){.has-text-left-desktop{text-align:left!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-left-desktop-only{text-align:left!important}}@media screen and (min-width:1216px){.has-text-left-widescreen{text-align:left!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-left-widescreen-only{text-align:left!important}}@media screen and (min-width:1408px){.has-text-left-fullhd{text-align:left!important}}@media screen and (max-width:768px){.has-text-right-mobile{text-align:right!important}}@media screen and (min-width:769px),print{.has-text-right-tablet{text-align:right!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-right-tablet-only{text-align:right!important}}@media screen and (max-width:1023px){.has-text-right-touch{text-align:right!important}}@media screen and (min-width:1024px){.has-text-right-desktop{text-align:right!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-right-desktop-only{text-align:right!important}}@media screen and (min-width:1216px){.has-text-right-widescreen{text-align:right!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-right-widescreen-only{text-align:right!important}}@media screen and (min-width:1408px){.has-text-right-fullhd{text-align:right!important}}.is-capitalized{text-transform:capitalize!important}.is-lowercase{text-transform:lowercase!important}.is-uppercase{text-transform:uppercase!important}.is-italic{font-style:italic!important}.is-underlined{text-decoration:underline!important}.has-text-weight-light{font-weight:300!important}.has-text-weight-normal{font-weight:400!important}.has-text-weight-medium{font-weight:500!important}.has-text-weight-semibold{font-weight:600!important}.has-text-weight-bold{font-weight:700!important}.is-family-primary{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif!important}.is-family-secondary{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif!important}.is-family-sans-serif{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif!important}.is-family-monospace{font-family:monospace!important}.is-family-code{font-family:monospace!important}.is-block{display:block!important}@media screen and (max-width:768px){.is-block-mobile{display:block!important}}@media screen and (min-width:769px),print{.is-block-tablet{display:block!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-block-tablet-only{display:block!important}}@media screen and (max-width:1023px){.is-block-touch{display:block!important}}@media screen and (min-width:1024px){.is-block-desktop{display:block!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-block-desktop-only{display:block!important}}@media screen and (min-width:1216px){.is-block-widescreen{display:block!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-block-widescreen-only{display:block!important}}@media screen and (min-width:1408px){.is-block-fullhd{display:block!important}}.is-flex{display:flex!important}@media screen and (max-width:768px){.is-flex-mobile{display:flex!important}}@media screen and (min-width:769px),print{.is-flex-tablet{display:flex!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-flex-tablet-only{display:flex!important}}@media screen and (max-width:1023px){.is-flex-touch{display:flex!important}}@media screen and (min-width:1024px){.is-flex-desktop{display:flex!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-flex-desktop-only{display:flex!important}}@media screen and (min-width:1216px){.is-flex-widescreen{display:flex!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-flex-widescreen-only{display:flex!important}}@media screen and (min-width:1408px){.is-flex-fullhd{display:flex!important}}.is-inline{display:inline!important}@media screen and (max-width:768px){.is-inline-mobile{display:inline!important}}@media screen and (min-width:769px),print{.is-inline-tablet{display:inline!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-inline-tablet-only{display:inline!important}}@media screen and (max-width:1023px){.is-inline-touch{display:inline!important}}@media screen and (min-width:1024px){.is-inline-desktop{display:inline!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-inline-desktop-only{display:inline!important}}@media screen and (min-width:1216px){.is-inline-widescreen{display:inline!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-inline-widescreen-only{display:inline!important}}@media screen and (min-width:1408px){.is-inline-fullhd{display:inline!important}}.is-inline-block{display:inline-block!important}@media screen and (max-width:768px){.is-inline-block-mobile{display:inline-block!important}}@media screen and (min-width:769px),print{.is-inline-block-tablet{display:inline-block!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-inline-block-tablet-only{display:inline-block!important}}@media screen and (max-width:1023px){.is-inline-block-touch{display:inline-block!important}}@media screen and (min-width:1024px){.is-inline-block-desktop{display:inline-block!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-inline-block-desktop-only{display:inline-block!important}}@media screen and (min-width:1216px){.is-inline-block-widescreen{display:inline-block!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-inline-block-widescreen-only{display:inline-block!important}}@media screen and (min-width:1408px){.is-inline-block-fullhd{display:inline-block!important}}.is-inline-flex{display:inline-flex!important}@media screen and (max-width:768px){.is-inline-flex-mobile{display:inline-flex!important}}@media screen and (min-width:769px),print{.is-inline-flex-tablet{display:inline-flex!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-inline-flex-tablet-only{display:inline-flex!important}}@media screen and (max-width:1023px){.is-inline-flex-touch{display:inline-flex!important}}@media screen and (min-width:1024px){.is-inline-flex-desktop{display:inline-flex!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-inline-flex-desktop-only{display:inline-flex!important}}@media screen and (min-width:1216px){.is-inline-flex-widescreen{display:inline-flex!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-inline-flex-widescreen-only{display:inline-flex!important}}@media screen and (min-width:1408px){.is-inline-flex-fullhd{display:inline-flex!important}}.is-hidden{display:none!important}.is-sr-only{border:none!important;clip:rect(0,0,0,0)!important;height:.01em!important;overflow:hidden!important;padding:0!important;position:absolute!important;white-space:nowrap!important;width:.01em!important}@media screen and (max-width:768px){.is-hidden-mobile{display:none!important}}@media screen and (min-width:769px),print{.is-hidden-tablet{display:none!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-hidden-tablet-only{display:none!important}}@media screen and (max-width:1023px){.is-hidden-touch{display:none!important}}@media screen and (min-width:1024px){.is-hidden-desktop{display:none!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-hidden-desktop-only{display:none!important}}@media screen and (min-width:1216px){.is-hidden-widescreen{display:none!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-hidden-widescreen-only{display:none!important}}@media screen and (min-width:1408px){.is-hidden-fullhd{display:none!important}}.is-invisible{visibility:hidden!important}@media screen and (max-width:768px){.is-invisible-mobile{visibility:hidden!important}}@media screen and (min-width:769px),print{.is-invisible-tablet{visibility:hidden!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-invisible-tablet-only{visibility:hidden!important}}@media screen and (max-width:1023px){.is-invisible-touch{visibility:hidden!important}}@media screen and (min-width:1024px){.is-invisible-desktop{visibility:hidden!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-invisible-desktop-only{visibility:hidden!important}}@media screen and (min-width:1216px){.is-invisible-widescreen{visibility:hidden!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-invisible-widescreen-only{visibility:hidden!important}}@media screen and (min-width:1408px){.is-invisible-fullhd{visibility:hidden!important}}.hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}.hero .navbar{background:0 0}.hero .tabs ul{border-bottom:none}.hero.is-white{background-color:#fff;color:#0a0a0a}.hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-white strong{color:inherit}.hero.is-white .title{color:#0a0a0a}.hero.is-white .subtitle{color:rgba(10,10,10,.9)}.hero.is-white .subtitle a:not(.button),.hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width:1023px){.hero.is-white .navbar-menu{background-color:#fff}}.hero.is-white .navbar-item,.hero.is-white .navbar-link{color:rgba(10,10,10,.7)}.hero.is-white .navbar-link.is-active,.hero.is-white .navbar-link:hover,.hero.is-white a.navbar-item.is-active,.hero.is-white a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.hero.is-white .tabs a{color:#0a0a0a;opacity:.9}.hero.is-white .tabs a:hover{opacity:1}.hero.is-white .tabs li.is-active a{color:#fff!important;opacity:1}.hero.is-white .tabs.is-boxed a,.hero.is-white .tabs.is-toggle a{color:#0a0a0a}.hero.is-white .tabs.is-boxed a:hover,.hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-white .tabs.is-boxed li.is-active a,.hero.is-white .tabs.is-boxed li.is-active a:hover,.hero.is-white .tabs.is-toggle li.is-active a,.hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.hero.is-white.is-bold{background-image:linear-gradient(141deg,#e6e6e6 0,#fff 71%,#fff 100%)}@media screen and (max-width:768px){.hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg,#e6e6e6 0,#fff 71%,#fff 100%)}}.hero.is-black{background-color:#0a0a0a;color:#fff}.hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-black strong{color:inherit}.hero.is-black .title{color:#fff}.hero.is-black .subtitle{color:rgba(255,255,255,.9)}.hero.is-black .subtitle a:not(.button),.hero.is-black .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-black .navbar-menu{background-color:#0a0a0a}}.hero.is-black .navbar-item,.hero.is-black .navbar-link{color:rgba(255,255,255,.7)}.hero.is-black .navbar-link.is-active,.hero.is-black .navbar-link:hover,.hero.is-black a.navbar-item.is-active,.hero.is-black a.navbar-item:hover{background-color:#000;color:#fff}.hero.is-black .tabs a{color:#fff;opacity:.9}.hero.is-black .tabs a:hover{opacity:1}.hero.is-black .tabs li.is-active a{color:#0a0a0a!important;opacity:1}.hero.is-black .tabs.is-boxed a,.hero.is-black .tabs.is-toggle a{color:#fff}.hero.is-black .tabs.is-boxed a:hover,.hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-black .tabs.is-boxed li.is-active a,.hero.is-black .tabs.is-boxed li.is-active a:hover,.hero.is-black .tabs.is-toggle li.is-active a,.hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.hero.is-black.is-bold{background-image:linear-gradient(141deg,#000 0,#0a0a0a 71%,#181616 100%)}@media screen and (max-width:768px){.hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg,#000 0,#0a0a0a 71%,#181616 100%)}}.hero.is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-light strong{color:inherit}.hero.is-light .title{color:rgba(0,0,0,.7)}.hero.is-light .subtitle{color:rgba(0,0,0,.9)}.hero.is-light .subtitle a:not(.button),.hero.is-light .subtitle strong{color:rgba(0,0,0,.7)}@media screen and (max-width:1023px){.hero.is-light .navbar-menu{background-color:#f5f5f5}}.hero.is-light .navbar-item,.hero.is-light .navbar-link{color:rgba(0,0,0,.7)}.hero.is-light .navbar-link.is-active,.hero.is-light .navbar-link:hover,.hero.is-light a.navbar-item.is-active,.hero.is-light a.navbar-item:hover{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.hero.is-light .tabs a{color:rgba(0,0,0,.7);opacity:.9}.hero.is-light .tabs a:hover{opacity:1}.hero.is-light .tabs li.is-active a{color:#f5f5f5!important;opacity:1}.hero.is-light .tabs.is-boxed a,.hero.is-light .tabs.is-toggle a{color:rgba(0,0,0,.7)}.hero.is-light .tabs.is-boxed a:hover,.hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-light .tabs.is-boxed li.is-active a,.hero.is-light .tabs.is-boxed li.is-active a:hover,.hero.is-light .tabs.is-toggle li.is-active a,.hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,.7);border-color:rgba(0,0,0,.7);color:#f5f5f5}.hero.is-light.is-bold{background-image:linear-gradient(141deg,#dfd8d9 0,#f5f5f5 71%,#fff 100%)}@media screen and (max-width:768px){.hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg,#dfd8d9 0,#f5f5f5 71%,#fff 100%)}}.hero.is-dark{background-color:#363636;color:#fff}.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-dark strong{color:inherit}.hero.is-dark .title{color:#fff}.hero.is-dark .subtitle{color:rgba(255,255,255,.9)}.hero.is-dark .subtitle a:not(.button),.hero.is-dark .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-dark .navbar-menu{background-color:#363636}}.hero.is-dark .navbar-item,.hero.is-dark .navbar-link{color:rgba(255,255,255,.7)}.hero.is-dark .navbar-link.is-active,.hero.is-dark .navbar-link:hover,.hero.is-dark a.navbar-item.is-active,.hero.is-dark a.navbar-item:hover{background-color:#292929;color:#fff}.hero.is-dark .tabs a{color:#fff;opacity:.9}.hero.is-dark .tabs a:hover{opacity:1}.hero.is-dark .tabs li.is-active a{color:#363636!important;opacity:1}.hero.is-dark .tabs.is-boxed a,.hero.is-dark .tabs.is-toggle a{color:#fff}.hero.is-dark .tabs.is-boxed a:hover,.hero.is-dark .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-dark .tabs.is-boxed li.is-active a,.hero.is-dark .tabs.is-boxed li.is-active a:hover,.hero.is-dark .tabs.is-toggle li.is-active a,.hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#363636}.hero.is-dark.is-bold{background-image:linear-gradient(141deg,#1f191a 0,#363636 71%,#46403f 100%)}@media screen and (max-width:768px){.hero.is-dark.is-bold .navbar-menu{background-image:linear-gradient(141deg,#1f191a 0,#363636 71%,#46403f 100%)}}.hero.is-primary{background-color:#00d1b2;color:#fff}.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-primary strong{color:inherit}.hero.is-primary .title{color:#fff}.hero.is-primary .subtitle{color:rgba(255,255,255,.9)}.hero.is-primary .subtitle a:not(.button),.hero.is-primary .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-primary .navbar-menu{background-color:#00d1b2}}.hero.is-primary .navbar-item,.hero.is-primary .navbar-link{color:rgba(255,255,255,.7)}.hero.is-primary .navbar-link.is-active,.hero.is-primary .navbar-link:hover,.hero.is-primary a.navbar-item.is-active,.hero.is-primary a.navbar-item:hover{background-color:#00b89c;color:#fff}.hero.is-primary .tabs a{color:#fff;opacity:.9}.hero.is-primary .tabs a:hover{opacity:1}.hero.is-primary .tabs li.is-active a{color:#00d1b2!important;opacity:1}.hero.is-primary .tabs.is-boxed a,.hero.is-primary .tabs.is-toggle a{color:#fff}.hero.is-primary .tabs.is-boxed a:hover,.hero.is-primary .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-primary .tabs.is-boxed li.is-active a,.hero.is-primary .tabs.is-boxed li.is-active a:hover,.hero.is-primary .tabs.is-toggle li.is-active a,.hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#00d1b2}.hero.is-primary.is-bold{background-image:linear-gradient(141deg,#009e6c 0,#00d1b2 71%,#00e7eb 100%)}@media screen and (max-width:768px){.hero.is-primary.is-bold .navbar-menu{background-image:linear-gradient(141deg,#009e6c 0,#00d1b2 71%,#00e7eb 100%)}}.hero.is-link{background-color:#485fc7;color:#fff}.hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-link strong{color:inherit}.hero.is-link .title{color:#fff}.hero.is-link .subtitle{color:rgba(255,255,255,.9)}.hero.is-link .subtitle a:not(.button),.hero.is-link .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-link .navbar-menu{background-color:#485fc7}}.hero.is-link .navbar-item,.hero.is-link .navbar-link{color:rgba(255,255,255,.7)}.hero.is-link .navbar-link.is-active,.hero.is-link .navbar-link:hover,.hero.is-link a.navbar-item.is-active,.hero.is-link a.navbar-item:hover{background-color:#3a51bb;color:#fff}.hero.is-link .tabs a{color:#fff;opacity:.9}.hero.is-link .tabs a:hover{opacity:1}.hero.is-link .tabs li.is-active a{color:#485fc7!important;opacity:1}.hero.is-link .tabs.is-boxed a,.hero.is-link .tabs.is-toggle a{color:#fff}.hero.is-link .tabs.is-boxed a:hover,.hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-link .tabs.is-boxed li.is-active a,.hero.is-link .tabs.is-boxed li.is-active a:hover,.hero.is-link .tabs.is-toggle li.is-active a,.hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#485fc7}.hero.is-link.is-bold{background-image:linear-gradient(141deg,#2959b3 0,#485fc7 71%,#5658d2 100%)}@media screen and (max-width:768px){.hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg,#2959b3 0,#485fc7 71%,#5658d2 100%)}}.hero.is-info{background-color:#3e8ed0;color:#fff}.hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-info strong{color:inherit}.hero.is-info .title{color:#fff}.hero.is-info .subtitle{color:rgba(255,255,255,.9)}.hero.is-info .subtitle a:not(.button),.hero.is-info .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-info .navbar-menu{background-color:#3e8ed0}}.hero.is-info .navbar-item,.hero.is-info .navbar-link{color:rgba(255,255,255,.7)}.hero.is-info .navbar-link.is-active,.hero.is-info .navbar-link:hover,.hero.is-info a.navbar-item.is-active,.hero.is-info a.navbar-item:hover{background-color:#3082c5;color:#fff}.hero.is-info .tabs a{color:#fff;opacity:.9}.hero.is-info .tabs a:hover{opacity:1}.hero.is-info .tabs li.is-active a{color:#3e8ed0!important;opacity:1}.hero.is-info .tabs.is-boxed a,.hero.is-info .tabs.is-toggle a{color:#fff}.hero.is-info .tabs.is-boxed a:hover,.hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-info .tabs.is-boxed li.is-active a,.hero.is-info .tabs.is-boxed li.is-active a:hover,.hero.is-info .tabs.is-toggle li.is-active a,.hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#3e8ed0}.hero.is-info.is-bold{background-image:linear-gradient(141deg,#208fbc 0,#3e8ed0 71%,#4d83db 100%)}@media screen and (max-width:768px){.hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg,#208fbc 0,#3e8ed0 71%,#4d83db 100%)}}.hero.is-success{background-color:#48c78e;color:#fff}.hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-success strong{color:inherit}.hero.is-success .title{color:#fff}.hero.is-success .subtitle{color:rgba(255,255,255,.9)}.hero.is-success .subtitle a:not(.button),.hero.is-success .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-success .navbar-menu{background-color:#48c78e}}.hero.is-success .navbar-item,.hero.is-success .navbar-link{color:rgba(255,255,255,.7)}.hero.is-success .navbar-link.is-active,.hero.is-success .navbar-link:hover,.hero.is-success a.navbar-item.is-active,.hero.is-success a.navbar-item:hover{background-color:#3abb81;color:#fff}.hero.is-success .tabs a{color:#fff;opacity:.9}.hero.is-success .tabs a:hover{opacity:1}.hero.is-success .tabs li.is-active a{color:#48c78e!important;opacity:1}.hero.is-success .tabs.is-boxed a,.hero.is-success .tabs.is-toggle a{color:#fff}.hero.is-success .tabs.is-boxed a:hover,.hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-success .tabs.is-boxed li.is-active a,.hero.is-success .tabs.is-boxed li.is-active a:hover,.hero.is-success .tabs.is-toggle li.is-active a,.hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#48c78e}.hero.is-success.is-bold{background-image:linear-gradient(141deg,#29b35e 0,#48c78e 71%,#56d2af 100%)}@media screen and (max-width:768px){.hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg,#29b35e 0,#48c78e 71%,#56d2af 100%)}}.hero.is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-warning strong{color:inherit}.hero.is-warning .title{color:rgba(0,0,0,.7)}.hero.is-warning .subtitle{color:rgba(0,0,0,.9)}.hero.is-warning .subtitle a:not(.button),.hero.is-warning .subtitle strong{color:rgba(0,0,0,.7)}@media screen and (max-width:1023px){.hero.is-warning .navbar-menu{background-color:#ffe08a}}.hero.is-warning .navbar-item,.hero.is-warning .navbar-link{color:rgba(0,0,0,.7)}.hero.is-warning .navbar-link.is-active,.hero.is-warning .navbar-link:hover,.hero.is-warning a.navbar-item.is-active,.hero.is-warning a.navbar-item:hover{background-color:#ffd970;color:rgba(0,0,0,.7)}.hero.is-warning .tabs a{color:rgba(0,0,0,.7);opacity:.9}.hero.is-warning .tabs a:hover{opacity:1}.hero.is-warning .tabs li.is-active a{color:#ffe08a!important;opacity:1}.hero.is-warning .tabs.is-boxed a,.hero.is-warning .tabs.is-toggle a{color:rgba(0,0,0,.7)}.hero.is-warning .tabs.is-boxed a:hover,.hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-warning .tabs.is-boxed li.is-active a,.hero.is-warning .tabs.is-boxed li.is-active a:hover,.hero.is-warning .tabs.is-toggle li.is-active a,.hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,.7);border-color:rgba(0,0,0,.7);color:#ffe08a}.hero.is-warning.is-bold{background-image:linear-gradient(141deg,#ffb657 0,#ffe08a 71%,#fff6a3 100%)}@media screen and (max-width:768px){.hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg,#ffb657 0,#ffe08a 71%,#fff6a3 100%)}}.hero.is-danger{background-color:#f14668;color:#fff}.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-danger strong{color:inherit}.hero.is-danger .title{color:#fff}.hero.is-danger .subtitle{color:rgba(255,255,255,.9)}.hero.is-danger .subtitle a:not(.button),.hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-danger .navbar-menu{background-color:#f14668}}.hero.is-danger .navbar-item,.hero.is-danger .navbar-link{color:rgba(255,255,255,.7)}.hero.is-danger .navbar-link.is-active,.hero.is-danger .navbar-link:hover,.hero.is-danger a.navbar-item.is-active,.hero.is-danger a.navbar-item:hover{background-color:#ef2e55;color:#fff}.hero.is-danger .tabs a{color:#fff;opacity:.9}.hero.is-danger .tabs a:hover{opacity:1}.hero.is-danger .tabs li.is-active a{color:#f14668!important;opacity:1}.hero.is-danger .tabs.is-boxed a,.hero.is-danger .tabs.is-toggle a{color:#fff}.hero.is-danger .tabs.is-boxed a:hover,.hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-danger .tabs.is-boxed li.is-active a,.hero.is-danger .tabs.is-boxed li.is-active a:hover,.hero.is-danger .tabs.is-toggle li.is-active a,.hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#f14668}.hero.is-danger.is-bold{background-image:linear-gradient(141deg,#fa0a62 0,#f14668 71%,#f7595f 100%)}@media screen and (max-width:768px){.hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg,#fa0a62 0,#f14668 71%,#f7595f 100%)}}.hero.is-small .hero-body{padding:1.5rem}@media screen and (min-width:769px),print{.hero.is-medium .hero-body{padding:9rem 4.5rem}}@media screen and (min-width:769px),print{.hero.is-large .hero-body{padding:18rem 6rem}}.hero.is-fullheight .hero-body,.hero.is-fullheight-with-navbar .hero-body,.hero.is-halfheight .hero-body{align-items:center;display:flex}.hero.is-fullheight .hero-body>.container,.hero.is-fullheight-with-navbar .hero-body>.container,.hero.is-halfheight .hero-body>.container{flex-grow:1;flex-shrink:1}.hero.is-halfheight{min-height:50vh}.hero.is-fullheight{min-height:100vh}.hero-video{overflow:hidden}.hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;transform:translate3d(-50%,-50%,0)}.hero-video.is-transparent{opacity:.3}@media screen and (max-width:768px){.hero-video{display:none}}.hero-buttons{margin-top:1.5rem}@media screen and (max-width:768px){.hero-buttons .button{display:flex}.hero-buttons .button:not(:last-child){margin-bottom:.75rem}}@media screen and (min-width:769px),print{.hero-buttons{display:flex;justify-content:center}.hero-buttons .button:not(:last-child){margin-left:1.5rem}}.hero-foot,.hero-head{flex-grow:0;flex-shrink:0}.hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}@media screen and (min-width:769px),print{.hero-body{padding:3rem 3rem}}.section{padding:3rem 1.5rem}@media screen and (min-width:1024px){.section{padding:3rem 3rem}.section.is-medium{padding:9rem 4.5rem}.section.is-large{padding:18rem 6rem}}.footer{background-color:#fafafa;padding:3rem 1.5rem 6rem} \ No newline at end of file diff --git a/pagetop/static/bulmix/css/bulma-rtl.min.css.map b/pagetop/static/bulmix/css/bulma-rtl.min.css.map new file mode 100644 index 00000000..731168fb --- /dev/null +++ b/pagetop/static/bulmix/css/bulma-rtl.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../bulma.sass","../sass/utilities/_all.sass","../sass/utilities/extends.sass","../sass/utilities/controls.sass","../sass/utilities/initial-variables.sass","bulma-rtl.css","../sass/utilities/mixins.sass","../sass/base/_all.sass","../sass/base/minireset.sass","../sass/base/generic.sass","../sass/utilities/derived-variables.sass","../sass/base/animations.sass","../sass/elements/_all.sass","../sass/elements/box.sass","../sass/elements/button.sass","../sass/utilities/functions.sass","../sass/elements/container.sass","../sass/elements/content.sass","../sass/elements/icon.sass","../sass/elements/image.sass","../sass/elements/notification.sass","../sass/elements/progress.sass","../sass/elements/table.sass","../sass/elements/tag.sass","../sass/elements/title.sass","../sass/elements/other.sass","../sass/form/_all.sass","../sass/form/shared.sass","../sass/form/input-textarea.sass","../sass/form/checkbox-radio.sass","../sass/form/select.sass","../sass/form/file.sass","../sass/form/tools.sass","../sass/components/_all.sass","../sass/components/breadcrumb.sass","../sass/components/card.sass","../sass/components/dropdown.sass","../sass/components/level.sass","../sass/components/media.sass","../sass/components/menu.sass","../sass/components/message.sass","../sass/components/modal.sass","../sass/components/navbar.sass","../sass/components/pagination.sass","../sass/components/panel.sass","../sass/components/tabs.sass","../sass/grid/_all.sass","../sass/grid/columns.sass","../sass/grid/tiles.sass","../sass/helpers/_all.sass","../sass/helpers/color.sass","../sass/helpers/flexbox.sass","../sass/helpers/float.sass","../sass/helpers/other.sass","../sass/helpers/overflow.sass","../sass/helpers/position.sass","../sass/helpers/spacing.sass","../sass/helpers/typography.sass","../sass/helpers/visibility.sass","../sass/layout/_all.sass","../sass/layout/hero.sass","../sass/layout/section.sass","../sass/layout/footer.sass"],"names":[],"mappings":"AACA,6DAAA;ACDA,oBAAA;ACEA;;;;;ECYE,qBAAqB;EACrB,wBAAwB;EACxB,mBAAmB;EACnB,6BAA+C;EAC/C,kBCmDU;EDlDV,gBAAgB;EAChB,oBAAoB;EACpB,eCgBW;EDfX,aAfoB;EAgBpB,2BAA2B;EAC3B,gBAhBuB;EAiBvB,iCAf+D;EAgB/D,gCAfkE;EAgBlE,iCAhBkE;EAiBlE,8BAlB+D;EAmB/D,kBAAkB;EAClB,mBAAmB;AENrB;;AFQE;;;;;;;;;;;;;;;;;EAIE,aAAa;AEQjB;;AFPE;;;;;;;;;;;;;;;;EAEE,mBAAmB;AEwBvB;;AH1DA;;;;EIoKE,2BAA2B;EAC3B,yBAAyB;EACzB,sBAAsB;EACtB,qBAAqB;EACrB,iBAAiB;ADnGnB;;AHlEA;EIwKE,6BAD8B;EAE9B,kBAAkB;EAClB,eAAe;EACf,aAAa;EACb,YAAY;EACZ,cAAc;EACd,eAAe;EACf,qBAAqB;EACrB,oBAAoB;EACpB,kBAAkB;EAClB,QAAQ;EACR,yBAAyB;EACzB,wBAAwB;EACxB,cAAc;ADlGhB;;ACqGE;;EACE,qBFjJkB;ACgDtB;;AHlFA;EI2JE,2BAA2B;EAC3B,yBAAyB;EACzB,sBAAsB;EACtB,qBAAqB;EACrB,iBAAiB;EAwBjB,qBAAqB;EACrB,wBAAwB;EACxB,uCFrM2B;EEsM3B,YAAY;EACZ,qBFlIqB;EEmIrB,eAAe;EACf,oBAAoB;EACpB,qBAAqB;EACrB,YAAY;EACZ,cAAc;EACd,YAAY;EACZ,YAAY;EACZ,gBAAgB;EAChB,eAAe;EACf,gBAAgB;EAChB,eAAe;EACf,aAAa;EACb,kBAAkB;EAClB,mBAAmB;EACnB,WAAW;AD5Fb;;AC6FE;EAEE,uBF5M2B;EE6M3B,WAAW;EACX,cAAc;EACd,SAAS;EACT,kBAAkB;EAClB,QAAQ;EACR,0DAA0D;EAC1D,+BAA+B;AD3FnC;;AC4FE;EACE,WAAW;EACX,UAAU;ADzFd;;AC0FE;EACE,WAAW;EACX,UAAU;ADvFd;;ACwFE;EAEE,uCFzOyB;ACmJ7B;;ACuFE;EACE,uCF3OyB;ACuJ7B;;ACsFE;EACE,YAAY;EACZ,gBAAgB;EAChB,eAAe;EACf,gBAAgB;EAChB,eAAe;EACf,WAAW;ADnFf;;ACoFE;EACE,YAAY;EACZ,gBAAgB;EAChB,eAAe;EACf,gBAAgB;EAChB,eAAe;EACf,WAAW;ADjFf;;ACkFE;EACE,YAAY;EACZ,gBAAgB;EAChB,eAAe;EACf,gBAAgB;EAChB,eAAe;EACf,WAAW;AD/Ef;;AHnKA;EIqPE,mDAA2C;UAA3C,2CAA2C;EAC3C,yBF7P4B;EE8P5B,qBFjMqB;EEkMrB,+BAA+B;EAC/B,6BAA6B;EAC7B,WAAW;EACX,cAAc;EACd,WAAW;EACX,kBAAkB;EAClB,UAAU;AD9EZ;;AH7KA;;;;;;;;;;;;;;;;;EI8PE,SADuB;EAEvB,OAFuB;EAGvB,kBAAkB;EAClB,QAJuB;EAKvB,MALuB;ADxDzB;;AHlMA;EIgDE,qBAAqB;EACrB,wBAAwB;EACxB,gBAAgB;EAChB,gBAAgB;EAChB,YAAY;EACZ,mBAAmB;EACnB,oBAAoB;EACpB,cAAc;EACd,SAAS;EACT,UAAU;ADsJZ;;AEtOA,eAAA;ACAA,0EAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;EAuBE,SAAS;EACT,UAAU;AHyOZ;;AGtOA;;;;;;EAME,eAAe;EACf,mBAAmB;AHyOrB;;AGtOA;EACE,gBAAgB;AHyOlB;;AGtOA;;;;EAIE,SAAS;AHyOX;;AGtOA;EACE,sBAAsB;AHyOxB;;AGvOA;EAII,mBAAmB;AHuOvB;;AGpOA;;EAEE,YAAY;EACZ,eAAe;AHuOjB;;AGpOA;EACE,SAAS;AHuOX;;AGpOA;EACE,yBAAyB;EACzB,iBAAiB;AHuOnB;;AGrOA;;EAEE,UAAU;AHwOZ;;AG1OA;;EAII,mBAAmB;AH2OvB;;AGvQA;EChBE,uBLnB6B;EKoB7B,eAhCc;EAiCd,kCAAkC;EAClC,mCAAmC;EACnC,gBAlCoB;EAmCpB,kBAhCsB;EAiCtB,kBAhCsB;EAiCtB,kCApCiC;EAqCjC,8BAAsB;KAAtB,2BAAsB;UAAtB,sBAAsB;AJ2RxB;;AIzRA;;;;;;;EAOE,cAAc;AJ4RhB;;AI1RA;;;;;;EAME,oLL/ByL;AC4T3L;;AI3RA;;EAEE,6BAA6B;EAC7B,4BAA4B;EAC5B,sBLpC0B;ACkU5B;;AI5RA;EACE,cL7D4B;EK8D5B,cA1DkB;EA2DlB,gBL7BiB;EK8BjB,gBA1DoB;AJyVtB;;AI3RA;EACE,cLtDgC;EKuDhC,eAAe;EACf,qBAAqB;AJ8RvB;;AIjSA;EAKI,mBAAmB;AJgSvB;;AIrSA;EAOI,cL5E0B;AC8W9B;;AIhSA;EACE,4BLxE4B;EKyE5B,cCnBsB;EDoBtB,kBArEiB;EAsEjB,mBAvEkB;EAwElB,4BAzEgC;AJ4WlC;;AIjSA;EACE,4BL/E4B;EKgF5B,YAAY;EACZ,cAAc;EACd,WAxEa;EAyEb,gBAxEkB;AJ4WpB;;AIlSA;EACE,YAAY;EACZ,eAAe;AJqSjB;;AInSA;;EAEE,wBAAwB;AJsS1B;;AIpSA;EACE,kBAvFuB;AJ8XzB;;AIrSA;EACE,mBAAmB;EACnB,oBAAoB;AJwStB;;AItSA;EACE,cL5G4B;EK6G5B,gBLvEe;ACgXjB;;AIrSA;EACE,YAAY;AJwSd;;AItSA;EH5DE,iCAAiC;EG8DjC,4BL/G4B;EKgH5B,cLtH4B;EKuH5B,kBAjGqB;EAkGrB,gBAAgB;EAChB,uBAlG0B;EAmG1B,gBAAgB;EAChB,iBAAiB;AJySnB;;AIjTA;EAUI,6BAA6B;EAC7B,mBAAmB;EACnB,cAvGoB;EAwGpB,UAAU;AJ2Sd;;AIzSA;;EAGI,mBAAmB;AJ2SvB;;AI9SA;;EAKM,mBAAmB;AJ8SzB;;AInTA;EAOI,cL1I0B;AC0b9B;;AMhcA;EACE;IACE,uBAAuB;ENmczB;EMlcA;IACE,yBAAyB;ENoc3B;AACF;;AMzcA;EACE;IACE,uBAAuB;ENmczB;EMlcA;IACE,yBAAyB;ENoc3B;AACF;;AOzcA,mBAAA;ACWA;EAEE,uBTE6B;ESD7B,kBTwDgB;ESvDhB,0FTb2B;ESc3B,cTT4B;ESU5B,cAAc;EACd,gBAZmB;AR6crB;;AQ/bA;EAGI,yETD8B;ACiclC;;AQncA;EAKI,oETH8B;ACqclC;;AShaA;EAGE,uBV/C6B;EUgD7B,qBVrD4B;EUsD5B,iBX3DwB;EW4DxB,cV3D4B;EU4D5B,eAAe;EAGf,uBAAuB;EACvB,iCA5D6D;EA6D7D,iBA5D6B;EA6D7B,kBA7D6B;EA8D7B,8BA/D6D;EAgE7D,kBAAkB;EAClB,mBAAmB;AT+ZrB;;AS/aA;EAkBI,cAAc;ATialB;;ASnbA;EAwBM,aAAa;EACb,YAAY;AT+ZlB;;ASxbA;ER+FI,gCQpEsG;ERoEtG,mBQnEmE;ATiavE;;AS7bA;ER+FI,oBQjEmE;ERiEnE,+BQhEsG;ATma1G;;ASlcA;EAiCM,+BAAiF;EACjF,gCAAkF;ATqaxF;;ASvcA;EAsCI,qBVxF0B;EUyF1B,cV5F0B;ACigB9B;;AS5cA;EA0CI,qBV/E8B;EUgF9B,cVhG0B;ACsgB9B;;ASjdA;EA6CM,iDVlF4B;AC0flC;;ASrdA;EAgDI,qBVpG0B;EUqG1B,cVtG0B;AC+gB9B;;AS1dA;EAoDI,6BAA6B;EAC7B,yBAAyB;EACzB,cV1G0B;EU2G1B,0BAzF8B;ATmgBlC;;ASjeA;EA4DM,4BV1GwB;EU2GxB,cVlHwB;AC2hB9B;;ASteA;EAgEM,yBCd2B;EDe3B,cVtHwB;ACgiB9B;;AS3eA;;EAoEM,6BAA6B;EAC7B,yBAAyB;EACzB,gBAAgB;AT4atB;;ASlfA;EAwEI,gBAtG0B;EAuG1B,yBAtGmC;EAuGnC,cV/G8B;EUgH9B,qBAtG0B;ATohB9B;;ASzfA;EA8EM,cVnH4B;EUoH5B,0BAxGmC;ATuhBzC;;AS9fA;EAoFM,uBVhIyB;EUiIzB,yBAAyB;EACzB,cV/IuB;AC6jB7B;;ASpgBA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,cVpJqB;ACmkB7B;;AS1gBA;EA8FQ,yBAAyB;EACzB,cVxJqB;ACwkB7B;;AS/gBA;EAiGU,mDV7IqB;AC+jB/B;;ASnhBA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,cV/JqB;ACklB7B;;ASzhBA;;EAyGQ,uBVrJuB;EUsJvB,yBAAyB;EACzB,gBAAgB;ATqbxB;;AShiBA;EA6GQ,yBVtKqB;EUuKrB,YV1JuB;ACilB/B;;ASriBA;EAiHU,uBC/DuB;AVufjC;;ASziBA;;EAoHU,yBV7KmB;EU8KnB,yBAAyB;EACzB,gBAAgB;EAChB,YVnKqB;AC6lB/B;;ASjjBA;EA0HU,gEAA4E;AT2btF;;ASrjBA;EA4HQ,6BAA6B;EAC7B,mBVzKuB;EU0KvB,YV1KuB;ACumB/B;;AS3jBA;EAmIU,uBV/KqB;EUgLrB,mBVhLqB;EUiLrB,cV9LmB;AC0nB7B;;ASjkBA;EAwIY,4DAA8D;AT6b1E;;ASrkBA;EA8Ic,gEAA4E;AT2b1F;;ASzkBA;;EAiJU,6BAA6B;EAC7B,mBV9LqB;EU+LrB,gBAAgB;EAChB,YVhMqB;AC6nB/B;;ASjlBA;EAsJQ,6BAA6B;EAC7B,qBVhNqB;EUiNrB,cVjNqB;ACgpB7B;;ASvlBA;EA6JU,yBVtNmB;EUuNnB,YV1MqB;ACwoB/B;;AS5lBA;EAqKc,4DAA8D;AT2b5E;;AShmBA;;EAwKU,6BAA6B;EAC7B,qBVlOmB;EUmOnB,gBAAgB;EAChB,cVpOmB;ACiqB7B;;ASxmBA;EAoFM,yBV7IuB;EU8IvB,yBAAyB;EACzB,YVlIyB;AC0pB/B;;AS9mBA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,YVvIuB;ACgqB/B;;ASpnBA;EA8FQ,yBAAyB;EACzB,YV3IuB;ACqqB/B;;ASznBA;EAiGU,gDV1JmB;ACsrB7B;;AS7nBA;EAoGQ,uBClDyB;EDmDzB,yBAAyB;EACzB,YVlJuB;AC+qB/B;;ASnoBA;;EAyGQ,yBVlKqB;EUmKrB,yBAAyB;EACzB,gBAAgB;AT+hBxB;;AS1oBA;EA6GQ,uBVzJuB;EU0JvB,cVvKqB;ACwsB7B;;AS/oBA;EAiHU,yBC/DuB;AVimBjC;;ASnpBA;;EAoHU,uBVhKqB;EUiKrB,yBAAyB;EACzB,gBAAgB;EAChB,cVhLmB;ACotB7B;;AS3pBA;EA0HU,4DAA4E;ATqiBtF;;AS/pBA;EA4HQ,6BAA6B;EAC7B,qBVtLqB;EUuLrB,cVvLqB;AC8tB7B;;ASrqBA;EAmIU,yBV5LmB;EU6LnB,qBV7LmB;EU8LnB,YVjLqB;ACutB/B;;AS3qBA;EAwIY,gEAA8D;ATuiB1E;;AS/qBA;EA8Ic,4DAA4E;ATqiB1F;;ASnrBA;;EAiJU,6BAA6B;EAC7B,qBV3MmB;EU4MnB,gBAAgB;EAChB,cV7MmB;ACovB7B;;AS3rBA;EAsJQ,6BAA6B;EAC7B,mBVnMuB;EUoMvB,YVpMuB;AC6uB/B;;ASjsBA;EA6JU,uBVzMqB;EU0MrB,cVvNmB;AC+vB7B;;AStsBA;EAqKc,gEAA8D;ATqiB5E;;AS1sBA;;EAwKU,6BAA6B;EAC7B,mBVrNqB;EUsNrB,gBAAgB;EAChB,YVvNqB;AC8vB/B;;ASltBA;EAoFM,4BVlIwB;EUmIxB,yBAAyB;EACzB,yBCjEe;AVmsBrB;;ASxtBA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,yBCtEa;AVysBrB;;AS9tBA;EA8FQ,yBAAyB;EACzB,yBC1Ea;AV8sBrB;;ASnuBA;EAiGU,mDV/IoB;ACqxB9B;;ASvuBA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,yBCjFa;AVwtBrB;;AS7uBA;;EAyGQ,4BVvJsB;EUwJtB,yBAAyB;EACzB,gBAAgB;ATyoBxB;;ASpvBA;EA6GQ,oCCxFa;EDyFb,iBV5JsB;ACuyB9B;;ASzvBA;EAiHU,oCC/DuB;AV2sBjC;;AS7vBA;;EAoHU,oCC/FW;EDgGX,yBAAyB;EACzB,gBAAgB;EAChB,iBVrKoB;ACmzB9B;;ASrwBA;EA0HU,sFAA4E;AT+oBtF;;ASzwBA;EA4HQ,6BAA6B;EAC7B,wBV3KsB;EU4KtB,iBV5KsB;AC6zB9B;;AS/wBA;EAmIU,4BVjLoB;EUkLpB,wBVlLoB;EUmLpB,yBChHW;AVgwBrB;;ASrxBA;EAwIY,sEAA8D;ATipB1E;;ASzxBA;EA8Ic,sFAA4E;AT+oB1F;;AS7xBA;;EAiJU,6BAA6B;EAC7B,wBVhMoB;EUiMpB,gBAAgB;EAChB,iBVlMoB;ACm1B9B;;ASryBA;EAsJQ,6BAA6B;EAC7B,gCClIa;EDmIb,yBCnIa;AVsxBrB;;AS3yBA;EA6JU,oCCxIW;EDyIX,iBV5MoB;AC81B9B;;AShzBA;EAqKc,sEAA8D;AT+oB5E;;ASpzBA;;EAwKU,6BAA6B;EAC7B,gCCpJW;EDqJX,gBAAgB;EAChB,yBCtJW;AVuyBrB;;AS5zBA;EAoFM,yBVzIwB;EU0IxB,yBAAyB;EACzB,WC/DU;AV2yBhB;;ASl0BA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,WCpEQ;AVizBhB;;ASx0BA;EA8FQ,yBAAyB;EACzB,WCxEQ;AVszBhB;;AS70BA;EAiGU,gDVtJoB;ACs4B9B;;ASj1BA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,WC/EQ;AVg0BhB;;ASv1BA;;EAyGQ,yBV9JsB;EU+JtB,yBAAyB;EACzB,gBAAgB;ATmvBxB;;AS91BA;EA6GQ,sBCtFQ;EDuFR,cVnKsB;ACw5B9B;;ASn2BA;EAiHU,yBC/DuB;AVqzBjC;;ASv2BA;;EAoHU,sBC7FM;ED8FN,yBAAyB;EACzB,gBAAgB;EAChB,cV5KoB;ACo6B9B;;AS/2BA;EA0HU,0DAA4E;ATyvBtF;;ASn3BA;EA4HQ,6BAA6B;EAC7B,qBVlLsB;EUmLtB,cVnLsB;AC86B9B;;ASz3BA;EAmIU,yBVxLoB;EUyLpB,qBVzLoB;EU0LpB,WC9GM;AVw2BhB;;AS/3BA;EAwIY,gEAA8D;AT2vB1E;;ASn4BA;EA8Ic,0DAA4E;ATyvB1F;;ASv4BA;;EAiJU,6BAA6B;EAC7B,qBVvMoB;EUwMpB,gBAAgB;EAChB,cVzMoB;ACo8B9B;;AS/4BA;EAsJQ,6BAA6B;EAC7B,kBChIQ;EDiIR,WCjIQ;AV83BhB;;ASr5BA;EA6JU,sBCtIM;EDuIN,cVnNoB;AC+8B9B;;AS15BA;EAqKc,gEAA8D;ATyvB5E;;AS95BA;;EAwKU,6BAA6B;EAC7B,kBClJM;EDmJN,gBAAgB;EAChB,WCpJM;AV+4BhB;;ASt6BA;EAoFM,yBV3H4B;EU4H5B,yBAAyB;EACzB,WC/DU;AVq5BhB;;AS56BA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,WCpEQ;AV25BhB;;ASl7BA;EA8FQ,yBAAyB;EACzB,WCxEQ;AVg6BhB;;ASv7BA;EAiGU,iDVxIwB;ACk+BlC;;AS37BA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,WC/EQ;AV06BhB;;ASj8BA;;EAyGQ,yBVhJ0B;EUiJ1B,yBAAyB;EACzB,gBAAgB;AT61BxB;;ASx8BA;EA6GQ,sBCtFQ;EDuFR,cVrJ0B;ACo/BlC;;AS78BA;EAiHU,yBC/DuB;AV+5BjC;;ASj9BA;;EAoHU,sBC7FM;ED8FN,yBAAyB;EACzB,gBAAgB;EAChB,cV9JwB;ACggClC;;ASz9BA;EA0HU,0DAA4E;ATm2BtF;;AS79BA;EA4HQ,6BAA6B;EAC7B,qBVpK0B;EUqK1B,cVrK0B;AC0gClC;;ASn+BA;EAmIU,yBV1KwB;EU2KxB,qBV3KwB;EU4KxB,WC9GM;AVk9BhB;;ASz+BA;EAwIY,gEAA8D;ATq2B1E;;AS7+BA;EA8Ic,0DAA4E;ATm2B1F;;ASj/BA;;EAiJU,6BAA6B;EAC7B,qBVzLwB;EU0LxB,gBAAgB;EAChB,cV3LwB;ACgiClC;;ASz/BA;EAsJQ,6BAA6B;EAC7B,kBChIQ;EDiIR,WCjIQ;AVw+BhB;;AS//BA;EA6JU,sBCtIM;EDuIN,cVrMwB;AC2iClC;;ASpgCA;EAqKc,gEAA8D;ATm2B5E;;ASxgCA;;EAwKU,6BAA6B;EAC7B,kBClJM;EDmJN,gBAAgB;EAChB,WCpJM;AVy/BhB;;AShhCA;EAiLU,yBCnJsC;EDoJtC,cC3I2D;AV8+BrE;;ASrhCA;EAqLY,yBCnIqB;EDoIrB,yBAAyB;EACzB,cChJyD;AVo/BrE;;AS3hCA;EA0LY,yBCxIqB;EDyIrB,yBAAyB;EACzB,cCrJyD;AV0/BrE;;ASjiCA;EAoFM,yBVzH4B;EU0H5B,yBAAyB;EACzB,WC/DU;AVghChB;;ASviCA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,WCpEQ;AVshChB;;AS7iCA;EA8FQ,yBAAyB;EACzB,WCxEQ;AV2hChB;;ASljCA;EAiGU,iDVtIwB;AC2lClC;;AStjCA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,WC/EQ;AVqiChB;;AS5jCA;;EAyGQ,yBV9I0B;EU+I1B,yBAAyB;EACzB,gBAAgB;ATw9BxB;;ASnkCA;EA6GQ,sBCtFQ;EDuFR,cVnJ0B;AC6mClC;;ASxkCA;EAiHU,yBC/DuB;AV0hCjC;;AS5kCA;;EAoHU,sBC7FM;ED8FN,yBAAyB;EACzB,gBAAgB;EAChB,cV5JwB;ACynClC;;ASplCA;EA0HU,0DAA4E;AT89BtF;;ASxlCA;EA4HQ,6BAA6B;EAC7B,qBVlK0B;EUmK1B,cVnK0B;ACmoClC;;AS9lCA;EAmIU,yBVxKwB;EUyKxB,qBVzKwB;EU0KxB,WC9GM;AV6kChB;;ASpmCA;EAwIY,gEAA8D;ATg+B1E;;ASxmCA;EA8Ic,0DAA4E;AT89B1F;;AS5mCA;;EAiJU,6BAA6B;EAC7B,qBVvLwB;EUwLxB,gBAAgB;EAChB,cVzLwB;ACypClC;;ASpnCA;EAsJQ,6BAA6B;EAC7B,kBChIQ;EDiIR,WCjIQ;AVmmChB;;AS1nCA;EA6JU,sBCtIM;EDuIN,cVnMwB;ACoqClC;;AS/nCA;EAqKc,gEAA8D;AT89B5E;;ASnoCA;;EAwKU,6BAA6B;EAC7B,kBClJM;EDmJN,gBAAgB;EAChB,WCpJM;AVonChB;;AS3oCA;EAiLU,yBCnJsC;EDoJtC,cC3I2D;AVymCrE;;AShpCA;EAqLY,yBCnIqB;EDoIrB,yBAAyB;EACzB,cChJyD;AV+mCrE;;AStpCA;EA0LY,yBCxIqB;EDyIrB,yBAAyB;EACzB,cCrJyD;AVqnCrE;;AS5pCA;EAoFM,yBV1H4B;EU2H5B,yBAAyB;EACzB,WC/DU;AV2oChB;;ASlqCA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,WCpEQ;AVipChB;;ASxqCA;EA8FQ,yBAAyB;EACzB,WCxEQ;AVspChB;;AS7qCA;EAiGU,kDVvIwB;ACutClC;;ASjrCA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,WC/EQ;AVgqChB;;ASvrCA;;EAyGQ,yBV/I0B;EUgJ1B,yBAAyB;EACzB,gBAAgB;ATmlCxB;;AS9rCA;EA6GQ,sBCtFQ;EDuFR,cVpJ0B;ACyuClC;;ASnsCA;EAiHU,yBC/DuB;AVqpCjC;;ASvsCA;;EAoHU,sBC7FM;ED8FN,yBAAyB;EACzB,gBAAgB;EAChB,cV7JwB;ACqvClC;;AS/sCA;EA0HU,0DAA4E;ATylCtF;;ASntCA;EA4HQ,6BAA6B;EAC7B,qBVnK0B;EUoK1B,cVpK0B;AC+vClC;;ASztCA;EAmIU,yBVzKwB;EU0KxB,qBV1KwB;EU2KxB,WC9GM;AVwsChB;;AS/tCA;EAwIY,gEAA8D;AT2lC1E;;ASnuCA;EA8Ic,0DAA4E;ATylC1F;;ASvuCA;;EAiJU,6BAA6B;EAC7B,qBVxLwB;EUyLxB,gBAAgB;EAChB,cV1LwB;ACqxClC;;AS/uCA;EAsJQ,6BAA6B;EAC7B,kBChIQ;EDiIR,WCjIQ;AV8tChB;;ASrvCA;EA6JU,sBCtIM;EDuIN,cVpMwB;ACgyClC;;AS1vCA;EAqKc,gEAA8D;ATylC5E;;AS9vCA;;EAwKU,6BAA6B;EAC7B,kBClJM;EDmJN,gBAAgB;EAChB,WCpJM;AV+uChB;;AStwCA;EAiLU,yBCnJsC;EDoJtC,cC3I2D;AVouCrE;;AS3wCA;EAqLY,yBCnIqB;EDoIrB,yBAAyB;EACzB,cChJyD;AV0uCrE;;ASjxCA;EA0LY,yBCxIqB;EDyIrB,yBAAyB;EACzB,cCrJyD;AVgvCrE;;ASvxCA;EAoFM,yBV5H4B;EU6H5B,yBAAyB;EACzB,WC/DU;AVswChB;;AS7xCA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,WCpEQ;AV4wChB;;ASnyCA;EA8FQ,yBAAyB;EACzB,WCxEQ;AVixChB;;ASxyCA;EAiGU,kDVzIwB;ACo1ClC;;AS5yCA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,WC/EQ;AV2xChB;;ASlzCA;;EAyGQ,yBVjJ0B;EUkJ1B,yBAAyB;EACzB,gBAAgB;AT8sCxB;;ASzzCA;EA6GQ,sBCtFQ;EDuFR,cVtJ0B;ACs2ClC;;AS9zCA;EAiHU,yBC/DuB;AVgxCjC;;ASl0CA;;EAoHU,sBC7FM;ED8FN,yBAAyB;EACzB,gBAAgB;EAChB,cV/JwB;ACk3ClC;;AS10CA;EA0HU,0DAA4E;ATotCtF;;AS90CA;EA4HQ,6BAA6B;EAC7B,qBVrK0B;EUsK1B,cVtK0B;AC43ClC;;ASp1CA;EAmIU,yBV3KwB;EU4KxB,qBV5KwB;EU6KxB,WC9GM;AVm0ChB;;AS11CA;EAwIY,gEAA8D;ATstC1E;;AS91CA;EA8Ic,0DAA4E;ATotC1F;;ASl2CA;;EAiJU,6BAA6B;EAC7B,qBV1LwB;EU2LxB,gBAAgB;EAChB,cV5LwB;ACk5ClC;;AS12CA;EAsJQ,6BAA6B;EAC7B,kBChIQ;EDiIR,WCjIQ;AVy1ChB;;ASh3CA;EA6JU,sBCtIM;EDuIN,cVtMwB;AC65ClC;;ASr3CA;EAqKc,gEAA8D;ATotC5E;;ASz3CA;;EAwKU,6BAA6B;EAC7B,kBClJM;EDmJN,gBAAgB;EAChB,WCpJM;AV02ChB;;ASj4CA;EAiLU,yBCnJsC;EDoJtC,cC3I2D;AV+1CrE;;ASt4CA;EAqLY,yBCnIqB;EDoIrB,yBAAyB;EACzB,cChJyD;AVq2CrE;;AS54CA;EA0LY,yBCxIqB;EDyIrB,yBAAyB;EACzB,cCrJyD;AV22CrE;;ASl5CA;EAoFM,yBV7H4B;EU8H5B,yBAAyB;EACzB,yBCjEe;AVm4CrB;;ASx5CA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,yBCtEa;AVy4CrB;;AS95CA;EA8FQ,yBAAyB;EACzB,yBC1Ea;AV84CrB;;ASn6CA;EAiGU,mDV1IwB;ACg9ClC;;ASv6CA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,yBCjFa;AVw5CrB;;AS76CA;;EAyGQ,yBVlJ0B;EUmJ1B,yBAAyB;EACzB,gBAAgB;ATy0CxB;;ASp7CA;EA6GQ,oCCxFa;EDyFb,cVvJ0B;ACk+ClC;;ASz7CA;EAiHU,oCC/DuB;AV24CjC;;AS77CA;;EAoHU,oCC/FW;EDgGX,yBAAyB;EACzB,gBAAgB;EAChB,cVhKwB;AC8+ClC;;ASr8CA;EA0HU,sFAA4E;AT+0CtF;;ASz8CA;EA4HQ,6BAA6B;EAC7B,qBVtK0B;EUuK1B,cVvK0B;ACw/ClC;;AS/8CA;EAmIU,yBV5KwB;EU6KxB,qBV7KwB;EU8KxB,yBChHW;AVg8CrB;;ASr9CA;EAwIY,gEAA8D;ATi1C1E;;ASz9CA;EA8Ic,sFAA4E;AT+0C1F;;AS79CA;;EAiJU,6BAA6B;EAC7B,qBV3LwB;EU4LxB,gBAAgB;EAChB,cV7LwB;AC8gDlC;;ASr+CA;EAsJQ,6BAA6B;EAC7B,gCClIa;EDmIb,yBCnIa;AVs9CrB;;AS3+CA;EA6JU,oCCxIW;EDyIX,cVvMwB;ACyhDlC;;ASh/CA;EAqKc,gEAA8D;AT+0C5E;;ASp/CA;;EAwKU,6BAA6B;EAC7B,gCCpJW;EDqJX,gBAAgB;EAChB,yBCtJW;AVu+CrB;;AS5/CA;EAiLU,yBCnJsC;EDoJtC,cC3I2D;AV09CrE;;ASjgDA;EAqLY,yBCnIqB;EDoIrB,yBAAyB;EACzB,cChJyD;AVg+CrE;;ASvgDA;EA0LY,yBCxIqB;EDyIrB,yBAAyB;EACzB,cCrJyD;AVs+CrE;;AS7gDA;EAoFM,yBVvH2B;EUwH3B,yBAAyB;EACzB,WC/DU;AV4/ChB;;ASnhDA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,WCpEQ;AVkgDhB;;ASzhDA;EA8FQ,yBAAyB;EACzB,WCxEQ;AVugDhB;;AS9hDA;EAiGU,kDVpIuB;ACqkDjC;;ASliDA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,WC/EQ;AVihDhB;;ASxiDA;;EAyGQ,yBV5IyB;EU6IzB,yBAAyB;EACzB,gBAAgB;ATo8CxB;;AS/iDA;EA6GQ,sBCtFQ;EDuFR,cVjJyB;ACulDjC;;ASpjDA;EAiHU,yBC/DuB;AVsgDjC;;ASxjDA;;EAoHU,sBC7FM;ED8FN,yBAAyB;EACzB,gBAAgB;EAChB,cV1JuB;ACmmDjC;;AShkDA;EA0HU,0DAA4E;AT08CtF;;ASpkDA;EA4HQ,6BAA6B;EAC7B,qBVhKyB;EUiKzB,cVjKyB;AC6mDjC;;AS1kDA;EAmIU,yBVtKuB;EUuKvB,qBVvKuB;EUwKvB,WC9GM;AVyjDhB;;AShlDA;EAwIY,gEAA8D;AT48C1E;;ASplDA;EA8Ic,0DAA4E;AT08C1F;;ASxlDA;;EAiJU,6BAA6B;EAC7B,qBVrLuB;EUsLvB,gBAAgB;EAChB,cVvLuB;ACmoDjC;;AShmDA;EAsJQ,6BAA6B;EAC7B,kBChIQ;EDiIR,WCjIQ;AV+kDhB;;AStmDA;EA6JU,sBCtIM;EDuIN,cVjMuB;AC8oDjC;;AS3mDA;EAqKc,gEAA8D;AT08C5E;;AS/mDA;;EAwKU,6BAA6B;EAC7B,kBClJM;EDmJN,gBAAgB;EAChB,WCpJM;AVgmDhB;;ASvnDA;EAiLU,yBCnJsC;EDoJtC,cC3I2D;AVqlDrE;;AS5nDA;EAqLY,yBCnIqB;EDoIrB,yBAAyB;EACzB,cChJyD;AV2lDrE;;ASloDA;EA0LY,yBCxIqB;EDyIrB,yBAAyB;EACzB,cCrJyD;AVimDrE;;ASxoDA;EARE,kBVbc;ACiqDhB;;AStpDE;EACE,kBVkBc;ACuoDlB;;AShpDA;EANE,eVhBW;AC0qDb;;ASppDA;EAJE,kBVnBc;AC+qDhB;;ASxpDA;EAFE,iBVtBa;ACorDf;;AS5pDA;;EAyMI,uBVrP2B;EUsP3B,qBV3P0B;EU4P1B,gBAhOyB;EAiOzB,YAhOyB;ATwrD7B;;ASpqDA;EA8MI,aAAa;EACb,WAAW;AT09Cf;;ASzqDA;EAiNI,6BAA6B;EAC7B,oBAAoB;AT49CxB;;AS9qDA;ERlDE,kBAAkB;EAKhB,6BAAmC;EACnC,4BAAkC;EQkQhC,6BAA6B;AT+9CnC;;ASrrDA;EAwNI,4BVtQ0B;EUuQ1B,qBV1Q0B;EU2Q1B,cV7Q0B;EU8Q1B,gBAAgB;EAChB,oBAAoB;ATi+CxB;;AS7rDA;EA8NI,qBVlNmB;EUmNnB,gCAA0D;EAC1D,iCAA2D;ATm+C/D;;ASj+CA;EACE,mBAAmB;EACnB,aAAa;EACb,eAAe;EACf,2BAA2B;ATo+C7B;;ASx+CA;EAMI,qBAAqB;ATs+CzB;;AS5+CA;ERnII,mBQ2IwC;ATw+C5C;;ASh/CA;EAUI,sBAAsB;AT0+C1B;;ASp/CA;EAYI,mBAAmB;AT4+CvB;;ASx/CA;EA1OE,kBVbc;ACmvDhB;;ASxuDE;EACE,kBVkBc;ACytDlB;;AShgDA;EAtOE,kBVnBc;AC6vDhB;;ASpgDA;EApOE,iBVtBa;ACkwDf;;ASxgDA;EA0BQ,4BAA4B;EAC5B,yBAAyB;ATk/CjC;;AS7gDA;EA6BQ,6BAA6B;EAC7B,0BAA0B;ERjK9B,iBQkKwC;ATo/C5C;;ASnhDA;ERnII,cQoKqC;ATs/CzC;;ASvhDA;EAoCQ,UAAU;ATu/ClB;;AS3hDA;EA0CQ,UAAU;ATq/ClB;;AS/hDA;EA4CU,UAAU;ATu/CpB;;ASniDA;EA8CQ,YAAY;EACZ,cAAc;ATy/CtB;;ASxiDA;EAiDI,uBAAuB;AT2/C3B;;AS5iDA;EAoDQ,oBAAoB;EACpB,qBAAqB;AT4/C7B;;ASjjDA;EAuDI,yBAAyB;AT8/C7B;;ASrjDA;EA0DQ,oBAAoB;EACpB,qBAAqB;AT+/C7B;;AWl1DA;EACE,YAAY;EACZ,cAAc;EACd,kBAAkB;EAClB,WA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wB;EgBsCxB,WLsCU;AVovEhB;;Ae3zEA;EAgCM,yBhBvB4B;EgBwB5B,WLsCU;AVyvEhB;;Aeh0EA;EAuCU,yBLuCsC;EKtCtC,cL+C2D;AV8uErE;;Aer0EA;EAgCM,yBhBrB4B;EgBsB5B,WLsCU;AVmwEhB;;Ae10EA;EAuCU,yBLuCsC;EKtCtC,cL+C2D;AVwvErE;;Ae/0EA;EAgCM,yBhBtB4B;EgBuB5B,WLsCU;AV6wEhB;;Aep1EA;EAuCU,yBLuCsC;EKtCtC,cL+C2D;AVkwErE;;Aez1EA;EAgCM,yBhBxB4B;EgByB5B,WLsCU;AVuxEhB;;Ae91EA;EAuCU,yBLuCsC;EKtCtC,cL+C2D;AV4wErE;;Aen2EA;EAgCM,yBhBzB4B;EgB0B5B,yBLoCe;AVmyErB;;Aex2EA;EAuCU,yBLuCsC;EKtCtC,cL+C2D;AVsxErE;;Ae72EA;EAgCM,yBhBnB2B;EgBoB3B,WLsCU;AV2yEhB;;Ael3EA;EAuCU,yBLuCsC;EKtCtC,cL+C2D;AVgyErE;;AgBx3EA;EAEE,qBAAqB;EACrB,wBAAwB;EACxB,YAAY;EACZ,qBjBwDqB;EiBvDrB,cAAc;EACd,YjBoBW;EiBnBX,gBAAgB;EAChB,UAAU;EACV,WAAW;AhB03Eb;;AgBp4EA;EAYI,yBjBX2B;ACu4E/B;;AgBx4EA;EAcI,yBjBjB0B;AC+4E9B;;AgB54EA;EAgBI,yBjBnB0B;ACm5E9B;;AgBh5EA;EAkBI,yBjBrB0B;EiBsB1B,YAAY;AhBk4EhB;;AgBr5EA;EAyBQ,uBjBpBuB;ACo5E/B;;AgBz5EA;EA2BQ,uBjBtBuB;ACw5E/B;;AgB75EA;EA6BQ,uBjBxBuB;AC45E/B;;AgBj6EA;EA+BQ,mEAA2F;AhBs4EnG;;AgBr6EA;EAyBQ,yBjBjCqB;ACi7E7B;;AgBz6EA;EA2BQ,yBjBnCqB;ACq7E7B;;AgB76EA;EA6BQ,yBjBrCqB;ACy7E7B;;AgBj7EA;EA+BQ,qEAA2F;AhBs5EnG;;AgBr7EA;EAyBQ,4BjBtBsB;ACs7E9B;;AgBz7EA;EA2BQ,4BjBxBsB;AC07E9B;;AgB77EA;EA6BQ,4BjB1BsB;AC87E9B;;AgBj8EA;EA+BQ,wEAA2F;AhBs6EnG;;AgBr8EA;EAyBQ,yBjB7BsB;AC68E9B;;AgBz8EA;EA2BQ,yBjB/BsB;ACi9E9B;;AgB78EA;EA6BQ,yBjBjCsB;ACq9E9B;;AgBj9EA;EA+BQ,qEAA2F;AhBs7EnG;;AgBr9EA;EAyBQ,yBjBf0B;AC+8ElC;;AgBz9EA;EA2BQ,yBjBjB0B;ACm9ElC;;AgB79EA;EA6BQ,yBjBnB0B;ACu9ElC;;AgBj+EA;EA+BQ,qEAA2F;AhBs8EnG;;AgBr+EA;EAyBQ,yBjBb0B;AC69ElC;;AgBz+EA;EA2BQ,yBjBf0B;ACi+ElC;;AgB7+EA;EA6BQ,yBjBjB0B;ACq+ElC;;AgBj/EA;EA+BQ,qEAA2F;AhBs9EnG;;AgBr/EA;EAyBQ,yBjBd0B;AC8+ElC;;AgBz/EA;EA2BQ,yBjBhB0B;ACk/ElC;;AgB7/EA;EA6BQ,yBjBlB0B;ACs/ElC;;AgBjgFA;EA+BQ,qEAA2F;AhBs+EnG;;AgBrgFA;EAyBQ,yBjBhB0B;ACggFlC;;AgBzgFA;EA2BQ,yBjBlB0B;ACogFlC;;AgB7gFA;EA6BQ,yBjBpB0B;ACwgFlC;;AgBjhFA;EA+BQ,qEAA2F;AhBs/EnG;;AgBrhFA;EAyBQ,yBjBjB0B;ACihFlC;;AgBzhFA;EA2BQ,yBjBnB0B;ACqhFlC;;AgB7hFA;EA6BQ,yBjBrB0B;ACyhFlC;;AgBjiFA;EA+BQ,qEAA2F;AhBsgFnG;;AgBriFA;EAyBQ,yBjBXyB;AC2hFjC;;AgBziFA;EA2BQ,yBjBbyB;AC+hFjC;;AgB7iFA;EA6BQ,yBjBfyB;ACmiFjC;;AgBjjFA;EA+BQ,qEAA2F;AhBshFnG;;AgBrjFA;EAkCI,gCAtCkC;UAsClC,wBAtCkC;EAuClC,2CAAmC;UAAnC,mCAAmC;EACnC,yCAAiC;UAAjC,iCAAiC;EACjC,yCAAiC;UAAjC,iCAAiC;EACjC,yBjBrC2B;EiBsC3B,qEAA0F;EAC1F,6BAA6B;EAC7B,4BAA4B;EAC5B,0BAA0B;AhBuhF9B;;AgBjkFA;EA4CM,6BAA6B;AhByhFnC;;AgBrkFA;EA8CM,6BAA6B;AhB2hFnC;;AgBzkFA;EAgDM,oBAAoB;AhB6hF1B;;AgB7kFA;EAoDI,ejBxBY;ACqjFhB;;AgBjlFA;EAsDI,ejB5BY;AC2jFhB;;AgBrlFA;EAwDI,cjB/BW;ACgkFf;;AgB/hFA;EACE;IACE,2BAA2B;EhBkiF7B;EgBjiFA;IACE,4BAA4B;EhBmiF9B;AACF;;AgBxiFA;EACE;IACE,2BAA2B;EhBkiF7B;EgBjiFA;IACE,4BAA4B;EhBmiF9B;AACF;;AiB/kFA;EAEE,uBlBhB6B;EkBiB7B,clB1B4B;AC2mF9B;;AiBplFA;;EAMI,yBlBzB0B;EkB0B1B,qBA9B6B;EA+B7B,qBA9B6B;EA+B7B,mBAAmB;AjBmlFvB;;AiB5lFA;;EAeQ,uBlB7BuB;EkB8BvB,mBlB9BuB;EkB+BvB,clB5CqB;AC8nF7B;;AiBnmFA;;EAeQ,yBlB1CqB;EkB2CrB,qBlB3CqB;EkB4CrB,YlB/BuB;ACwnF/B;;AiB1mFA;;EAeQ,4BlB/BsB;EkBgCtB,wBlBhCsB;EkBiCtB,yBPkCa;AV8jFrB;;AiBjnFA;;EAeQ,yBlBtCsB;EkBuCtB,qBlBvCsB;EkBwCtB,WPoCQ;AVmkFhB;;AiBxnFA;;EAeQ,yBlBxB0B;EkByB1B,qBlBzB0B;EkB0B1B,WPoCQ;AV0kFhB;;AiB/nFA;;EAeQ,yBlBtB0B;EkBuB1B,qBlBvB0B;EkBwB1B,WPoCQ;AVilFhB;;AiBtoFA;;EAeQ,yBlBvB0B;EkBwB1B,qBlBxB0B;EkByB1B,WPoCQ;AVwlFhB;;AiB7oFA;;EAeQ,yBlBzB0B;EkB0B1B,qBlB1B0B;EkB2B1B,WPoCQ;AV+lFhB;;AiBppFA;;EAeQ,yBlB1B0B;EkB2B1B,qBlB3B0B;EkB4B1B,yBPkCa;AVwmFrB;;AiB3pFA;;EAeQ,yBlBpByB;EkBqBzB,qBlBrByB;EkBsBzB,WPoCQ;AV6mFhB;;AiBlqFA;;EAoBM,mBAAmB;EACnB,SAAS;AjBmpFf;;AiBxqFA;;EAuBM,yBlBhC4B;EkBiC5B,WP6BU;AVynFhB;;AiB9qFA;;;;EA2BQ,mBAAmB;AjB0pF3B;;AiBrrFA;;EA6BM,sBAAsB;AjB6pF5B;;AiB1rFA;EA+BI,clBtD0B;ACqtF9B;;AiB9rFA;EAiCM,mBAAmB;AjBiqFzB;;AiBlsFA;EAoCM,yBlB7C4B;EkB8C5B,WPgBU;AVkpFhB;;AiBvsFA;;EAwCQ,mBAAmB;AjBoqF3B;;AiB5sFA;;EA2CQ,kBPUQ;EOTR,mBAAmB;AjBsqF3B;;AiBltFA;EA8CI,6BA5DqC;AjBouFzC;;AiBttFA;;EAiDM,qBApEgC;EAqEhC,clBzEwB;ACmvF9B;;AiB5tFA;EAoDI,6BAhEqC;AjB4uFzC;;AiBhuFA;;EAuDM,qBAxEgC;EAyEhC,clB/EwB;AC6vF9B;;AiBtuFA;EA0DI,6BAvEqC;AjBuvFzC;;AiB1uFA;;EA+DU,sBAAsB;AjBgrFhC;;AiB/uFA;;EAoEM,iBAAiB;AjBgrFvB;;AiBpvFA;;EAyEU,wBAAwB;AjBgrFlC;;AiBzvFA;EA2EI,WAAW;AjBkrFf;;AiB7vFA;EAgFU,yBlB/FoB;ACgxF9B;;AiBjwFA;EAqFY,yBlBpGkB;ACoxF9B;;AiBrwFA;EAuFc,4BlBvGgB;ACyxF9B;;AiBzwFA;;EA2FM,qBAAqB;AjBmrF3B;;AiB9wFA;EAgGU,yBlB/GoB;ACiyF9B;;AiBhrFA;EhBjEE,iCAAiC;EgBoEjC,cAAc;EACd,kBAAkB;EAClB,eAAe;AjBkrFjB;;AkB7yFA;EACE,mBAAmB;EACnB,aAAa;EACb,eAAe;EACf,2BAA2B;AlBgzF7B;;AkBpzFA;EAMI,qBAAqB;AlBkzFzB;;AkBxzFA;EjBiJI,mBiBzIwC;AlBozF5C;;AkB5zFA;EAUI,sBAAsB;AlBszF1B;;AkBh0FA;EAYI,mBAAmB;AlBwzFvB;;AkBp0FA;EAgBM,enBYO;AC4yFb;;AkBx0FA;EAmBM,kBnBQU;ACizFhB;;AkB50FA;EAqBI,uBAAuB;AlB2zF3B;;AkBh1FA;EAuBM,qBAAqB;EACrB,oBAAoB;AlB6zF1B;;AkBr1FA;EA0BI,yBAAyB;AlB+zF7B;;AkBz1FA;EA6BQ,mBAAmB;AlBg0F3B;;AkB71FA;EA+BQ,eAAe;AlBk0FvB;;AkBj2FA;EjBiJI,ciB/GmC;AlBm0FvC;;AkBr2FA;EjBiJI,eiB7GqC;EAK/B,0BAA0B;EAC1B,6BAA6B;AlBi0FvC;;AkB32FA;EAgDU,yBAAyB;EACzB,4BAA4B;AlB+zFtC;;AkB7zFA;EACE,mBAAmB;EACnB,4BnBjD4B;EmBkD5B,kBnBMU;EmBLV,cnBzD4B;EmB0D5B,oBAAoB;EACpB,kBnB5Bc;EmB6Bd,WAAW;EACX,uBAAuB;EACvB,gBAAgB;EAChB,oBAAoB;EACpB,qBAAqB;EACrB,mBAAmB;AlBg0FrB;;AkB50FA;EjB8FI,qBiBhFuC;EjBgFvC,sBiB/EyC;AlBk0F7C;;AkBj1FA;EAqBM,uBnBlEyB;EmBmEzB,cnBhFuB;ACg5F7B;;AkBt1FA;EAqBM,yBnB/EuB;EmBgFvB,YnBnEyB;ACw4F/B;;AkB31FA;EAqBM,4BnBpEwB;EmBqExB,yBRFe;AV40FrB;;AkBh2FA;EAqBM,yBnB3EwB;EmB4ExB,WRAU;AV+0FhB;;AkBr2FA;EAqBM,yBnB7D4B;EmB8D5B,WRAU;AVo1FhB;;AkB12FA;EA4BU,yBRCsC;EQAtC,cRS2D;AVy0FrE;;AkB/2FA;EAqBM,yBnB3D4B;EmB4D5B,WRAU;AV81FhB;;AkBp3FA;EA4BU,yBRCsC;EQAtC,cRS2D;AVm1FrE;;AkBz3FA;EAqBM,yBnB5D4B;EmB6D5B,WRAU;AVw2FhB;;AkB93FA;EA4BU,yBRCsC;EQAtC,cRS2D;AV61FrE;;AkBn4FA;EAqBM,yBnB9D4B;EmB+D5B,WRAU;AVk3FhB;;AkBx4FA;EA4BU,yBRCsC;EQAtC,cRS2D;AVu2FrE;;AkB74FA;EAqBM,yBnB/D4B;EmBgE5B,yBRFe;AV83FrB;;AkBl5FA;EA4BU,yBRCsC;EQAtC,cRS2D;AVi3FrE;;AkBv5FA;EAqBM,yBnBzD2B;EmB0D3B,WRAU;AVs4FhB;;AkB55FA;EA4BU,yBRCsC;EQAtC,cRS2D;AV23FrE;;AkBj6FA;EAgCI,kBnBtDY;AC27FhB;;AkBr6FA;EAkCI,enBzDS;ACg8Fb;;AkBz6FA;EAoCI,kBnB5DY;ACq8FhB;;AkB76FA;EjB8FI,sBiBvD0C;EjBuD1C,qBiBtD0C;AlB04F9C;;AkBl7FA;EjB8FI,sBiBpD0C;EjBoD1C,qBiBnD0C;AlB44F9C;;AkBv7FA;EjB8FI,sBiBjD0C;EjBiD1C,qBiBhD0C;AlB84F9C;;AkB57FA;EjB8FI,iBiBrJmB;EAyGnB,UAAU;EACV,kBAAkB;EAClB,UAAU;AlB+4Fd;;AkBn8FA;EAuDM,8BAA8B;EAC9B,WAAW;EACX,cAAc;EACd,SAAS;EACT,kBAAkB;EAClB,QAAQ;EACR,0DAA0D;EAC1D,+BAA+B;AlBg5FrC;;AkB98FA;EAgEM,WAAW;EACX,UAAU;AlBk5FhB;;AkBn9FA;EAmEM,WAAW;EACX,UAAU;AlBo5FhB;;AkBx9FA;EAuEM,yBAAmD;AlBq5FzD;;AkB59FA;EAyEM,yBAAoD;AlBu5F1D;;AkBh+FA;EA2EI,qBnBhEmB;ACy9FvB;;AkBv5FA;EAEI,0BAA0B;AlBy5F9B;;AmB/gGA;;EAGE,sBAAsB;AnBihGxB;;AmBphGA;;;;EAMI,oBAAoB;AnBqhGxB;;AmB3hGA;;EAQI,iBApBmB;AnB4iGvB;;AmBhiGA;;EAUI,iBArBmB;AnBgjGvB;;AmBriGA;;EAYI,sBAAsB;AnB8hG1B;;AmB5hGA;EACE,cpB9B4B;EoBiC5B,epBLW;EoBMX,gBpBGmB;EoBFnB,kBAnCuB;AnBgkGzB;;AmBniGA;EAQI,cApCwB;EAqCxB,oBApCyB;AnBmkG7B;;AmBxiGA;EAWI,oBA3B+B;AnB4jGnC;;AmB5iGA;EAgBM,epBnBO;ACmjGb;;AmBhjGA;EAgBM,iBpBlBS;ACsjGf;;AmBpjGA;EAgBM,epBjBO;ACyjGb;;AmBxjGA;EAgBM,iBpBhBS;AC4jGf;;AmB5jGA;EAgBM,kBpBfU;AC+jGhB;;AmBhkGA;EAgBM,epBdO;ACkkGb;;AmBpkGA;EAgBM,kBpBbU;ACqkGhB;;AmBtjGA;EACE,cpB/C4B;EoBkD5B,kBpBrBc;EoBsBd,gBpBjBiB;EoBkBjB,iBA3CyB;AnBkmG3B;;AmB7jGA;EAQI,cpBvD0B;EoBwD1B,gBpBnBiB;AC4kGrB;;AmBlkGA;EAWI,oBA7C+B;AnBwmGnC;;AmBtkGA;EAgBM,epBrCO;AC+lGb;;AmB1kGA;EAgBM,iBpBpCS;ACkmGf;;AmB9kGA;EAgBM,epBnCO;ACqmGb;;AmBllGA;EAgBM,iBpBlCS;ACwmGf;;AmBtlGA;EAgBM,kBpBjCU;AC2mGhB;;AmB1lGA;EAgBM,epBhCO;AC8mGb;;AmB9lGA;EAgBM,kBpB/BU;ACinGhB;;AoB/oGA;EACE,cAAc;EACd,eAAe;EACf,mBAAmB;EACnB,kBAAkB;EAClB,yBAAyB;ApBkpG3B;;AoB7oGA;EACE,mBAAmB;EACnB,4BrBP4B;EqBQ5B,qBrBkDqB;EqBjDrB,oBAAoB;EACpB,kBrBac;EqBZd,WAAW;EACX,uBAAuB;EACvB,oBAAoB;EACpB,gBAAgB;EAChB,uBAAuB;EACvB,kBAAkB;EAClB,mBAAmB;ApBgpGrB;;AqB9qGA,eAAA;AC0DA;EAxBE,uBvBnB6B;EuBoB7B,qBvBzB4B;EuB0B5B,kBvBiCU;EuBhCV,cvB/B4B;ACgrG9B;;ACnnGI;EqB5BA,4BvBjC0B;ACorG9B;;ACvnGI;EqB5BA,4BvBjC0B;ACwrG9B;;AC3nGI;EqB5BA,4BvBjC0B;AC4rG9B;;AC/nGI;EqB5BA,4BvBjC0B;ACgsG9B;;AsB9pGE;EAEE,qBvBjC0B;ACisG9B;;AsB/pGE;EAIE,qBvBzB8B;EuB0B9B,iDvB1B8B;ACyrGlC;;AsB9pGE;;;;;EAEE,4BvBtC0B;EuBuC1B,wBvBvC0B;EuBwC1B,gBAAgB;EAChB,cvB9C0B;ACktG9B;;ACvpGI;;;;;EqBXE,+BvBhDwB;AC0tG9B;;AC/pGI;;;;;EqBXE,+BvBhDwB;ACkuG9B;;ACvqGI;;;;;EqBXE,+BvBhDwB;AC0uG9B;;AC/qGI;;;;;EqBXE,+BvBhDwB;ACkvG9B;;AuBpvGA;EAEE,2DxBN2B;EwBO3B,eAAe;EACf,WAAW;AvBsvGb;;AuBrvGE;EACE,gBAAgB;AvBwvGpB;;AuBpvGI;EACE,mBxBFyB;ACyvG/B;;AuBxvGK;EAMG,mDxBPuB;AC6vG/B;;AuB5vGI;EACE,qBxBfuB;AC8wG7B;;AuBhwGK;EAMG,gDxBpBqB;ACkxG7B;;AuBpwGI;EACE,wBxBJwB;AC2wG9B;;AuBxwGK;EAMG,mDxBTsB;AC+wG9B;;AuB5wGI;EACE,qBxBXwB;AC0xG9B;;AuBhxGK;EAMG,gDxBhBsB;AC8xG9B;;AuBpxGI;EACE,qBxBG4B;ACoxGlC;;AuBxxGK;EAMG,iDxBF0B;ACwxGlC;;AuB5xGI;EACE,qBxBK4B;AC0xGlC;;AuBhyGK;EAMG,iDxBA0B;AC8xGlC;;AuBpyGI;EACE,qBxBI4B;ACmyGlC;;AuBxyGK;EAMG,kDxBD0B;ACuyGlC;;AuB5yGI;EACE,qBxBE4B;AC6yGlC;;AuBhzGK;EAMG,kDxBH0B;ACizGlC;;AuBpzGI;EACE,qBxBC4B;ACszGlC;;AuBxzGK;EAMG,mDxBJ0B;AC0zGlC;;AuB5zGI;EACE,qBxBO2B;ACwzGjC;;AuBh0GK;EAMG,kDxBEyB;AC4zGjC;;AuB5zGE;EzBmBA,kBCyBgB;EDxBhB,kBCNc;ACmzGhB;;AuB/zGE;EzBoBA,kBCVc;ACyzGhB;;AuBj0GE;EzBoBA,iBCba;AC8zGf;;AuBl0GE;EACE,cAAc;EACd,WAAW;AvBq0Gf;;AuBp0GE;EACE,eAAe;EACf,WAAW;AvBu0Gf;;AuBr0GA;EAGI,qBxB8BmB;EwB7BnB,gDAA4D;EAC5D,iDAA6D;AvBs0GjE;;AuB30GA;EAOI,6BAA6B;EAC7B,yBAAyB;EACzB,gBAAgB;EAChB,eAAe;EACf,gBAAgB;AvBw0GpB;;AuBt0GA;EAEE,cAAc;EACd,eAAe;EACf,eAAe;EACf,2BzB7CkE;EyB8ClE,gBAAgB;AvBw0GlB;;AuB90GA;EAQI,gBA1DsB;EA2DtB,eA1DqB;AvBo4GzB;;AuBn1GA;EAWI,eAAe;AvB40GnB;;AuBv1GA;EAcI,YAAY;AvB60GhB;;AwB94GA;EACE,eAAe;EACf,qBAAqB;EACrB,iBAAiB;EACjB,kBAAkB;AxBi5GpB;;AwBh5GE;EACE,eAAe;AxBm5GnB;;AwBl5GE;EACE,czBF0B;ACu5G9B;;AwBp5GE;;;;;EAGE,czBJ0B;EyBK1B,mBAAmB;AxBy5GvB;;AwBp5GA;EvBwII,mBuBrIqC;AxBq5GzC;;AyBx6GA;EACE,qBAAqB;EACrB,eAAe;EACf,kBAAkB;EAClB,mBAAmB;AzB26GrB;;AyB/6GA;EAMI,a3BDkB;AE86GtB;;AyBn7GA;EAUM,qB1BU4B;EE4I9B,awBrJ+B;EAC7B,UAAU;AzB66GhB;;AyBz7GA;EAeM,qB1BsDiB;EEmFnB,kBwBxIsC;AzB86G1C;;AyB97GA;EAmBI,eAAe;EACf,cAAc;EACd,cAAc;EACd,eAAe;EACf,aAAa;AzB+6GjB;;AyBt8GA;EAyBM,aAAa;AzBi7GnB;;AyB18GA;;EA4BM,wB1BjBwB;ACo8G9B;;AyB/8GA;ExBwJI,mBwB1HwC;AzBq7G5C;;AyBn9GA;EAgCM,YAAY;EACZ,UAAU;AzBu7GhB;;AyBx9GA;EAmCQ,kBAAkB;AzBy7G1B;;AyB59GA;EAuCM,qB1BnCwB;AC49G9B;;AyBh+GA;EA6CQ,mB1BhCuB;ACu9G/B;;AyBp+GA;EA+CQ,mB1BlCuB;AC29G/B;;AyBx+GA;EAkDU,qBfyDuB;AVi4GjC;;AyB5+GA;EAuDU,mD1B1CqB;ACm+G/B;;AyBh/GA;EA6CQ,qB1B7CqB;ACo/G7B;;AyBp/GA;EA+CQ,qB1B/CqB;ACw/G7B;;AyBx/GA;EAkDU,mBfyDuB;AVi5GjC;;AyB5/GA;EAuDU,gD1BvDmB;ACggH7B;;AyBhgHA;EA6CQ,wB1BlCsB;ACy/G9B;;AyBpgHA;EA+CQ,wB1BpCsB;AC6/G9B;;AyBxgHA;EAkDU,qBfyDuB;AVi6GjC;;AyB5gHA;EAuDU,mD1B5CoB;ACqgH9B;;AyBhhHA;EA6CQ,qB1BzCsB;ACghH9B;;AyBphHA;EA+CQ,qB1B3CsB;ACohH9B;;AyBxhHA;EAkDU,qBfyDuB;AVi7GjC;;AyB5hHA;EAuDU,gD1BnDoB;AC4hH9B;;AyBhiHA;EA6CQ,qB1B3B0B;ACkhHlC;;AyBpiHA;EA+CQ,qB1B7B0B;ACshHlC;;AyBxiHA;EAkDU,qBfyDuB;AVi8GjC;;AyB5iHA;EAuDU,iD1BrCwB;AC8hHlC;;AyBhjHA;EA6CQ,qB1BzB0B;ACgiHlC;;AyBpjHA;EA+CQ,qB1B3B0B;ACoiHlC;;AyBxjHA;EAkDU,qBfyDuB;AVi9GjC;;AyB5jHA;EAuDU,iD1BnCwB;AC4iHlC;;AyBhkHA;EA6CQ,qB1B1B0B;ACijHlC;;AyBpkHA;EA+CQ,qB1B5B0B;ACqjHlC;;AyBxkHA;EAkDU,qBfyDuB;AVi+GjC;;AyB5kHA;EAuDU,kD1BpCwB;AC6jHlC;;AyBhlHA;EA6CQ,qB1B5B0B;ACmkHlC;;AyBplHA;EA+CQ,qB1B9B0B;ACukHlC;;AyBxlHA;EAkDU,qBfyDuB;AVi/GjC;;AyB5lHA;EAuDU,kD1BtCwB;AC+kHlC;;AyBhmHA;EA6CQ,qB1B7B0B;AColHlC;;AyBpmHA;EA+CQ,qB1B/B0B;ACwlHlC;;AyBxmHA;EAkDU,qBfyDuB;AVigHjC;;AyB5mHA;EAuDU,mD1BvCwB;ACgmHlC;;AyBhnHA;EA6CQ,qB1BvByB;AC8lHjC;;AyBpnHA;EA+CQ,qB1BzByB;ACkmHjC;;AyBxnHA;EAkDU,qBfyDuB;AVihHjC;;AyB5nHA;EAuDU,kD1BjCuB;AC0mHjC;;AyBhoHA;E3ByCE,kBCyBgB;EDxBhB,kBCNc;ACimHhB;;AyBroHA;E3B4CE,kBCVc;ACumHhB;;AyBzoHA;E3B8CE,iBCba;AC4mHf;;AyB7oHA;EAkEM,qB1B5DwB;AC2oH9B;;AyBjpHA;EAoEI,WAAW;AzBilHf;;AyBrpHA;EAsEM,WAAW;AzBmlHjB;;AyBzpHA;EA0EM,aAAa;EACb,kBAAkB;ExBqFpB,awBpF+B;EAC7B,YAAY;EACZ,eAAe;AzBmlHrB;;AyBjqHA;EAgFM,kB1B5CU;ACioHhB;;AyBrqHA;EAkFM,kB1BhDU;ACuoHhB;;AyBzqHA;EAoFM,iB1BnDS;AC4oHf;;A0BhqHA;EAEE,oBAAoB;EACpB,aAAa;EACb,2BAA2B;EAC3B,kBAAkB;A1BkqHpB;;A0BvqHA;EAYQ,uB3BZuB;E2BavB,yBAAyB;EACzB,c3B3BqB;AC0rH7B;;A0B7qHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,c3BjCmB;ACgsH7B;;A0BnrHA;EAwBU,yBAAyB;EACzB,+C3BzBqB;E2B0BrB,c3BvCmB;ACssH7B;;A0BzrHA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,c3B7CmB;AC4sH7B;;A0B/rHA;EAYQ,yB3BzBqB;E2B0BrB,yBAAyB;EACzB,Y3BduB;ACqsH/B;;A0BrsHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,Y3BpBqB;AC2sH/B;;A0B3sHA;EAwBU,yBAAyB;EACzB,4C3BtCmB;E2BuCnB,Y3B1BqB;ACitH/B;;A0BjtHA;EA8BU,uBhBgEuB;EgB/DvB,yBAAyB;EACzB,Y3BhCqB;ACutH/B;;A0BvtHA;EAYQ,4B3BdsB;E2BetB,yBAAyB;EACzB,yBhBmDa;AV4pHrB;;A0B7tHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,yBhB6CW;AVkqHrB;;A0BnuHA;EAwBU,yBAAyB;EACzB,+C3B3BoB;E2B4BpB,yBhBuCW;AVwqHrB;;A0BzuHA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,yBhBiCW;AV8qHrB;;A0B/uHA;EAYQ,yB3BrBsB;E2BsBtB,yBAAyB;EACzB,WhBqDQ;AVkrHhB;;A0BrvHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,WhB+CM;AVwrHhB;;A0B3vHA;EAwBU,yBAAyB;EACzB,4C3BlCoB;E2BmCpB,WhByCM;AV8rHhB;;A0BjwHA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,WhBmCM;AVosHhB;;A0BvwHA;EAYQ,yB3BP0B;E2BQ1B,yBAAyB;EACzB,WhBqDQ;AV0sHhB;;A0B7wHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,WhB+CM;AVgtHhB;;A0BnxHA;EAwBU,yBAAyB;EACzB,6C3BpBwB;E2BqBxB,WhByCM;AVstHhB;;A0BzxHA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,WhBmCM;AV4tHhB;;A0B/xHA;EAYQ,yB3BL0B;E2BM1B,yBAAyB;EACzB,WhBqDQ;AVkuHhB;;A0BryHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,WhB+CM;AVwuHhB;;A0B3yHA;EAwBU,yBAAyB;EACzB,6C3BlBwB;E2BmBxB,WhByCM;AV8uHhB;;A0BjzHA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,WhBmCM;AVovHhB;;A0BvzHA;EAYQ,yB3BN0B;E2BO1B,yBAAyB;EACzB,WhBqDQ;AV0vHhB;;A0B7zHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,WhB+CM;AVgwHhB;;A0Bn0HA;EAwBU,yBAAyB;EACzB,8C3BnBwB;E2BoBxB,WhByCM;AVswHhB;;A0Bz0HA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,WhBmCM;AV4wHhB;;A0B/0HA;EAYQ,yB3BR0B;E2BS1B,yBAAyB;EACzB,WhBqDQ;AVkxHhB;;A0Br1HA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,WhB+CM;AVwxHhB;;A0B31HA;EAwBU,yBAAyB;EACzB,8C3BrBwB;E2BsBxB,WhByCM;AV8xHhB;;A0Bj2HA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,WhBmCM;AVoyHhB;;A0Bv2HA;EAYQ,yB3BT0B;E2BU1B,yBAAyB;EACzB,yBhBmDa;AV4yHrB;;A0B72HA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,yBhB6CW;AVkzHrB;;A0Bn3HA;EAwBU,yBAAyB;EACzB,+C3BtBwB;E2BuBxB,yBhBuCW;AVwzHrB;;A0Bz3HA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,yBhBiCW;AV8zHrB;;A0B/3HA;EAYQ,yB3BHyB;E2BIzB,yBAAyB;EACzB,WhBqDQ;AVk0HhB;;A0Br4HA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,WhB+CM;AVw0HhB;;A0B34HA;EAwBU,yBAAyB;EACzB,8C3BhBuB;E2BiBvB,WhByCM;AV80HhB;;A0Bj5HA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,WhBmCM;AVo1HhB;;A0Bv5HA;EAmCI,kB3BZY;ACo4HhB;;A0B35HA;EAqCI,e3BfS;ACy4Hb;;A0B/5HA;EAuCI,kB3BlBY;AC84HhB;;A0Bn6HA;EA0CQ,eAAe;A1B63HvB;;A0Bv6HA;EA4CI,iB3BxBW;ACu5Hf;;A0B36HA;EA+CQ,eAAe;A1Bg4HvB;;A0B/6HA;EAmDM,6BAA6B;EAC7B,0BAA0B;A1Bg4HhC;;A0Bp7HA;EAsDM,4BAA4B;EAC5B,yBAAyB;A1Bk4H/B;;A0Bz7HA;EA0DQ,kB3BJI;ACu4HZ;;A0B77HA;EA4DQ,aAAa;A1Bq4HrB;;A0Bj8HA;EA+DM,sBAAsB;A1Bs4H5B;;A0Br8HA;EAiEM,sBAAsB;EACtB,YAAY;EACZ,gBAAgB;A1Bw4HtB;;A0B38HA;EAqEM,uBAAuB;A1B04H7B;;A0B/8HA;EAuEM,aAAa;EACb,YAAY;A1B44HlB;;A0Bp9HA;EA0EQ,eAAe;A1B84HvB;;A0Bx9HA;EA6EQ,eAAe;A1B+4HvB;;A0B59HA;EAgFQ,eAAe;A1Bg5HvB;;A0Bh+HA;EAmFQ,eAAe;A1Bi5HvB;;A0Bp+HA;EAsFQ,0BAA4C;A1Bk5HpD;;A0Bx+HA;EAwFQ,0B3BlCI;E2BmCJ,uBAAuB;A1Bo5H/B;;A0B7+HA;EA2FI,uBAAuB;A1Bs5H3B;;A0Bj/HA;EA8FM,WAAW;A1Bu5HjB;;A0Br/HA;EAgGM,YAAY;EACZ,eAAe;A1By5HrB;;A0B1/HA;EAmGI,yBAAyB;A1B25H7B;;A0B9/HA;EAqGM,0BAA4C;A1B65HlD;;A0BlgIA;EAuGM,0B3BjDM;E2BkDN,2BAA2B;EAC3B,SAAS;A1B+5Hf;;A0B75HA;EACE,oBAAoB;EACpB,aAAa;EACb,eAAe;EACf,2BAA2B;EAC3B,gBAAgB;EAChB,kBAAkB;A1Bg6HpB;;A0Bt6HA;EASM,yBhBtB2B;EgBuB3B,c3B9HwB;AC+hI9B;;A0B36HA;EAYM,qBhBzB2B;AV47HjC;;A0B/6HA;EAeM,yBhB5B2B;EgB6B3B,c3BpIwB;ACwiI9B;;A0Bp7HA;EAkBM,qBhB/B2B;AVq8HjC;;A0Bp6HA;EACE,YAAY;EACZ,OAAO;EACP,UAAU;EACV,aAAa;EACb,kBAAkB;EAClB,MAAM;EACN,WAAW;A1Bu6Hb;;A0Br6HA;;EAGE,qB3BhJ4B;E2BiJ5B,kB3BtFU;E2BuFV,cAAc;EACd,iBAAiB;EACjB,kBAAkB;EAClB,mBAAmB;A1Bu6HrB;;A0Br6HA;EACE,4B3BrJ4B;E2BsJ5B,c3B5J4B;ACokI9B;;A0Bt6HA;EACE,qB3B5J4B;E2B6J5B,mBA9J4B;EA+J5B,2BA9JoC;EA+JpC,cAAc;EACd,eA/JwB;EAgKxB,gBAAgB;EAChB,mBAAmB;EACnB,uBAAuB;A1By6HzB;;A0Bv6HA;EACE,mBAAmB;EACnB,aAAa;EACb,WAAW;EACX,uBAAuB;EzBzBrB,kByB0BmC;EACrC,UAAU;A1B06HZ;;A0Bh7HA;EAQI,eAAe;A1B46HnB;;A2B5lIA;EACE,c5BF4B;E4BG5B,cAAc;EACd,e5B2BW;E4B1BX,gB5BiCe;AC8jIjB;;A2BnmIA;EAMI,oBAAoB;A3BimIxB;;A2BvmIA;EASI,kB5BsBY;AC4kIhB;;A2B3mIA;EAWI,kB5BkBY;ACklIhB;;A2B/mIA;EAaI,iB5BeW;ACulIf;;A2BpmIA;EACE,cAAc;EACd,kB5Bcc;E4Bbd,mBAAmB;A3BumIrB;;A2B1mIA;EAOM,Y5BdyB;ACqnI/B;;A2B9mIA;EAOM,c5B3BuB;ACsoI7B;;A2BlnIA;EAOM,iB5BhBwB;AC+nI9B;;A2BtnIA;EAOM,c5BvBwB;AC0oI9B;;A2B1nIA;EAOM,c5BT4B;ACgoIlC;;A2B9nIA;EAOM,c5BP4B;ACkoIlC;;A2BloIA;EAOM,c5BR4B;ACuoIlC;;A2BtoIA;EAOM,c5BV4B;AC6oIlC;;A2B1oIA;EAOM,c5BX4B;ACkpIlC;;A2B9oIA;EAOM,c5BL2B;ACgpIjC;;A2BvoIA;EAEI,sBAAsB;A3ByoI1B;;A2B3oIA;EAKI,aAAa;EACb,2BAA2B;A3B0oI/B;;A2BhpIA;E1ByHI,iB0BhHwC;A3B2oI5C;;A2BppIA;;;EAcU,gBAAgB;A3B4oI1B;;A2B1pIA;;;EAuBY,4BAA4B;EAC5B,yBAAyB;A3ByoIrC;;A2BjqIA;;;EAiCY,6BAA6B;EAC7B,0BAA0B;A3BsoItC;;A2BxqIA;;;;;EAyCY,UAAU;A3BuoItB;;A2BhrIA;;;;;;;;;EA8CY,UAAU;A3B8oItB;;A2B5rIA;;;;;;;;;EAgDc,UAAU;A3BwpIxB;;A2BxsIA;EAkDQ,YAAY;EACZ,cAAc;A3B0pItB;;A2B7sIA;EAqDM,uBAAuB;A3B4pI7B;;A2BjtIA;EAuDM,yBAAyB;A3B8pI/B;;A2BrtIA;EA0DQ,YAAY;EACZ,cAAc;A3B+pItB;;A2B1tIA;EA6DI,aAAa;EACb,2BAA2B;A3BiqI/B;;A2B/tIA;EAgEM,cAAc;A3BmqIpB;;A2BnuIA;EAkEQ,gBAAgB;E1BuDpB,oB0BtD2C;A3BqqI/C;;A2BxuIA;EAqEQ,YAAY;EACZ,cAAc;A3BuqItB;;A2B7uIA;EAwEM,uBAAuB;A3ByqI7B;;A2BjvIA;EA0EM,yBAAyB;A3B2qI/B;;A2BrvIA;EA4EM,eAAe;A3B6qIrB;;A2BzvIA;EAgFU,sBAAsB;A3B6qIhC;;A2B7vIA;EAkFQ,uBAAuB;A3B+qI/B;;A2BjwIA;EAoFQ,gBAAgB;A3BirIxB;;ACrsIE;E0BhEF;IAuFM,aAAa;E3BmrIjB;AACF;;A2BlrIA;EAEI,kBAAkB;A3BorItB;;ACntIE;E0B6BF;IAII,qBAAqB;E3BurIvB;AACF;;ACrtIE;E0ByBF;IAMI,aAAa;IACb,YAAY;IACZ,cAAc;I1BwBd,mB0BvBsC;IACtC,iBAAiB;E3B2rInB;E2BrsIF;IAYM,kB5BhGU;I4BiGV,oBAAoB;E3B4rIxB;E2BzsIF;IAeM,oBAAoB;E3B6rIxB;E2B5sIF;IAiBM,kB5BvGU;I4BwGV,oBAAoB;E3B8rIxB;E2BhtIF;IAoBM,iB5B3GS;I4B4GT,oBAAoB;E3B+rIxB;AACF;;A2B9rIA;EAEI,gBAAgB;A3BgsIpB;;AClvIE;E0BgDF;IAII,aAAa;IACb,aAAa;IACb,YAAY;IACZ,cAAc;E3BmsIhB;E2B1sIF;IASM,gBAAgB;E3BosIpB;E2B7sIF;IAWM,cAAc;E3BqsIlB;E2BhtIF;IAaQ,YAAY;E3BssIlB;E2BntIF;I1BSI,oB0BM2C;E3BusI7C;AACF;;A2BtsIA;EACE,sBAAsB;EACtB,WAAW;EACX,e5BhIW;E4BiIX,kBAAkB;EAClB,mBAAmB;A3BysIrB;;A2B9sIA;;;EAaU,c5BxKoB;AC+2I9B;;A2BptIA;;;EAeQ,kB5B3IQ;ACs1IhB;;A2B1tIA;;;EAiBQ,kB5B/IQ;AC81IhB;;A2BhuIA;;;EAmBQ,iB5BlJO;ACq2If;;A2BtuIA;EAqBM,c5B7KwB;E4B8KxB,a7BjLgB;E6BkLhB,oBAAoB;EACpB,kBAAkB;EAClB,MAAM;EACN,Y7BrLgB;E6BsLhB,UAAU;A3BqtIhB;;A2BhvIA;;EA+BM,mB7B1LgB;AEg5ItB;;A2BrvIA;EAiCM,OAAO;A3BwtIb;;A2BzvIA;;EAqCM,oB7BhMgB;AEy5ItB;;A2B9vIA;EAuCM,QAAQ;A3B2tId;;A2BlwIA;EA2CM,6BAA6B;E1B3C/B,a0B4C+B;EAC7B,YAAY;EACZ,UAAU;A3B2tIhB;;A2BzwIA;EAgDM,kB5B5KU;ACy4IhB;;A2B7wIA;EAkDM,kB5BhLU;AC+4IhB;;A2BjxIA;EAoDM,iB5BnLS;ACo5If;;A4Bv7IA,qBAAA;ACWA;EAGE,e9BuBW;E8BtBX,mBAAmB;A7B86IrB;;A6Bl7IA;EAMI,mBAAmB;EACnB,c9BI8B;E8BH9B,aAAa;EACb,uBAAuB;EACvB,iBAduC;A7B87I3C;;A6B17IA;EAYM,c9BjBwB;ACm8I9B;;A6B97IA;EAcI,mBAAmB;EACnB,aAAa;A7Bo7IjB;;A6Bn8IA;E5B+II,gB4B9HoC;A7Bs7IxC;;A6Bv8IA;EAoBQ,c9BzBsB;E8B0BtB,eAAe;EACf,oBAAoB;A7Bu7I5B;;A6B78IA;EAwBM,c9B1BwB;E8B2BxB,iBAAiB;A7By7IvB;;A6Bl9IA;;EA4BI,uBAAuB;EACvB,aAAa;EACb,eAAe;EACf,2BAA2B;A7B27I/B;;A6B19IA;E5B+II,kB4B7GuC;A7B47I3C;;A6B99IA;E5B+II,mB4B3GuC;A7B87I3C;;A6Bl+IA;;EAyCM,uBAAuB;A7B87I7B;;A6Bv+IA;;EA6CM,yBAAyB;A7B+7I/B;;A6B5+IA;EAgDI,kB9BrBY;ACq9IhB;;A6Bh/IA;EAkDI,kB9BzBY;AC29IhB;;A6Bp/IA;EAoDI,iB9B5BW;ACg+If;;A6Bx/IA;EAwDM,iBAAiB;A7Bo8IvB;;A6B5/IA;EA2DM,iBAAiB;A7Bq8IvB;;A6BhgJA;EA8DM,iBAAiB;A7Bs8IvB;;A6BpgJA;EAiEM,iBAAiB;A7Bu8IvB;;A8B7/IA;EACE,uB/BR6B;E+BS7B,sBAnBmB;EAoBnB,0F/BvB2B;E+BwB3B,c/BnB4B;E+BoB5B,eAAe;EACf,kBAAkB;A9BggJpB;;A8B7/IE;EACE,+BA3BiB;EA4BjB,gCA5BiB;A9B4hJrB;;A8B//IE;EACE,kCA9BiB;EA+BjB,mCA/BiB;A9BiiJrB;;A8BhgJA;EAEE,6BAjCwC;EAkCxC,oBAAoB;EACpB,kD/BxC2B;E+ByC3B,aAAa;A9BkgJf;;A8BhgJA;EACE,mBAAmB;EACnB,c/BzC4B;E+B0C5B,aAAa;EACb,YAAY;EACZ,gB/BNe;E+BOf,qBA1CgC;A9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B;;AiCp0JA;EAgBQ,kBAlBsB;AjC00J9B;;AiCx0JA;EAkBI,8ClCnB0B;EkCoB1B,gBA1BgB;EA2BhB,iBA3BgB;AjCq1JpB;;AiC90JA;EAwBM,kBA9BsB;EA+BtB,mBA/BsB;AjCy1J5B;;AiCxzJA;;EAEE,gBAAgB;EAChB,YAAY;EACZ,cAAc;AjC2zJhB;;AiCzzJA;EhC8GI,iBgCtJgB;AjCq2JpB;;AiC1zJA;EhC2GI,kBgCtJgB;AjCy2JpB;;AiC3zJA;EACE,gBAAgB;EAChB,YAAY;EACZ,cAAc;EACd,mBAAmB;AjC8zJrB;;ACvxJE;EgC3CF;IAQI,gBAAgB;EjC+zJlB;AACF;;AkCt2JA;EACE,enCgBW;ACy1Jb;;AkC12JA;EAII,kBnCcY;AC41JhB;;AkC92JA;EAMI,kBnCUY;ACk2JhB;;AkCl3JA;EAQI,iBnCOW;ACu2Jf;;AkC52JA;EACE,iBArB0B;AlCo4J5B;;AkCh3JA;EAGI,kBnCmCc;EmClCd,cnC3B0B;EmC4B1B,cAAc;EACd,qBAzBiC;AlC04JrC;;AkCv3JA;EAQM,4BnCzBwB;EmC0BxB,cnCjCwB;ACo5J9B;;AkC53JA;EAYM,yBnCpB4B;EmCqB5B,WxBuCU;AV60JhB;;AkCj4JA;EjC4HI,+BFhJ0B;EmCqCxB,cAnC0B;EjC8I5B,qBiC7IkC;AlCw5JtC;;AkCn3JA;EACE,cnC3C4B;EmC4C5B,iBApC2B;EAqC3B,qBApC+B;EAqC/B,yBAAyB;AlCs3J3B;;AkC13JA;EAMI,eAtCoB;AlC85JxB;;AkC93JA;EAQI,kBAxCoB;AlCk6JxB;;AmC75JA;EAEE,4BpCZ4B;EoCa5B,kBpC2CU;EoC1CV,epCUW;ACq5Jb;;AmCn6JA;EAMI,mBAAmB;AnCi6JvB;;AmCv6JA;EAQI,mBAAmB;EACnB,0BAA0B;AnCm6J9B;;AmC56JA;EAYI,kBpCGY;ACi6JhB;;AmCh7JA;EAcI,kBpCDY;ACu6JhB;;AmCp7JA;EAgBI,iBpCJW;AC46Jf;;AmCx7JA;EAsCM,uBAH+C;AnCy5JrD;;AmC57JA;EAwCQ,uBpChDuB;EoCiDvB,cpC9DqB;ACs9J7B;;AmCj8JA;EA2CQ,mBpCnDuB;AC68J/B;;AmCr8JA;EAsCM,yBAH+C;AnCs6JrD;;AmCz8JA;EAwCQ,yBpC7DqB;EoC8DrB,YpCjDuB;ACs9J/B;;AmC98JA;EA2CQ,qBpChEqB;ACu+J7B;;AmCl9JA;EAsCM,yBAH+C;AnCm7JrD;;AmCt9JA;EAwCQ,4BpClDsB;EoCmDtB,yBzBgBa;AVk6JrB;;AmC39JA;EA2CQ,wBpCrDsB;ACy+J9B;;AmC/9JA;EAsCM,yBAH+C;AnCg8JrD;;AmCn+JA;EAwCQ,yBpCzDsB;EoC0DtB,WzBkBQ;AV66JhB;;AmCx+JA;EA2CQ,qBpC5DsB;AC6/J9B;;AmC5+JA;EAsCM,yBzB4B0C;AV86JhD;;AmCh/JA;EAwCQ,yBpC3C0B;EoC4C1B,WzBkBQ;AV07JhB;;AmCr/JA;EA2CQ,qBpC9C0B;EoC+C1B,czB+B6D;AV+6JrE;;AmC1/JA;EAsCM,yBzB4B0C;AV47JhD;;AmC9/JA;EAwCQ,yBpCzC0B;EoC0C1B,WzBkBQ;AVw8JhB;;AmCngKA;EA2CQ,qBpC5C0B;EoC6C1B,czB+B6D;AV67JrE;;AmCxgKA;EAsCM,yBzB4B0C;AV08JhD;;AmC5gKA;EAwCQ,yBpC1C0B;EoC2C1B,WzBkBQ;AVs9JhB;;AmCjhKA;EA2CQ,qBpC7C0B;EoC8C1B,czB+B6D;AV28JrE;;AmCthKA;EAsCM,yBzB4B0C;AVw9JhD;;AmC1hKA;EAwCQ,yBpC5C0B;EoC6C1B,WzBkBQ;AVo+JhB;;AmC/hKA;EA2CQ,qBpC/C0B;EoCgD1B,czB+B6D;AVy9JrE;;AmCpiKA;EAsCM,yBzB4B0C;AVs+JhD;;AmCxiKA;EAwCQ,yBpC7C0B;EoC8C1B,yBzBgBa;AVo/JrB;;AmC7iKA;EA2CQ,qBpChD0B;EoCiD1B,czB+B6D;AVu+JrE;;AmCljKA;EAsCM,yBzB4B0C;AVo/JhD;;AmCtjKA;EAwCQ,yBpCvCyB;EoCwCzB,WzBkBQ;AVggKhB;;AmC3jKA;EA2CQ,qBpC1CyB;EoC2CzB,czB+B6D;AVq/JrE;;AmClhKA;EACE,mBAAmB;EACnB,yBpChE4B;EoCiE5B,0BAAgE;EAChE,WzBSc;EyBRd,aAAa;EACb,gBpC/Be;EoCgCf,8BAA8B;EAC9B,iBAAiB;EACjB,mBAtEiC;EAuEjC,kBAAkB;AnCqhKpB;;AmC/hKA;EAYI,YAAY;EACZ,cAAc;ElCwEd,oBkCvEsC;AnCuhK1C;;AmCriKA;EAgBI,eAjEgC;EAkEhC,yBAAyB;EACzB,0BAA0B;AnCyhK9B;;AmCvhKA;EACE,qBpChF4B;EoCiF5B,kBpCtBU;EoCuBV,mBAAmB;EACnB,uBAjFmC;EAkFnC,cpCvF4B;EoCwF5B,qBAjFiC;AnC2mKnC;;AmChiKA;;EASI,uBpCnF2B;AC+mK/B;;AmCriKA;EAWI,6BAlFgD;AnCgnKpD;;AoChmKA;EAEE,mBAAmB;EACnB,aAAa;EACb,sBAAsB;EACtB,uBAAuB;EACvB,gBAAgB;EAChB,eAAe;EACf,WAxCU;ApC0oKZ;;AoC1mKA;EAWI,aAAa;ApCmmKjB;;AoCjmKA;EAEE,wCrC/C2B;ACkpK7B;;AoCjmKA;;EAEE,cA9CgC;EA+ChC,+BAA0D;EAC1D,cAAc;EACd,kBAAkB;EAClB,WAAW;ApComKb;;ACxkKE;EmClCF;;IASI,cAAc;IACd,8BAA0D;IAC1D,YAxDuB;EpC+pKzB;AACF;;AoCtmKA;EAEE,gBAAgB;EAChB,YAxD2B;EAyD3B,eAAe;EnC8Fb,UmCtJoB;EA0DtB,SAzDoB;EA0DpB,WA5D2B;ApCoqK7B;;AoCtmKA;EACE,aAAa;EACb,sBAAsB;EACtB,8BAAgD;EAChD,gBAAgB;EAChB,uBAAuB;ApCymKzB;;AoCvmKA;;EAEE,mBAAmB;EACnB,4BrCtE4B;EqCuE5B,aAAa;EACb,cAAc;EACd,2BAA2B;EAC3B,aApE4B;EAqE5B,kBAAkB;ApC0mKpB;;AoCxmKA;EACE,gCrCjF4B;EqCkF5B,2BrCtBgB;EqCuBhB,4BrCvBgB;ACkoKlB;;AoCzmKA;EACE,crC1F4B;EqC2F5B,YAAY;EACZ,cAAc;EACd,iBrChEa;EqCiEb,cA7E8B;ApCyrKhC;;AoC1mKA;EACE,8BrCjCgB;EqCkChB,+BrClCgB;EqCmChB,6BrC/F4B;AC4sK9B;;AoChnKA;EnCoDI,kBmC9CuC;ApC8mK3C;;AoC5mKA;EnChDE,iCAAiC;EmCkDjC,uBrCjG6B;EqCkG7B,YAAY;EACZ,cAAc;EACd,cAAc;EACd,aAtF4B;ApCqsK9B;;AqCzqKA;EACE,uBtC5C6B;EsC6C7B,mBAvDqB;EAwDrB,kBAAkB;EAClB,WAtDW;ArCkuKb;;AqChrKA;EASM,uBtCpDyB;EsCqDzB,ctClEuB;AC6uK7B;;AqCrrKA;;EAcU,ctCtEmB;ACkvK7B;;AqC1rKA;;;;EAoBY,yB3B+BqB;E2B9BrB,ctC7EiB;AC0vK7B;;AqClsKA;EAwBY,qBtChFiB;AC8vK7B;;AqCtsKA;EA0BQ,ctClFqB;ACkwK7B;;AC/qKE;EoC3BF;;;;IAgCY,ctCxFiB;EC0wK3B;EqCltKF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,ctC/Fe;ECuxK3B;EqC/tKF;;IA0Cc,qBtClGe;EC2xK3B;EqCnuKF;;;IA8CU,yB3BKuB;I2BJvB,ctCvGmB;ECiyK3B;EqCzuKF;IAmDc,uBtC9FiB;IsC+FjB,ctC5Ge;ECqyK3B;AACF;;AqC9uKA;EASM,yBtCjEuB;EsCkEvB,YtCrDyB;AC8xK/B;;AqCnvKA;;EAcU,YtCzDqB;ACmyK/B;;AqCxvKA;;;;EAoBY,uB3B+BqB;E2B9BrB,YtChEmB;AC2yK/B;;AqChwKA;EAwBY,mBtCnEmB;AC+yK/B;;AqCpwKA;EA0BQ,YtCrEuB;ACmzK/B;;AC7uKE;EoC3BF;;;;IAgCY,YtC3EmB;EC2zK7B;EqChxKF;;;;;;;;;;IAsCc,uB3BamB;I2BZnB,YtClFiB;ECw0K7B;EqC7xKF;;IA0Cc,mBtCrFiB;EC40K7B;EqCjyKF;;;IA8CU,uB3BKuB;I2BJvB,YtC1FqB;ECk1K7B;EqCvyKF;IAmDc,yBtC3Ge;IsC4Gf,YtC/FiB;ECs1K7B;AACF;;AqC5yKA;EASM,4BtCtDwB;EsCuDxB,yB3BYe;AV2xKrB;;AqCjzKA;;EAcU,yB3BQW;AVgyKrB;;AqCtzKA;;;;EAoBY,yB3B+BqB;E2B9BrB,yB3BCS;AVwyKrB;;AqC9zKA;EAwBY,gC3BFS;AV4yKrB;;AqCl0KA;EA0BQ,yB3BJa;AVgzKrB;;AC3yKE;EoC3BF;;;;IAgCY,yB3BVS;EVwzKnB;EqC90KF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,yB3BjBO;EVq0KnB;EqC31KF;;IA0Cc,gC3BpBO;EVy0KnB;EqC/1KF;;;IA8CU,yB3BKuB;I2BJvB,yB3BzBW;EV+0KnB;EqCr2KF;IAmDc,4BtChGgB;IsCiGhB,yB3B9BO;EVm1KnB;AACF;;AqC12KA;EASM,yBtC7DwB;EsC8DxB,W3BcU;AVu1KhB;;AqC/2KA;;EAcU,W3BUM;AV41KhB;;AqCp3KA;;;;EAoBY,yB3B+BqB;E2B9BrB,W3BGI;AVo2KhB;;AqC53KA;EAwBY,kB3BAI;AVw2KhB;;AqCh4KA;EA0BQ,W3BFQ;AV42KhB;;ACz2KE;EoC3BF;;;;IAgCY,W3BRI;EVo3Kd;EqC54KF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,W3BfE;EVi4Kd;EqCz5KF;;IA0Cc,kB3BlBE;EVq4Kd;EqC75KF;;;IA8CU,yB3BKuB;I2BJvB,W3BvBM;EV24Kd;EqCn6KF;IAmDc,yBtCvGgB;IsCwGhB,W3B5BE;EV+4Kd;AACF;;AqCx6KA;EASM,yBtC/C4B;EsCgD5B,W3BcU;AVq5KhB;;AqC76KA;;EAcU,W3BUM;AV05KhB;;AqCl7KA;;;;EAoBY,yB3B+BqB;E2B9BrB,W3BGI;AVk6KhB;;AqC17KA;EAwBY,kB3BAI;AVs6KhB;;AqC97KA;EA0BQ,W3BFQ;AV06KhB;;ACv6KE;EoC3BF;;;;IAgCY,W3BRI;EVk7Kd;EqC18KF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,W3BfE;EV+7Kd;EqCv9KF;;IA0Cc,kB3BlBE;EVm8Kd;EqC39KF;;;IA8CU,yB3BKuB;I2BJvB,W3BvBM;EVy8Kd;EqCj+KF;IAmDc,yBtCzFoB;IsC0FpB,W3B5BE;EV68Kd;AACF;;AqCt+KA;EASM,yBtC7C4B;EsC8C5B,W3BcU;AVm9KhB;;AqC3+KA;;EAcU,W3BUM;AVw9KhB;;AqCh/KA;;;;EAoBY,yB3B+BqB;E2B9BrB,W3BGI;AVg+KhB;;AqCx/KA;EAwBY,kB3BAI;AVo+KhB;;AqC5/KA;EA0BQ,W3BFQ;AVw+KhB;;ACr+KE;EoC3BF;;;;IAgCY,W3BRI;EVg/Kd;EqCxgLF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,W3BfE;EV6/Kd;EqCrhLF;;IA0Cc,kB3BlBE;EVigLd;EqCzhLF;;;IA8CU,yB3BKuB;I2BJvB,W3BvBM;EVugLd;EqC/hLF;IAmDc,yBtCvFoB;IsCwFpB,W3B5BE;EV2gLd;AACF;;AqCpiLA;EASM,yBtC9C4B;EsC+C5B,W3BcU;AVihLhB;;AqCziLA;;EAcU,W3BUM;AVshLhB;;AqC9iLA;;;;EAoBY,yB3B+BqB;E2B9BrB,W3BGI;AV8hLhB;;AqCtjLA;EAwBY,kB3BAI;AVkiLhB;;AqC1jLA;EA0BQ,W3BFQ;AVsiLhB;;ACniLE;EoC3BF;;;;IAgCY,W3BRI;EV8iLd;EqCtkLF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,W3BfE;EV2jLd;EqCnlLF;;IA0Cc,kB3BlBE;EV+jLd;EqCvlLF;;;IA8CU,yB3BKuB;I2BJvB,W3BvBM;EVqkLd;EqC7lLF;IAmDc,yBtCxFoB;IsCyFpB,W3B5BE;EVykLd;AACF;;AqClmLA;EASM,yBtChD4B;EsCiD5B,W3BcU;AV+kLhB;;AqCvmLA;;EAcU,W3BUM;AVolLhB;;AqC5mLA;;;;EAoBY,yB3B+BqB;E2B9BrB,W3BGI;AV4lLhB;;AqCpnLA;EAwBY,kB3BAI;AVgmLhB;;AqCxnLA;EA0BQ,W3BFQ;AVomLhB;;ACjmLE;EoC3BF;;;;IAgCY,W3BRI;EV4mLd;EqCpoLF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,W3BfE;EVynLd;EqCjpLF;;IA0Cc,kB3BlBE;EV6nLd;EqCrpLF;;;IA8CU,yB3BKuB;I2BJvB,W3BvBM;EVmoLd;EqC3pLF;IAmDc,yBtC1FoB;IsC2FpB,W3B5BE;EVuoLd;AACF;;AqChqLA;EASM,yBtCjD4B;EsCkD5B,yB3BYe;AV+oLrB;;AqCrqLA;;EAcU,yB3BQW;AVopLrB;;AqC1qLA;;;;EAoBY,yB3B+BqB;E2B9BrB,yB3BCS;AV4pLrB;;AqClrLA;EAwBY,gC3BFS;AVgqLrB;;AqCtrLA;EA0BQ,yB3BJa;AVoqLrB;;AC/pLE;EoC3BF;;;;IAgCY,yB3BVS;EV4qLnB;EqClsLF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,yB3BjBO;EVyrLnB;EqC/sLF;;IA0Cc,gC3BpBO;EV6rLnB;EqCntLF;;;IA8CU,yB3BKuB;I2BJvB,yB3BzBW;EVmsLnB;EqCztLF;IAmDc,yBtC3FoB;IsC4FpB,yB3B9BO;EVusLnB;AACF;;AqC9tLA;EASM,yBtC3C2B;EsC4C3B,W3BcU;AV2sLhB;;AqCnuLA;;EAcU,W3BUM;AVgtLhB;;AqCxuLA;;;;EAoBY,yB3B+BqB;E2B9BrB,W3BGI;AVwtLhB;;AqChvLA;EAwBY,kB3BAI;AV4tLhB;;AqCpvLA;EA0BQ,W3BFQ;AVguLhB;;AC7tLE;EoC3BF;;;;IAgCY,W3BRI;EVwuLd;EqChwLF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,W3BfE;EVqvLd;EqC7wLF;;IA0Cc,kB3BlBE;EVyvLd;EqCjxLF;;;IA8CU,yB3BKuB;I2BJvB,W3BvBM;EV+vLd;EqCvxLF;IAmDc,yBtCrFmB;IsCsFnB,W3B5BE;EVmwLd;AACF;;AqC5xLA;EAsDI,oBAAoB;EACpB,aAAa;EACb,mBA7GmB;EA8GnB,WAAW;ArC0uLf;;AqCnyLA;EA2DI,gCtCxG0B;ACo1L9B;;AqCvyLA;EALE,OAAO;EACP,eAAe;EACf,QAAQ;EACR,WA/CiB;ArC+1LnB;;AqC9yLA;EAgEI,SAAS;ArCkvLb;;AqClzLA;EAkEM,iCtC/GwB;ACm2L9B;;AqCtzLA;EAoEI,MAAM;ArCsvLV;;AqCpvLA;;EAGI,oBA9HmB;ArCo3LvB;;AqCzvLA;;EAKI,uBAhImB;ArCy3LvB;;AqCvvLA;;EAEE,oBAAoB;EACpB,aAAa;EACb,cAAc;EACd,mBAvIqB;ArCi4LvB;;AqCxvLA;EAIM,6BAA6B;ArCwvLnC;;AqCtvLA;EpCtFE,iCAAiC;EoCwFjC,gBAAgB;EAChB,gBAAgB;EAChB,kBAAkB;ArCyvLpB;;AqCvvLA;EAEE,ctCrJ4B;EEoB5B,eAAe;EACf,cAAc;EACd,eoCxBqB;EpCyBrB,kBAAkB;EAClB,coC1BqB;EpCqJnB,kBoCIkC;ArC6vLtC;;AC33LE;EACE,8BAA8B;EAC9B,cAAc;EACd,WAAW;EACX,qBAAqB;EACrB,kBAAkB;EAClB,wBAAwB;EACxB,yBFiCQ;EEhCR,yDAAyD;EACzD,oCF0Ba;EEzBb,WAAW;AD83Lf;;AC73LI;EACE,oBAAoB;ADg4L1B;;AC/3LI;EACE,oBAAoB;ADk4L1B;;ACj4LI;EACE,oBAAoB;ADo4L1B;;ACn4LE;EACE,qCAAiC;ADs4LrC;;ACl4LM;EACE,wCAAwC;ADq4LhD;;ACp4LM;EACE,UAAU;ADu4LlB;;ACt4LM;EACE,0CAA0C;ADy4LlD;;AqCpyLA;EACE,aAAa;ArCuyLf;;AqCryLA;;EAEE,ctC9J4B;EsC+J5B,cAAc;EACd,gBAAgB;EAChB,uBAAuB;EACvB,kBAAkB;ArCwyLpB;;AqC9yLA;;EASM,qBAAqB;EACrB,sBAAsB;ArC0yL5B;;AqCxyLA;;EAEE,eAAe;ArC2yLjB;;AqC7yLA;;;;;EAOI,yBtCxK0B;EsCyK1B,ctCjK8B;AC+8LlC;;AqC5yLA;EACE,YAAY;EACZ,cAAc;ArC+yLhB;;AqCjzLA;EAII,mBA7KgC;ArC89LpC;;AqCrzLA;EAMI,UAAU;ArCmzLd;;AqCzzLA;EAQI,YAAY;EACZ,cAAc;ArCqzLlB;;AqC9zLA;EAWI,oCAAoC;EACpC,mBAhMmB;EAiMnB,kCAAkC;ArCuzLtC;;AqCp0LA;EAgBM,6BArLyC;EAsLzC,4BtCpL4B;AC4+LlC;;AqCz0LA;EAmBM,6BArL0C;EAsL1C,4BtCvL4B;EsCwL5B,0BArLuC;EAsLvC,wBArLqC;EAsLrC,ctC1L4B;EsC2L5B,kCAAwE;ArC0zL9E;;AqCxzLA;EACE,YAAY;EACZ,cAAc;ArC2zLhB;;AqCzzLA;EpC7DI,mBoC8DoC;ArC4zLxC;;AqC7zLA;EAII,qBtCrM8B;EsCsM9B,oBAAoB;EpC1DpB,aoC2D6B;ArC6zLjC;;AqC3zLA;EACE,mBAAmB;EACnB,sBAAsB;EACtB,mBAAmB;ArC8zLrB;;AqCj0LA;EAKI,oBAAoB;EACpB,qBAAqB;ArCg0LzB;;AqC9zLA;EACE,4BtC3N4B;EsC4N5B,YAAY;EACZ,aAAa;EACb,WA/LyB;EAgMzB,gBAAgB;ArCi0LlB;;ACp9LE;EoC/BF;IAsLI,cAAc;ErCk0LhB;EqCj0LA;;IAGI,mBAAmB;IACnB,aAAa;ErCk0LjB;EqCj0LA;IAEI,aAAa;ErCk0LjB;EqC15LF;IA0FI,uBtC3O2B;IsC4O3B,4CtCzPyB;IsC0PzB,iBAAiB;ErCm0LnB;EqCt0LA;IAKI,cAAc;ErCo0LlB;EqCl0LA;IA3MA,OAAO;IACP,eAAe;IACf,QAAQ;IACR,WA/CiB;ErC+jMjB;EqCx0LA;IAKI,SAAS;ErCs0Lb;EqC30LA;IAOM,4CtCrQqB;EC4kM3B;EqC90LA;IASI,MAAM;ErCw0LV;EqCj1LA;IpClMA,iCAAiC;IoCgN3B,iCAA2C;IAC3C,cAAc;ErCu0LpB;EqCt0LA;;IAGI,oBA9QiB;ErCqlMrB;EqC10LA;;IAKI,uBAhRiB;ErCylMrB;AACF;;AC1gME;EoCmMA;;;;IAIE,oBAAoB;IACpB,aAAa;ErC20Lf;EqC9iMF;IAqOI,mBA1RmB;ErCsmMrB;EqC70LA;IAGI,kBA1R0B;ErCumM9B;EqCh1LA;;IAMM,mBAAmB;ErC80LzB;EqCp1LA;;IASM,kBtClOI;ECijMV;EqCx1LA;;;;IAgBQ,wCAAwC;ErC80LhD;EqC91LA;IAuBU,wCAAwC;ErC00LlD;EqCj2LA;IA4BU,4BtC7SkB;IsC8SlB,ctCzTiB;ECioM3B;EqCr2LA;IA+BU,4BtChTkB;IsCiTlB,ctCxSsB;ECinMhC;EqC7+LF;IAsKI,aAAa;ErC00Lf;EqCv+LF;;IAgKI,mBAAmB;IACnB,aAAa;ErC20Lf;EqCt9LF;IA8IM,oBAAoB;ErC20LxB;EqC70LA;IAKM,oDAAoD;ErC20L1D;EqCh1LA;IAOM,gCtClUsB;IsCmUtB,0BAAkE;IAClE,gBAAgB;IAChB,YAAY;IACZ,4CtC9UqB;IsC+UrB,SAAS;ErC40Lf;EqCx1LA;IAkBM,cAAc;ErCy0LpB;EqCx0LM;IAEE,UAAU;IACV,oBAAoB;IACpB,wBAAwB;ErCy0LhC;EqCrgMF;IA8LI,YAAY;IACZ,cAAc;ErC00LhB;EqCz0LA;IACE,2BAA2B;IpCvM3B,iBoCwMoC;ErC20LtC;EqC10LA;IACE,yBAAyB;IpC1MzB,kBoC2MoC;ErC40LtC;EqCl9LF;IAwII,uBtCxV2B;IsCyV3B,8BtClSc;IsCmSd,+BtCnSc;IsCoSd,6BtChW0B;IsCiW1B,2CtCzWyB;IsC0WzB,aAAa;IACb,mBAAmB;IpC3MnB,QoC4MuB;IACvB,eAAe;IACf,kBAAkB;IAClB,SAAS;IACT,WAjVkB;ErC8pMpB;EqCh+LF;IAqJM,sBAAsB;IACtB,mBAAmB;ErC80LvB;EqC71LA;IpC5ME,kBoC6NuC;ErC+0LzC;EqCh2LA;IAoBM,4BtC7WsB;IsC8WtB,ctCzXqB;ECwsM3B;EqCp2LA;IAuBM,4BtChXsB;IsCiXtB,ctCxW0B;ECwrMhC;EqC/0LE;IAEE,kBtC3TY;IsC4TZ,gBAAgB;IAChB,4EtCjYuB;IsCkYvB,cAAc;IACd,UAAU;IACV,oBAAoB;IACpB,wBAA8C;IAC9C,2BAA2B;IAC3B,yBtCjUM;IsCkUN,uCAAuC;ErCg1L3C;EqCp3LA;IAsCI,UAAU;IACV,QAAQ;ErCi1LZ;EqCv/LF;IAwKI,cAAc;ErCk1LhB;EqCj1LA;;IpCtPE,sBoCyPyC;ErCk1L3C;EqCr1LA;;IpCtPE,qBoC2PyC;ErCo1L3C;EqCl1LA;IAlWA,OAAO;IACP,eAAe;IACf,QAAQ;IACR,WA/CiB;ErCsuMjB;EqCx1LA;IAKI,SAAS;ErCs1Lb;EqC31LA;IAOM,4CtC5ZqB;ECmvM3B;EqC91LA;IASI,MAAM;ErCw1LV;EqCv1LA;;IAGI,oBA/ZiB;ErCuvMrB;EqC31LA;;IAKI,uBAjaiB;ErC2vMrB;EqC/1LA;;IAOI,oBAA4D;ErC41LhE;EqCn2LA;;IASI,uBAA+D;ErC81LnE;EqC51LA;;IAGI,ctC7auB;EC0wM3B;EqCh2LA;;IAKI,6BAla2C;ErCiwM/C;EqC91LA;IAKM,yBtCzasB;ECqwM5B;AACF;;AqCz1LA;EAEI,iCAA2C;ArC21L/C;;AsCnvMA;EAEE,evCFW;EuCGX,gBAnC0B;AtCwxM5B;;AsCxvMA;EAMI,kBvCLY;AC2vMhB;;AsC5vMA;EAQI,kBvCTY;ACiwMhB;;AsChwMA;EAUI,iBvCZW;ACswMf;;AsCpwMA;;EAcM,iBAAiB;EACjB,kBAAkB;EAClB,qBvCkBiB;ACyuMvB;;AsC3wMA;EAkBM,qBvCgBiB;AC6uMvB;;AsC3vMA;;EAEE,mBAAmB;EACnB,aAAa;EACb,uBAAuB;EACvB,kBAAkB;AtC8vMpB;;AsC5vMA;;;;EAME,cA9D6B;EA+D7B,uBAAuB;EACvB,eA/D8B;EAgE9B,mBA/DkC;EAgElC,oBA/DmC;EAgEnC,kBAAkB;AtC6vMpB;;AsC3vMA;;;EAGE,qBvCtE4B;EuCuE5B,cvC3E4B;EuC4E5B,gBxC3EoB;AEy0MtB;;AsCnwMA;;;EAOI,qBvC3E0B;EuC4E1B,cvC/E0B;ACi1M9B;;AsC1wMA;;;EAUI,qBvCjE8B;ACu0MlC;;AsChxMA;;;EAYI,iDvCvFyB;ACi2M7B;;AsCtxMA;;;EAcI,yBvCjF0B;EuCkF1B,qBvClF0B;EuCmF1B,gBAAgB;EAChB,cvCtF0B;EuCuF1B,YAAY;AtC8wMhB;;AsC5wMA;;EAEE,oBAtFkC;EAuFlC,qBAtFmC;EAuFnC,mBAAmB;AtC+wMrB;;AsC7wMA;EAEI,yBvCnF8B;EuCoF9B,qBvCpF8B;EuCqF9B,W5BzBY;AVwyMhB;;AsC7wMA;EACE,cvCrG4B;EuCsG5B,oBAAoB;AtCgxMtB;;AsC9wMA;EACE,eAAe;AtCixMjB;;AsClxMA;EAGI,gBAAgB;AtCmxMpB;;AC1yME;EqCxDF;IAmFI,eAAe;EtCoxMjB;EsC3yMF;;IA0BI,YAAY;IACZ,cAAc;EtCqxMhB;EsChyMF;IAcM,YAAY;IACZ,cAAc;EtCqxMlB;AACF;;ACrzME;EqCgBF;IAmBI,YAAY;IACZ,cAAc;IACd,2BAA2B;IAC3B,QAAQ;EtCuxMV;EsC91MF;;;;IA4EI,gBAAgB;IAChB,aAAa;EtCwxMf;EsCvxMA;IACE,QAAQ;EtCyxMV;EsCxxMA;IACE,QAAQ;EtC0xMV;EsCt4MF;IA8GI,8BAA8B;IAC9B,gBAAgB;IAChB,aAAa;EtC2xMf;EsC9xMA;IAMM,QAAQ;EtC2xMd;EsCjyMA;IAQM,uBAAuB;IACvB,QAAQ;EtC4xMd;EsCryMA;IAWM,QAAQ;EtC6xMd;EsCxyMA;IAcM,QAAQ;EtC6xMd;EsC3yMA;IAgBM,QAAQ;EtC8xMd;EsC9yMA;IAkBM,yBAAyB;IACzB,QAAQ;EtC+xMd;AACF;;AuCr6MA;EACE,kBxCqCgB;EwCpChB,0FxChC2B;EwCiC3B,exCEW;ACs6Mb;;AuC36MA;EAKI,qBxCWkB;AC+5MtB;;AuC/6MA;EAYQ,uBxC7BuB;EwC8BvB,cxC3CqB;ACk9M7B;;AuCp7MA;EAeQ,0BxChCuB;ACy8M/B;;AuCx7MA;EAiBQ,YxClCuB;AC68M/B;;AuC57MA;EAYQ,yBxC1CqB;EwC2CrB,YxC9BuB;ACk9M/B;;AuCj8MA;EAeQ,4BxC7CqB;ACm+M7B;;AuCr8MA;EAiBQ,cxC/CqB;ACu+M7B;;AuCz8MA;EAYQ,4BxC/BsB;EwCgCtB,yB7BmCa;AV85MrB;;AuC98MA;EAeQ,+BxClCsB;ACq+M9B;;AuCl9MA;EAiBQ,iBxCpCsB;ACy+M9B;;AuCt9MA;EAYQ,yBxCtCsB;EwCuCtB,W7BqCQ;AVy6MhB;;AuC39MA;EAeQ,4BxCzCsB;ACy/M9B;;AuC/9MA;EAiBQ,cxC3CsB;AC6/M9B;;AuCn+MA;EAYQ,yBxCxB0B;EwCyB1B,W7BqCQ;AVs7MhB;;AuCx+MA;EAeQ,4BxC3B0B;ACw/MlC;;AuC5+MA;EAiBQ,cxC7B0B;AC4/MlC;;AuCh/MA;EAYQ,yBxCtB0B;EwCuB1B,W7BqCQ;AVm8MhB;;AuCr/MA;EAeQ,4BxCzB0B;ACmgNlC;;AuCz/MA;EAiBQ,cxC3B0B;ACugNlC;;AuC7/MA;EAYQ,yBxCvB0B;EwCwB1B,W7BqCQ;AVg9MhB;;AuClgNA;EAeQ,4BxC1B0B;ACihNlC;;AuCtgNA;EAiBQ,cxC5B0B;ACqhNlC;;AuC1gNA;EAYQ,yBxCzB0B;EwC0B1B,W7BqCQ;AV69MhB;;AuC/gNA;EAeQ,4BxC5B0B;ACgiNlC;;AuCnhNA;EAiBQ,cxC9B0B;ACoiNlC;;AuCvhNA;EAYQ,yBxC1B0B;EwC2B1B,yB7BmCa;AV4+MrB;;AuC5hNA;EAeQ,4BxC7B0B;AC8iNlC;;AuChiNA;EAiBQ,cxC/B0B;ACkjNlC;;AuCpiNA;EAYQ,yBxCpByB;EwCqBzB,W7BqCQ;AVu/MhB;;AuCziNA;EAeQ,4BxCvByB;ACqjNjC;;AuC7iNA;EAiBQ,cxCzByB;ACyjNjC;;AuC9hNA;;EAGI,gCxC3C2B;AC2kN/B;;AuC9hNA;EACE,yBxC9C6B;EwC+C7B,0BAA8C;EAC9C,cxCrD4B;EwCsD5B,iBAhDyB;EAiDzB,gBxCjBe;EwCkBf,iBArD8B;EAsD9B,mBArDgC;AvCslNlC;;AuC/hNA;EACE,qBAAqB;EACrB,aAAa;EACb,kBArD4B;EAsD5B,uBAAuB;AvCkiNzB;;AuCtiNA;EAMI,gCxC7D0B;EwC8D1B,mBAAmB;EACnB,cAAc;AvCoiNlB;;AuC5iNA;EAWM,4BxCrEwB;EwCsExB,cxCvEwB;AC4mN9B;;AuCniNA;EAEI,cxC1E0B;AC+mN9B;;AuCviNA;EAIM,cxC7D4B;AComNlC;;AuCriNA;EACE,mBAAmB;EACnB,cxCjF4B;EwCkF5B,aAAa;EACb,2BAA2B;EAC3B,qBAAqB;AvCwiNvB;;AuC7iNA;EtCqEI,mBsC9DsC;AvC0iN1C;;AuCjjNA;EASI,YAAY;EACZ,cAAc;EACd,WAAW;AvC4iNf;;AuCvjNA;EAaI,eAAe;AvC8iNnB;;AuC3jNA;EAeI,0BxC9E8B;EwC+E9B,cxC/F0B;AC+oN9B;;AuChkNA;EAkBM,cxCjF4B;ACmoNlC;;AuCpkNA;EAoBI,8BxCnCc;EwCoCd,+BxCpCc;ACwlNlB;;AuCljNA;;EAEE,eAAe;AvCqjNjB;;AuCvjNA;;EAII,4BxCnG0B;AC2pN9B;;AuCtjNA;EtChGE,qBAAqB;EACrB,esCgGgB;EtC/FhB,WsC+FqB;EtC9FrB,gBsC8FqB;EtC7FrB,kBAAkB;EAClB,mBAAmB;EACnB,UsC2FqB;EACrB,cxC5G4B;EEkJ1B,mBsCrCoC;AvC+jNxC;;AuClkNA;EAKI,kBAAkB;EAClB,oBAAoB;AvCikNxB;;AwC3pNA;EvCgCE,iCAAiC;EuC5BjC,oBAAoB;EACpB,aAAa;EACb,ezCCW;EyCAX,8BAA8B;EAC9B,gBAAgB;EAChB,gBAAgB;EAChB,mBAAmB;AxC4pNrB;;AwCtqNA;EAYI,mBAAmB;EACnB,4BzCjC0B;EyCkC1B,0BAzC4B;EA0C5B,wBAzC0B;EA0C1B,czCvC0B;EyCwC1B,aAAa;EACb,uBAAuB;EACvB,mBAA6C;EAC7C,kBAxCyB;EAyCzB,mBAAmB;AxC8pNvB;;AwCnrNA;EAuBM,4BzC/CwB;EyCgDxB,czChDwB;ACgtN9B;;AwCxrNA;EA0BI,cAAc;AxCkqNlB;;AwC5rNA;EA6BQ,4BzCrC0B;EyCsC1B,czCtC0B;ACysNlC;;AwCjsNA;EAgCI,mBAAmB;EACnB,4BzCrD0B;EyCsD1B,0BA7D4B;EA8D5B,wBA7D0B;EA8D1B,aAAa;EACb,YAAY;EACZ,cAAc;EACd,2BAA2B;AxCqqN/B;;AwC5sNA;EAyCM,qBAAqB;AxCuqN3B;;AwChtNA;EA2CM,UAAU;EACV,uBAAuB;EACvB,oBAAoB;EACpB,qBAAqB;AxCyqN3B;;AwCvtNA;EAgDM,yBAAyB;EACzB,oBAAoB;AxC2qN1B;;AwC5tNA;EvC4HI,kBuCxEuC;AxC4qN3C;;AwChuNA;EvC4HI,mBuCtEuC;AxC8qN3C;;AwCpuNA;EA0DM,uBAAuB;AxC8qN7B;;AwCxuNA;EA6DM,yBAAyB;AxC+qN/B;;AwC5uNA;EAiEM,6BAA6B;EAI3B,0BzC9BI;AC0sNZ;;AwCjvNA;EAuEQ,4BzCxFsB;EyCyFtB,4BzC5FsB;AC0wN9B;;AwCtvNA;EA4EU,uBzC3FqB;EyC4FrB,qBzCjGoB;EyCkGpB,2CAA2E;AxC8qNrF;;AwC5vNA;EAiFM,YAAY;EACZ,cAAc;AxC+qNpB;;AwCjwNA;EAqFM,qBzCzGwB;EyC0GxB,mBA/F+B;EAgG/B,iBA/F6B;EAgG7B,gBAAgB;EAChB,kBAAkB;AxCgrNxB;;AwCzwNA;EA2FQ,4BzC5GsB;EyC6GtB,qBzCjHsB;EyCkHtB,UAAU;AxCkrNlB;;AwC/wNA;EvC4HI,kBuC5BuE;AxCmrN3E;;AwCnxNA;EAsGU,4BzC/DE;EyCgEF,+BzChEE;ACivNZ;;AwCxxNA;EA6GU,2BzCtEE;EyCuEF,8BzCvEE;ACsvNZ;;AwC7xNA;EAiHU,yBzCzHwB;EyC0HxB,qBzC1HwB;EyC2HxB,W9B/DM;E8BgEN,UAAU;AxCgrNpB;;AwCpyNA;EAsHM,mBAAmB;AxCkrNzB;;AwCxyNA;EA+HY,kCzCtFW;EyCuFX,+BzCvFW;EyCwFX,qBAAqB;AxC6qNjC;;AwC9yNA;EAwIY,iCzC/FW;EyCgGX,8BzChGW;EyCiGX,oBAAoB;AxC0qNhC;;AwCpzNA;EA6II,kBzCrIY;ACgzNhB;;AwCxzNA;EA+II,kBzCzIY;ACszNhB;;AwC5zNA;EAiJI,iBzC5IW;AC2zNf;;AyC91NA,eAAA;ACIA;EACE,cAAc;EACd,aAAa;EACb,YAAY;EACZ,cAAc;EACd,gBAPkB;A1Cq2NpB;;A0C71NE;EACE,UAAU;EACV,YAAY;A1Cg2NhB;;A0C/1NE;EACE,UAAU;EACV,WAAW;A1Ck2Nf;;A0Cj2NE;EACE,UAAU;EACV,UAAU;A1Co2Nd;;A0Cn2NE;EACE,UAAU;EACV,eAAe;A1Cs2NnB;;A0Cr2NE;EACE,UAAU;EACV,UAAU;A1Cw2Nd;;A0Cv2NE;EACE,UAAU;EACV,eAAe;A1C02NnB;;A0Cz2NE;EACE,UAAU;EACV,UAAU;A1C42Nd;;A0C32NE;EACE,UAAU;EACV,UAAU;A1C82Nd;;A0C72NE;EACE,UAAU;EACV,UAAU;A1Cg3Nd;;A0C/2NE;EACE,UAAU;EACV,UAAU;A1Ck3Nd;;A0Cj3NE;EACE,UAAU;EACV,UAAU;A1Co3Nd;;A0Cn3NE;EzC+GE,iByC9GmC;A1Cs3NvC;;A0Cr3NE;EzC6GE,sByC5GwC;A1Cw3N5C;;A0Cv3NE;EzC2GE,iByC1GmC;A1C03NvC;;A0Cz3NE;EzCyGE,sByCxGwC;A1C43N5C;;A0C33NE;EzCuGE,iByCtGmC;A1C83NvC;;A0C73NE;EzCqGE,iByCpGmC;A1Cg4NvC;;A0C/3NE;EzCmGE,iByClGmC;A1Ck4NvC;;A0Cj4NE;EzCiGE,iByChGmC;A1Co4NvC;;A0Cn4NE;EzC+FE,iByC9FmC;A1Cs4NvC;;A0Cp4NI;EACE,UAAU;EACV,SAAiC;A1Cu4NvC;;A0Ct4NI;EzCyFA,gByCxF4D;A1Cy4NhE;;A0C74NI;EACE,UAAU;EACV,eAAiC;A1Cg5NvC;;A0C/4NI;EzCyFA,sByCxF4D;A1Ck5NhE;;A0Ct5NI;EACE,UAAU;EACV,gBAAiC;A1Cy5NvC;;A0Cx5NI;EzCyFA,uByCxF4D;A1C25NhE;;A0C/5NI;EACE,UAAU;EACV,UAAiC;A1Ck6NvC;;A0Cj6NI;EzCyFA,iByCxF4D;A1Co6NhE;;A0Cx6NI;EACE,UAAU;EACV,gBAAiC;A1C26NvC;;A0C16NI;EzCyFA,uByCxF4D;A1C66NhE;;A0Cj7NI;EACE,UAAU;EACV,gBAAiC;A1Co7NvC;;A0Cn7NI;EzCyFA,uByCxF4D;A1Cs7NhE;;A0C17NI;EACE,UAAU;EACV,UAAiC;A1C67NvC;;A0C57NI;EzCyFA,iByCxF4D;A1C+7NhE;;A0Cn8NI;EACE,UAAU;EACV,gBAAiC;A1Cs8NvC;;A0Cr8NI;EzCyFA,uByCxF4D;A1Cw8NhE;;A0C58NI;EACE,UAAU;EACV,gBAAiC;A1C+8NvC;;A0C98NI;EzCyFA,uByCxF4D;A1Ci9NhE;;A0Cr9NI;EACE,UAAU;EACV,UAAiC;A1Cw9NvC;;A0Cv9NI;EzCyFA,iByCxF4D;A1C09NhE;;A0C99NI;EACE,UAAU;EACV,gBAAiC;A1Ci+NvC;;A0Ch+NI;EzCyFA,uByCxF4D;A1Cm+NhE;;A0Cv+NI;EACE,UAAU;EACV,gBAAiC;A1C0+NvC;;A0Cz+NI;EzCyFA,uByCxF4D;A1C4+NhE;;A0Ch/NI;EACE,UAAU;EACV,WAAiC;A1Cm/NvC;;A0Cl/NI;EzCyFA,kByCxF4D;A1Cq/NhE;;AC19NE;EyCzFF;IAiEM,UAAU;IACV,YAAY;E1Cu/NhB;E0CzjOF;IAoEM,UAAU;IACV,WAAW;E1Cw/Nf;E0C7jOF;IAuEM,UAAU;IACV,UAAU;E1Cy/Nd;E0CjkOF;IA0EM,UAAU;IACV,eAAe;E1C0/NnB;E0CrkOF;IA6EM,UAAU;IACV,UAAU;E1C2/Nd;E0CzkOF;IAgFM,UAAU;IACV,eAAe;E1C4/NnB;E0C7kOF;IAmFM,UAAU;IACV,UAAU;E1C6/Nd;E0CjlOF;IAsFM,UAAU;IACV,UAAU;E1C8/Nd;E0CrlOF;IAyFM,UAAU;IACV,UAAU;E1C+/Nd;E0CzlOF;IA4FM,UAAU;IACV,UAAU;E1CggOd;E0C7lOF;IA+FM,UAAU;IACV,UAAU;E1CigOd;E0CjmOF;IzCsJI,iByCpDqC;E1CkgOvC;E0CpmOF;IzCsJI,sByClD0C;E1CmgO5C;E0CvmOF;IzCsJI,iByChDqC;E1CogOvC;E0C1mOF;IzCsJI,sByC9C0C;E1CqgO5C;E0C7mOF;IzCsJI,iByC5CqC;E1CsgOvC;E0ChnOF;IzCsJI,iByC1CqC;E1CugOvC;E0CnnOF;IzCsJI,iByCxCqC;E1CwgOvC;E0CtnOF;IzCsJI,iByCtCqC;E1CygOvC;E0CznOF;IzCsJI,iByCpCqC;E1C0gOvC;E0C5nOF;IAqHQ,UAAU;IACV,SAAiC;E1C0gOvC;E0ChoOF;IzCsJI,gByC9B8D;E1C2gOhE;E0CnoOF;IAqHQ,UAAU;IACV,eAAiC;E1CihOvC;E0CvoOF;IzCsJI,sByC9B8D;E1CkhOhE;E0C1oOF;IAqHQ,UAAU;IACV,gBAAiC;E1CwhOvC;E0C9oOF;IzCsJI,uByC9B8D;E1CyhOhE;E0CjpOF;IAqHQ,UAAU;IACV,UAAiC;E1C+hOvC;E0CrpOF;IzCsJI,iByC9B8D;E1CgiOhE;E0CxpOF;IAqHQ,UAAU;IACV,gBAAiC;E1CsiOvC;E0C5pOF;IzCsJI,uByC9B8D;E1CuiOhE;E0C/pOF;IAqHQ,UAAU;IACV,gBAAiC;E1C6iOvC;E0CnqOF;IzCsJI,uByC9B8D;E1C8iOhE;E0CtqOF;IAqHQ,UAAU;IACV,UAAiC;E1CojOvC;E0C1qOF;IzCsJI,iByC9B8D;E1CqjOhE;E0C7qOF;IAqHQ,UAAU;IACV,gBAAiC;E1C2jOvC;E0CjrOF;IzCsJI,uByC9B8D;E1C4jOhE;E0CprOF;IAqHQ,UAAU;IACV,gBAAiC;E1CkkOvC;E0CxrOF;IzCsJI,uByC9B8D;E1CmkOhE;E0C3rOF;IAqHQ,UAAU;IACV,UAAiC;E1CykOvC;E0C/rOF;IzCsJI,iByC9B8D;E1C0kOhE;E0ClsOF;IAqHQ,UAAU;IACV,gBAAiC;E1CglOvC;E0CtsOF;IzCsJI,uByC9B8D;E1CilOhE;E0CzsOF;IAqHQ,UAAU;IACV,gBAAiC;E1CulOvC;E0C7sOF;IzCsJI,uByC9B8D;E1CwlOhE;E0ChtOF;IAqHQ,UAAU;IACV,WAAiC;E1C8lOvC;E0CptOF;IzCsJI,kByC9B8D;E1C+lOhE;AACF;;AC3nOE;EyC7FF;IA4HM,UAAU;IACV,YAAY;E1CimOhB;E0C9tOF;IAgIM,UAAU;IACV,WAAW;E1CimOf;E0CluOF;IAoIM,UAAU;IACV,UAAU;E1CimOd;E0CtuOF;IAwIM,UAAU;IACV,eAAe;E1CimOnB;E0C1uOF;IA4IM,UAAU;IACV,UAAU;E1CimOd;E0C9uOF;IAgJM,UAAU;IACV,eAAe;E1CimOnB;E0ClvOF;IAoJM,UAAU;IACV,UAAU;E1CimOd;E0CtvOF;IAwJM,UAAU;IACV,UAAU;E1CimOd;E0C1vOF;IA4JM,UAAU;IACV,UAAU;E1CimOd;E0C9vOF;IAgKM,UAAU;IACV,UAAU;E1CimOd;E0ClwOF;IAoKM,UAAU;IACV,UAAU;E1CimOd;E0CtwOF;IzCsJI,iByCkBqC;E1CimOvC;E0CzwOF;IzCsJI,sByCqB0C;E1CimO5C;E0C5wOF;IzCsJI,iByCwBqC;E1CimOvC;E0C/wOF;IzCsJI,sByC2B0C;E1CimO5C;E0ClxOF;IzCsJI,iByC8BqC;E1CimOvC;E0CrxOF;IzCsJI,iByCiCqC;E1CimOvC;E0CxxOF;IzCsJI,iByCoCqC;E1CimOvC;E0C3xOF;IzCsJI,iByCuCqC;E1CimOvC;E0C9xOF;IzCsJI,iByC0CqC;E1CimOvC;E0CjyOF;IAoMQ,UAAU;IACV,SAAiC;E1CgmOvC;E0CryOF;IzCsJI,gByCkD8D;E1CgmOhE;E0CxyOF;IAoMQ,UAAU;IACV,eAAiC;E1CumOvC;E0C5yOF;IzCsJI,sByCkD8D;E1CumOhE;E0C/yOF;IAoMQ,UAAU;IACV,gBAAiC;E1C8mOvC;E0CnzOF;IzCsJI,uByCkD8D;E1C8mOhE;E0CtzOF;IAoMQ,UAAU;IACV,UAAiC;E1CqnOvC;E0C1zOF;IzCsJI,iByCkD8D;E1CqnOhE;E0C7zOF;IAoMQ,UAAU;IACV,gBAAiC;E1C4nOvC;E0Cj0OF;IzCsJI,uByCkD8D;E1C4nOhE;E0Cp0OF;IAoMQ,UAAU;IACV,gBAAiC;E1CmoOvC;E0Cx0OF;IzCsJI,uByCkD8D;E1CmoOhE;E0C30OF;IAoMQ,UAAU;IACV,UAAiC;E1C0oOvC;E0C/0OF;IzCsJI,iByCkD8D;E1C0oOhE;E0Cl1OF;IAoMQ,UAAU;IACV,gBAAiC;E1CipOvC;E0Ct1OF;IzCsJI,uByCkD8D;E1CipOhE;E0Cz1OF;IAoMQ,UAAU;IACV,gBAAiC;E1CwpOvC;E0C71OF;IzCsJI,uByCkD8D;E1CwpOhE;E0Ch2OF;IAoMQ,UAAU;IACV,UAAiC;E1C+pOvC;E0Cp2OF;IzCsJI,iByCkD8D;E1C+pOhE;E0Cv2OF;IAoMQ,UAAU;IACV,gBAAiC;E1CsqOvC;E0C32OF;IzCsJI,uByCkD8D;E1CsqOhE;E0C92OF;IAoMQ,UAAU;IACV,gBAAiC;E1C6qOvC;E0Cl3OF;IzCsJI,uByCkD8D;E1C6qOhE;E0Cr3OF;IAoMQ,UAAU;IACV,WAAiC;E1CorOvC;E0Cz3OF;IzCsJI,kByCkD8D;E1CorOhE;AACF;;ACxxOE;EyCrGF;IA2MM,UAAU;IACV,YAAY;E1CurOhB;E0Cn4OF;IA8MM,UAAU;IACV,WAAW;E1CwrOf;E0Cv4OF;IAiNM,UAAU;IACV,UAAU;E1CyrOd;E0C34OF;IAoNM,UAAU;IACV,eAAe;E1C0rOnB;E0C/4OF;IAuNM,UAAU;IACV,UAAU;E1C2rOd;E0Cn5OF;IA0NM,UAAU;IACV,eAAe;E1C4rOnB;E0Cv5OF;IA6NM,UAAU;IACV,UAAU;E1C6rOd;E0C35OF;IAgOM,UAAU;IACV,UAAU;E1C8rOd;E0C/5OF;IAmOM,UAAU;IACV,UAAU;E1C+rOd;E0Cn6OF;IAsOM,UAAU;IACV,UAAU;E1CgsOd;E0Cv6OF;IAyOM,UAAU;IACV,UAAU;E1CisOd;E0C36OF;IzCsJI,iByCsFqC;E1CksOvC;E0C96OF;IzCsJI,sByCwF0C;E1CmsO5C;E0Cj7OF;IzCsJI,iByC0FqC;E1CosOvC;E0Cp7OF;IzCsJI,sByC4F0C;E1CqsO5C;E0Cv7OF;IzCsJI,iByC8FqC;E1CssOvC;E0C17OF;IzCsJI,iByCgGqC;E1CusOvC;E0C77OF;IzCsJI,iByCkGqC;E1CwsOvC;E0Ch8OF;IzCsJI,iByCoGqC;E1CysOvC;E0Cn8OF;IzCsJI,iByCsGqC;E1C0sOvC;E0Ct8OF;IA+PQ,UAAU;IACV,SAAiC;E1C0sOvC;E0C18OF;IzCsJI,gByC4G8D;E1C2sOhE;E0C78OF;IA+PQ,UAAU;IACV,eAAiC;E1CitOvC;E0Cj9OF;IzCsJI,sByC4G8D;E1CktOhE;E0Cp9OF;IA+PQ,UAAU;IACV,gBAAiC;E1CwtOvC;E0Cx9OF;IzCsJI,uByC4G8D;E1CytOhE;E0C39OF;IA+PQ,UAAU;IACV,UAAiC;E1C+tOvC;E0C/9OF;IzCsJI,iByC4G8D;E1CguOhE;E0Cl+OF;IA+PQ,UAAU;IACV,gBAAiC;E1CsuOvC;E0Ct+OF;IzCsJI,uByC4G8D;E1CuuOhE;E0Cz+OF;IA+PQ,UAAU;IACV,gBAAiC;E1C6uOvC;E0C7+OF;IzCsJI,uByC4G8D;E1C8uOhE;E0Ch/OF;IA+PQ,UAAU;IACV,UAAiC;E1CovOvC;E0Cp/OF;IzCsJI,iByC4G8D;E1CqvOhE;E0Cv/OF;IA+PQ,UAAU;IACV,gBAAiC;E1C2vOvC;E0C3/OF;IzCsJI,uByC4G8D;E1C4vOhE;E0C9/OF;IA+PQ,UAAU;IACV,gBAAiC;E1CkwOvC;E0ClgPF;IzCsJI,uByC4G8D;E1CmwOhE;E0CrgPF;IA+PQ,UAAU;IACV,UAAiC;E1CywOvC;E0CzgPF;IzCsJI,iByC4G8D;E1C0wOhE;E0C5gPF;IA+PQ,UAAU;IACV,gBAAiC;E1CgxOvC;E0ChhPF;IzCsJI,uByC4G8D;E1CixOhE;E0CnhPF;IA+PQ,UAAU;IACV,gBAAiC;E1CuxOvC;E0CvhPF;IzCsJI,uByC4G8D;E1CwxOhE;E0C1hPF;IA+PQ,UAAU;IACV,WAAiC;E1C8xOvC;E0C9hPF;IzCsJI,kByC4G8D;E1C+xOhE;AACF;;ACz7OE;EyCzGF;IAqQM,UAAU;IACV,YAAY;E1CkyOhB;E0CxiPF;IAwQM,UAAU;IACV,WAAW;E1CmyOf;E0C5iPF;IA2QM,UAAU;IACV,UAAU;E1CoyOd;E0ChjPF;IA8QM,UAAU;IACV,eAAe;E1CqyOnB;E0CpjPF;IAiRM,UAAU;IACV,UAAU;E1CsyOd;E0CxjPF;IAoRM,UAAU;IACV,eAAe;E1CuyOnB;E0C5jPF;IAuRM,UAAU;IACV,UAAU;E1CwyOd;E0ChkPF;IA0RM,UAAU;IACV,UAAU;E1CyyOd;E0CpkPF;IA6RM,UAAU;IACV,UAAU;E1C0yOd;E0CxkPF;IAgSM,UAAU;IACV,UAAU;E1C2yOd;E0C5kPF;IAmSM,UAAU;IACV,UAAU;E1C4yOd;E0ChlPF;IzCsJI,iByCgJqC;E1C6yOvC;E0CnlPF;IzCsJI,sByCkJ0C;E1C8yO5C;E0CtlPF;IzCsJI,iByCoJqC;E1C+yOvC;E0CzlPF;IzCsJI,sByCsJ0C;E1CgzO5C;E0C5lPF;IzCsJI,iByCwJqC;E1CizOvC;E0C/lPF;IzCsJI,iByC0JqC;E1CkzOvC;E0ClmPF;IzCsJI,iByC4JqC;E1CmzOvC;E0CrmPF;IzCsJI,iByC8JqC;E1CozOvC;E0CxmPF;IzCsJI,iByCgKqC;E1CqzOvC;E0C3mPF;IAyTQ,UAAU;IACV,SAAiC;E1CqzOvC;E0C/mPF;IzCsJI,gByCsK8D;E1CszOhE;E0ClnPF;IAyTQ,UAAU;IACV,eAAiC;E1C4zOvC;E0CtnPF;IzCsJI,sByCsK8D;E1C6zOhE;E0CznPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cm0OvC;E0C7nPF;IzCsJI,uByCsK8D;E1Co0OhE;E0ChoPF;IAyTQ,UAAU;IACV,UAAiC;E1C00OvC;E0CpoPF;IzCsJI,iByCsK8D;E1C20OhE;E0CvoPF;IAyTQ,UAAU;IACV,gBAAiC;E1Ci1OvC;E0C3oPF;IzCsJI,uByCsK8D;E1Ck1OhE;E0C9oPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cw1OvC;E0ClpPF;IzCsJI,uByCsK8D;E1Cy1OhE;E0CrpPF;IAyTQ,UAAU;IACV,UAAiC;E1C+1OvC;E0CzpPF;IzCsJI,iByCsK8D;E1Cg2OhE;E0C5pPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cs2OvC;E0ChqPF;IzCsJI,uByCsK8D;E1Cu2OhE;E0CnqPF;IAyTQ,UAAU;IACV,gBAAiC;E1C62OvC;E0CvqPF;IzCsJI,uByCsK8D;E1C82OhE;E0C1qPF;IAyTQ,UAAU;IACV,UAAiC;E1Co3OvC;E0C9qPF;IzCsJI,iByCsK8D;E1Cq3OhE;E0CjrPF;IAyTQ,UAAU;IACV,gBAAiC;E1C23OvC;E0CrrPF;IzCsJI,uByCsK8D;E1C43OhE;E0CxrPF;IAyTQ,UAAU;IACV,gBAAiC;E1Ck4OvC;E0C5rPF;IzCsJI,uByCsK8D;E1Cm4OhE;E0C/rPF;IAyTQ,UAAU;IACV,WAAiC;E1Cy4OvC;E0CnsPF;IzCsJI,kByCsK8D;E1C04OhE;AACF;;AC/kPI;EyCxHJ;IA+TM,UAAU;IACV,YAAY;E1C64OhB;E0C7sPF;IAkUM,UAAU;IACV,WAAW;E1C84Of;E0CjtPF;IAqUM,UAAU;IACV,UAAU;E1C+4Od;E0CrtPF;IAwUM,UAAU;IACV,eAAe;E1Cg5OnB;E0CztPF;IA2UM,UAAU;IACV,UAAU;E1Ci5Od;E0C7tPF;IA8UM,UAAU;IACV,eAAe;E1Ck5OnB;E0CjuPF;IAiVM,UAAU;IACV,UAAU;E1Cm5Od;E0CruPF;IAoVM,UAAU;IACV,UAAU;E1Co5Od;E0CzuPF;IAuVM,UAAU;IACV,UAAU;E1Cq5Od;E0C7uPF;IA0VM,UAAU;IACV,UAAU;E1Cs5Od;E0CjvPF;IA6VM,UAAU;IACV,UAAU;E1Cu5Od;E0CrvPF;IzCsJI,iByC0MqC;E1Cw5OvC;E0CxvPF;IzCsJI,sByC4M0C;E1Cy5O5C;E0C3vPF;IzCsJI,iByC8MqC;E1C05OvC;E0C9vPF;IzCsJI,sByCgN0C;E1C25O5C;E0CjwPF;IzCsJI,iByCkNqC;E1C45OvC;E0CpwPF;IzCsJI,iByCoNqC;E1C65OvC;E0CvwPF;IzCsJI,iByCsNqC;E1C85OvC;E0C1wPF;IzCsJI,iByCwNqC;E1C+5OvC;E0C7wPF;IzCsJI,iByC0NqC;E1Cg6OvC;E0ChxPF;IAmXQ,UAAU;IACV,SAAiC;E1Cg6OvC;E0CpxPF;IzCsJI,gByCgO8D;E1Ci6OhE;E0CvxPF;IAmXQ,UAAU;IACV,eAAiC;E1Cu6OvC;E0C3xPF;IzCsJI,sByCgO8D;E1Cw6OhE;E0C9xPF;IAmXQ,UAAU;IACV,gBAAiC;E1C86OvC;E0ClyPF;IzCsJI,uByCgO8D;E1C+6OhE;E0CryPF;IAmXQ,UAAU;IACV,UAAiC;E1Cq7OvC;E0CzyPF;IzCsJI,iByCgO8D;E1Cs7OhE;E0C5yPF;IAmXQ,UAAU;IACV,gBAAiC;E1C47OvC;E0ChzPF;IzCsJI,uByCgO8D;E1C67OhE;E0CnzPF;IAmXQ,UAAU;IACV,gBAAiC;E1Cm8OvC;E0CvzPF;IzCsJI,uByCgO8D;E1Co8OhE;E0C1zPF;IAmXQ,UAAU;IACV,UAAiC;E1C08OvC;E0C9zPF;IzCsJI,iByCgO8D;E1C28OhE;E0Cj0PF;IAmXQ,UAAU;IACV,gBAAiC;E1Ci9OvC;E0Cr0PF;IzCsJI,uByCgO8D;E1Ck9OhE;E0Cx0PF;IAmXQ,UAAU;IACV,gBAAiC;E1Cw9OvC;E0C50PF;IzCsJI,uByCgO8D;E1Cy9OhE;E0C/0PF;IAmXQ,UAAU;IACV,UAAiC;E1C+9OvC;E0Cn1PF;IzCsJI,iByCgO8D;E1Cg+OhE;E0Ct1PF;IAmXQ,UAAU;IACV,gBAAiC;E1Cs+OvC;E0C11PF;IzCsJI,uByCgO8D;E1Cu+OhE;E0C71PF;IAmXQ,UAAU;IACV,gBAAiC;E1C6+OvC;E0Cj2PF;IzCsJI,uByCgO8D;E1C8+OhE;E0Cp2PF;IAmXQ,UAAU;IACV,WAAiC;E1Co/OvC;E0Cx2PF;IzCsJI,kByCgO8D;E1Cq/OhE;AACF;;ACruPI;EyCvIJ;IAyXM,UAAU;IACV,YAAY;E1Cw/OhB;E0Cl3PF;IA4XM,UAAU;IACV,WAAW;E1Cy/Of;E0Ct3PF;IA+XM,UAAU;IACV,UAAU;E1C0/Od;E0C13PF;IAkYM,UAAU;IACV,eAAe;E1C2/OnB;E0C93PF;IAqYM,UAAU;IACV,UAAU;E1C4/Od;E0Cl4PF;IAwYM,UAAU;IACV,eAAe;E1C6/OnB;E0Ct4PF;IA2YM,UAAU;IACV,UAAU;E1C8/Od;E0C14PF;IA8YM,UAAU;IACV,UAAU;E1C+/Od;E0C94PF;IAiZM,UAAU;IACV,UAAU;E1CggPd;E0Cl5PF;IAoZM,UAAU;IACV,UAAU;E1CigPd;E0Ct5PF;IAuZM,UAAU;IACV,UAAU;E1CkgPd;E0C15PF;IzCsJI,iByCoQqC;E1CmgPvC;E0C75PF;IzCsJI,sByCsQ0C;E1CogP5C;E0Ch6PF;IzCsJI,iByCwQqC;E1CqgPvC;E0Cn6PF;IzCsJI,sByC0Q0C;E1CsgP5C;E0Ct6PF;IzCsJI,iByC4QqC;E1CugPvC;E0Cz6PF;IzCsJI,iByC8QqC;E1CwgPvC;E0C56PF;IzCsJI,iByCgRqC;E1CygPvC;E0C/6PF;IzCsJI,iByCkRqC;E1C0gPvC;E0Cl7PF;IzCsJI,iByCoRqC;E1C2gPvC;E0Cr7PF;IA6aQ,UAAU;IACV,SAAiC;E1C2gPvC;E0Cz7PF;IzCsJI,gByC0R8D;E1C4gPhE;E0C57PF;IA6aQ,UAAU;IACV,eAAiC;E1CkhPvC;E0Ch8PF;IzCsJI,sByC0R8D;E1CmhPhE;E0Cn8PF;IA6aQ,UAAU;IACV,gBAAiC;E1CyhPvC;E0Cv8PF;IzCsJI,uByC0R8D;E1C0hPhE;E0C18PF;IA6aQ,UAAU;IACV,UAAiC;E1CgiPvC;E0C98PF;IzCsJI,iByC0R8D;E1CiiPhE;E0Cj9PF;IA6aQ,UAAU;IACV,gBAAiC;E1CuiPvC;E0Cr9PF;IzCsJI,uByC0R8D;E1CwiPhE;E0Cx9PF;IA6aQ,UAAU;IACV,gBAAiC;E1C8iPvC;E0C59PF;IzCsJI,uByC0R8D;E1C+iPhE;E0C/9PF;IA6aQ,UAAU;IACV,UAAiC;E1CqjPvC;E0Cn+PF;IzCsJI,iByC0R8D;E1CsjPhE;E0Ct+PF;IA6aQ,UAAU;IACV,gBAAiC;E1C4jPvC;E0C1+PF;IzCsJI,uByC0R8D;E1C6jPhE;E0C7+PF;IA6aQ,UAAU;IACV,gBAAiC;E1CmkPvC;E0Cj/PF;IzCsJI,uByC0R8D;E1CokPhE;E0Cp/PF;IA6aQ,UAAU;IACV,UAAiC;E1C0kPvC;E0Cx/PF;IzCsJI,iByC0R8D;E1C2kPhE;E0C3/PF;IA6aQ,UAAU;IACV,gBAAiC;E1CilPvC;E0C//PF;IzCsJI,uByC0R8D;E1CklPhE;E0ClgQF;IA6aQ,UAAU;IACV,gBAAiC;E1CwlPvC;E0CtgQF;IzCsJI,uByC0R8D;E1CylPhE;E0CzgQF;IA6aQ,UAAU;IACV,WAAiC;E1C+lPvC;E0C7gQF;IzCsJI,kByC0R8D;E1CgmPhE;AACF;;A0C/lPA;EzC5RI,sByCxJgB;EzCwJhB,qByCxJgB;EAublB,oBAvbkB;A1CyhQpB;;A0CrmPA;EAKI,uBAzbgB;A1C6hQpB;;A0CzmPA;EAOI,qCAA4C;A1CsmPhD;;A0C7mPA;EAUI,uBAAuB;A1CumP3B;;A0CjnPA;EzC5RI,eyCwSiC;EzCxSjC,cyCySiC;EACjC,aAAa;A1CymPjB;;A0CvnPA;EAgBM,SAAS;EACT,qBAAqB;A1C2mP3B;;A0C5nPA;EAmBM,qBAAqB;A1C6mP3B;;A0ChoPA;EAqBM,gBAAgB;A1C+mPtB;;A0CpoPA;EAuBI,aAAa;A1CinPjB;;A0CxoPA;EAyBI,eAAe;A1CmnPnB;;A0C5oPA;EA2BI,mBAAmB;A1CqnPvB;;ACr+PE;EyCqVF;IA+BM,aAAa;E1CsnPjB;AACF;;AC/9PE;EyCyUF;IAmCM,aAAa;E1CwnPjB;AACF;;A0CtnPE;EACE,oBAAY;EzCnUZ,yCyCoU2D;EzCpU3D,wCyCqU2D;A1CynP/D;;A0C5nPE;EAKI,8BAA8B;EAC9B,+BAA+B;A1C2nPrC;;A0CjoPE;EASM,iBAAY;A1C4nPpB;;ACpgQE;EyC+XA;IAYQ,iBAAY;E1C8nPpB;AACF;;ACtgQE;EyC2XA;IAeQ,iBAAY;E1CioPpB;AACF;;ACxgQE;EyCuXA;IAkBQ,iBAAY;E1CooPpB;AACF;;AC1gQE;EyCmXA;IAqBQ,iBAAY;E1CuoPpB;AACF;;AC5gQE;EyC+WA;IAwBQ,iBAAY;E1C0oPpB;AACF;;AC7gQI;EyC0WF;IA2BQ,iBAAY;E1C6oPpB;AACF;;ACzgQI;EyCgWF;IA8BQ,iBAAY;E1CgpPpB;AACF;;AC1gQI;EyC2VF;IAiCQ,iBAAY;E1CmpPpB;AACF;;ACtgQI;EyCiVF;IAoCQ,iBAAY;E1CspPpB;AACF;;A0C3rPE;EASM,oBAAY;A1CsrPpB;;AC9jQE;EyC+XA;IAYQ,oBAAY;E1CwrPpB;AACF;;AChkQE;EyC2XA;IAeQ,oBAAY;E1C2rPpB;AACF;;AClkQE;EyCuXA;IAkBQ,oBAAY;E1C8rPpB;AACF;;ACpkQE;EyCmXA;IAqBQ,oBAAY;E1CisPpB;AACF;;ACtkQE;EyC+WA;IAwBQ,oBAAY;E1CosPpB;AACF;;ACvkQI;EyC0WF;IA2BQ,oBAAY;E1CusPpB;AACF;;ACnkQI;EyCgWF;IA8BQ,oBAAY;E1C0sPpB;AACF;;ACpkQI;EyC2VF;IAiCQ,oBAAY;E1C6sPpB;AACF;;AChkQI;EyCiVF;IAoCQ,oBAAY;E1CgtPpB;AACF;;A0CrvPE;EASM,mBAAY;A1CgvPpB;;ACxnQE;EyC+XA;IAYQ,mBAAY;E1CkvPpB;AACF;;AC1nQE;EyC2XA;IAeQ,mBAAY;E1CqvPpB;AACF;;AC5nQE;EyCuXA;IAkBQ,mBAAY;E1CwvPpB;AACF;;AC9nQE;EyCmXA;IAqBQ,mBAAY;E1C2vPpB;AACF;;AChoQE;EyC+WA;IAwBQ,mBAAY;E1C8vPpB;AACF;;ACjoQI;EyC0WF;IA2BQ,mBAAY;E1CiwPpB;AACF;;AC7nQI;EyCgWF;IA8BQ,mBAAY;E1CowPpB;AACF;;AC9nQI;EyC2VF;IAiCQ,mBAAY;E1CuwPpB;AACF;;AC1nQI;EyCiVF;IAoCQ,mBAAY;E1C0wPpB;AACF;;A0C/yPE;EASM,oBAAY;A1C0yPpB;;AClrQE;EyC+XA;IAYQ,oBAAY;E1C4yPpB;AACF;;ACprQE;EyC2XA;IAeQ,oBAAY;E1C+yPpB;AACF;;ACtrQE;EyCuXA;IAkBQ,oBAAY;E1CkzPpB;AACF;;ACxrQE;EyCmXA;IAqBQ,oBAAY;E1CqzPpB;AACF;;AC1rQE;EyC+WA;IAwBQ,oBAAY;E1CwzPpB;AACF;;AC3rQI;EyC0WF;IA2BQ,oBAAY;E1C2zPpB;AACF;;ACvrQI;EyCgWF;IA8BQ,oBAAY;E1C8zPpB;AACF;;ACxrQI;EyC2VF;IAiCQ,oBAAY;E1Ci0PpB;AACF;;ACprQI;EyCiVF;IAoCQ,oBAAY;E1Co0PpB;AACF;;A0Cz2PE;EASM,iBAAY;A1Co2PpB;;AC5uQE;EyC+XA;IAYQ,iBAAY;E1Cs2PpB;AACF;;AC9uQE;EyC2XA;IAeQ,iBAAY;E1Cy2PpB;AACF;;AChvQE;EyCuXA;IAkBQ,iBAAY;E1C42PpB;AACF;;AClvQE;EyCmXA;IAqBQ,iBAAY;E1C+2PpB;AACF;;ACpvQE;EyC+WA;IAwBQ,iBAAY;E1Ck3PpB;AACF;;ACrvQI;EyC0WF;IA2BQ,iBAAY;E1Cq3PpB;AACF;;ACjvQI;EyCgWF;IA8BQ,iBAAY;E1Cw3PpB;AACF;;AClvQI;EyC2VF;IAiCQ,iBAAY;E1C23PpB;AACF;;AC9uQI;EyCiVF;IAoCQ,iBAAY;E1C83PpB;AACF;;A0Cn6PE;EASM,oBAAY;A1C85PpB;;ACtyQE;EyC+XA;IAYQ,oBAAY;E1Cg6PpB;AACF;;ACxyQE;EyC2XA;IAeQ,oBAAY;E1Cm6PpB;AACF;;AC1yQE;EyCuXA;IAkBQ,oBAAY;E1Cs6PpB;AACF;;AC5yQE;EyCmXA;IAqBQ,oBAAY;E1Cy6PpB;AACF;;AC9yQE;EyC+WA;IAwBQ,oBAAY;E1C46PpB;AACF;;AC/yQI;EyC0WF;IA2BQ,oBAAY;E1C+6PpB;AACF;;AC3yQI;EyCgWF;IA8BQ,oBAAY;E1Ck7PpB;AACF;;AC5yQI;EyC2VF;IAiCQ,oBAAY;E1Cq7PpB;AACF;;ACxyQI;EyCiVF;IAoCQ,oBAAY;E1Cw7PpB;AACF;;A0C79PE;EASM,mBAAY;A1Cw9PpB;;ACh2QE;EyC+XA;IAYQ,mBAAY;E1C09PpB;AACF;;ACl2QE;EyC2XA;IAeQ,mBAAY;E1C69PpB;AACF;;ACp2QE;EyCuXA;IAkBQ,mBAAY;E1Cg+PpB;AACF;;ACt2QE;EyCmXA;IAqBQ,mBAAY;E1Cm+PpB;AACF;;ACx2QE;EyC+WA;IAwBQ,mBAAY;E1Cs+PpB;AACF;;ACz2QI;EyC0WF;IA2BQ,mBAAY;E1Cy+PpB;AACF;;ACr2QI;EyCgWF;IA8BQ,mBAAY;E1C4+PpB;AACF;;ACt2QI;EyC2VF;IAiCQ,mBAAY;E1C++PpB;AACF;;ACl2QI;EyCiVF;IAoCQ,mBAAY;E1Ck/PpB;AACF;;A0CvhQE;EASM,oBAAY;A1CkhQpB;;AC15QE;EyC+XA;IAYQ,oBAAY;E1CohQpB;AACF;;AC55QE;EyC2XA;IAeQ,oBAAY;E1CuhQpB;AACF;;AC95QE;EyCuXA;IAkBQ,oBAAY;E1C0hQpB;AACF;;ACh6QE;EyCmXA;IAqBQ,oBAAY;E1C6hQpB;AACF;;ACl6QE;EyC+WA;IAwBQ,oBAAY;E1CgiQpB;AACF;;ACn6QI;EyC0WF;IA2BQ,oBAAY;E1CmiQpB;AACF;;AC/5QI;EyCgWF;IA8BQ,oBAAY;E1CsiQpB;AACF;;ACh6QI;EyC2VF;IAiCQ,oBAAY;E1CyiQpB;AACF;;AC55Q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E,yBAA6B;A7C+zRnC;;A6C9zRI;EAGI,yBAAgD;A7C+zRxD;;A6C9zRI;EACE,oCAAwC;A7Ci0R9C;;A6C71RE;EACE,yBAAwB;A7Cg2R5B;;A6C/1RE;EAGI,yBAA0C;A7Cg2RhD;;A6C/1RE;EACE,oCAAmC;A7Ck2RvC;;A6C71RI;EACE,yBAA8B;A7Cg2RpC;;A6C/1RI;EAGI,yBAAgD;A7Cg2RxD;;A6C/1RI;EACE,oCAAyC;A7Ck2R/C;;A6Ch2RI;EACE,yBAA6B;A7Cm2RnC;;A6Cl2RI;EAGI,yBAAgD;A7Cm2RxD;;A6Cl2RI;EACE,oCAAwC;A7Cq2R9C;;A6Cj4RE;EACE,yBAAwB;A7Co4R5B;;A6Cn4RE;EAGI,yBAA0C;A7Co4RhD;;A6Cn4RE;EACE,oCAAmC;A7Cs4RvC;;A6Cj4RI;EACE,yBAA8B;A7Co4RpC;;A6Cn4RI;EAGI,yBAAgD;A7Co4RxD;;A6Cn4RI;EACE,oCAAyC;A7Cs4R/C;;A6Cp4RI;EACE,yBAA6B;A7Cu4RnC;;A6Ct4RI;EAGI,yBAAgD;A7Cu4RxD;;A6Ct4RI;EACE,oCAAwC;A7Cy4R9C;;A6Cr6RE;EACE,yBAAwB;A7Cw6R5B;;A6Cv6RE;EAGI,yBAA0C;A7Cw6RhD;;A6Cv6RE;EACE,oCAAmC;A7C06RvC;;A6Cr6RI;EACE,yBAA8B;A7Cw6RpC;;A6Cv6RI;EAGI,yBAAgD;A7Cw6RxD;;A6Cv6RI;EACE,oCAAyC;A7C06R/C;;A6Cx6RI;EACE,yBAA6B;A7C26RnC;;A6C16RI;EAGI,yBAAgD;A7C26RxD;;A6C16RI;EACE,oCAAwC;A7C66R9C;;A6C16RE;EACE,yBAAwB;A7C66R5B;;A6C56RE;EACE,oCAAmC;A7C+6RvC;;A6Cl7RE;EACE,yBAAwB;A7Cq7R5B;;A6Cp7RE;EACE,oCAAmC;A7Cu7RvC;;A6C17RE;EACE,yBAAwB;A7C67R5B;;A6C57RE;EACE,oCAAmC;A7C+7RvC;;A6Cl8RE;EACE,yBAAwB;A7Cq8R5B;;A6Cp8RE;EACE,oCAAmC;A7Cu8RvC;;A6C18RE;EACE,yBAAwB;A7C68R5B;;A6C58RE;EACE,oCAAmC;A7C+8RvC;;A6Cl9RE;EACE,yBAAwB;A7Cq9R5B;;A6Cp9RE;EACE,oCAAmC;A7Cu9RvC;;A6C19RE;EACE,yBAAwB;A7C69R5B;;A6C59RE;EACE,oCAAmC;A7C+9RvC;;A6Cl+RE;EACE,4BAAwB;A7Cq+R5B;;A6Cp+RE;EACE,uCAAmC;A7Cu+RvC;;A6C1+RE;EACE,yBAAwB;A7C6+R5B;;A6C5+RE;EACE,oCAAmC;A7C++RvC;;A8CnhSE;EACE,8BAAiC;A9CshSrC;;A8CvhSE;EACE,sCAAiC;A9C0hSrC;;A8C3hSE;EACE,iCAAiC;A9C8hSrC;;A8C/hSE;EACE,yCAAiC;A9CkiSrC;;A8C9hSE;EACE,4BAA4B;A9CiiShC;;A8CliSE;EACE,0BAA4B;A9CqiShC;;A8CtiSE;EACE,kCAA4B;A9CyiShC;;A8CriSE;EACE,sCAAkC;A9CwiStC;;A8CziSE;EACE,oCAAkC;A9C4iStC;;A8C7iSE;EACE,kCAAkC;A9CgjStC;;A8CjjSE;EACE,yCAAkC;A9CojStC;;A8CrjSE;EACE,wCAAkC;A9CwjStC;;A8CzjSE;EACE,wCAAkC;A9C4jStC;;A8C7jSE;EACE,iCAAkC;A9CgkStC;;A8CjkSE;EACE,+BAAkC;A9CokStC;;A8CrkSE;EACE,gCAAkC;A9CwkStC;;A8CzkSE;EACE,iCAAkC;A9C4kStC;;A8CxkSE;EACE,oCAAgC;A9C2kSpC;;A8C5kSE;EACE,kCAAgC;A9C+kSpC;;A8ChlSE;EACE,gCAAgC;A9CmlSpC;;A8CplSE;EACE,uCAAgC;A9CulSpC;;A8CxlSE;EACE,sCAAgC;A9C2lSpC;;A8C5lSE;EACE,sCAAgC;A9C+lSpC;;A8ChmSE;EACE,iCAAgC;A9CmmSpC;;A8CpmSE;EACE,+BAAgC;A9CumSpC;;A8CxmSE;EACE,6BAAgC;A9C2mSpC;;A8C5mSE;EACE,kCAAgC;A9C+mSpC;;A8C3mSE;EACE,+BAA8B;A9C8mSlC;;A8C/mSE;EACE,kCAA8B;A9CknSlC;;A8CnnSE;EACE,gCAA8B;A9CsnSlC;;A8CvnSE;EACE,8BAA8B;A9C0nSlC;;A8C3nSE;EACE,gCAA8B;A9C8nSlC;;A8C/nSE;EAC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A2B;ApD0vTjC;;AoD3vTI;EACE,0BAA2B;ApD8vTjC;;AoD/vTI;EACE,4BAA2B;ApDkwTjC;;AoDnwTI;EACE,6BAA2B;ApDswTjC;;AoDvwTI;EACE,0BAA2B;ApD0wTjC;;AoD3wTI;EACE,6BAA2B;ApD8wTjC;;ACvrTE;EmDxFE;IACE,0BAA2B;EpDmxT/B;EoDpxTE;IACE,4BAA2B;EpDsxT/B;EoDvxTE;IACE,0BAA2B;EpDyxT/B;EoD1xTE;IACE,4BAA2B;EpD4xT/B;EoD7xTE;IACE,6BAA2B;EpD+xT/B;EoDhyTE;IACE,0BAA2B;EpDkyT/B;EoDnyTE;IACE,6BAA2B;EpDqyT/B;AACF;;AC3sTE;EmD5FE;IACE,0BAA2B;EpD2yT/B;EoD5yTE;IACE,4BAA2B;EpD8yT/B;EoD/yTE;IACE,0BAA2B;EpDizT/B;EoDlzTE;IACE,4BAA2B;EpDozT/B;EoDrzTE;IACE,6BAA2B;EpDuzT/B;EoDxzTE;IACE,0BAA2B;EpD0zT/B;EoD3zTE;IACE,6BAA2B;EpD6zT/B;AACF;;AC3tTE;EmDpGE;IACE,0BAA2B;EpDm0T/B;EoDp0TE;IACE,4BAA2B;EpDs0T/B;EoDv0TE;IACE,0BAA2B;EpDy0T/B;EoD10TE;IACE,4BAA2B;EpD40T/B;EoD70TE;IACE,6BAA2B;EpD+0T/B;EoDh1TE;IACE,0BAA2B;EpDk1T/B;EoDn1TE;IACE,6BAA2B;EpDq1T/B;AACF;;AC/uTE;EmDxGE;IACE,0BAA2B;EpD21T/B;EoD51TE;IACE,4BAA2B;EpD81T/B;EoD/1TE;IACE,0BAA2B;EpDi2T/B;EoDl2TE;IACE,4BAA2B;EpDo2T/B;EoDr2TE;IACE,6BAA2B;EpDu2T/B;EoDx2TE;IACE,0BAA2B;EpD02T/B;EoD32TE;IACE,6BAA2B;EpD62T/B;AACF;;ACxvTI;EmDvHA;IACE,0BAA2B;EpDm3T/B;EoDp3TE;IACE,4BAA2B;EpDs3T/B;EoDv3TE;IACE,0BAA2B;EpDy3T/B;EoD13TE;IACE,4BAA2B;EpD43T/B;EoD73TE;IACE,6BAA2B;EpD+3T/B;EoDh4TE;IACE,0BAA2B;EpDk4T/B;EoDn4TE;IACE,6BAA2B;EpDq4T/B;AACF;;ACjwTI;EmDtIA;IACE,0BAA2B;EpD24T/B;EoD54TE;IACE,4BAA2B;EpD84T/B;EoD/4TE;IACE,0BAA2B;EpDi5T/B;EoDl5TE;IACE,4BAA2B;EpDo5T/B;EoDr5TE;IACE,6BAA2B;EpDu5T/B;EoDx5TE;IACE,0BAA2B;EpD05T/B;EoD35TE;IACE,6BAA2B;EpD65T/B;AACF;;AoDr4TE;EACE,6BAAqC;ApDw4TzC;;AoDz4TE;EACE,8BAAqC;ApD44TzC;;AoD74TE;EACE,2BAAqC;ApDg5TzC;;AoDj5TE;EACE,4BAAqC;ApDo5TzC;;ACv1TE;EmDzDE;IACE,6BAAqC;EpDo5TzC;AACF;;ACz1TE;EmD1DE;IACE,6BAAqC;EpDu5TzC;AACF;;AC31TE;EmD3DE;IACE,6BAAqC;EpD05TzC;AACF;;AC71TE;EmD5DE;IACE,6BAAqC;EpD65TzC;AACF;;AC/1TE;EmD7DE;IACE,6BAAqC;EpDg6TzC;AACF;;ACh2TI;EmD/DA;IACE,6BAAqC;EpDm6TzC;AACF;;AC51TI;EmDtEA;IACE,6BAAqC;EpDs6TzC;AACF;;AC71TI;EmDxEA;IACE,6BAAqC;EpDy6TzC;AACF;;ACz1TI;EmD/EA;IACE,6BAAqC;EpD46TzC;AACF;;AC74TE;EmDzDE;IACE,8BAAqC;EpD08TzC;AACF;;AC/4TE;EmD1DE;IACE,8BAAqC;EpD68TzC;AACF;;ACj5TE;EmD3DE;IACE,8BAAqC;EpDg9TzC;AACF;;ACn5TE;EmD5DE;IACE,8BAAqC;EpDm9TzC;AACF;;ACr5TE;EmD7DE;IACE,8BAAqC;EpDs9TzC;AACF;;ACt5TI;EmD/DA;IACE,8BAAqC;EpDy9TzC;AACF;;ACl5TI;EmDtEA;IACE,8BAAqC;EpD49TzC;AACF;;ACn5TI;EmDxEA;IACE,8BAAqC;EpD+9TzC;AACF;;AC/4TI;EmD/EA;IACE,8BAAqC;EpDk+TzC;AACF;;ACn8TE;EmDzDE;IACE,2BAAqC;EpDggUzC;AACF;;ACr8TE;EmD1DE;IACE,2BAAqC;EpDmgUzC;AACF;;ACv8TE;EmD3DE;IACE,2BAAqC;EpDsgUzC;AACF;;ACz8TE;EmD5DE;IACE,2BAAqC;EpDygUzC;AACF;;AC38TE;EmD7DE;IACE,2BAAqC;EpD4gUzC;AACF;;AC58TI;EmD/DA;IACE,2BAAqC;EpD+gUzC;AACF;;ACx8TI;EmDtEA;IACE,2BAAqC;EpDkhUzC;AACF;;ACz8TI;EmDxEA;IACE,2BAAqC;EpDqhUzC;AACF;;ACr8TI;EmD/EA;IACE,2BAAqC;EpDwhUzC;AACF;;ACz/TE;EmDzDE;IACE,4BAAqC;EpDsjUzC;AACF;;AC3/TE;EmD1DE;IACE,4BAAqC;EpDyjUzC;AACF;;AC7/TE;EmD3DE;IACE,4BAAqC;EpD4jUzC;AACF;;AC//TE;EmD5DE;IACE,4BAAqC;EpD+jUzC;AACF;;ACjgUE;EmD7DE;IACE,4BAAqC;EpDkkUzC;AACF;;AClgUI;EmD/DA;IACE,4BAAqC;EpDqkUzC;AACF;;AC9/TI;EmDtEA;IACE,4BAAqC;EpDwkUzC;AACF;;AC//TI;EmDxEA;IACE,4BAAqC;EpD2kUzC;AACF;;AC3/TI;EmD/EA;IACE,4BAAqC;EpD8kUzC;AACF;;AoD7kUA;EACE,qCAAqC;ApDglUvC;;AoD9kUA;EACE,oCAAoC;ApDilUtC;;AoD/kUA;EACE,oCAAoC;ApDklUtC;;AoDhlUA;EACE,6BAA6B;ApDmlU/B;;AoDjlUA;EACE,qCAAqC;ApDolUvC;;AoDllUA;EACE,2BAAqC;ApDqlUvC;;AoDplUA;EACE,2BAAsC;ApDulUxC;;AoDtlUA;EACE,2BAAsC;ApDylUxC;;AoDxlUA;EACE,2BAAwC;ApD2lU1C;;AoD1lUA;EACE,2BAAoC;ApD6lUtC;;AoD3lUA;EACE,+LAAuC;ApD8lUzC;;AoD5lUA;EACE,+LAAyC;ApD+lU3C;;AoD7lUA;EACE,+LAA0C;ApDgmU5C;;AoD9lUA;EACE,iCAAyC;ApDimU3C;;AoD/lUA;EACE,iCAAoC;ApDkmUtC;;AqDnsUE;EACE,yBAA+B;ArDssUnC;;AC/mUE;EoDrFE;IACE,yBAA+B;ErDwsUnC;AACF;;ACjnUE;EoDtFE;IACE,yBAA+B;ErD2sUnC;AACF;;ACnnUE;EoDvFE;IACE,yBAA+B;ErD8sUnC;AACF;;ACrnUE;EoDxFE;IACE,yBAA+B;ErDitUnC;AACF;;ACvnUE;EoDzFE;IACE,yBAA+B;ErDotUnC;AACF;;ACxnUI;EoD3FA;IACE,yBAA+B;ErDutUnC;AACF;;ACpnUI;EoDlGA;IACE,yBAA+B;ErD0tUnC;AACF;;ACrnUI;EoDpGA;IACE,yBAA+B;ErD6tUnC;AACF;;ACjnUI;EoD3GA;IACE,yBAA+B;ErDguUnC;AACF;;AqD7vUE;EACE,wBAA+B;ArDgwUnC;;ACzqUE;EoDrFE;IACE,wBAA+B;ErDkwUnC;AACF;;AC3qUE;EoDtFE;IACE,wBAA+B;ErDqwUnC;AACF;;AC7qUE;EoDvFE;IACE,wBAA+B;ErDwwUnC;AACF;;AC/qUE;EoDxFE;IACE,wBAA+B;ErD2wUnC;AACF;;ACjrUE;EoDzFE;IACE,wBAA+B;ErD8wUnC;AACF;;AClrUI;EoD3FA;IACE,wBAA+B;ErDixUnC;AACF;;AC9qUI;EoDlGA;IACE,wBAA+B;ErDoxUnC;AACF;;AC/qUI;EoDpGA;IACE,wBAA+B;ErDuxUnC;AACF;;AC3qUI;EoD3GA;IACE,wBAA+B;ErD0xUnC;AACF;;AqDvzUE;EACE,0BAA+B;ArD0zUnC;;ACnuUE;EoDrFE;IACE,0BAA+B;ErD4zUnC;AACF;;ACruUE;EoDtFE;IACE,0BAA+B;ErD+zUnC;AACF;;ACvuUE;EoDvFE;IACE,0BAA+B;ErDk0UnC;AACF;;ACzuUE;EoDxFE;IACE,0BAA+B;ErDq0UnC;AACF;;AC3uUE;EoDzFE;IACE,0BAA+B;ErDw0UnC;AACF;;AC5uUI;EoD3FA;IACE,0BAA+B;ErD20UnC;AACF;;ACxuUI;EoDlGA;IACE,0BAA+B;ErD80UnC;AACF;;ACzuUI;EoDpGA;IACE,0BAA+B;ErDi1UnC;AACF;;ACruUI;EoD3GA;IACE,0BAA+B;ErDo1UnC;AACF;;AqDj3UE;EACE,gCAA+B;ArDo3UnC;;AC7xUE;EoDrFE;IACE,gCAA+B;ErDs3UnC;AACF;;AC/xUE;EoDtFE;IACE,gCAA+B;ErDy3UnC;AACF;;ACjyUE;EoDvFE;IACE,gCAA+B;ErD43UnC;AACF;;ACnyUE;EoDxFE;IACE,gCAA+B;ErD+3UnC;AACF;;ACryUE;EoDzFE;IACE,gCAA+B;ErDk4UnC;AACF;;ACtyUI;EoD3FA;IACE,gCAA+B;ErDq4UnC;AACF;;AClyUI;EoDlGA;IACE,gCAA+B;ErDw4UnC;AACF;;ACnyUI;EoDpGA;IACE,gCAA+B;ErD24UnC;AACF;;AC/xUI;EoD3GA;IACE,gCAA+B;ErD84UnC;AACF;;AqD36UE;EACE,+BAA+B;ArD86UnC;;ACv1UE;EoDrFE;IACE,+BAA+B;ErDg7UnC;AACF;;ACz1UE;EoDtFE;IACE,+BAA+B;ErDm7UnC;AACF;;AC31UE;EoDvFE;IACE,+BAA+B;ErDs7UnC;AACF;;AC71UE;EoDxFE;IACE,+BAA+B;ErDy7UnC;AACF;;AC/1UE;EoDzFE;IACE,+BAA+B;ErD47UnC;AACF;;ACh2UI;EoD3FA;IACE,+BAA+B;ErD+7UnC;AACF;;AC51UI;EoDlGA;IACE,+BAA+B;ErDk8UnC;AACF;;AC71UI;EoDpGA;IACE,+BAA+B;ErDq8UnC;AACF;;ACz1UI;EoD3GA;IACE,+BAA+B;ErDw8UnC;AACF;;AqDv8UA;EACE,wBAAwB;ArD08U1B;;AqDx8UA;EACE,uBAAuB;EACvB,iCAAiC;EACjC,yBAAyB;EACzB,2BAA2B;EAC3B,qBAAqB;EACrB,6BAA6B;EAC7B,8BAA8B;EAC9B,wBAAwB;ArD28U1B;;AC55UE;EoD5CA;IACE,wBAAwB;ErD48U1B;AACF;;AC95UE;EoD5CA;IACE,wBAAwB;ErD88U1B;AACF;;ACh6UE;EoD5CA;IACE,wBAAwB;ErDg9U1B;AACF;;ACl6UE;EoD5CA;IACE,wBAAwB;ErDk9U1B;AACF;;ACp6UE;EoD5CA;IACE,wBAAwB;ErDo9U1B;AACF;;ACr6UI;EoD7CF;IACE,wBAAwB;ErDs9U1B;AACF;;ACj6UI;EoDnDF;IACE,wBAAwB;ErDw9U1B;AACF;;ACl6UI;EoDpDF;IACE,wBAAwB;ErD09U1B;AACF;;AC95UI;EoD1DF;IACE,wBAAwB;ErD49U1B;AACF;;AqD39UA;EACE,6BAA6B;ArD89U/B;;ACt9UE;EoDLA;IACE,6BAA6B;ErD+9U/B;AACF;;ACx9UE;EoDLA;IACE,6BAA6B;ErDi+U/B;AACF;;AC19UE;EoDLA;IACE,6BAA6B;ErDm+U/B;AACF;;AC59UE;EoDLA;IACE,6BAA6B;ErDq+U/B;AACF;;AC99UE;EoDLA;IACE,6BAA6B;ErDu+U/B;AACF;;AC/9UI;EoDNF;IACE,6BAA6B;ErDy+U/B;AACF;;AC39UI;EoDZF;IACE,6BAA6B;ErD2+U/B;AACF;;AC59UI;EoDbF;IACE,6BAA6B;ErD6+U/B;AACF;;ACx9UI;EoDnBF;IACE,6BAA6B;ErD++U/B;AACF;;AsDzmVA,iBAAA;ACWA;EACE,oBAAoB;EACpB,aAAa;EACb,sBAAsB;EACtB,8BAA8B;AvDkmVhC;;AuDtmVA;EAMI,gBAAgB;AvDomVpB;;AuD1mVA;EASM,mBAAmB;AvDqmVzB;;AuD9mVA;EAeM,uBxDXyB;EwDYzB,cxDzBuB;AC4nV7B;;AuDnnVA;;EAmBQ,cAAc;AvDqmVtB;;AuDxnVA;EAqBQ,cxD9BqB;ACqoV7B;;AuD5nVA;EAuBQ,4BxDhCqB;ACyoV7B;;AuDhoVA;;EA0BU,cxDnCmB;AC8oV7B;;ACviVE;EsD9FF;IA6BU,uBxDzBqB;ECsoV7B;AACF;;AuD3oVA;;EAgCQ,4BxDzCqB;ACypV7B;;AuDhpVA;;;EAqCU,yB7C6DuB;E6C5DvB,cxD/CmB;ACgqV7B;;AuDvpVA;EAyCU,cxDlDmB;EwDmDnB,YAAY;AvDknVtB;;AuD5pVA;EA4CY,UAAU;AvDonVtB;;AuDhqVA;EA+CY,uBAAwB;EACxB,UAAU;AvDqnVtB;;AuDrqVA;EAoDY,cxD7DiB;ACkrV7B;;AuDzqVA;EAsDc,uCxD/De;ACsrV7B;;AuD7qVA;EA0Dc,yBxDnEe;EwDoEf,qBxDpEe;EwDqEf,YxDxDiB;AC+qV/B;;AuDnrVA;EAkEU,4EAAyG;AvDqnVnH;;ACrmVE;EsDlFF;IAqEc,4EAAyG;EvDunVrH;AACF;;AuD7rVA;EAeM,yBxDxBuB;EwDyBvB,YxDZyB;AC8rV/B;;AuDlsVA;;EAmBQ,cAAc;AvDorVtB;;AuDvsVA;EAqBQ,YxDjBuB;ACusV/B;;AuD3sVA;EAuBQ,+BxDnBuB;AC2sV/B;;AuD/sVA;;EA0BU,YxDtBqB;ACgtV/B;;ACtnVE;EsD9FF;IA6BU,yBxDtCmB;ECkuV3B;AACF;;AuD1tVA;;EAgCQ,+BxD5BuB;AC2tV/B;;AuD/tVA;;;EAqCU,uB7C6DuB;E6C5DvB,YxDlCqB;ACkuV/B;;AuDtuVA;EAyCU,YxDrCqB;EwDsCrB,YAAY;AvDisVtB;;AuD3uVA;EA4CY,UAAU;AvDmsVtB;;AuD/uVA;EA+CY,yBAAwB;EACxB,UAAU;AvDosVtB;;AuDpvVA;EAoDY,YxDhDmB;ACovV/B;;AuDxvVA;EAsDc,uCxD/De;ACqwV7B;;AuD5vVA;EA0Dc,uBxDtDiB;EwDuDjB,mBxDvDiB;EwDwDjB,cxDrEe;AC2wV7B;;AuDlwVA;EAkEU,8EAAyG;AvDosVnH;;ACprVE;EsDlFF;IAqEc,8EAAyG;EvDssVrH;AACF;;AuD5wVA;EAeM,4BxDbwB;EwDcxB,yB7CqDe;AV4sVrB;;AuDjxVA;;EAmBQ,cAAc;AvDmwVtB;;AuDtxVA;EAqBQ,yB7CgDa;AVqtVrB;;AuD1xVA;EAuBQ,yB7C8Ca;AVytVrB;;AuD9xVA;;EA0BU,yB7C2CW;AV8tVrB;;ACrsVE;EsD9FF;IA6BU,4BxD3BoB;ECsyV5B;AACF;;AuDzyVA;;EAgCQ,yB7CqCa;AVyuVrB;;AuD9yVA;;;EAqCU,yB7C6DuB;E6C5DvB,yB7C+BW;AVgvVrB;;AuDrzVA;EAyCU,yB7C4BW;E6C3BX,YAAY;AvDgxVtB;;AuD1zVA;EA4CY,UAAU;AvDkxVtB;;AuD9zVA;EA+CY,4BAAwB;EACxB,UAAU;AvDmxVtB;;AuDn0VA;EAoDY,yB7CiBS;AVkwVrB;;AuDv0VA;EAsDc,uCxD/De;ACo1V7B;;AuD30VA;EA0Dc,oC7CWO;E6CVP,gC7CUO;E6CTP,iBxD1DgB;AC+0V9B;;AuDj1VA;EAkEU,iFAAyG;AvDmxVnH;;ACnwVE;EsDlFF;IAqEc,iFAAyG;EvDqxVrH;AACF;;AuD31VA;EAeM,yBxDpBwB;EwDqBxB,W7CuDU;AVyxVhB;;AuDh2VA;;EAmBQ,cAAc;AvDk1VtB;;AuDr2VA;EAqBQ,W7CkDQ;AVkyVhB;;AuDz2VA;EAuBQ,+B7CgDQ;AVsyVhB;;AuD72VA;;EA0BU,W7C6CM;AV2yVhB;;ACpxVE;EsD9FF;IA6BU,yBxDlCoB;EC43V5B;AACF;;AuDx3VA;;EAgCQ,+B7CuCQ;AVszVhB;;AuD73VA;;;EAqCU,yB7C6DuB;E6C5DvB,W7CiCM;AV6zVhB;;AuDp4VA;EAyCU,W7C8BM;E6C7BN,YAAY;AvD+1VtB;;AuDz4VA;EA4CY,UAAU;AvDi2VtB;;AuD74VA;EA+CY,yBAAwB;EACxB,UAAU;AvDk2VtB;;AuDl5VA;EAoDY,W7CmBI;AV+0VhB;;AuDt5VA;EAsDc,uCxD/De;ACm6V7B;;AuD15VA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDjEgB;ACq6V9B;;AuDh6VA;EAkEU,gFAAyG;AvDk2VnH;;ACl1VE;EsDlFF;IAqEc,gFAAyG;EvDo2VrH;AACF;;AuD16VA;EAeM,yBxDN4B;EwDO5B,W7CuDU;AVw2VhB;;AuD/6VA;;EAmBQ,cAAc;AvDi6VtB;;AuDp7VA;EAqBQ,W7CkDQ;AVi3VhB;;AuDx7VA;EAuBQ,+B7CgDQ;AVq3VhB;;AuD57VA;;EA0BU,W7C6CM;AV03VhB;;ACn2VE;EsD9FF;IA6BU,yBxDpBwB;EC67VhC;AACF;;AuDv8VA;;EAgCQ,+B7CuCQ;AVq4VhB;;AuD58VA;;;EAqCU,yB7C6DuB;E6C5DvB,W7CiCM;AV44VhB;;AuDn9VA;EAyCU,W7C8BM;E6C7BN,YAAY;AvD86VtB;;AuDx9VA;EA4CY,UAAU;AvDg7VtB;;AuD59VA;EA+CY,yBAAwB;EACxB,UAAU;AvDi7VtB;;AuDj+VA;EAoDY,W7CmBI;AV85VhB;;AuDr+VA;EAsDc,uCxD/De;ACk/V7B;;AuDz+VA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDnDoB;ACs+VlC;;AuD/+VA;EAkEU,gFAAyG;AvDi7VnH;;ACj6VE;EsDlFF;IAqEc,gFAAyG;EvDm7VrH;AACF;;AuDz/VA;EAeM,yBxDJ4B;EwDK5B,W7CuDU;AVu7VhB;;AuD9/VA;;EAmBQ,cAAc;AvDg/VtB;;AuDngWA;EAqBQ,W7CkDQ;AVg8VhB;;AuDvgWA;EAuBQ,+B7CgDQ;AVo8VhB;;AuD3gWA;;EA0BU,W7C6CM;AVy8VhB;;ACl7VE;EsD9FF;IA6BU,yBxDlBwB;EC0gWhC;AACF;;AuDthWA;;EAgCQ,+B7CuCQ;AVo9VhB;;AuD3hWA;;;EAqCU,yB7C6DuB;E6C5DvB,W7CiCM;AV29VhB;;AuDliWA;EAyCU,W7C8BM;E6C7BN,YAAY;AvD6/VtB;;AuDviWA;EA4CY,UAAU;AvD+/VtB;;AuD3iWA;EA+CY,yBAAwB;EACxB,UAAU;AvDggWtB;;AuDhjWA;EAoDY,W7CmBI;AV6+VhB;;AuDpjWA;EAsDc,uCxD/De;ACikW7B;;AuDxjWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDjDoB;ACmjWlC;;AuD9jWA;EAkEU,gFAAyG;AvDggWnH;;ACh/VE;EsDlFF;IAqEc,gFAAyG;EvDkgWrH;AACF;;AuDxkWA;EAeM,yBxDL4B;EwDM5B,W7CuDU;AVsgWhB;;AuD7kWA;;EAmBQ,cAAc;AvD+jWtB;;AuDllWA;EAqBQ,W7CkDQ;AV+gWhB;;AuDtlWA;EAuBQ,+B7CgDQ;AVmhWhB;;AuD1lWA;;EA0BU,W7C6CM;AVwhWhB;;ACjgWE;EsD9FF;IA6BU,yBxDnBwB;EC0lWhC;AACF;;AuDrmWA;;EAgCQ,+B7CuCQ;AVmiWhB;;AuD1mWA;;;EAqCU,yB7C6DuB;E6C5DvB,W7CiCM;AV0iWhB;;AuDjnWA;EAyCU,W7C8BM;E6C7BN,YAAY;AvD4kWtB;;AuDtnWA;EA4CY,UAAU;AvD8kWtB;;AuD1nWA;EA+CY,yBAAwB;EACxB,UAAU;AvD+kWtB;;AuD/nWA;EAoDY,W7CmBI;AV4jWhB;;AuDnoWA;EAsDc,uCxD/De;ACgpW7B;;AuDvoWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDlDoB;ACmoWlC;;AuD7oWA;EAkEU,gFAAyG;AvD+kWnH;;AC/jWE;EsDlFF;IAqEc,gFAAyG;EvDilWrH;AACF;;AuDvpWA;EAeM,yBxDP4B;EwDQ5B,W7CuDU;AVqlWhB;;AuD5pWA;;EAmBQ,cAAc;AvD8oWtB;;AuDjqWA;EAqBQ,W7CkDQ;AV8lWhB;;AuDrqWA;EAuBQ,+B7CgDQ;AVkmWhB;;AuDzqWA;;EA0BU,W7C6CM;AVumWhB;;AChlWE;EsD9FF;IA6BU,yBxDrBwB;EC2qWhC;AACF;;AuDprWA;;EAgCQ,+B7CuCQ;AVknWhB;;AuDzrWA;;;EAqCU,yB7C6DuB;E6C5DvB,W7CiCM;AVynWhB;;AuDhsWA;EAyCU,W7C8BM;E6C7BN,YAAY;AvD2pWtB;;AuDrsWA;EA4CY,UAAU;AvD6pWtB;;AuDzsWA;EA+CY,yBAAwB;EACxB,UAAU;AvD8pWtB;;AuD9sWA;EAoDY,W7CmBI;AV2oWhB;;AuDltWA;EAsDc,uCxD/De;AC+tW7B;;AuDttWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDpDoB;ACotWlC;;AuD5tWA;EAkEU,gFAAyG;AvD8pWnH;;AC9oWE;EsDlFF;IAqEc,gFAAyG;EvDgqWrH;AACF;;AuDtuWA;EAeM,yBxDR4B;EwDS5B,yB7CqDe;AVsqWrB;;AuD3uWA;;EAmBQ,cAAc;AvD6tWtB;;AuDhvWA;EAqBQ,yB7CgDa;AV+qWrB;;AuDpvWA;EAuBQ,yB7C8Ca;AVmrWrB;;AuDxvWA;;EA0BU,yB7C2CW;AVwrWrB;;AC/pWE;EsD9FF;IA6BU,yBxDtBwB;EC2vWhC;AACF;;AuDnwWA;;EAgCQ,yB7CqCa;AVmsWrB;;AuDxwWA;;;EAqCU,yB7C6DuB;E6C5DvB,yB7C+BW;AV0sWrB;;AuD/wWA;EAyCU,yB7C4BW;E6C3BX,YAAY;AvD0uWtB;;AuDpxWA;EA4CY,UAAU;AvD4uWtB;;AuDxxWA;EA+CY,yBAAwB;EACxB,UAAU;AvD6uWtB;;AuD7xWA;EAoDY,yB7CiBS;AV4tWrB;;AuDjyWA;EAsDc,uCxD/De;AC8yW7B;;AuDryWA;EA0Dc,oC7CWO;E6CVP,gC7CUO;E6CTP,cxDrDoB;ACoyWlC;;AuD3yWA;EAkEU,gFAAyG;AvD6uWnH;;AC7tWE;EsDlFF;IAqEc,gFAAyG;EvD+uWrH;AACF;;AuDrzWA;EAeM,yBxDF2B;EwDG3B,W7CuDU;AVmvWhB;;AuD1zWA;;EAmBQ,cAAc;AvD4yWtB;;AuD/zWA;EAqBQ,W7CkDQ;AV4vWhB;;AuDn0WA;EAuBQ,+B7CgDQ;AVgwWhB;;AuDv0WA;;EA0BU,W7C6CM;AVqwWhB;;AC9uWE;EsD9FF;IA6BU,yBxDhBuB;ECo0W/B;AACF;;AuDl1WA;;EAgCQ,+B7CuCQ;AVgxWhB;;AuDv1WA;;;EAqCU,yB7C6DuB;E6C5DvB,W7CiCM;AVuxWhB;;AuD91WA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDyzWtB;;AuDn2WA;EA4CY,UAAU;AvD2zWtB;;AuDv2WA;EA+CY,yBAAwB;EACxB,UAAU;AvD4zWtB;;AuD52WA;EAoDY,W7CmBI;AVyyWhB;;AuDh3WA;EAsDc,uCxD/De;AC63W7B;;AuDp3WA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxD/CmB;AC62WjC;;AuD13WA;EAkEU,gFAAyG;AvD4zWnH;;AC5yWE;EsDlFF;IAqEc,gFAAyG;EvD8zWrH;AACF;;AuDp4WA;EAyEM,eAhF0B;AvD+4WhC;;AClzWE;EsDtFF;IA6EQ,oBAnF8B;EvDm5WpC;AACF;;ACxzWE;EsDtFF;IAiFQ,mBAtF4B;EvDw5WlC;AACF;;AuDp5WA;EAsFM,mBAAmB;EACnB,aAAa;AvDk0WnB;;AuDz5WA;EAyFQ,YAAY;EACZ,cAAc;AvDo0WtB;;AuD95WA;EA4FI,gBAAgB;AvDs0WpB;;AuDl6WA;EA8FI,iBAAiB;AvDw0WrB;;AuDp0WA;EAEE,gBAAgB;AvDs0WlB;;AuDx0WA;EAII,SAAS;EACT,gBAAgB;EAChB,eAAe;EACf,kBAAkB;EAClB,QAAQ;EACR,qCAAqC;AvDw0WzC;;AuDj1WA;EAYI,YAAY;AvDy0WhB;;ACr2WE;EsDgBF;IAeI,aAAa;EvD20Wf;AACF;;AuD10WA;EACE,kBAAkB;AvD60WpB;;AC/2WE;EsDiCF;IAKM,aAAa;EvD80WjB;EuDn1WF;IAOQ,sBAAsB;EvD+0W5B;AACF;;ACp3WE;EsD6BF;IASI,aAAa;IACb,uBAAuB;EvDm1WzB;EuD71WF;ItD4BI,mBsDhBwC;EvDo1W1C;AACF;;AuDj1WA;;EAEE,YAAY;EACZ,cAAc;AvDo1WhB;;AuDl1WA;EACE,YAAY;EACZ,cAAc;EACd,oBApJ6B;AvDy+W/B;;AC14WE;EsDkDF;IAKI,kBArJgC;EvD6+WlC;AACF;;AwD1+WA;EACE,oBAN2B;AxDm/W7B;;ACx4WE;EuDtGF;IAII,kBAR+B;ExDu/WjC;EwDn/WF;IAOM,oBAV8B;ExDy/WlC;EwDt/WF;IASM,mBAX4B;ExD2/WhC;AACF;;AyD3/WA;EACE,yB1DO4B;E0DN5B,yBAJ+B;AzDkgXjC","file":"bulma-rtl.css"} \ No newline at end of file diff --git a/pagetop/static/bulmix/css/bulma.min.css b/pagetop/static/bulmix/css/bulma.min.css new file mode 100644 index 00000000..be16f726 --- /dev/null +++ b/pagetop/static/bulmix/css/bulma.min.css @@ -0,0 +1 @@ +/*! bulma.io v0.9.3 | MIT License | github.com/jgthms/bulma */.button,.file-cta,.file-name,.input,.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous,.select select,.textarea{-moz-appearance:none;-webkit-appearance:none;align-items:center;border:1px solid transparent;border-radius:4px;box-shadow:none;display:inline-flex;font-size:1rem;height:2.5em;justify-content:flex-start;line-height:1.5;padding-bottom:calc(.5em - 1px);padding-left:calc(.75em - 1px);padding-right:calc(.75em - 1px);padding-top:calc(.5em - 1px);position:relative;vertical-align:top}.button:active,.button:focus,.file-cta:active,.file-cta:focus,.file-name:active,.file-name:focus,.input:active,.input:focus,.is-active.button,.is-active.file-cta,.is-active.file-name,.is-active.input,.is-active.pagination-ellipsis,.is-active.pagination-link,.is-active.pagination-next,.is-active.pagination-previous,.is-active.textarea,.is-focused.button,.is-focused.file-cta,.is-focused.file-name,.is-focused.input,.is-focused.pagination-ellipsis,.is-focused.pagination-link,.is-focused.pagination-next,.is-focused.pagination-previous,.is-focused.textarea,.pagination-ellipsis:active,.pagination-ellipsis:focus,.pagination-link:active,.pagination-link:focus,.pagination-next:active,.pagination-next:focus,.pagination-previous:active,.pagination-previous:focus,.select select.is-active,.select select.is-focused,.select select:active,.select select:focus,.textarea:active,.textarea:focus{outline:0}.button[disabled],.file-cta[disabled],.file-name[disabled],.input[disabled],.pagination-ellipsis[disabled],.pagination-link[disabled],.pagination-next[disabled],.pagination-previous[disabled],.select fieldset[disabled] select,.select select[disabled],.textarea[disabled],fieldset[disabled] .button,fieldset[disabled] .file-cta,fieldset[disabled] .file-name,fieldset[disabled] .input,fieldset[disabled] .pagination-ellipsis,fieldset[disabled] .pagination-link,fieldset[disabled] .pagination-next,fieldset[disabled] .pagination-previous,fieldset[disabled] .select select,fieldset[disabled] .textarea{cursor:not-allowed}.breadcrumb,.button,.file,.is-unselectable,.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous,.tabs{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.navbar-link:not(.is-arrowless)::after,.select:not(.is-multiple):not(.is-loading)::after{border:3px solid transparent;border-radius:2px;border-right:0;border-top:0;content:" ";display:block;height:.625em;margin-top:-.4375em;pointer-events:none;position:absolute;top:50%;transform:rotate(-45deg);transform-origin:center;width:.625em}.block:not(:last-child),.box:not(:last-child),.breadcrumb:not(:last-child),.content:not(:last-child),.level:not(:last-child),.message:not(:last-child),.notification:not(:last-child),.pagination:not(:last-child),.progress:not(:last-child),.subtitle:not(:last-child),.table-container:not(:last-child),.table:not(:last-child),.tabs:not(:last-child),.title:not(:last-child){margin-bottom:1.5rem}.delete,.modal-close{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-moz-appearance:none;-webkit-appearance:none;background-color:rgba(10,10,10,.2);border:none;border-radius:9999px;cursor:pointer;pointer-events:auto;display:inline-block;flex-grow:0;flex-shrink:0;font-size:0;height:20px;max-height:20px;max-width:20px;min-height:20px;min-width:20px;outline:0;position:relative;vertical-align:top;width:20px}.delete::after,.delete::before,.modal-close::after,.modal-close::before{background-color:#fff;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.delete::before,.modal-close::before{height:2px;width:50%}.delete::after,.modal-close::after{height:50%;width:2px}.delete:focus,.delete:hover,.modal-close:focus,.modal-close:hover{background-color:rgba(10,10,10,.3)}.delete:active,.modal-close:active{background-color:rgba(10,10,10,.4)}.is-small.delete,.is-small.modal-close{height:16px;max-height:16px;max-width:16px;min-height:16px;min-width:16px;width:16px}.is-medium.delete,.is-medium.modal-close{height:24px;max-height:24px;max-width:24px;min-height:24px;min-width:24px;width:24px}.is-large.delete,.is-large.modal-close{height:32px;max-height:32px;max-width:32px;min-height:32px;min-width:32px;width:32px}.button.is-loading::after,.control.is-loading::after,.loader,.select.is-loading::after{-webkit-animation:spinAround .5s infinite linear;animation:spinAround .5s infinite linear;border:2px solid #dbdbdb;border-radius:9999px;border-right-color:transparent;border-top-color:transparent;content:"";display:block;height:1em;position:relative;width:1em}.hero-video,.image.is-16by9 .has-ratio,.image.is-16by9 img,.image.is-1by1 .has-ratio,.image.is-1by1 img,.image.is-1by2 .has-ratio,.image.is-1by2 img,.image.is-1by3 .has-ratio,.image.is-1by3 img,.image.is-2by1 .has-ratio,.image.is-2by1 img,.image.is-2by3 .has-ratio,.image.is-2by3 img,.image.is-3by1 .has-ratio,.image.is-3by1 img,.image.is-3by2 .has-ratio,.image.is-3by2 img,.image.is-3by4 .has-ratio,.image.is-3by4 img,.image.is-3by5 .has-ratio,.image.is-3by5 img,.image.is-4by3 .has-ratio,.image.is-4by3 img,.image.is-4by5 .has-ratio,.image.is-4by5 img,.image.is-5by3 .has-ratio,.image.is-5by3 img,.image.is-5by4 .has-ratio,.image.is-5by4 img,.image.is-9by16 .has-ratio,.image.is-9by16 img,.image.is-square .has-ratio,.image.is-square img,.is-overlay,.modal,.modal-background{bottom:0;left:0;position:absolute;right:0;top:0}.navbar-burger{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:0 0;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0}/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */blockquote,body,dd,dl,dt,fieldset,figure,h1,h2,h3,h4,h5,h6,hr,html,iframe,legend,li,ol,p,pre,textarea,ul{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:400}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,::after,::before{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}td:not([align]),th:not([align]){text-align:inherit}html{background-color:#fff;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:hidden;overflow-y:scroll;text-rendering:optimizeLegibility;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%}article,aside,figure,footer,header,hgroup,section{display:block}body,button,input,optgroup,select,textarea{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif}code,pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:monospace}body{color:#4a4a4a;font-size:1em;font-weight:400;line-height:1.5}a{color:#485fc7;cursor:pointer;text-decoration:none}a strong{color:currentColor}a:hover{color:#363636}code{background-color:#f5f5f5;color:#da1039;font-size:.875em;font-weight:400;padding:.25em .5em .25em}hr{background-color:#f5f5f5;border:none;display:block;height:2px;margin:1.5rem 0}img{height:auto;max-width:100%}input[type=checkbox],input[type=radio]{vertical-align:baseline}small{font-size:.875em}span{font-style:inherit;font-weight:inherit}strong{color:#363636;font-weight:700}fieldset{border:none}pre{-webkit-overflow-scrolling:touch;background-color:#f5f5f5;color:#4a4a4a;font-size:.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}table td,table th{vertical-align:top}table td:not([align]),table th:not([align]){text-align:inherit}table th{color:#363636}@-webkit-keyframes spinAround{from{transform:rotate(0)}to{transform:rotate(359deg)}}@keyframes spinAround{from{transform:rotate(0)}to{transform:rotate(359deg)}}.box{background-color:#fff;border-radius:6px;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);color:#4a4a4a;display:block;padding:1.25rem}a.box:focus,a.box:hover{box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px #485fc7}a.box:active{box-shadow:inset 0 1px 2px rgba(10,10,10,.2),0 0 0 1px #485fc7}.button{background-color:#fff;border-color:#dbdbdb;border-width:1px;color:#363636;cursor:pointer;justify-content:center;padding-bottom:calc(.5em - 1px);padding-left:1em;padding-right:1em;padding-top:calc(.5em - 1px);text-align:center;white-space:nowrap}.button strong{color:inherit}.button .icon,.button .icon.is-large,.button .icon.is-medium,.button .icon.is-small{height:1.5em;width:1.5em}.button .icon:first-child:not(:last-child){margin-left:calc(-.5em - 1px);margin-right:.25em}.button .icon:last-child:not(:first-child){margin-left:.25em;margin-right:calc(-.5em - 1px)}.button .icon:first-child:last-child{margin-left:calc(-.5em - 1px);margin-right:calc(-.5em - 1px)}.button.is-hovered,.button:hover{border-color:#b5b5b5;color:#363636}.button.is-focused,.button:focus{border-color:#485fc7;color:#363636}.button.is-focused:not(:active),.button:focus:not(:active){box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.button.is-active,.button:active{border-color:#4a4a4a;color:#363636}.button.is-text{background-color:transparent;border-color:transparent;color:#4a4a4a;text-decoration:underline}.button.is-text.is-focused,.button.is-text.is-hovered,.button.is-text:focus,.button.is-text:hover{background-color:#f5f5f5;color:#363636}.button.is-text.is-active,.button.is-text:active{background-color:#e8e8e8;color:#363636}.button.is-text[disabled],fieldset[disabled] .button.is-text{background-color:transparent;border-color:transparent;box-shadow:none}.button.is-ghost{background:0 0;border-color:transparent;color:#485fc7;text-decoration:none}.button.is-ghost.is-hovered,.button.is-ghost:hover{color:#485fc7;text-decoration:underline}.button.is-white{background-color:#fff;border-color:transparent;color:#0a0a0a}.button.is-white.is-hovered,.button.is-white:hover{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.button.is-white.is-focused,.button.is-white:focus{border-color:transparent;color:#0a0a0a}.button.is-white.is-focused:not(:active),.button.is-white:focus:not(:active){box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.button.is-white.is-active,.button.is-white:active{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.button.is-white[disabled],fieldset[disabled] .button.is-white{background-color:#fff;border-color:transparent;box-shadow:none}.button.is-white.is-inverted{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted.is-hovered,.button.is-white.is-inverted:hover{background-color:#000}.button.is-white.is-inverted[disabled],fieldset[disabled] .button.is-white.is-inverted{background-color:#0a0a0a;border-color:transparent;box-shadow:none;color:#fff}.button.is-white.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-white.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-white.is-outlined.is-focused,.button.is-white.is-outlined.is-hovered,.button.is-white.is-outlined:focus,.button.is-white.is-outlined:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.button.is-white.is-outlined.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-white.is-outlined.is-loading.is-focused::after,.button.is-white.is-outlined.is-loading.is-hovered::after,.button.is-white.is-outlined.is-loading:focus::after,.button.is-white.is-outlined.is-loading:hover::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-white.is-outlined[disabled],fieldset[disabled] .button.is-white.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-white.is-inverted.is-outlined.is-focused,.button.is-white.is-inverted.is-outlined.is-hovered,.button.is-white.is-inverted.is-outlined:focus,.button.is-white.is-inverted.is-outlined:hover{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-white.is-inverted.is-outlined.is-loading:focus::after,.button.is-white.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-white.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black{background-color:#0a0a0a;border-color:transparent;color:#fff}.button.is-black.is-hovered,.button.is-black:hover{background-color:#040404;border-color:transparent;color:#fff}.button.is-black.is-focused,.button.is-black:focus{border-color:transparent;color:#fff}.button.is-black.is-focused:not(:active),.button.is-black:focus:not(:active){box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.button.is-black.is-active,.button.is-black:active{background-color:#000;border-color:transparent;color:#fff}.button.is-black[disabled],fieldset[disabled] .button.is-black{background-color:#0a0a0a;border-color:transparent;box-shadow:none}.button.is-black.is-inverted{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted.is-hovered,.button.is-black.is-inverted:hover{background-color:#f2f2f2}.button.is-black.is-inverted[disabled],fieldset[disabled] .button.is-black.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#0a0a0a}.button.is-black.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-black.is-outlined.is-focused,.button.is-black.is-outlined.is-hovered,.button.is-black.is-outlined:focus,.button.is-black.is-outlined:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.button.is-black.is-outlined.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-black.is-outlined.is-loading.is-focused::after,.button.is-black.is-outlined.is-loading.is-hovered::after,.button.is-black.is-outlined.is-loading:focus::after,.button.is-black.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-black.is-outlined[disabled],fieldset[disabled] .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-black.is-inverted.is-outlined.is-focused,.button.is-black.is-inverted.is-outlined.is-hovered,.button.is-black.is-inverted.is-outlined:focus,.button.is-black.is-inverted.is-outlined:hover{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-black.is-inverted.is-outlined.is-loading:focus::after,.button.is-black.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-black.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-light{background-color:#f5f5f5;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light.is-hovered,.button.is-light:hover{background-color:#eee;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light.is-focused,.button.is-light:focus{border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light.is-focused:not(:active),.button.is-light:focus:not(:active){box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.button.is-light.is-active,.button.is-light:active{background-color:#e8e8e8;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light[disabled],fieldset[disabled] .button.is-light{background-color:#f5f5f5;border-color:transparent;box-shadow:none}.button.is-light.is-inverted{background-color:rgba(0,0,0,.7);color:#f5f5f5}.button.is-light.is-inverted.is-hovered,.button.is-light.is-inverted:hover{background-color:rgba(0,0,0,.7)}.button.is-light.is-inverted[disabled],fieldset[disabled] .button.is-light.is-inverted{background-color:rgba(0,0,0,.7);border-color:transparent;box-shadow:none;color:#f5f5f5}.button.is-light.is-loading::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;color:#f5f5f5}.button.is-light.is-outlined.is-focused,.button.is-light.is-outlined.is-hovered,.button.is-light.is-outlined:focus,.button.is-light.is-outlined:hover{background-color:#f5f5f5;border-color:#f5f5f5;color:rgba(0,0,0,.7)}.button.is-light.is-outlined.is-loading::after{border-color:transparent transparent #f5f5f5 #f5f5f5!important}.button.is-light.is-outlined.is-loading.is-focused::after,.button.is-light.is-outlined.is-loading.is-hovered::after,.button.is-light.is-outlined.is-loading:focus::after,.button.is-light.is-outlined.is-loading:hover::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-light.is-outlined[disabled],fieldset[disabled] .button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;box-shadow:none;color:#f5f5f5}.button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);color:rgba(0,0,0,.7)}.button.is-light.is-inverted.is-outlined.is-focused,.button.is-light.is-inverted.is-outlined.is-hovered,.button.is-light.is-inverted.is-outlined:focus,.button.is-light.is-inverted.is-outlined:hover{background-color:rgba(0,0,0,.7);color:#f5f5f5}.button.is-light.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-light.is-inverted.is-outlined.is-loading:focus::after,.button.is-light.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #f5f5f5 #f5f5f5!important}.button.is-light.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);box-shadow:none;color:rgba(0,0,0,.7)}.button.is-dark{background-color:#363636;border-color:transparent;color:#fff}.button.is-dark.is-hovered,.button.is-dark:hover{background-color:#2f2f2f;border-color:transparent;color:#fff}.button.is-dark.is-focused,.button.is-dark:focus{border-color:transparent;color:#fff}.button.is-dark.is-focused:not(:active),.button.is-dark:focus:not(:active){box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.button.is-dark.is-active,.button.is-dark:active{background-color:#292929;border-color:transparent;color:#fff}.button.is-dark[disabled],fieldset[disabled] .button.is-dark{background-color:#363636;border-color:transparent;box-shadow:none}.button.is-dark.is-inverted{background-color:#fff;color:#363636}.button.is-dark.is-inverted.is-hovered,.button.is-dark.is-inverted:hover{background-color:#f2f2f2}.button.is-dark.is-inverted[disabled],fieldset[disabled] .button.is-dark.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#363636}.button.is-dark.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-dark.is-outlined{background-color:transparent;border-color:#363636;color:#363636}.button.is-dark.is-outlined.is-focused,.button.is-dark.is-outlined.is-hovered,.button.is-dark.is-outlined:focus,.button.is-dark.is-outlined:hover{background-color:#363636;border-color:#363636;color:#fff}.button.is-dark.is-outlined.is-loading::after{border-color:transparent transparent #363636 #363636!important}.button.is-dark.is-outlined.is-loading.is-focused::after,.button.is-dark.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-outlined.is-loading:focus::after,.button.is-dark.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-dark.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-outlined{background-color:transparent;border-color:#363636;box-shadow:none;color:#363636}.button.is-dark.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-dark.is-inverted.is-outlined.is-focused,.button.is-dark.is-inverted.is-outlined.is-hovered,.button.is-dark.is-inverted.is-outlined:focus,.button.is-dark.is-inverted.is-outlined:hover{background-color:#fff;color:#363636}.button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-inverted.is-outlined.is-loading:focus::after,.button.is-dark.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #363636 #363636!important}.button.is-dark.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-primary{background-color:#00d1b2;border-color:transparent;color:#fff}.button.is-primary.is-hovered,.button.is-primary:hover{background-color:#00c4a7;border-color:transparent;color:#fff}.button.is-primary.is-focused,.button.is-primary:focus{border-color:transparent;color:#fff}.button.is-primary.is-focused:not(:active),.button.is-primary:focus:not(:active){box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.button.is-primary.is-active,.button.is-primary:active{background-color:#00b89c;border-color:transparent;color:#fff}.button.is-primary[disabled],fieldset[disabled] .button.is-primary{background-color:#00d1b2;border-color:transparent;box-shadow:none}.button.is-primary.is-inverted{background-color:#fff;color:#00d1b2}.button.is-primary.is-inverted.is-hovered,.button.is-primary.is-inverted:hover{background-color:#f2f2f2}.button.is-primary.is-inverted[disabled],fieldset[disabled] .button.is-primary.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#00d1b2}.button.is-primary.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-primary.is-outlined{background-color:transparent;border-color:#00d1b2;color:#00d1b2}.button.is-primary.is-outlined.is-focused,.button.is-primary.is-outlined.is-hovered,.button.is-primary.is-outlined:focus,.button.is-primary.is-outlined:hover{background-color:#00d1b2;border-color:#00d1b2;color:#fff}.button.is-primary.is-outlined.is-loading::after{border-color:transparent transparent #00d1b2 #00d1b2!important}.button.is-primary.is-outlined.is-loading.is-focused::after,.button.is-primary.is-outlined.is-loading.is-hovered::after,.button.is-primary.is-outlined.is-loading:focus::after,.button.is-primary.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-primary.is-outlined[disabled],fieldset[disabled] .button.is-primary.is-outlined{background-color:transparent;border-color:#00d1b2;box-shadow:none;color:#00d1b2}.button.is-primary.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-primary.is-inverted.is-outlined.is-focused,.button.is-primary.is-inverted.is-outlined.is-hovered,.button.is-primary.is-inverted.is-outlined:focus,.button.is-primary.is-inverted.is-outlined:hover{background-color:#fff;color:#00d1b2}.button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-primary.is-inverted.is-outlined.is-loading:focus::after,.button.is-primary.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #00d1b2 #00d1b2!important}.button.is-primary.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-primary.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-primary.is-light{background-color:#ebfffc;color:#00947e}.button.is-primary.is-light.is-hovered,.button.is-primary.is-light:hover{background-color:#defffa;border-color:transparent;color:#00947e}.button.is-primary.is-light.is-active,.button.is-primary.is-light:active{background-color:#d1fff8;border-color:transparent;color:#00947e}.button.is-link{background-color:#485fc7;border-color:transparent;color:#fff}.button.is-link.is-hovered,.button.is-link:hover{background-color:#3e56c4;border-color:transparent;color:#fff}.button.is-link.is-focused,.button.is-link:focus{border-color:transparent;color:#fff}.button.is-link.is-focused:not(:active),.button.is-link:focus:not(:active){box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.button.is-link.is-active,.button.is-link:active{background-color:#3a51bb;border-color:transparent;color:#fff}.button.is-link[disabled],fieldset[disabled] .button.is-link{background-color:#485fc7;border-color:transparent;box-shadow:none}.button.is-link.is-inverted{background-color:#fff;color:#485fc7}.button.is-link.is-inverted.is-hovered,.button.is-link.is-inverted:hover{background-color:#f2f2f2}.button.is-link.is-inverted[disabled],fieldset[disabled] .button.is-link.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#485fc7}.button.is-link.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-link.is-outlined{background-color:transparent;border-color:#485fc7;color:#485fc7}.button.is-link.is-outlined.is-focused,.button.is-link.is-outlined.is-hovered,.button.is-link.is-outlined:focus,.button.is-link.is-outlined:hover{background-color:#485fc7;border-color:#485fc7;color:#fff}.button.is-link.is-outlined.is-loading::after{border-color:transparent transparent #485fc7 #485fc7!important}.button.is-link.is-outlined.is-loading.is-focused::after,.button.is-link.is-outlined.is-loading.is-hovered::after,.button.is-link.is-outlined.is-loading:focus::after,.button.is-link.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-link.is-outlined[disabled],fieldset[disabled] .button.is-link.is-outlined{background-color:transparent;border-color:#485fc7;box-shadow:none;color:#485fc7}.button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-link.is-inverted.is-outlined.is-focused,.button.is-link.is-inverted.is-outlined.is-hovered,.button.is-link.is-inverted.is-outlined:focus,.button.is-link.is-inverted.is-outlined:hover{background-color:#fff;color:#485fc7}.button.is-link.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-link.is-inverted.is-outlined.is-loading:focus::after,.button.is-link.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #485fc7 #485fc7!important}.button.is-link.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-link.is-light{background-color:#eff1fa;color:#3850b7}.button.is-link.is-light.is-hovered,.button.is-link.is-light:hover{background-color:#e6e9f7;border-color:transparent;color:#3850b7}.button.is-link.is-light.is-active,.button.is-link.is-light:active{background-color:#dce0f4;border-color:transparent;color:#3850b7}.button.is-info{background-color:#3e8ed0;border-color:transparent;color:#fff}.button.is-info.is-hovered,.button.is-info:hover{background-color:#3488ce;border-color:transparent;color:#fff}.button.is-info.is-focused,.button.is-info:focus{border-color:transparent;color:#fff}.button.is-info.is-focused:not(:active),.button.is-info:focus:not(:active){box-shadow:0 0 0 .125em rgba(62,142,208,.25)}.button.is-info.is-active,.button.is-info:active{background-color:#3082c5;border-color:transparent;color:#fff}.button.is-info[disabled],fieldset[disabled] .button.is-info{background-color:#3e8ed0;border-color:transparent;box-shadow:none}.button.is-info.is-inverted{background-color:#fff;color:#3e8ed0}.button.is-info.is-inverted.is-hovered,.button.is-info.is-inverted:hover{background-color:#f2f2f2}.button.is-info.is-inverted[disabled],fieldset[disabled] .button.is-info.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#3e8ed0}.button.is-info.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-info.is-outlined{background-color:transparent;border-color:#3e8ed0;color:#3e8ed0}.button.is-info.is-outlined.is-focused,.button.is-info.is-outlined.is-hovered,.button.is-info.is-outlined:focus,.button.is-info.is-outlined:hover{background-color:#3e8ed0;border-color:#3e8ed0;color:#fff}.button.is-info.is-outlined.is-loading::after{border-color:transparent transparent #3e8ed0 #3e8ed0!important}.button.is-info.is-outlined.is-loading.is-focused::after,.button.is-info.is-outlined.is-loading.is-hovered::after,.button.is-info.is-outlined.is-loading:focus::after,.button.is-info.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-info.is-outlined[disabled],fieldset[disabled] .button.is-info.is-outlined{background-color:transparent;border-color:#3e8ed0;box-shadow:none;color:#3e8ed0}.button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-info.is-inverted.is-outlined.is-focused,.button.is-info.is-inverted.is-outlined.is-hovered,.button.is-info.is-inverted.is-outlined:focus,.button.is-info.is-inverted.is-outlined:hover{background-color:#fff;color:#3e8ed0}.button.is-info.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-info.is-inverted.is-outlined.is-loading:focus::after,.button.is-info.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #3e8ed0 #3e8ed0!important}.button.is-info.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-info.is-light{background-color:#eff5fb;color:#296fa8}.button.is-info.is-light.is-hovered,.button.is-info.is-light:hover{background-color:#e4eff9;border-color:transparent;color:#296fa8}.button.is-info.is-light.is-active,.button.is-info.is-light:active{background-color:#dae9f6;border-color:transparent;color:#296fa8}.button.is-success{background-color:#48c78e;border-color:transparent;color:#fff}.button.is-success.is-hovered,.button.is-success:hover{background-color:#3ec487;border-color:transparent;color:#fff}.button.is-success.is-focused,.button.is-success:focus{border-color:transparent;color:#fff}.button.is-success.is-focused:not(:active),.button.is-success:focus:not(:active){box-shadow:0 0 0 .125em rgba(72,199,142,.25)}.button.is-success.is-active,.button.is-success:active{background-color:#3abb81;border-color:transparent;color:#fff}.button.is-success[disabled],fieldset[disabled] .button.is-success{background-color:#48c78e;border-color:transparent;box-shadow:none}.button.is-success.is-inverted{background-color:#fff;color:#48c78e}.button.is-success.is-inverted.is-hovered,.button.is-success.is-inverted:hover{background-color:#f2f2f2}.button.is-success.is-inverted[disabled],fieldset[disabled] .button.is-success.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#48c78e}.button.is-success.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-success.is-outlined{background-color:transparent;border-color:#48c78e;color:#48c78e}.button.is-success.is-outlined.is-focused,.button.is-success.is-outlined.is-hovered,.button.is-success.is-outlined:focus,.button.is-success.is-outlined:hover{background-color:#48c78e;border-color:#48c78e;color:#fff}.button.is-success.is-outlined.is-loading::after{border-color:transparent transparent #48c78e #48c78e!important}.button.is-success.is-outlined.is-loading.is-focused::after,.button.is-success.is-outlined.is-loading.is-hovered::after,.button.is-success.is-outlined.is-loading:focus::after,.button.is-success.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-success.is-outlined[disabled],fieldset[disabled] .button.is-success.is-outlined{background-color:transparent;border-color:#48c78e;box-shadow:none;color:#48c78e}.button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-success.is-inverted.is-outlined.is-focused,.button.is-success.is-inverted.is-outlined.is-hovered,.button.is-success.is-inverted.is-outlined:focus,.button.is-success.is-inverted.is-outlined:hover{background-color:#fff;color:#48c78e}.button.is-success.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-success.is-inverted.is-outlined.is-loading:focus::after,.button.is-success.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #48c78e #48c78e!important}.button.is-success.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-success.is-light{background-color:#effaf5;color:#257953}.button.is-success.is-light.is-hovered,.button.is-success.is-light:hover{background-color:#e6f7ef;border-color:transparent;color:#257953}.button.is-success.is-light.is-active,.button.is-success.is-light:active{background-color:#dcf4e9;border-color:transparent;color:#257953}.button.is-warning{background-color:#ffe08a;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-hovered,.button.is-warning:hover{background-color:#ffdc7d;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-focused,.button.is-warning:focus{border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-focused:not(:active),.button.is-warning:focus:not(:active){box-shadow:0 0 0 .125em rgba(255,224,138,.25)}.button.is-warning.is-active,.button.is-warning:active{background-color:#ffd970;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning[disabled],fieldset[disabled] .button.is-warning{background-color:#ffe08a;border-color:transparent;box-shadow:none}.button.is-warning.is-inverted{background-color:rgba(0,0,0,.7);color:#ffe08a}.button.is-warning.is-inverted.is-hovered,.button.is-warning.is-inverted:hover{background-color:rgba(0,0,0,.7)}.button.is-warning.is-inverted[disabled],fieldset[disabled] .button.is-warning.is-inverted{background-color:rgba(0,0,0,.7);border-color:transparent;box-shadow:none;color:#ffe08a}.button.is-warning.is-loading::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-warning.is-outlined{background-color:transparent;border-color:#ffe08a;color:#ffe08a}.button.is-warning.is-outlined.is-focused,.button.is-warning.is-outlined.is-hovered,.button.is-warning.is-outlined:focus,.button.is-warning.is-outlined:hover{background-color:#ffe08a;border-color:#ffe08a;color:rgba(0,0,0,.7)}.button.is-warning.is-outlined.is-loading::after{border-color:transparent transparent #ffe08a #ffe08a!important}.button.is-warning.is-outlined.is-loading.is-focused::after,.button.is-warning.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-outlined.is-loading:focus::after,.button.is-warning.is-outlined.is-loading:hover::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-warning.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-outlined{background-color:transparent;border-color:#ffe08a;box-shadow:none;color:#ffe08a}.button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);color:rgba(0,0,0,.7)}.button.is-warning.is-inverted.is-outlined.is-focused,.button.is-warning.is-inverted.is-outlined.is-hovered,.button.is-warning.is-inverted.is-outlined:focus,.button.is-warning.is-inverted.is-outlined:hover{background-color:rgba(0,0,0,.7);color:#ffe08a}.button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-inverted.is-outlined.is-loading:focus::after,.button.is-warning.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #ffe08a #ffe08a!important}.button.is-warning.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);box-shadow:none;color:rgba(0,0,0,.7)}.button.is-warning.is-light{background-color:#fffaeb;color:#946c00}.button.is-warning.is-light.is-hovered,.button.is-warning.is-light:hover{background-color:#fff6de;border-color:transparent;color:#946c00}.button.is-warning.is-light.is-active,.button.is-warning.is-light:active{background-color:#fff3d1;border-color:transparent;color:#946c00}.button.is-danger{background-color:#f14668;border-color:transparent;color:#fff}.button.is-danger.is-hovered,.button.is-danger:hover{background-color:#f03a5f;border-color:transparent;color:#fff}.button.is-danger.is-focused,.button.is-danger:focus{border-color:transparent;color:#fff}.button.is-danger.is-focused:not(:active),.button.is-danger:focus:not(:active){box-shadow:0 0 0 .125em rgba(241,70,104,.25)}.button.is-danger.is-active,.button.is-danger:active{background-color:#ef2e55;border-color:transparent;color:#fff}.button.is-danger[disabled],fieldset[disabled] .button.is-danger{background-color:#f14668;border-color:transparent;box-shadow:none}.button.is-danger.is-inverted{background-color:#fff;color:#f14668}.button.is-danger.is-inverted.is-hovered,.button.is-danger.is-inverted:hover{background-color:#f2f2f2}.button.is-danger.is-inverted[disabled],fieldset[disabled] .button.is-danger.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#f14668}.button.is-danger.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-danger.is-outlined{background-color:transparent;border-color:#f14668;color:#f14668}.button.is-danger.is-outlined.is-focused,.button.is-danger.is-outlined.is-hovered,.button.is-danger.is-outlined:focus,.button.is-danger.is-outlined:hover{background-color:#f14668;border-color:#f14668;color:#fff}.button.is-danger.is-outlined.is-loading::after{border-color:transparent transparent #f14668 #f14668!important}.button.is-danger.is-outlined.is-loading.is-focused::after,.button.is-danger.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-outlined.is-loading:focus::after,.button.is-danger.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-danger.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-outlined{background-color:transparent;border-color:#f14668;box-shadow:none;color:#f14668}.button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-danger.is-inverted.is-outlined.is-focused,.button.is-danger.is-inverted.is-outlined.is-hovered,.button.is-danger.is-inverted.is-outlined:focus,.button.is-danger.is-inverted.is-outlined:hover{background-color:#fff;color:#f14668}.button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-inverted.is-outlined.is-loading:focus::after,.button.is-danger.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #f14668 #f14668!important}.button.is-danger.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-danger.is-light{background-color:#feecf0;color:#cc0f35}.button.is-danger.is-light.is-hovered,.button.is-danger.is-light:hover{background-color:#fde0e6;border-color:transparent;color:#cc0f35}.button.is-danger.is-light.is-active,.button.is-danger.is-light:active{background-color:#fcd4dc;border-color:transparent;color:#cc0f35}.button.is-small{font-size:.75rem}.button.is-small:not(.is-rounded){border-radius:2px}.button.is-normal{font-size:1rem}.button.is-medium{font-size:1.25rem}.button.is-large{font-size:1.5rem}.button[disabled],fieldset[disabled] .button{background-color:#fff;border-color:#dbdbdb;box-shadow:none;opacity:.5}.button.is-fullwidth{display:flex;width:100%}.button.is-loading{color:transparent!important;pointer-events:none}.button.is-loading::after{position:absolute;left:calc(50% - (1em * .5));top:calc(50% - (1em * .5));position:absolute!important}.button.is-static{background-color:#f5f5f5;border-color:#dbdbdb;color:#7a7a7a;box-shadow:none;pointer-events:none}.button.is-rounded{border-radius:9999px;padding-left:calc(1em + .25em);padding-right:calc(1em + .25em)}.buttons{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.buttons .button{margin-bottom:.5rem}.buttons .button:not(:last-child):not(.is-fullwidth){margin-right:.5rem}.buttons:last-child{margin-bottom:-.5rem}.buttons:not(:last-child){margin-bottom:1rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large){font-size:.75rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded){border-radius:2px}.buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large){font-size:1.25rem}.buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium){font-size:1.5rem}.buttons.has-addons .button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.buttons.has-addons .button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}.buttons.has-addons .button:last-child{margin-right:0}.buttons.has-addons .button.is-hovered,.buttons.has-addons .button:hover{z-index:2}.buttons.has-addons .button.is-active,.buttons.has-addons .button.is-focused,.buttons.has-addons .button.is-selected,.buttons.has-addons .button:active,.buttons.has-addons .button:focus{z-index:3}.buttons.has-addons .button.is-active:hover,.buttons.has-addons .button.is-focused:hover,.buttons.has-addons .button.is-selected:hover,.buttons.has-addons .button:active:hover,.buttons.has-addons .button:focus:hover{z-index:4}.buttons.has-addons .button.is-expanded{flex-grow:1;flex-shrink:1}.buttons.is-centered{justify-content:center}.buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth){margin-left:.25rem;margin-right:.25rem}.buttons.is-right{justify-content:flex-end}.buttons.is-right:not(.has-addons) .button:not(.is-fullwidth){margin-left:.25rem;margin-right:.25rem}.container{flex-grow:1;margin:0 auto;position:relative;width:auto}.container.is-fluid{max-width:none!important;padding-left:32px;padding-right:32px;width:100%}@media screen and (min-width:1024px){.container{max-width:960px}}@media screen and (max-width:1215px){.container.is-widescreen:not(.is-max-desktop){max-width:1152px}}@media screen and (max-width:1407px){.container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}@media screen and (min-width:1216px){.container:not(.is-max-desktop){max-width:1152px}}@media screen and (min-width:1408px){.container:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}.content li+li{margin-top:.25em}.content blockquote:not(:last-child),.content dl:not(:last-child),.content ol:not(:last-child),.content p:not(:last-child),.content pre:not(:last-child),.content table:not(:last-child),.content ul:not(:last-child){margin-bottom:1em}.content h1,.content h2,.content h3,.content h4,.content h5,.content h6{color:#363636;font-weight:600;line-height:1.125}.content h1{font-size:2em;margin-bottom:.5em}.content h1:not(:first-child){margin-top:1em}.content h2{font-size:1.75em;margin-bottom:.5714em}.content h2:not(:first-child){margin-top:1.1428em}.content h3{font-size:1.5em;margin-bottom:.6666em}.content h3:not(:first-child){margin-top:1.3333em}.content h4{font-size:1.25em;margin-bottom:.8em}.content h5{font-size:1.125em;margin-bottom:.8888em}.content h6{font-size:1em;margin-bottom:1em}.content blockquote{background-color:#f5f5f5;border-left:5px solid #dbdbdb;padding:1.25em 1.5em}.content ol{list-style-position:outside;margin-left:2em;margin-top:1em}.content ol:not([type]){list-style-type:decimal}.content ol:not([type]).is-lower-alpha{list-style-type:lower-alpha}.content ol:not([type]).is-lower-roman{list-style-type:lower-roman}.content ol:not([type]).is-upper-alpha{list-style-type:upper-alpha}.content ol:not([type]).is-upper-roman{list-style-type:upper-roman}.content ul{list-style:disc outside;margin-left:2em;margin-top:1em}.content ul ul{list-style-type:circle;margin-top:.5em}.content ul ul ul{list-style-type:square}.content dd{margin-left:2em}.content figure{margin-left:2em;margin-right:2em;text-align:center}.content figure:not(:first-child){margin-top:2em}.content figure:not(:last-child){margin-bottom:2em}.content figure img{display:inline-block}.content figure figcaption{font-style:italic}.content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:1.25em 1.5em;white-space:pre;word-wrap:normal}.content sub,.content sup{font-size:75%}.content table{width:100%}.content table td,.content table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:.5em .75em;vertical-align:top}.content table th{color:#363636}.content table th:not([align]){text-align:inherit}.content table thead td,.content table thead th{border-width:0 0 2px;color:#363636}.content table tfoot td,.content table tfoot th{border-width:2px 0 0;color:#363636}.content table tbody tr:last-child td,.content table tbody tr:last-child th{border-bottom-width:0}.content .tabs li+li{margin-top:0}.content.is-small{font-size:.75rem}.content.is-normal{font-size:1rem}.content.is-medium{font-size:1.25rem}.content.is-large{font-size:1.5rem}.icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}.icon.is-small{height:1rem;width:1rem}.icon.is-medium{height:2rem;width:2rem}.icon.is-large{height:3rem;width:3rem}.icon-text{align-items:flex-start;color:inherit;display:inline-flex;flex-wrap:wrap;line-height:1.5rem;vertical-align:top}.icon-text .icon{flex-grow:0;flex-shrink:0}.icon-text .icon:not(:last-child){margin-right:.25em}.icon-text .icon:not(:first-child){margin-left:.25em}div.icon-text{display:flex}.image{display:block;position:relative}.image img{display:block;height:auto;width:100%}.image img.is-rounded{border-radius:9999px}.image.is-fullwidth{width:100%}.image.is-16by9 .has-ratio,.image.is-16by9 img,.image.is-1by1 .has-ratio,.image.is-1by1 img,.image.is-1by2 .has-ratio,.image.is-1by2 img,.image.is-1by3 .has-ratio,.image.is-1by3 img,.image.is-2by1 .has-ratio,.image.is-2by1 img,.image.is-2by3 .has-ratio,.image.is-2by3 img,.image.is-3by1 .has-ratio,.image.is-3by1 img,.image.is-3by2 .has-ratio,.image.is-3by2 img,.image.is-3by4 .has-ratio,.image.is-3by4 img,.image.is-3by5 .has-ratio,.image.is-3by5 img,.image.is-4by3 .has-ratio,.image.is-4by3 img,.image.is-4by5 .has-ratio,.image.is-4by5 img,.image.is-5by3 .has-ratio,.image.is-5by3 img,.image.is-5by4 .has-ratio,.image.is-5by4 img,.image.is-9by16 .has-ratio,.image.is-9by16 img,.image.is-square .has-ratio,.image.is-square img{height:100%;width:100%}.image.is-1by1,.image.is-square{padding-top:100%}.image.is-5by4{padding-top:80%}.image.is-4by3{padding-top:75%}.image.is-3by2{padding-top:66.6666%}.image.is-5by3{padding-top:60%}.image.is-16by9{padding-top:56.25%}.image.is-2by1{padding-top:50%}.image.is-3by1{padding-top:33.3333%}.image.is-4by5{padding-top:125%}.image.is-3by4{padding-top:133.3333%}.image.is-2by3{padding-top:150%}.image.is-3by5{padding-top:166.6666%}.image.is-9by16{padding-top:177.7777%}.image.is-1by2{padding-top:200%}.image.is-1by3{padding-top:300%}.image.is-16x16{height:16px;width:16px}.image.is-24x24{height:24px;width:24px}.image.is-32x32{height:32px;width:32px}.image.is-48x48{height:48px;width:48px}.image.is-64x64{height:64px;width:64px}.image.is-96x96{height:96px;width:96px}.image.is-128x128{height:128px;width:128px}.notification{background-color:#f5f5f5;border-radius:4px;position:relative;padding:1.25rem 2.5rem 1.25rem 1.5rem}.notification a:not(.button):not(.dropdown-item){color:currentColor;text-decoration:underline}.notification strong{color:currentColor}.notification code,.notification pre{background:#fff}.notification pre code{background:0 0}.notification>.delete{right:.5rem;position:absolute;top:.5rem}.notification .content,.notification .subtitle,.notification .title{color:currentColor}.notification.is-white{background-color:#fff;color:#0a0a0a}.notification.is-black{background-color:#0a0a0a;color:#fff}.notification.is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.notification.is-dark{background-color:#363636;color:#fff}.notification.is-primary{background-color:#00d1b2;color:#fff}.notification.is-primary.is-light{background-color:#ebfffc;color:#00947e}.notification.is-link{background-color:#485fc7;color:#fff}.notification.is-link.is-light{background-color:#eff1fa;color:#3850b7}.notification.is-info{background-color:#3e8ed0;color:#fff}.notification.is-info.is-light{background-color:#eff5fb;color:#296fa8}.notification.is-success{background-color:#48c78e;color:#fff}.notification.is-success.is-light{background-color:#effaf5;color:#257953}.notification.is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.notification.is-warning.is-light{background-color:#fffaeb;color:#946c00}.notification.is-danger{background-color:#f14668;color:#fff}.notification.is-danger.is-light{background-color:#feecf0;color:#cc0f35}.progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:9999px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}.progress::-webkit-progress-bar{background-color:#ededed}.progress::-webkit-progress-value{background-color:#4a4a4a}.progress::-moz-progress-bar{background-color:#4a4a4a}.progress::-ms-fill{background-color:#4a4a4a;border:none}.progress.is-white::-webkit-progress-value{background-color:#fff}.progress.is-white::-moz-progress-bar{background-color:#fff}.progress.is-white::-ms-fill{background-color:#fff}.progress.is-white:indeterminate{background-image:linear-gradient(to right,#fff 30%,#ededed 30%)}.progress.is-black::-webkit-progress-value{background-color:#0a0a0a}.progress.is-black::-moz-progress-bar{background-color:#0a0a0a}.progress.is-black::-ms-fill{background-color:#0a0a0a}.progress.is-black:indeterminate{background-image:linear-gradient(to right,#0a0a0a 30%,#ededed 30%)}.progress.is-light::-webkit-progress-value{background-color:#f5f5f5}.progress.is-light::-moz-progress-bar{background-color:#f5f5f5}.progress.is-light::-ms-fill{background-color:#f5f5f5}.progress.is-light:indeterminate{background-image:linear-gradient(to right,#f5f5f5 30%,#ededed 30%)}.progress.is-dark::-webkit-progress-value{background-color:#363636}.progress.is-dark::-moz-progress-bar{background-color:#363636}.progress.is-dark::-ms-fill{background-color:#363636}.progress.is-dark:indeterminate{background-image:linear-gradient(to right,#363636 30%,#ededed 30%)}.progress.is-primary::-webkit-progress-value{background-color:#00d1b2}.progress.is-primary::-moz-progress-bar{background-color:#00d1b2}.progress.is-primary::-ms-fill{background-color:#00d1b2}.progress.is-primary:indeterminate{background-image:linear-gradient(to right,#00d1b2 30%,#ededed 30%)}.progress.is-link::-webkit-progress-value{background-color:#485fc7}.progress.is-link::-moz-progress-bar{background-color:#485fc7}.progress.is-link::-ms-fill{background-color:#485fc7}.progress.is-link:indeterminate{background-image:linear-gradient(to right,#485fc7 30%,#ededed 30%)}.progress.is-info::-webkit-progress-value{background-color:#3e8ed0}.progress.is-info::-moz-progress-bar{background-color:#3e8ed0}.progress.is-info::-ms-fill{background-color:#3e8ed0}.progress.is-info:indeterminate{background-image:linear-gradient(to right,#3e8ed0 30%,#ededed 30%)}.progress.is-success::-webkit-progress-value{background-color:#48c78e}.progress.is-success::-moz-progress-bar{background-color:#48c78e}.progress.is-success::-ms-fill{background-color:#48c78e}.progress.is-success:indeterminate{background-image:linear-gradient(to right,#48c78e 30%,#ededed 30%)}.progress.is-warning::-webkit-progress-value{background-color:#ffe08a}.progress.is-warning::-moz-progress-bar{background-color:#ffe08a}.progress.is-warning::-ms-fill{background-color:#ffe08a}.progress.is-warning:indeterminate{background-image:linear-gradient(to right,#ffe08a 30%,#ededed 30%)}.progress.is-danger::-webkit-progress-value{background-color:#f14668}.progress.is-danger::-moz-progress-bar{background-color:#f14668}.progress.is-danger::-ms-fill{background-color:#f14668}.progress.is-danger:indeterminate{background-image:linear-gradient(to right,#f14668 30%,#ededed 30%)}.progress:indeterminate{-webkit-animation-duration:1.5s;animation-duration:1.5s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:moveIndeterminate;animation-name:moveIndeterminate;-webkit-animation-timing-function:linear;animation-timing-function:linear;background-color:#ededed;background-image:linear-gradient(to right,#4a4a4a 30%,#ededed 30%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}.progress:indeterminate::-webkit-progress-bar{background-color:transparent}.progress:indeterminate::-moz-progress-bar{background-color:transparent}.progress:indeterminate::-ms-fill{animation-name:none}.progress.is-small{height:.75rem}.progress.is-medium{height:1.25rem}.progress.is-large{height:1.5rem}@-webkit-keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}@keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}.table{background-color:#fff;color:#363636}.table td,.table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:.5em .75em;vertical-align:top}.table td.is-white,.table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}.table td.is-black,.table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.table td.is-light,.table th.is-light{background-color:#f5f5f5;border-color:#f5f5f5;color:rgba(0,0,0,.7)}.table td.is-dark,.table th.is-dark{background-color:#363636;border-color:#363636;color:#fff}.table td.is-primary,.table th.is-primary{background-color:#00d1b2;border-color:#00d1b2;color:#fff}.table td.is-link,.table th.is-link{background-color:#485fc7;border-color:#485fc7;color:#fff}.table td.is-info,.table th.is-info{background-color:#3e8ed0;border-color:#3e8ed0;color:#fff}.table td.is-success,.table th.is-success{background-color:#48c78e;border-color:#48c78e;color:#fff}.table td.is-warning,.table th.is-warning{background-color:#ffe08a;border-color:#ffe08a;color:rgba(0,0,0,.7)}.table td.is-danger,.table th.is-danger{background-color:#f14668;border-color:#f14668;color:#fff}.table td.is-narrow,.table th.is-narrow{white-space:nowrap;width:1%}.table td.is-selected,.table th.is-selected{background-color:#00d1b2;color:#fff}.table td.is-selected a,.table td.is-selected strong,.table th.is-selected a,.table th.is-selected strong{color:currentColor}.table td.is-vcentered,.table th.is-vcentered{vertical-align:middle}.table th{color:#363636}.table th:not([align]){text-align:inherit}.table tr.is-selected{background-color:#00d1b2;color:#fff}.table tr.is-selected a,.table tr.is-selected strong{color:currentColor}.table tr.is-selected td,.table tr.is-selected th{border-color:#fff;color:currentColor}.table thead{background-color:transparent}.table thead td,.table thead th{border-width:0 0 2px;color:#363636}.table tfoot{background-color:transparent}.table tfoot td,.table tfoot th{border-width:2px 0 0;color:#363636}.table tbody{background-color:transparent}.table tbody tr:last-child td,.table tbody tr:last-child th{border-bottom-width:0}.table.is-bordered td,.table.is-bordered th{border-width:1px}.table.is-bordered tr:last-child td,.table.is-bordered tr:last-child th{border-bottom-width:1px}.table.is-fullwidth{width:100%}.table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even){background-color:#f5f5f5}.table.is-narrow td,.table.is-narrow th{padding:.25em .5em}.table.is-striped tbody tr:not(.is-selected):nth-child(even){background-color:#fafafa}.table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}.tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.tags .tag{margin-bottom:.5rem}.tags .tag:not(:last-child){margin-right:.5rem}.tags:last-child{margin-bottom:-.5rem}.tags:not(:last-child){margin-bottom:1rem}.tags.are-medium .tag:not(.is-normal):not(.is-large){font-size:1rem}.tags.are-large .tag:not(.is-normal):not(.is-medium){font-size:1.25rem}.tags.is-centered{justify-content:center}.tags.is-centered .tag{margin-right:.25rem;margin-left:.25rem}.tags.is-right{justify-content:flex-end}.tags.is-right .tag:not(:first-child){margin-left:.5rem}.tags.is-right .tag:not(:last-child){margin-right:0}.tags.has-addons .tag{margin-right:0}.tags.has-addons .tag:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}.tags.has-addons .tag:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.tag:not(body){align-items:center;background-color:#f5f5f5;border-radius:4px;color:#4a4a4a;display:inline-flex;font-size:.75rem;height:2em;justify-content:center;line-height:1.5;padding-left:.75em;padding-right:.75em;white-space:nowrap}.tag:not(body) .delete{margin-left:.25rem;margin-right:-.375rem}.tag:not(body).is-white{background-color:#fff;color:#0a0a0a}.tag:not(body).is-black{background-color:#0a0a0a;color:#fff}.tag:not(body).is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.tag:not(body).is-dark{background-color:#363636;color:#fff}.tag:not(body).is-primary{background-color:#00d1b2;color:#fff}.tag:not(body).is-primary.is-light{background-color:#ebfffc;color:#00947e}.tag:not(body).is-link{background-color:#485fc7;color:#fff}.tag:not(body).is-link.is-light{background-color:#eff1fa;color:#3850b7}.tag:not(body).is-info{background-color:#3e8ed0;color:#fff}.tag:not(body).is-info.is-light{background-color:#eff5fb;color:#296fa8}.tag:not(body).is-success{background-color:#48c78e;color:#fff}.tag:not(body).is-success.is-light{background-color:#effaf5;color:#257953}.tag:not(body).is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.tag:not(body).is-warning.is-light{background-color:#fffaeb;color:#946c00}.tag:not(body).is-danger{background-color:#f14668;color:#fff}.tag:not(body).is-danger.is-light{background-color:#feecf0;color:#cc0f35}.tag:not(body).is-normal{font-size:.75rem}.tag:not(body).is-medium{font-size:1rem}.tag:not(body).is-large{font-size:1.25rem}.tag:not(body) .icon:first-child:not(:last-child){margin-left:-.375em;margin-right:.1875em}.tag:not(body) .icon:last-child:not(:first-child){margin-left:.1875em;margin-right:-.375em}.tag:not(body) .icon:first-child:last-child{margin-left:-.375em;margin-right:-.375em}.tag:not(body).is-delete{margin-left:1px;padding:0;position:relative;width:2em}.tag:not(body).is-delete::after,.tag:not(body).is-delete::before{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.tag:not(body).is-delete::before{height:1px;width:50%}.tag:not(body).is-delete::after{height:50%;width:1px}.tag:not(body).is-delete:focus,.tag:not(body).is-delete:hover{background-color:#e8e8e8}.tag:not(body).is-delete:active{background-color:#dbdbdb}.tag:not(body).is-rounded{border-radius:9999px}a.tag:hover{text-decoration:underline}.subtitle,.title{word-break:break-word}.subtitle em,.subtitle span,.title em,.title span{font-weight:inherit}.subtitle sub,.title sub{font-size:.75em}.subtitle sup,.title sup{font-size:.75em}.subtitle .tag,.title .tag{vertical-align:middle}.title{color:#363636;font-size:2rem;font-weight:600;line-height:1.125}.title strong{color:inherit;font-weight:inherit}.title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}.title.is-1{font-size:3rem}.title.is-2{font-size:2.5rem}.title.is-3{font-size:2rem}.title.is-4{font-size:1.5rem}.title.is-5{font-size:1.25rem}.title.is-6{font-size:1rem}.title.is-7{font-size:.75rem}.subtitle{color:#4a4a4a;font-size:1.25rem;font-weight:400;line-height:1.25}.subtitle strong{color:#363636;font-weight:600}.subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}.subtitle.is-1{font-size:3rem}.subtitle.is-2{font-size:2.5rem}.subtitle.is-3{font-size:2rem}.subtitle.is-4{font-size:1.5rem}.subtitle.is-5{font-size:1.25rem}.subtitle.is-6{font-size:1rem}.subtitle.is-7{font-size:.75rem}.heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}.number{align-items:center;background-color:#f5f5f5;border-radius:9999px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:.25rem .5rem;text-align:center;vertical-align:top}.input,.select select,.textarea{background-color:#fff;border-color:#dbdbdb;border-radius:4px;color:#363636}.input::-moz-placeholder,.select select::-moz-placeholder,.textarea::-moz-placeholder{color:rgba(54,54,54,.3)}.input::-webkit-input-placeholder,.select select::-webkit-input-placeholder,.textarea::-webkit-input-placeholder{color:rgba(54,54,54,.3)}.input:-moz-placeholder,.select select:-moz-placeholder,.textarea:-moz-placeholder{color:rgba(54,54,54,.3)}.input:-ms-input-placeholder,.select select:-ms-input-placeholder,.textarea:-ms-input-placeholder{color:rgba(54,54,54,.3)}.input:hover,.is-hovered.input,.is-hovered.textarea,.select select.is-hovered,.select select:hover,.textarea:hover{border-color:#b5b5b5}.input:active,.input:focus,.is-active.input,.is-active.textarea,.is-focused.input,.is-focused.textarea,.select select.is-active,.select select.is-focused,.select select:active,.select select:focus,.textarea:active,.textarea:focus{border-color:#485fc7;box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.input[disabled],.select fieldset[disabled] select,.select select[disabled],.textarea[disabled],fieldset[disabled] .input,fieldset[disabled] .select select,fieldset[disabled] .textarea{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none;color:#7a7a7a}.input[disabled]::-moz-placeholder,.select fieldset[disabled] select::-moz-placeholder,.select select[disabled]::-moz-placeholder,.textarea[disabled]::-moz-placeholder,fieldset[disabled] .input::-moz-placeholder,fieldset[disabled] .select select::-moz-placeholder,fieldset[disabled] .textarea::-moz-placeholder{color:rgba(122,122,122,.3)}.input[disabled]::-webkit-input-placeholder,.select fieldset[disabled] select::-webkit-input-placeholder,.select select[disabled]::-webkit-input-placeholder,.textarea[disabled]::-webkit-input-placeholder,fieldset[disabled] .input::-webkit-input-placeholder,fieldset[disabled] .select select::-webkit-input-placeholder,fieldset[disabled] .textarea::-webkit-input-placeholder{color:rgba(122,122,122,.3)}.input[disabled]:-moz-placeholder,.select fieldset[disabled] select:-moz-placeholder,.select select[disabled]:-moz-placeholder,.textarea[disabled]:-moz-placeholder,fieldset[disabled] .input:-moz-placeholder,fieldset[disabled] .select select:-moz-placeholder,fieldset[disabled] .textarea:-moz-placeholder{color:rgba(122,122,122,.3)}.input[disabled]:-ms-input-placeholder,.select fieldset[disabled] select:-ms-input-placeholder,.select select[disabled]:-ms-input-placeholder,.textarea[disabled]:-ms-input-placeholder,fieldset[disabled] .input:-ms-input-placeholder,fieldset[disabled] .select select:-ms-input-placeholder,fieldset[disabled] .textarea:-ms-input-placeholder{color:rgba(122,122,122,.3)}.input,.textarea{box-shadow:inset 0 .0625em .125em rgba(10,10,10,.05);max-width:100%;width:100%}.input[readonly],.textarea[readonly]{box-shadow:none}.is-white.input,.is-white.textarea{border-color:#fff}.is-white.input:active,.is-white.input:focus,.is-white.is-active.input,.is-white.is-active.textarea,.is-white.is-focused.input,.is-white.is-focused.textarea,.is-white.textarea:active,.is-white.textarea:focus{box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.is-black.input,.is-black.textarea{border-color:#0a0a0a}.is-black.input:active,.is-black.input:focus,.is-black.is-active.input,.is-black.is-active.textarea,.is-black.is-focused.input,.is-black.is-focused.textarea,.is-black.textarea:active,.is-black.textarea:focus{box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.is-light.input,.is-light.textarea{border-color:#f5f5f5}.is-light.input:active,.is-light.input:focus,.is-light.is-active.input,.is-light.is-active.textarea,.is-light.is-focused.input,.is-light.is-focused.textarea,.is-light.textarea:active,.is-light.textarea:focus{box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.is-dark.input,.is-dark.textarea{border-color:#363636}.is-dark.input:active,.is-dark.input:focus,.is-dark.is-active.input,.is-dark.is-active.textarea,.is-dark.is-focused.input,.is-dark.is-focused.textarea,.is-dark.textarea:active,.is-dark.textarea:focus{box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.is-primary.input,.is-primary.textarea{border-color:#00d1b2}.is-primary.input:active,.is-primary.input:focus,.is-primary.is-active.input,.is-primary.is-active.textarea,.is-primary.is-focused.input,.is-primary.is-focused.textarea,.is-primary.textarea:active,.is-primary.textarea:focus{box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.is-link.input,.is-link.textarea{border-color:#485fc7}.is-link.input:active,.is-link.input:focus,.is-link.is-active.input,.is-link.is-active.textarea,.is-link.is-focused.input,.is-link.is-focused.textarea,.is-link.textarea:active,.is-link.textarea:focus{box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.is-info.input,.is-info.textarea{border-color:#3e8ed0}.is-info.input:active,.is-info.input:focus,.is-info.is-active.input,.is-info.is-active.textarea,.is-info.is-focused.input,.is-info.is-focused.textarea,.is-info.textarea:active,.is-info.textarea:focus{box-shadow:0 0 0 .125em rgba(62,142,208,.25)}.is-success.input,.is-success.textarea{border-color:#48c78e}.is-success.input:active,.is-success.input:focus,.is-success.is-active.input,.is-success.is-active.textarea,.is-success.is-focused.input,.is-success.is-focused.textarea,.is-success.textarea:active,.is-success.textarea:focus{box-shadow:0 0 0 .125em rgba(72,199,142,.25)}.is-warning.input,.is-warning.textarea{border-color:#ffe08a}.is-warning.input:active,.is-warning.input:focus,.is-warning.is-active.input,.is-warning.is-active.textarea,.is-warning.is-focused.input,.is-warning.is-focused.textarea,.is-warning.textarea:active,.is-warning.textarea:focus{box-shadow:0 0 0 .125em rgba(255,224,138,.25)}.is-danger.input,.is-danger.textarea{border-color:#f14668}.is-danger.input:active,.is-danger.input:focus,.is-danger.is-active.input,.is-danger.is-active.textarea,.is-danger.is-focused.input,.is-danger.is-focused.textarea,.is-danger.textarea:active,.is-danger.textarea:focus{box-shadow:0 0 0 .125em rgba(241,70,104,.25)}.is-small.input,.is-small.textarea{border-radius:2px;font-size:.75rem}.is-medium.input,.is-medium.textarea{font-size:1.25rem}.is-large.input,.is-large.textarea{font-size:1.5rem}.is-fullwidth.input,.is-fullwidth.textarea{display:block;width:100%}.is-inline.input,.is-inline.textarea{display:inline;width:auto}.input.is-rounded{border-radius:9999px;padding-left:calc(calc(.75em - 1px) + .375em);padding-right:calc(calc(.75em - 1px) + .375em)}.input.is-static{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}.textarea{display:block;max-width:100%;min-width:100%;padding:calc(.75em - 1px);resize:vertical}.textarea:not([rows]){max-height:40em;min-height:8em}.textarea[rows]{height:initial}.textarea.has-fixed-size{resize:none}.checkbox,.radio{cursor:pointer;display:inline-block;line-height:1.25;position:relative}.checkbox input,.radio input{cursor:pointer}.checkbox:hover,.radio:hover{color:#363636}.checkbox input[disabled],.checkbox[disabled],.radio input[disabled],.radio[disabled],fieldset[disabled] .checkbox,fieldset[disabled] .radio{color:#7a7a7a;cursor:not-allowed}.radio+.radio{margin-left:.5em}.select{display:inline-block;max-width:100%;position:relative;vertical-align:top}.select:not(.is-multiple){height:2.5em}.select:not(.is-multiple):not(.is-loading)::after{border-color:#485fc7;right:1.125em;z-index:4}.select.is-rounded select{border-radius:9999px;padding-left:1em}.select select{cursor:pointer;display:block;font-size:1em;max-width:100%;outline:0}.select select::-ms-expand{display:none}.select select[disabled]:hover,fieldset[disabled] .select select:hover{border-color:#f5f5f5}.select select:not([multiple]){padding-right:2.5em}.select select[multiple]{height:auto;padding:0}.select select[multiple] option{padding:.5em 1em}.select:not(.is-multiple):not(.is-loading):hover::after{border-color:#363636}.select.is-white:not(:hover)::after{border-color:#fff}.select.is-white select{border-color:#fff}.select.is-white select.is-hovered,.select.is-white select:hover{border-color:#f2f2f2}.select.is-white select.is-active,.select.is-white select.is-focused,.select.is-white select:active,.select.is-white select:focus{box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.select.is-black:not(:hover)::after{border-color:#0a0a0a}.select.is-black select{border-color:#0a0a0a}.select.is-black select.is-hovered,.select.is-black select:hover{border-color:#000}.select.is-black select.is-active,.select.is-black select.is-focused,.select.is-black select:active,.select.is-black select:focus{box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.select.is-light:not(:hover)::after{border-color:#f5f5f5}.select.is-light select{border-color:#f5f5f5}.select.is-light select.is-hovered,.select.is-light select:hover{border-color:#e8e8e8}.select.is-light select.is-active,.select.is-light select.is-focused,.select.is-light select:active,.select.is-light select:focus{box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.select.is-dark:not(:hover)::after{border-color:#363636}.select.is-dark select{border-color:#363636}.select.is-dark select.is-hovered,.select.is-dark select:hover{border-color:#292929}.select.is-dark select.is-active,.select.is-dark select.is-focused,.select.is-dark select:active,.select.is-dark select:focus{box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.select.is-primary:not(:hover)::after{border-color:#00d1b2}.select.is-primary select{border-color:#00d1b2}.select.is-primary select.is-hovered,.select.is-primary select:hover{border-color:#00b89c}.select.is-primary select.is-active,.select.is-primary select.is-focused,.select.is-primary select:active,.select.is-primary select:focus{box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.select.is-link:not(:hover)::after{border-color:#485fc7}.select.is-link select{border-color:#485fc7}.select.is-link select.is-hovered,.select.is-link select:hover{border-color:#3a51bb}.select.is-link select.is-active,.select.is-link select.is-focused,.select.is-link select:active,.select.is-link select:focus{box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.select.is-info:not(:hover)::after{border-color:#3e8ed0}.select.is-info select{border-color:#3e8ed0}.select.is-info select.is-hovered,.select.is-info select:hover{border-color:#3082c5}.select.is-info select.is-active,.select.is-info select.is-focused,.select.is-info select:active,.select.is-info select:focus{box-shadow:0 0 0 .125em rgba(62,142,208,.25)}.select.is-success:not(:hover)::after{border-color:#48c78e}.select.is-success select{border-color:#48c78e}.select.is-success select.is-hovered,.select.is-success select:hover{border-color:#3abb81}.select.is-success select.is-active,.select.is-success select.is-focused,.select.is-success select:active,.select.is-success select:focus{box-shadow:0 0 0 .125em rgba(72,199,142,.25)}.select.is-warning:not(:hover)::after{border-color:#ffe08a}.select.is-warning select{border-color:#ffe08a}.select.is-warning select.is-hovered,.select.is-warning select:hover{border-color:#ffd970}.select.is-warning select.is-active,.select.is-warning select.is-focused,.select.is-warning select:active,.select.is-warning select:focus{box-shadow:0 0 0 .125em rgba(255,224,138,.25)}.select.is-danger:not(:hover)::after{border-color:#f14668}.select.is-danger select{border-color:#f14668}.select.is-danger select.is-hovered,.select.is-danger select:hover{border-color:#ef2e55}.select.is-danger select.is-active,.select.is-danger select.is-focused,.select.is-danger select:active,.select.is-danger select:focus{box-shadow:0 0 0 .125em rgba(241,70,104,.25)}.select.is-small{border-radius:2px;font-size:.75rem}.select.is-medium{font-size:1.25rem}.select.is-large{font-size:1.5rem}.select.is-disabled::after{border-color:#7a7a7a}.select.is-fullwidth{width:100%}.select.is-fullwidth select{width:100%}.select.is-loading::after{margin-top:0;position:absolute;right:.625em;top:.625em;transform:none}.select.is-loading.is-small:after{font-size:.75rem}.select.is-loading.is-medium:after{font-size:1.25rem}.select.is-loading.is-large:after{font-size:1.5rem}.file{align-items:stretch;display:flex;justify-content:flex-start;position:relative}.file.is-white .file-cta{background-color:#fff;border-color:transparent;color:#0a0a0a}.file.is-white.is-hovered .file-cta,.file.is-white:hover .file-cta{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.file.is-white.is-focused .file-cta,.file.is-white:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(255,255,255,.25);color:#0a0a0a}.file.is-white.is-active .file-cta,.file.is-white:active .file-cta{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.file.is-black .file-cta{background-color:#0a0a0a;border-color:transparent;color:#fff}.file.is-black.is-hovered .file-cta,.file.is-black:hover .file-cta{background-color:#040404;border-color:transparent;color:#fff}.file.is-black.is-focused .file-cta,.file.is-black:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(10,10,10,.25);color:#fff}.file.is-black.is-active .file-cta,.file.is-black:active .file-cta{background-color:#000;border-color:transparent;color:#fff}.file.is-light .file-cta{background-color:#f5f5f5;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-light.is-hovered .file-cta,.file.is-light:hover .file-cta{background-color:#eee;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-light.is-focused .file-cta,.file.is-light:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(245,245,245,.25);color:rgba(0,0,0,.7)}.file.is-light.is-active .file-cta,.file.is-light:active .file-cta{background-color:#e8e8e8;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-dark .file-cta{background-color:#363636;border-color:transparent;color:#fff}.file.is-dark.is-hovered .file-cta,.file.is-dark:hover .file-cta{background-color:#2f2f2f;border-color:transparent;color:#fff}.file.is-dark.is-focused .file-cta,.file.is-dark:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(54,54,54,.25);color:#fff}.file.is-dark.is-active .file-cta,.file.is-dark:active .file-cta{background-color:#292929;border-color:transparent;color:#fff}.file.is-primary .file-cta{background-color:#00d1b2;border-color:transparent;color:#fff}.file.is-primary.is-hovered .file-cta,.file.is-primary:hover .file-cta{background-color:#00c4a7;border-color:transparent;color:#fff}.file.is-primary.is-focused .file-cta,.file.is-primary:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(0,209,178,.25);color:#fff}.file.is-primary.is-active .file-cta,.file.is-primary:active .file-cta{background-color:#00b89c;border-color:transparent;color:#fff}.file.is-link .file-cta{background-color:#485fc7;border-color:transparent;color:#fff}.file.is-link.is-hovered .file-cta,.file.is-link:hover .file-cta{background-color:#3e56c4;border-color:transparent;color:#fff}.file.is-link.is-focused .file-cta,.file.is-link:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(72,95,199,.25);color:#fff}.file.is-link.is-active .file-cta,.file.is-link:active .file-cta{background-color:#3a51bb;border-color:transparent;color:#fff}.file.is-info .file-cta{background-color:#3e8ed0;border-color:transparent;color:#fff}.file.is-info.is-hovered .file-cta,.file.is-info:hover .file-cta{background-color:#3488ce;border-color:transparent;color:#fff}.file.is-info.is-focused .file-cta,.file.is-info:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(62,142,208,.25);color:#fff}.file.is-info.is-active .file-cta,.file.is-info:active .file-cta{background-color:#3082c5;border-color:transparent;color:#fff}.file.is-success .file-cta{background-color:#48c78e;border-color:transparent;color:#fff}.file.is-success.is-hovered .file-cta,.file.is-success:hover .file-cta{background-color:#3ec487;border-color:transparent;color:#fff}.file.is-success.is-focused .file-cta,.file.is-success:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(72,199,142,.25);color:#fff}.file.is-success.is-active .file-cta,.file.is-success:active .file-cta{background-color:#3abb81;border-color:transparent;color:#fff}.file.is-warning .file-cta{background-color:#ffe08a;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-warning.is-hovered .file-cta,.file.is-warning:hover .file-cta{background-color:#ffdc7d;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-warning.is-focused .file-cta,.file.is-warning:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(255,224,138,.25);color:rgba(0,0,0,.7)}.file.is-warning.is-active .file-cta,.file.is-warning:active .file-cta{background-color:#ffd970;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-danger .file-cta{background-color:#f14668;border-color:transparent;color:#fff}.file.is-danger.is-hovered .file-cta,.file.is-danger:hover .file-cta{background-color:#f03a5f;border-color:transparent;color:#fff}.file.is-danger.is-focused .file-cta,.file.is-danger:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(241,70,104,.25);color:#fff}.file.is-danger.is-active .file-cta,.file.is-danger:active .file-cta{background-color:#ef2e55;border-color:transparent;color:#fff}.file.is-small{font-size:.75rem}.file.is-normal{font-size:1rem}.file.is-medium{font-size:1.25rem}.file.is-medium .file-icon .fa{font-size:21px}.file.is-large{font-size:1.5rem}.file.is-large .file-icon .fa{font-size:28px}.file.has-name .file-cta{border-bottom-right-radius:0;border-top-right-radius:0}.file.has-name .file-name{border-bottom-left-radius:0;border-top-left-radius:0}.file.has-name.is-empty .file-cta{border-radius:4px}.file.has-name.is-empty .file-name{display:none}.file.is-boxed .file-label{flex-direction:column}.file.is-boxed .file-cta{flex-direction:column;height:auto;padding:1em 3em}.file.is-boxed .file-name{border-width:0 1px 1px}.file.is-boxed .file-icon{height:1.5em;width:1.5em}.file.is-boxed .file-icon .fa{font-size:21px}.file.is-boxed.is-small .file-icon .fa{font-size:14px}.file.is-boxed.is-medium .file-icon .fa{font-size:28px}.file.is-boxed.is-large .file-icon .fa{font-size:35px}.file.is-boxed.has-name .file-cta{border-radius:4px 4px 0 0}.file.is-boxed.has-name .file-name{border-radius:0 0 4px 4px;border-width:0 1px 1px}.file.is-centered{justify-content:center}.file.is-fullwidth .file-label{width:100%}.file.is-fullwidth .file-name{flex-grow:1;max-width:none}.file.is-right{justify-content:flex-end}.file.is-right .file-cta{border-radius:0 4px 4px 0}.file.is-right .file-name{border-radius:4px 0 0 4px;border-width:1px 0 1px 1px;order:-1}.file-label{align-items:stretch;display:flex;cursor:pointer;justify-content:flex-start;overflow:hidden;position:relative}.file-label:hover .file-cta{background-color:#eee;color:#363636}.file-label:hover .file-name{border-color:#d5d5d5}.file-label:active .file-cta{background-color:#e8e8e8;color:#363636}.file-label:active .file-name{border-color:#cfcfcf}.file-input{height:100%;left:0;opacity:0;outline:0;position:absolute;top:0;width:100%}.file-cta,.file-name{border-color:#dbdbdb;border-radius:4px;font-size:1em;padding-left:1em;padding-right:1em;white-space:nowrap}.file-cta{background-color:#f5f5f5;color:#4a4a4a}.file-name{border-color:#dbdbdb;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:inherit;text-overflow:ellipsis}.file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:.5em;width:1em}.file-icon .fa{font-size:14px}.label{color:#363636;display:block;font-size:1rem;font-weight:700}.label:not(:last-child){margin-bottom:.5em}.label.is-small{font-size:.75rem}.label.is-medium{font-size:1.25rem}.label.is-large{font-size:1.5rem}.help{display:block;font-size:.75rem;margin-top:.25rem}.help.is-white{color:#fff}.help.is-black{color:#0a0a0a}.help.is-light{color:#f5f5f5}.help.is-dark{color:#363636}.help.is-primary{color:#00d1b2}.help.is-link{color:#485fc7}.help.is-info{color:#3e8ed0}.help.is-success{color:#48c78e}.help.is-warning{color:#ffe08a}.help.is-danger{color:#f14668}.field:not(:last-child){margin-bottom:.75rem}.field.has-addons{display:flex;justify-content:flex-start}.field.has-addons .control:not(:last-child){margin-right:-1px}.field.has-addons .control:not(:first-child):not(:last-child) .button,.field.has-addons .control:not(:first-child):not(:last-child) .input,.field.has-addons .control:not(:first-child):not(:last-child) .select select{border-radius:0}.field.has-addons .control:first-child:not(:only-child) .button,.field.has-addons .control:first-child:not(:only-child) .input,.field.has-addons .control:first-child:not(:only-child) .select select{border-bottom-right-radius:0;border-top-right-radius:0}.field.has-addons .control:last-child:not(:only-child) .button,.field.has-addons .control:last-child:not(:only-child) .input,.field.has-addons .control:last-child:not(:only-child) .select select{border-bottom-left-radius:0;border-top-left-radius:0}.field.has-addons .control .button:not([disabled]).is-hovered,.field.has-addons .control .button:not([disabled]):hover,.field.has-addons .control .input:not([disabled]).is-hovered,.field.has-addons .control .input:not([disabled]):hover,.field.has-addons .control .select select:not([disabled]).is-hovered,.field.has-addons .control .select select:not([disabled]):hover{z-index:2}.field.has-addons .control .button:not([disabled]).is-active,.field.has-addons .control .button:not([disabled]).is-focused,.field.has-addons .control .button:not([disabled]):active,.field.has-addons .control .button:not([disabled]):focus,.field.has-addons .control .input:not([disabled]).is-active,.field.has-addons .control .input:not([disabled]).is-focused,.field.has-addons .control .input:not([disabled]):active,.field.has-addons .control .input:not([disabled]):focus,.field.has-addons .control .select select:not([disabled]).is-active,.field.has-addons .control .select select:not([disabled]).is-focused,.field.has-addons .control .select select:not([disabled]):active,.field.has-addons .control .select select:not([disabled]):focus{z-index:3}.field.has-addons .control .button:not([disabled]).is-active:hover,.field.has-addons .control .button:not([disabled]).is-focused:hover,.field.has-addons .control .button:not([disabled]):active:hover,.field.has-addons .control .button:not([disabled]):focus:hover,.field.has-addons .control .input:not([disabled]).is-active:hover,.field.has-addons .control .input:not([disabled]).is-focused:hover,.field.has-addons .control .input:not([disabled]):active:hover,.field.has-addons .control .input:not([disabled]):focus:hover,.field.has-addons .control .select select:not([disabled]).is-active:hover,.field.has-addons .control .select select:not([disabled]).is-focused:hover,.field.has-addons .control .select select:not([disabled]):active:hover,.field.has-addons .control .select select:not([disabled]):focus:hover{z-index:4}.field.has-addons .control.is-expanded{flex-grow:1;flex-shrink:1}.field.has-addons.has-addons-centered{justify-content:center}.field.has-addons.has-addons-right{justify-content:flex-end}.field.has-addons.has-addons-fullwidth .control{flex-grow:1;flex-shrink:0}.field.is-grouped{display:flex;justify-content:flex-start}.field.is-grouped>.control{flex-shrink:0}.field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-right:.75rem}.field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}.field.is-grouped.is-grouped-centered{justify-content:center}.field.is-grouped.is-grouped-right{justify-content:flex-end}.field.is-grouped.is-grouped-multiline{flex-wrap:wrap}.field.is-grouped.is-grouped-multiline>.control:last-child,.field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:.75rem}.field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-.75rem}.field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width:769px),print{.field.is-horizontal{display:flex}}.field-label .label{font-size:inherit}@media screen and (max-width:768px){.field-label{margin-bottom:.5rem}}@media screen and (min-width:769px),print{.field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-right:1.5rem;text-align:right}.field-label.is-small{font-size:.75rem;padding-top:.375em}.field-label.is-normal{padding-top:.375em}.field-label.is-medium{font-size:1.25rem;padding-top:.375em}.field-label.is-large{font-size:1.5rem;padding-top:.375em}}.field-body .field .field{margin-bottom:0}@media screen and (min-width:769px),print{.field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}.field-body .field{margin-bottom:0}.field-body>.field{flex-shrink:1}.field-body>.field:not(.is-narrow){flex-grow:1}.field-body>.field:not(:last-child){margin-right:.75rem}}.control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:inherit}.control.has-icons-left .input:focus~.icon,.control.has-icons-left .select:focus~.icon,.control.has-icons-right .input:focus~.icon,.control.has-icons-right .select:focus~.icon{color:#4a4a4a}.control.has-icons-left .input.is-small~.icon,.control.has-icons-left .select.is-small~.icon,.control.has-icons-right .input.is-small~.icon,.control.has-icons-right .select.is-small~.icon{font-size:.75rem}.control.has-icons-left .input.is-medium~.icon,.control.has-icons-left .select.is-medium~.icon,.control.has-icons-right .input.is-medium~.icon,.control.has-icons-right .select.is-medium~.icon{font-size:1.25rem}.control.has-icons-left .input.is-large~.icon,.control.has-icons-left .select.is-large~.icon,.control.has-icons-right .input.is-large~.icon,.control.has-icons-right .select.is-large~.icon{font-size:1.5rem}.control.has-icons-left .icon,.control.has-icons-right .icon{color:#dbdbdb;height:2.5em;pointer-events:none;position:absolute;top:0;width:2.5em;z-index:4}.control.has-icons-left .input,.control.has-icons-left .select select{padding-left:2.5em}.control.has-icons-left .icon.is-left{left:0}.control.has-icons-right .input,.control.has-icons-right .select select{padding-right:2.5em}.control.has-icons-right .icon.is-right{right:0}.control.is-loading::after{position:absolute!important;right:.625em;top:.625em;z-index:4}.control.is-loading.is-small:after{font-size:.75rem}.control.is-loading.is-medium:after{font-size:1.25rem}.control.is-loading.is-large:after{font-size:1.5rem}.breadcrumb{font-size:1rem;white-space:nowrap}.breadcrumb a{align-items:center;color:#485fc7;display:flex;justify-content:center;padding:0 .75em}.breadcrumb a:hover{color:#363636}.breadcrumb li{align-items:center;display:flex}.breadcrumb li:first-child a{padding-left:0}.breadcrumb li.is-active a{color:#363636;cursor:default;pointer-events:none}.breadcrumb li+li::before{color:#b5b5b5;content:"\0002f"}.breadcrumb ol,.breadcrumb ul{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}.breadcrumb .icon:first-child{margin-right:.5em}.breadcrumb .icon:last-child{margin-left:.5em}.breadcrumb.is-centered ol,.breadcrumb.is-centered ul{justify-content:center}.breadcrumb.is-right ol,.breadcrumb.is-right ul{justify-content:flex-end}.breadcrumb.is-small{font-size:.75rem}.breadcrumb.is-medium{font-size:1.25rem}.breadcrumb.is-large{font-size:1.5rem}.breadcrumb.has-arrow-separator li+li::before{content:"\02192"}.breadcrumb.has-bullet-separator li+li::before{content:"\02022"}.breadcrumb.has-dot-separator li+li::before{content:"\000b7"}.breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}.card{background-color:#fff;border-radius:.25rem;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);color:#4a4a4a;max-width:100%;position:relative}.card-content:first-child,.card-footer:first-child,.card-header:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-content:last-child,.card-footer:last-child,.card-header:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-header{background-color:transparent;align-items:stretch;box-shadow:0 .125em .25em rgba(10,10,10,.1);display:flex}.card-header-title{align-items:center;color:#363636;display:flex;flex-grow:1;font-weight:700;padding:.75rem 1rem}.card-header-title.is-centered{justify-content:center}.card-header-icon{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:0 0;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0;align-items:center;cursor:pointer;display:flex;justify-content:center;padding:.75rem 1rem}.card-image{display:block;position:relative}.card-image:first-child img{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-image:last-child img{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-content{background-color:transparent;padding:1.5rem}.card-footer{background-color:transparent;border-top:1px solid #ededed;align-items:stretch;display:flex}.card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:.75rem}.card-footer-item:not(:last-child){border-right:1px solid #ededed}.card .media:not(:last-child){margin-bottom:1.5rem}.dropdown{display:inline-flex;position:relative;vertical-align:top}.dropdown.is-active .dropdown-menu,.dropdown.is-hoverable:hover .dropdown-menu{display:block}.dropdown.is-right .dropdown-menu{left:auto;right:0}.dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}.dropdown-menu{display:none;left:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}.dropdown-content{background-color:#fff;border-radius:4px;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);padding-bottom:.5rem;padding-top:.5rem}.dropdown-item{color:#4a4a4a;display:block;font-size:.875rem;line-height:1.5;padding:.375rem 1rem;position:relative}a.dropdown-item,button.dropdown-item{padding-right:3rem;text-align:inherit;white-space:nowrap;width:100%}a.dropdown-item:hover,button.dropdown-item:hover{background-color:#f5f5f5;color:#0a0a0a}a.dropdown-item.is-active,button.dropdown-item.is-active{background-color:#485fc7;color:#fff}.dropdown-divider{background-color:#ededed;border:none;display:block;height:1px;margin:.5rem 0}.level{align-items:center;justify-content:space-between}.level code{border-radius:4px}.level img{display:inline-block;vertical-align:top}.level.is-mobile{display:flex}.level.is-mobile .level-left,.level.is-mobile .level-right{display:flex}.level.is-mobile .level-left+.level-right{margin-top:0}.level.is-mobile .level-item:not(:last-child){margin-bottom:0;margin-right:.75rem}.level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width:769px),print{.level{display:flex}.level>.level-item:not(.is-narrow){flex-grow:1}}.level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}.level-item .subtitle,.level-item .title{margin-bottom:0}@media screen and (max-width:768px){.level-item:not(:last-child){margin-bottom:.75rem}}.level-left,.level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.level-left .level-item.is-flexible,.level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width:769px),print{.level-left .level-item:not(:last-child),.level-right .level-item:not(:last-child){margin-right:.75rem}}.level-left{align-items:center;justify-content:flex-start}@media screen and (max-width:768px){.level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width:769px),print{.level-left{display:flex}}.level-right{align-items:center;justify-content:flex-end}@media screen and (min-width:769px),print{.level-right{display:flex}}.media{align-items:flex-start;display:flex;text-align:inherit}.media .content:not(:last-child){margin-bottom:.75rem}.media .media{border-top:1px solid rgba(219,219,219,.5);display:flex;padding-top:.75rem}.media .media .content:not(:last-child),.media .media .control:not(:last-child){margin-bottom:.5rem}.media .media .media{padding-top:.5rem}.media .media .media+.media{margin-top:.5rem}.media+.media{border-top:1px solid rgba(219,219,219,.5);margin-top:1rem;padding-top:1rem}.media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}.media-left,.media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.media-left{margin-right:1rem}.media-right{margin-left:1rem}.media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:inherit}@media screen and (max-width:768px){.media-content{overflow-x:auto}}.menu{font-size:1rem}.menu.is-small{font-size:.75rem}.menu.is-medium{font-size:1.25rem}.menu.is-large{font-size:1.5rem}.menu-list{line-height:1.25}.menu-list a{border-radius:2px;color:#4a4a4a;display:block;padding:.5em .75em}.menu-list a:hover{background-color:#f5f5f5;color:#363636}.menu-list a.is-active{background-color:#485fc7;color:#fff}.menu-list li ul{border-left:1px solid #dbdbdb;margin:.75em;padding-left:.75em}.menu-label{color:#7a7a7a;font-size:.75em;letter-spacing:.1em;text-transform:uppercase}.menu-label:not(:first-child){margin-top:1em}.menu-label:not(:last-child){margin-bottom:1em}.message{background-color:#f5f5f5;border-radius:4px;font-size:1rem}.message strong{color:currentColor}.message a:not(.button):not(.tag):not(.dropdown-item){color:currentColor;text-decoration:underline}.message.is-small{font-size:.75rem}.message.is-medium{font-size:1.25rem}.message.is-large{font-size:1.5rem}.message.is-white{background-color:#fff}.message.is-white .message-header{background-color:#fff;color:#0a0a0a}.message.is-white .message-body{border-color:#fff}.message.is-black{background-color:#fafafa}.message.is-black .message-header{background-color:#0a0a0a;color:#fff}.message.is-black .message-body{border-color:#0a0a0a}.message.is-light{background-color:#fafafa}.message.is-light .message-header{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.message.is-light .message-body{border-color:#f5f5f5}.message.is-dark{background-color:#fafafa}.message.is-dark .message-header{background-color:#363636;color:#fff}.message.is-dark .message-body{border-color:#363636}.message.is-primary{background-color:#ebfffc}.message.is-primary .message-header{background-color:#00d1b2;color:#fff}.message.is-primary .message-body{border-color:#00d1b2;color:#00947e}.message.is-link{background-color:#eff1fa}.message.is-link .message-header{background-color:#485fc7;color:#fff}.message.is-link .message-body{border-color:#485fc7;color:#3850b7}.message.is-info{background-color:#eff5fb}.message.is-info .message-header{background-color:#3e8ed0;color:#fff}.message.is-info .message-body{border-color:#3e8ed0;color:#296fa8}.message.is-success{background-color:#effaf5}.message.is-success .message-header{background-color:#48c78e;color:#fff}.message.is-success .message-body{border-color:#48c78e;color:#257953}.message.is-warning{background-color:#fffaeb}.message.is-warning .message-header{background-color:#ffe08a;color:rgba(0,0,0,.7)}.message.is-warning .message-body{border-color:#ffe08a;color:#946c00}.message.is-danger{background-color:#feecf0}.message.is-danger .message-header{background-color:#f14668;color:#fff}.message.is-danger .message-body{border-color:#f14668;color:#cc0f35}.message-header{align-items:center;background-color:#4a4a4a;border-radius:4px 4px 0 0;color:#fff;display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:.75em 1em;position:relative}.message-header .delete{flex-grow:0;flex-shrink:0;margin-left:.75em}.message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}.message-body{border-color:#dbdbdb;border-radius:4px;border-style:solid;border-width:0 0 0 4px;color:#4a4a4a;padding:1.25em 1.5em}.message-body code,.message-body pre{background-color:#fff}.message-body pre code{background-color:transparent}.modal{align-items:center;display:none;flex-direction:column;justify-content:center;overflow:hidden;position:fixed;z-index:40}.modal.is-active{display:flex}.modal-background{background-color:rgba(10,10,10,.86)}.modal-card,.modal-content{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width:769px){.modal-card,.modal-content{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}.modal-close{background:0 0;height:40px;position:fixed;right:20px;top:20px;width:40px}.modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden;-ms-overflow-y:visible}.modal-card-foot,.modal-card-head{align-items:center;background-color:#f5f5f5;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}.modal-card-head{border-bottom:1px solid #dbdbdb;border-top-left-radius:6px;border-top-right-radius:6px}.modal-card-title{color:#363636;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}.modal-card-foot{border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:1px solid #dbdbdb}.modal-card-foot .button:not(:last-child){margin-right:.5em}.modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}.navbar{background-color:#fff;min-height:3.25rem;position:relative;z-index:30}.navbar.is-white{background-color:#fff;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link,.navbar.is-white .navbar-brand>.navbar-item{color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link.is-active,.navbar.is-white .navbar-brand .navbar-link:focus,.navbar.is-white .navbar-brand .navbar-link:hover,.navbar.is-white .navbar-brand>a.navbar-item.is-active,.navbar.is-white .navbar-brand>a.navbar-item:focus,.navbar.is-white .navbar-brand>a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-burger{color:#0a0a0a}@media screen and (min-width:1024px){.navbar.is-white .navbar-end .navbar-link,.navbar.is-white .navbar-end>.navbar-item,.navbar.is-white .navbar-start .navbar-link,.navbar.is-white .navbar-start>.navbar-item{color:#0a0a0a}.navbar.is-white .navbar-end .navbar-link.is-active,.navbar.is-white .navbar-end .navbar-link:focus,.navbar.is-white .navbar-end .navbar-link:hover,.navbar.is-white .navbar-end>a.navbar-item.is-active,.navbar.is-white .navbar-end>a.navbar-item:focus,.navbar.is-white .navbar-end>a.navbar-item:hover,.navbar.is-white .navbar-start .navbar-link.is-active,.navbar.is-white .navbar-start .navbar-link:focus,.navbar.is-white .navbar-start .navbar-link:hover,.navbar.is-white .navbar-start>a.navbar-item.is-active,.navbar.is-white .navbar-start>a.navbar-item:focus,.navbar.is-white .navbar-start>a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-end .navbar-link::after,.navbar.is-white .navbar-start .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-white .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-white .navbar-item.has-dropdown:hover .navbar-link{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}.navbar.is-black{background-color:#0a0a0a;color:#fff}.navbar.is-black .navbar-brand .navbar-link,.navbar.is-black .navbar-brand>.navbar-item{color:#fff}.navbar.is-black .navbar-brand .navbar-link.is-active,.navbar.is-black .navbar-brand .navbar-link:focus,.navbar.is-black .navbar-brand .navbar-link:hover,.navbar.is-black .navbar-brand>a.navbar-item.is-active,.navbar.is-black .navbar-brand>a.navbar-item:focus,.navbar.is-black .navbar-brand>a.navbar-item:hover{background-color:#000;color:#fff}.navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-black .navbar-end .navbar-link,.navbar.is-black .navbar-end>.navbar-item,.navbar.is-black .navbar-start .navbar-link,.navbar.is-black .navbar-start>.navbar-item{color:#fff}.navbar.is-black .navbar-end .navbar-link.is-active,.navbar.is-black .navbar-end .navbar-link:focus,.navbar.is-black .navbar-end .navbar-link:hover,.navbar.is-black .navbar-end>a.navbar-item.is-active,.navbar.is-black .navbar-end>a.navbar-item:focus,.navbar.is-black .navbar-end>a.navbar-item:hover,.navbar.is-black .navbar-start .navbar-link.is-active,.navbar.is-black .navbar-start .navbar-link:focus,.navbar.is-black .navbar-start .navbar-link:hover,.navbar.is-black .navbar-start>a.navbar-item.is-active,.navbar.is-black .navbar-start>a.navbar-item:focus,.navbar.is-black .navbar-start>a.navbar-item:hover{background-color:#000;color:#fff}.navbar.is-black .navbar-end .navbar-link::after,.navbar.is-black .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-black .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-black .navbar-item.has-dropdown:hover .navbar-link{background-color:#000;color:#fff}.navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}.navbar.is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-brand .navbar-link,.navbar.is-light .navbar-brand>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-light .navbar-brand .navbar-link.is-active,.navbar.is-light .navbar-brand .navbar-link:focus,.navbar.is-light .navbar-brand .navbar-link:hover,.navbar.is-light .navbar-brand>a.navbar-item.is-active,.navbar.is-light .navbar-brand>a.navbar-item:focus,.navbar.is-light .navbar-brand>a.navbar-item:hover{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-light .navbar-burger{color:rgba(0,0,0,.7)}@media screen and (min-width:1024px){.navbar.is-light .navbar-end .navbar-link,.navbar.is-light .navbar-end>.navbar-item,.navbar.is-light .navbar-start .navbar-link,.navbar.is-light .navbar-start>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-light .navbar-end .navbar-link.is-active,.navbar.is-light .navbar-end .navbar-link:focus,.navbar.is-light .navbar-end .navbar-link:hover,.navbar.is-light .navbar-end>a.navbar-item.is-active,.navbar.is-light .navbar-end>a.navbar-item:focus,.navbar.is-light .navbar-end>a.navbar-item:hover,.navbar.is-light .navbar-start .navbar-link.is-active,.navbar.is-light .navbar-start .navbar-link:focus,.navbar.is-light .navbar-start .navbar-link:hover,.navbar.is-light .navbar-start>a.navbar-item.is-active,.navbar.is-light .navbar-start>a.navbar-item:focus,.navbar.is-light .navbar-start>a.navbar-item:hover{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-end .navbar-link::after,.navbar.is-light .navbar-start .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-light .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-light .navbar-item.has-dropdown:hover .navbar-link{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:rgba(0,0,0,.7)}}.navbar.is-dark{background-color:#363636;color:#fff}.navbar.is-dark .navbar-brand .navbar-link,.navbar.is-dark .navbar-brand>.navbar-item{color:#fff}.navbar.is-dark .navbar-brand .navbar-link.is-active,.navbar.is-dark .navbar-brand .navbar-link:focus,.navbar.is-dark .navbar-brand .navbar-link:hover,.navbar.is-dark .navbar-brand>a.navbar-item.is-active,.navbar.is-dark .navbar-brand>a.navbar-item:focus,.navbar.is-dark .navbar-brand>a.navbar-item:hover{background-color:#292929;color:#fff}.navbar.is-dark .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-dark .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-dark .navbar-end .navbar-link,.navbar.is-dark .navbar-end>.navbar-item,.navbar.is-dark .navbar-start .navbar-link,.navbar.is-dark .navbar-start>.navbar-item{color:#fff}.navbar.is-dark .navbar-end .navbar-link.is-active,.navbar.is-dark .navbar-end .navbar-link:focus,.navbar.is-dark .navbar-end .navbar-link:hover,.navbar.is-dark .navbar-end>a.navbar-item.is-active,.navbar.is-dark .navbar-end>a.navbar-item:focus,.navbar.is-dark .navbar-end>a.navbar-item:hover,.navbar.is-dark .navbar-start .navbar-link.is-active,.navbar.is-dark .navbar-start .navbar-link:focus,.navbar.is-dark .navbar-start .navbar-link:hover,.navbar.is-dark .navbar-start>a.navbar-item.is-active,.navbar.is-dark .navbar-start>a.navbar-item:focus,.navbar.is-dark .navbar-start>a.navbar-item:hover{background-color:#292929;color:#fff}.navbar.is-dark .navbar-end .navbar-link::after,.navbar.is-dark .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link{background-color:#292929;color:#fff}.navbar.is-dark .navbar-dropdown a.navbar-item.is-active{background-color:#363636;color:#fff}}.navbar.is-primary{background-color:#00d1b2;color:#fff}.navbar.is-primary .navbar-brand .navbar-link,.navbar.is-primary .navbar-brand>.navbar-item{color:#fff}.navbar.is-primary .navbar-brand .navbar-link.is-active,.navbar.is-primary .navbar-brand .navbar-link:focus,.navbar.is-primary .navbar-brand .navbar-link:hover,.navbar.is-primary .navbar-brand>a.navbar-item.is-active,.navbar.is-primary .navbar-brand>a.navbar-item:focus,.navbar.is-primary .navbar-brand>a.navbar-item:hover{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-primary .navbar-end .navbar-link,.navbar.is-primary .navbar-end>.navbar-item,.navbar.is-primary .navbar-start .navbar-link,.navbar.is-primary .navbar-start>.navbar-item{color:#fff}.navbar.is-primary .navbar-end .navbar-link.is-active,.navbar.is-primary .navbar-end .navbar-link:focus,.navbar.is-primary .navbar-end .navbar-link:hover,.navbar.is-primary .navbar-end>a.navbar-item.is-active,.navbar.is-primary .navbar-end>a.navbar-item:focus,.navbar.is-primary .navbar-end>a.navbar-item:hover,.navbar.is-primary .navbar-start .navbar-link.is-active,.navbar.is-primary .navbar-start .navbar-link:focus,.navbar.is-primary .navbar-start .navbar-link:hover,.navbar.is-primary .navbar-start>a.navbar-item.is-active,.navbar.is-primary .navbar-start>a.navbar-item:focus,.navbar.is-primary .navbar-start>a.navbar-item:hover{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-end .navbar-link::after,.navbar.is-primary .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-dropdown a.navbar-item.is-active{background-color:#00d1b2;color:#fff}}.navbar.is-link{background-color:#485fc7;color:#fff}.navbar.is-link .navbar-brand .navbar-link,.navbar.is-link .navbar-brand>.navbar-item{color:#fff}.navbar.is-link .navbar-brand .navbar-link.is-active,.navbar.is-link .navbar-brand .navbar-link:focus,.navbar.is-link .navbar-brand .navbar-link:hover,.navbar.is-link .navbar-brand>a.navbar-item.is-active,.navbar.is-link .navbar-brand>a.navbar-item:focus,.navbar.is-link .navbar-brand>a.navbar-item:hover{background-color:#3a51bb;color:#fff}.navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-link .navbar-end .navbar-link,.navbar.is-link .navbar-end>.navbar-item,.navbar.is-link .navbar-start .navbar-link,.navbar.is-link .navbar-start>.navbar-item{color:#fff}.navbar.is-link .navbar-end .navbar-link.is-active,.navbar.is-link .navbar-end .navbar-link:focus,.navbar.is-link .navbar-end .navbar-link:hover,.navbar.is-link .navbar-end>a.navbar-item.is-active,.navbar.is-link .navbar-end>a.navbar-item:focus,.navbar.is-link .navbar-end>a.navbar-item:hover,.navbar.is-link .navbar-start .navbar-link.is-active,.navbar.is-link .navbar-start .navbar-link:focus,.navbar.is-link .navbar-start .navbar-link:hover,.navbar.is-link .navbar-start>a.navbar-item.is-active,.navbar.is-link .navbar-start>a.navbar-item:focus,.navbar.is-link .navbar-start>a.navbar-item:hover{background-color:#3a51bb;color:#fff}.navbar.is-link .navbar-end .navbar-link::after,.navbar.is-link .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-link .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-link .navbar-item.has-dropdown:hover .navbar-link{background-color:#3a51bb;color:#fff}.navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#485fc7;color:#fff}}.navbar.is-info{background-color:#3e8ed0;color:#fff}.navbar.is-info .navbar-brand .navbar-link,.navbar.is-info .navbar-brand>.navbar-item{color:#fff}.navbar.is-info .navbar-brand .navbar-link.is-active,.navbar.is-info .navbar-brand .navbar-link:focus,.navbar.is-info .navbar-brand .navbar-link:hover,.navbar.is-info .navbar-brand>a.navbar-item.is-active,.navbar.is-info .navbar-brand>a.navbar-item:focus,.navbar.is-info .navbar-brand>a.navbar-item:hover{background-color:#3082c5;color:#fff}.navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-info .navbar-end .navbar-link,.navbar.is-info .navbar-end>.navbar-item,.navbar.is-info .navbar-start .navbar-link,.navbar.is-info .navbar-start>.navbar-item{color:#fff}.navbar.is-info .navbar-end .navbar-link.is-active,.navbar.is-info .navbar-end .navbar-link:focus,.navbar.is-info .navbar-end .navbar-link:hover,.navbar.is-info .navbar-end>a.navbar-item.is-active,.navbar.is-info .navbar-end>a.navbar-item:focus,.navbar.is-info .navbar-end>a.navbar-item:hover,.navbar.is-info .navbar-start .navbar-link.is-active,.navbar.is-info .navbar-start .navbar-link:focus,.navbar.is-info .navbar-start .navbar-link:hover,.navbar.is-info .navbar-start>a.navbar-item.is-active,.navbar.is-info .navbar-start>a.navbar-item:focus,.navbar.is-info .navbar-start>a.navbar-item:hover{background-color:#3082c5;color:#fff}.navbar.is-info .navbar-end .navbar-link::after,.navbar.is-info .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-info .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-info .navbar-item.has-dropdown:hover .navbar-link{background-color:#3082c5;color:#fff}.navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#3e8ed0;color:#fff}}.navbar.is-success{background-color:#48c78e;color:#fff}.navbar.is-success .navbar-brand .navbar-link,.navbar.is-success .navbar-brand>.navbar-item{color:#fff}.navbar.is-success .navbar-brand .navbar-link.is-active,.navbar.is-success .navbar-brand .navbar-link:focus,.navbar.is-success .navbar-brand .navbar-link:hover,.navbar.is-success .navbar-brand>a.navbar-item.is-active,.navbar.is-success .navbar-brand>a.navbar-item:focus,.navbar.is-success .navbar-brand>a.navbar-item:hover{background-color:#3abb81;color:#fff}.navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-success .navbar-end .navbar-link,.navbar.is-success .navbar-end>.navbar-item,.navbar.is-success .navbar-start .navbar-link,.navbar.is-success .navbar-start>.navbar-item{color:#fff}.navbar.is-success .navbar-end .navbar-link.is-active,.navbar.is-success .navbar-end .navbar-link:focus,.navbar.is-success .navbar-end .navbar-link:hover,.navbar.is-success .navbar-end>a.navbar-item.is-active,.navbar.is-success .navbar-end>a.navbar-item:focus,.navbar.is-success .navbar-end>a.navbar-item:hover,.navbar.is-success .navbar-start .navbar-link.is-active,.navbar.is-success .navbar-start .navbar-link:focus,.navbar.is-success .navbar-start .navbar-link:hover,.navbar.is-success .navbar-start>a.navbar-item.is-active,.navbar.is-success .navbar-start>a.navbar-item:focus,.navbar.is-success .navbar-start>a.navbar-item:hover{background-color:#3abb81;color:#fff}.navbar.is-success .navbar-end .navbar-link::after,.navbar.is-success .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-success .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-success .navbar-item.has-dropdown:hover .navbar-link{background-color:#3abb81;color:#fff}.navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#48c78e;color:#fff}}.navbar.is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link,.navbar.is-warning .navbar-brand>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link.is-active,.navbar.is-warning .navbar-brand .navbar-link:focus,.navbar.is-warning .navbar-brand .navbar-link:hover,.navbar.is-warning .navbar-brand>a.navbar-item.is-active,.navbar.is-warning .navbar-brand>a.navbar-item:focus,.navbar.is-warning .navbar-brand>a.navbar-item:hover{background-color:#ffd970;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-burger{color:rgba(0,0,0,.7)}@media screen and (min-width:1024px){.navbar.is-warning .navbar-end .navbar-link,.navbar.is-warning .navbar-end>.navbar-item,.navbar.is-warning .navbar-start .navbar-link,.navbar.is-warning .navbar-start>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-end .navbar-link.is-active,.navbar.is-warning .navbar-end .navbar-link:focus,.navbar.is-warning .navbar-end .navbar-link:hover,.navbar.is-warning .navbar-end>a.navbar-item.is-active,.navbar.is-warning .navbar-end>a.navbar-item:focus,.navbar.is-warning .navbar-end>a.navbar-item:hover,.navbar.is-warning .navbar-start .navbar-link.is-active,.navbar.is-warning .navbar-start .navbar-link:focus,.navbar.is-warning .navbar-start .navbar-link:hover,.navbar.is-warning .navbar-start>a.navbar-item.is-active,.navbar.is-warning .navbar-start>a.navbar-item:focus,.navbar.is-warning .navbar-start>a.navbar-item:hover{background-color:#ffd970;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-end .navbar-link::after,.navbar.is-warning .navbar-start .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link{background-color:#ffd970;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ffe08a;color:rgba(0,0,0,.7)}}.navbar.is-danger{background-color:#f14668;color:#fff}.navbar.is-danger .navbar-brand .navbar-link,.navbar.is-danger .navbar-brand>.navbar-item{color:#fff}.navbar.is-danger .navbar-brand .navbar-link.is-active,.navbar.is-danger .navbar-brand .navbar-link:focus,.navbar.is-danger .navbar-brand .navbar-link:hover,.navbar.is-danger .navbar-brand>a.navbar-item.is-active,.navbar.is-danger .navbar-brand>a.navbar-item:focus,.navbar.is-danger .navbar-brand>a.navbar-item:hover{background-color:#ef2e55;color:#fff}.navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-danger .navbar-end .navbar-link,.navbar.is-danger .navbar-end>.navbar-item,.navbar.is-danger .navbar-start .navbar-link,.navbar.is-danger .navbar-start>.navbar-item{color:#fff}.navbar.is-danger .navbar-end .navbar-link.is-active,.navbar.is-danger .navbar-end .navbar-link:focus,.navbar.is-danger .navbar-end .navbar-link:hover,.navbar.is-danger .navbar-end>a.navbar-item.is-active,.navbar.is-danger .navbar-end>a.navbar-item:focus,.navbar.is-danger .navbar-end>a.navbar-item:hover,.navbar.is-danger .navbar-start .navbar-link.is-active,.navbar.is-danger .navbar-start .navbar-link:focus,.navbar.is-danger .navbar-start .navbar-link:hover,.navbar.is-danger .navbar-start>a.navbar-item.is-active,.navbar.is-danger .navbar-start>a.navbar-item:focus,.navbar.is-danger .navbar-start>a.navbar-item:hover{background-color:#ef2e55;color:#fff}.navbar.is-danger .navbar-end .navbar-link::after,.navbar.is-danger .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link{background-color:#ef2e55;color:#fff}.navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#f14668;color:#fff}}.navbar>.container{align-items:stretch;display:flex;min-height:3.25rem;width:100%}.navbar.has-shadow{box-shadow:0 2px 0 0 #f5f5f5}.navbar.is-fixed-bottom,.navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom{bottom:0}.navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #f5f5f5}.navbar.is-fixed-top{top:0}body.has-navbar-fixed-top,html.has-navbar-fixed-top{padding-top:3.25rem}body.has-navbar-fixed-bottom,html.has-navbar-fixed-bottom{padding-bottom:3.25rem}.navbar-brand,.navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:3.25rem}.navbar-brand a.navbar-item:focus,.navbar-brand a.navbar-item:hover{background-color:transparent}.navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}.navbar-burger{color:#4a4a4a;cursor:pointer;display:block;height:3.25rem;position:relative;width:3.25rem;margin-left:auto}.navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;transform-origin:center;transition-duration:86ms;transition-property:background-color,opacity,transform;transition-timing-function:ease-out;width:16px}.navbar-burger span:nth-child(1){top:calc(50% - 6px)}.navbar-burger span:nth-child(2){top:calc(50% - 1px)}.navbar-burger span:nth-child(3){top:calc(50% + 4px)}.navbar-burger:hover{background-color:rgba(0,0,0,.05)}.navbar-burger.is-active span:nth-child(1){transform:translateY(5px) rotate(45deg)}.navbar-burger.is-active span:nth-child(2){opacity:0}.navbar-burger.is-active span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}.navbar-menu{display:none}.navbar-item,.navbar-link{color:#4a4a4a;display:block;line-height:1.5;padding:.5rem .75rem;position:relative}.navbar-item .icon:only-child,.navbar-link .icon:only-child{margin-left:-.25rem;margin-right:-.25rem}.navbar-link,a.navbar-item{cursor:pointer}.navbar-link.is-active,.navbar-link:focus,.navbar-link:focus-within,.navbar-link:hover,a.navbar-item.is-active,a.navbar-item:focus,a.navbar-item:focus-within,a.navbar-item:hover{background-color:#fafafa;color:#485fc7}.navbar-item{flex-grow:0;flex-shrink:0}.navbar-item img{max-height:1.75rem}.navbar-item.has-dropdown{padding:0}.navbar-item.is-expanded{flex-grow:1;flex-shrink:1}.navbar-item.is-tab{border-bottom:1px solid transparent;min-height:3.25rem;padding-bottom:calc(.5rem - 1px)}.navbar-item.is-tab:focus,.navbar-item.is-tab:hover{background-color:transparent;border-bottom-color:#485fc7}.navbar-item.is-tab.is-active{background-color:transparent;border-bottom-color:#485fc7;border-bottom-style:solid;border-bottom-width:3px;color:#485fc7;padding-bottom:calc(.5rem - 3px)}.navbar-content{flex-grow:1;flex-shrink:1}.navbar-link:not(.is-arrowless){padding-right:2.5em}.navbar-link:not(.is-arrowless)::after{border-color:#485fc7;margin-top:-.375em;right:1.125em}.navbar-dropdown{font-size:.875rem;padding-bottom:.5rem;padding-top:.5rem}.navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}.navbar-divider{background-color:#f5f5f5;border:none;display:none;height:2px;margin:.5rem 0}@media screen and (max-width:1023px){.navbar>.container{display:block}.navbar-brand .navbar-item,.navbar-tabs .navbar-item{align-items:center;display:flex}.navbar-link::after{display:none}.navbar-menu{background-color:#fff;box-shadow:0 8px 16px rgba(10,10,10,.1);padding:.5rem 0}.navbar-menu.is-active{display:block}.navbar.is-fixed-bottom-touch,.navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-touch{bottom:0}.navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,.1)}.navbar.is-fixed-top-touch{top:0}.navbar.is-fixed-top .navbar-menu,.navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 3.25rem);overflow:auto}body.has-navbar-fixed-top-touch,html.has-navbar-fixed-top-touch{padding-top:3.25rem}body.has-navbar-fixed-bottom-touch,html.has-navbar-fixed-bottom-touch{padding-bottom:3.25rem}}@media screen and (min-width:1024px){.navbar,.navbar-end,.navbar-menu,.navbar-start{align-items:stretch;display:flex}.navbar{min-height:3.25rem}.navbar.is-spaced{padding:1rem 2rem}.navbar.is-spaced .navbar-end,.navbar.is-spaced .navbar-start{align-items:center}.navbar.is-spaced .navbar-link,.navbar.is-spaced a.navbar-item{border-radius:4px}.navbar.is-transparent .navbar-link.is-active,.navbar.is-transparent .navbar-link:focus,.navbar.is-transparent .navbar-link:hover,.navbar.is-transparent a.navbar-item.is-active,.navbar.is-transparent a.navbar-item:focus,.navbar.is-transparent a.navbar-item:hover{background-color:transparent!important}.navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent!important}.navbar.is-transparent .navbar-dropdown a.navbar-item:focus,.navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#485fc7}.navbar-burger{display:none}.navbar-item,.navbar-link{align-items:center;display:flex}.navbar-item.has-dropdown{align-items:stretch}.navbar-item.has-dropdown-up .navbar-link::after{transform:rotate(135deg) translate(.25em,-.25em)}.navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:2px solid #dbdbdb;border-radius:6px 6px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,.1);top:auto}.navbar-item.is-active .navbar-dropdown,.navbar-item.is-hoverable:focus .navbar-dropdown,.navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar-item.is-active .navbar-dropdown.is-boxed,.navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed,.navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed,.navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-active .navbar-dropdown,.navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown,.navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown{opacity:1;pointer-events:auto;transform:translateY(0)}.navbar-menu{flex-grow:1;flex-shrink:0}.navbar-start{justify-content:flex-start;margin-right:auto}.navbar-end{justify-content:flex-end;margin-left:auto}.navbar-dropdown{background-color:#fff;border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:2px solid #dbdbdb;box-shadow:0 8px 8px rgba(10,10,10,.1);display:none;font-size:.875rem;left:0;min-width:100%;position:absolute;top:100%;z-index:20}.navbar-dropdown .navbar-item{padding:.375rem 1rem;white-space:nowrap}.navbar-dropdown a.navbar-item{padding-right:3rem}.navbar-dropdown a.navbar-item:focus,.navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#485fc7}.navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-dropdown{border-radius:6px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));transform:translateY(-5px);transition-duration:86ms;transition-property:opacity,transform}.navbar-dropdown.is-right{left:auto;right:0}.navbar-divider{display:block}.container>.navbar .navbar-brand,.navbar>.container .navbar-brand{margin-left:-.75rem}.container>.navbar .navbar-menu,.navbar>.container .navbar-menu{margin-right:-.75rem}.navbar.is-fixed-bottom-desktop,.navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-desktop{bottom:0}.navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,.1)}.navbar.is-fixed-top-desktop{top:0}body.has-navbar-fixed-top-desktop,html.has-navbar-fixed-top-desktop{padding-top:3.25rem}body.has-navbar-fixed-bottom-desktop,html.has-navbar-fixed-bottom-desktop{padding-bottom:3.25rem}body.has-spaced-navbar-fixed-top,html.has-spaced-navbar-fixed-top{padding-top:5.25rem}body.has-spaced-navbar-fixed-bottom,html.has-spaced-navbar-fixed-bottom{padding-bottom:5.25rem}.navbar-link.is-active,a.navbar-item.is-active{color:#0a0a0a}.navbar-link.is-active:not(:focus):not(:hover),a.navbar-item.is-active:not(:focus):not(:hover){background-color:transparent}.navbar-item.has-dropdown.is-active .navbar-link,.navbar-item.has-dropdown:focus .navbar-link,.navbar-item.has-dropdown:hover .navbar-link{background-color:#fafafa}}.hero.is-fullheight-with-navbar{min-height:calc(100vh - 3.25rem)}.pagination{font-size:1rem;margin:-.25rem}.pagination.is-small{font-size:.75rem}.pagination.is-medium{font-size:1.25rem}.pagination.is-large{font-size:1.5rem}.pagination.is-rounded .pagination-next,.pagination.is-rounded .pagination-previous{padding-left:1em;padding-right:1em;border-radius:9999px}.pagination.is-rounded .pagination-link{border-radius:9999px}.pagination,.pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous{font-size:1em;justify-content:center;margin:.25rem;padding-left:.5em;padding-right:.5em;text-align:center}.pagination-link,.pagination-next,.pagination-previous{border-color:#dbdbdb;color:#363636;min-width:2.5em}.pagination-link:hover,.pagination-next:hover,.pagination-previous:hover{border-color:#b5b5b5;color:#363636}.pagination-link:focus,.pagination-next:focus,.pagination-previous:focus{border-color:#485fc7}.pagination-link:active,.pagination-next:active,.pagination-previous:active{box-shadow:inset 0 1px 2px rgba(10,10,10,.2)}.pagination-link[disabled],.pagination-next[disabled],.pagination-previous[disabled]{background-color:#dbdbdb;border-color:#dbdbdb;box-shadow:none;color:#7a7a7a;opacity:.5}.pagination-next,.pagination-previous{padding-left:.75em;padding-right:.75em;white-space:nowrap}.pagination-link.is-current{background-color:#485fc7;border-color:#485fc7;color:#fff}.pagination-ellipsis{color:#b5b5b5;pointer-events:none}.pagination-list{flex-wrap:wrap}.pagination-list li{list-style:none}@media screen and (max-width:768px){.pagination{flex-wrap:wrap}.pagination-next,.pagination-previous{flex-grow:1;flex-shrink:1}.pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width:769px),print{.pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous{margin-bottom:0;margin-top:0}.pagination-previous{order:2}.pagination-next{order:3}.pagination{justify-content:space-between;margin-bottom:0;margin-top:0}.pagination.is-centered .pagination-previous{order:1}.pagination.is-centered .pagination-list{justify-content:center;order:2}.pagination.is-centered .pagination-next{order:3}.pagination.is-right .pagination-previous{order:1}.pagination.is-right .pagination-next{order:2}.pagination.is-right .pagination-list{justify-content:flex-end;order:3}}.panel{border-radius:6px;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);font-size:1rem}.panel:not(:last-child){margin-bottom:1.5rem}.panel.is-white .panel-heading{background-color:#fff;color:#0a0a0a}.panel.is-white .panel-tabs a.is-active{border-bottom-color:#fff}.panel.is-white .panel-block.is-active .panel-icon{color:#fff}.panel.is-black .panel-heading{background-color:#0a0a0a;color:#fff}.panel.is-black .panel-tabs a.is-active{border-bottom-color:#0a0a0a}.panel.is-black .panel-block.is-active .panel-icon{color:#0a0a0a}.panel.is-light .panel-heading{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.panel.is-light .panel-tabs a.is-active{border-bottom-color:#f5f5f5}.panel.is-light .panel-block.is-active .panel-icon{color:#f5f5f5}.panel.is-dark .panel-heading{background-color:#363636;color:#fff}.panel.is-dark .panel-tabs a.is-active{border-bottom-color:#363636}.panel.is-dark .panel-block.is-active .panel-icon{color:#363636}.panel.is-primary .panel-heading{background-color:#00d1b2;color:#fff}.panel.is-primary .panel-tabs a.is-active{border-bottom-color:#00d1b2}.panel.is-primary .panel-block.is-active .panel-icon{color:#00d1b2}.panel.is-link .panel-heading{background-color:#485fc7;color:#fff}.panel.is-link .panel-tabs a.is-active{border-bottom-color:#485fc7}.panel.is-link .panel-block.is-active .panel-icon{color:#485fc7}.panel.is-info .panel-heading{background-color:#3e8ed0;color:#fff}.panel.is-info .panel-tabs a.is-active{border-bottom-color:#3e8ed0}.panel.is-info .panel-block.is-active .panel-icon{color:#3e8ed0}.panel.is-success .panel-heading{background-color:#48c78e;color:#fff}.panel.is-success .panel-tabs a.is-active{border-bottom-color:#48c78e}.panel.is-success .panel-block.is-active .panel-icon{color:#48c78e}.panel.is-warning .panel-heading{background-color:#ffe08a;color:rgba(0,0,0,.7)}.panel.is-warning .panel-tabs a.is-active{border-bottom-color:#ffe08a}.panel.is-warning .panel-block.is-active .panel-icon{color:#ffe08a}.panel.is-danger .panel-heading{background-color:#f14668;color:#fff}.panel.is-danger .panel-tabs a.is-active{border-bottom-color:#f14668}.panel.is-danger .panel-block.is-active .panel-icon{color:#f14668}.panel-block:not(:last-child),.panel-tabs:not(:last-child){border-bottom:1px solid #ededed}.panel-heading{background-color:#ededed;border-radius:6px 6px 0 0;color:#363636;font-size:1.25em;font-weight:700;line-height:1.25;padding:.75em 1em}.panel-tabs{align-items:flex-end;display:flex;font-size:.875em;justify-content:center}.panel-tabs a{border-bottom:1px solid #dbdbdb;margin-bottom:-1px;padding:.5em}.panel-tabs a.is-active{border-bottom-color:#4a4a4a;color:#363636}.panel-list a{color:#4a4a4a}.panel-list a:hover{color:#485fc7}.panel-block{align-items:center;color:#363636;display:flex;justify-content:flex-start;padding:.5em .75em}.panel-block input[type=checkbox]{margin-right:.75em}.panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}.panel-block.is-wrapped{flex-wrap:wrap}.panel-block.is-active{border-left-color:#485fc7;color:#363636}.panel-block.is-active .panel-icon{color:#485fc7}.panel-block:last-child{border-bottom-left-radius:6px;border-bottom-right-radius:6px}a.panel-block,label.panel-block{cursor:pointer}a.panel-block:hover,label.panel-block:hover{background-color:#f5f5f5}.panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#7a7a7a;margin-right:.75em}.panel-icon .fa{font-size:inherit;line-height:inherit}.tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:1rem;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}.tabs a{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;color:#4a4a4a;display:flex;justify-content:center;margin-bottom:-1px;padding:.5em 1em;vertical-align:top}.tabs a:hover{border-bottom-color:#363636;color:#363636}.tabs li{display:block}.tabs li.is-active a{border-bottom-color:#485fc7;color:#485fc7}.tabs ul{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}.tabs ul.is-left{padding-right:.75em}.tabs ul.is-center{flex:none;justify-content:center;padding-left:.75em;padding-right:.75em}.tabs ul.is-right{justify-content:flex-end;padding-left:.75em}.tabs .icon:first-child{margin-right:.5em}.tabs .icon:last-child{margin-left:.5em}.tabs.is-centered ul{justify-content:center}.tabs.is-right ul{justify-content:flex-end}.tabs.is-boxed a{border:1px solid transparent;border-radius:4px 4px 0 0}.tabs.is-boxed a:hover{background-color:#f5f5f5;border-bottom-color:#dbdbdb}.tabs.is-boxed li.is-active a{background-color:#fff;border-color:#dbdbdb;border-bottom-color:transparent!important}.tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}.tabs.is-toggle a{border-color:#dbdbdb;border-style:solid;border-width:1px;margin-bottom:0;position:relative}.tabs.is-toggle a:hover{background-color:#f5f5f5;border-color:#b5b5b5;z-index:2}.tabs.is-toggle li+li{margin-left:-1px}.tabs.is-toggle li:first-child a{border-top-left-radius:4px;border-bottom-left-radius:4px}.tabs.is-toggle li:last-child a{border-top-right-radius:4px;border-bottom-right-radius:4px}.tabs.is-toggle li.is-active a{background-color:#485fc7;border-color:#485fc7;color:#fff;z-index:1}.tabs.is-toggle ul{border-bottom:none}.tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-left-radius:9999px;border-top-left-radius:9999px;padding-left:1.25em}.tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:9999px;border-top-right-radius:9999px;padding-right:1.25em}.tabs.is-small{font-size:.75rem}.tabs.is-medium{font-size:1.25rem}.tabs.is-large{font-size:1.5rem}.column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>.column.is-narrow{flex:none;width:unset}.columns.is-mobile>.column.is-full{flex:none;width:100%}.columns.is-mobile>.column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>.column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>.column.is-half{flex:none;width:50%}.columns.is-mobile>.column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>.column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>.column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>.column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>.column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>.column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>.column.is-offset-three-quarters{margin-left:75%}.columns.is-mobile>.column.is-offset-two-thirds{margin-left:66.6666%}.columns.is-mobile>.column.is-offset-half{margin-left:50%}.columns.is-mobile>.column.is-offset-one-third{margin-left:33.3333%}.columns.is-mobile>.column.is-offset-one-quarter{margin-left:25%}.columns.is-mobile>.column.is-offset-one-fifth{margin-left:20%}.columns.is-mobile>.column.is-offset-two-fifths{margin-left:40%}.columns.is-mobile>.column.is-offset-three-fifths{margin-left:60%}.columns.is-mobile>.column.is-offset-four-fifths{margin-left:80%}.columns.is-mobile>.column.is-0{flex:none;width:0%}.columns.is-mobile>.column.is-offset-0{margin-left:0}.columns.is-mobile>.column.is-1{flex:none;width:8.33333%}.columns.is-mobile>.column.is-offset-1{margin-left:8.33333%}.columns.is-mobile>.column.is-2{flex:none;width:16.66667%}.columns.is-mobile>.column.is-offset-2{margin-left:16.66667%}.columns.is-mobile>.column.is-3{flex:none;width:25%}.columns.is-mobile>.column.is-offset-3{margin-left:25%}.columns.is-mobile>.column.is-4{flex:none;width:33.33333%}.columns.is-mobile>.column.is-offset-4{margin-left:33.33333%}.columns.is-mobile>.column.is-5{flex:none;width:41.66667%}.columns.is-mobile>.column.is-offset-5{margin-left:41.66667%}.columns.is-mobile>.column.is-6{flex:none;width:50%}.columns.is-mobile>.column.is-offset-6{margin-left:50%}.columns.is-mobile>.column.is-7{flex:none;width:58.33333%}.columns.is-mobile>.column.is-offset-7{margin-left:58.33333%}.columns.is-mobile>.column.is-8{flex:none;width:66.66667%}.columns.is-mobile>.column.is-offset-8{margin-left:66.66667%}.columns.is-mobile>.column.is-9{flex:none;width:75%}.columns.is-mobile>.column.is-offset-9{margin-left:75%}.columns.is-mobile>.column.is-10{flex:none;width:83.33333%}.columns.is-mobile>.column.is-offset-10{margin-left:83.33333%}.columns.is-mobile>.column.is-11{flex:none;width:91.66667%}.columns.is-mobile>.column.is-offset-11{margin-left:91.66667%}.columns.is-mobile>.column.is-12{flex:none;width:100%}.columns.is-mobile>.column.is-offset-12{margin-left:100%}@media screen and (max-width:768px){.column.is-narrow-mobile{flex:none;width:unset}.column.is-full-mobile{flex:none;width:100%}.column.is-three-quarters-mobile{flex:none;width:75%}.column.is-two-thirds-mobile{flex:none;width:66.6666%}.column.is-half-mobile{flex:none;width:50%}.column.is-one-third-mobile{flex:none;width:33.3333%}.column.is-one-quarter-mobile{flex:none;width:25%}.column.is-one-fifth-mobile{flex:none;width:20%}.column.is-two-fifths-mobile{flex:none;width:40%}.column.is-three-fifths-mobile{flex:none;width:60%}.column.is-four-fifths-mobile{flex:none;width:80%}.column.is-offset-three-quarters-mobile{margin-left:75%}.column.is-offset-two-thirds-mobile{margin-left:66.6666%}.column.is-offset-half-mobile{margin-left:50%}.column.is-offset-one-third-mobile{margin-left:33.3333%}.column.is-offset-one-quarter-mobile{margin-left:25%}.column.is-offset-one-fifth-mobile{margin-left:20%}.column.is-offset-two-fifths-mobile{margin-left:40%}.column.is-offset-three-fifths-mobile{margin-left:60%}.column.is-offset-four-fifths-mobile{margin-left:80%}.column.is-0-mobile{flex:none;width:0%}.column.is-offset-0-mobile{margin-left:0}.column.is-1-mobile{flex:none;width:8.33333%}.column.is-offset-1-mobile{margin-left:8.33333%}.column.is-2-mobile{flex:none;width:16.66667%}.column.is-offset-2-mobile{margin-left:16.66667%}.column.is-3-mobile{flex:none;width:25%}.column.is-offset-3-mobile{margin-left:25%}.column.is-4-mobile{flex:none;width:33.33333%}.column.is-offset-4-mobile{margin-left:33.33333%}.column.is-5-mobile{flex:none;width:41.66667%}.column.is-offset-5-mobile{margin-left:41.66667%}.column.is-6-mobile{flex:none;width:50%}.column.is-offset-6-mobile{margin-left:50%}.column.is-7-mobile{flex:none;width:58.33333%}.column.is-offset-7-mobile{margin-left:58.33333%}.column.is-8-mobile{flex:none;width:66.66667%}.column.is-offset-8-mobile{margin-left:66.66667%}.column.is-9-mobile{flex:none;width:75%}.column.is-offset-9-mobile{margin-left:75%}.column.is-10-mobile{flex:none;width:83.33333%}.column.is-offset-10-mobile{margin-left:83.33333%}.column.is-11-mobile{flex:none;width:91.66667%}.column.is-offset-11-mobile{margin-left:91.66667%}.column.is-12-mobile{flex:none;width:100%}.column.is-offset-12-mobile{margin-left:100%}}@media screen and (min-width:769px),print{.column.is-narrow,.column.is-narrow-tablet{flex:none;width:unset}.column.is-full,.column.is-full-tablet{flex:none;width:100%}.column.is-three-quarters,.column.is-three-quarters-tablet{flex:none;width:75%}.column.is-two-thirds,.column.is-two-thirds-tablet{flex:none;width:66.6666%}.column.is-half,.column.is-half-tablet{flex:none;width:50%}.column.is-one-third,.column.is-one-third-tablet{flex:none;width:33.3333%}.column.is-one-quarter,.column.is-one-quarter-tablet{flex:none;width:25%}.column.is-one-fifth,.column.is-one-fifth-tablet{flex:none;width:20%}.column.is-two-fifths,.column.is-two-fifths-tablet{flex:none;width:40%}.column.is-three-fifths,.column.is-three-fifths-tablet{flex:none;width:60%}.column.is-four-fifths,.column.is-four-fifths-tablet{flex:none;width:80%}.column.is-offset-three-quarters,.column.is-offset-three-quarters-tablet{margin-left:75%}.column.is-offset-two-thirds,.column.is-offset-two-thirds-tablet{margin-left:66.6666%}.column.is-offset-half,.column.is-offset-half-tablet{margin-left:50%}.column.is-offset-one-third,.column.is-offset-one-third-tablet{margin-left:33.3333%}.column.is-offset-one-quarter,.column.is-offset-one-quarter-tablet{margin-left:25%}.column.is-offset-one-fifth,.column.is-offset-one-fifth-tablet{margin-left:20%}.column.is-offset-two-fifths,.column.is-offset-two-fifths-tablet{margin-left:40%}.column.is-offset-three-fifths,.column.is-offset-three-fifths-tablet{margin-left:60%}.column.is-offset-four-fifths,.column.is-offset-four-fifths-tablet{margin-left:80%}.column.is-0,.column.is-0-tablet{flex:none;width:0%}.column.is-offset-0,.column.is-offset-0-tablet{margin-left:0}.column.is-1,.column.is-1-tablet{flex:none;width:8.33333%}.column.is-offset-1,.column.is-offset-1-tablet{margin-left:8.33333%}.column.is-2,.column.is-2-tablet{flex:none;width:16.66667%}.column.is-offset-2,.column.is-offset-2-tablet{margin-left:16.66667%}.column.is-3,.column.is-3-tablet{flex:none;width:25%}.column.is-offset-3,.column.is-offset-3-tablet{margin-left:25%}.column.is-4,.column.is-4-tablet{flex:none;width:33.33333%}.column.is-offset-4,.column.is-offset-4-tablet{margin-left:33.33333%}.column.is-5,.column.is-5-tablet{flex:none;width:41.66667%}.column.is-offset-5,.column.is-offset-5-tablet{margin-left:41.66667%}.column.is-6,.column.is-6-tablet{flex:none;width:50%}.column.is-offset-6,.column.is-offset-6-tablet{margin-left:50%}.column.is-7,.column.is-7-tablet{flex:none;width:58.33333%}.column.is-offset-7,.column.is-offset-7-tablet{margin-left:58.33333%}.column.is-8,.column.is-8-tablet{flex:none;width:66.66667%}.column.is-offset-8,.column.is-offset-8-tablet{margin-left:66.66667%}.column.is-9,.column.is-9-tablet{flex:none;width:75%}.column.is-offset-9,.column.is-offset-9-tablet{margin-left:75%}.column.is-10,.column.is-10-tablet{flex:none;width:83.33333%}.column.is-offset-10,.column.is-offset-10-tablet{margin-left:83.33333%}.column.is-11,.column.is-11-tablet{flex:none;width:91.66667%}.column.is-offset-11,.column.is-offset-11-tablet{margin-left:91.66667%}.column.is-12,.column.is-12-tablet{flex:none;width:100%}.column.is-offset-12,.column.is-offset-12-tablet{margin-left:100%}}@media screen and (max-width:1023px){.column.is-narrow-touch{flex:none;width:unset}.column.is-full-touch{flex:none;width:100%}.column.is-three-quarters-touch{flex:none;width:75%}.column.is-two-thirds-touch{flex:none;width:66.6666%}.column.is-half-touch{flex:none;width:50%}.column.is-one-third-touch{flex:none;width:33.3333%}.column.is-one-quarter-touch{flex:none;width:25%}.column.is-one-fifth-touch{flex:none;width:20%}.column.is-two-fifths-touch{flex:none;width:40%}.column.is-three-fifths-touch{flex:none;width:60%}.column.is-four-fifths-touch{flex:none;width:80%}.column.is-offset-three-quarters-touch{margin-left:75%}.column.is-offset-two-thirds-touch{margin-left:66.6666%}.column.is-offset-half-touch{margin-left:50%}.column.is-offset-one-third-touch{margin-left:33.3333%}.column.is-offset-one-quarter-touch{margin-left:25%}.column.is-offset-one-fifth-touch{margin-left:20%}.column.is-offset-two-fifths-touch{margin-left:40%}.column.is-offset-three-fifths-touch{margin-left:60%}.column.is-offset-four-fifths-touch{margin-left:80%}.column.is-0-touch{flex:none;width:0%}.column.is-offset-0-touch{margin-left:0}.column.is-1-touch{flex:none;width:8.33333%}.column.is-offset-1-touch{margin-left:8.33333%}.column.is-2-touch{flex:none;width:16.66667%}.column.is-offset-2-touch{margin-left:16.66667%}.column.is-3-touch{flex:none;width:25%}.column.is-offset-3-touch{margin-left:25%}.column.is-4-touch{flex:none;width:33.33333%}.column.is-offset-4-touch{margin-left:33.33333%}.column.is-5-touch{flex:none;width:41.66667%}.column.is-offset-5-touch{margin-left:41.66667%}.column.is-6-touch{flex:none;width:50%}.column.is-offset-6-touch{margin-left:50%}.column.is-7-touch{flex:none;width:58.33333%}.column.is-offset-7-touch{margin-left:58.33333%}.column.is-8-touch{flex:none;width:66.66667%}.column.is-offset-8-touch{margin-left:66.66667%}.column.is-9-touch{flex:none;width:75%}.column.is-offset-9-touch{margin-left:75%}.column.is-10-touch{flex:none;width:83.33333%}.column.is-offset-10-touch{margin-left:83.33333%}.column.is-11-touch{flex:none;width:91.66667%}.column.is-offset-11-touch{margin-left:91.66667%}.column.is-12-touch{flex:none;width:100%}.column.is-offset-12-touch{margin-left:100%}}@media screen and (min-width:1024px){.column.is-narrow-desktop{flex:none;width:unset}.column.is-full-desktop{flex:none;width:100%}.column.is-three-quarters-desktop{flex:none;width:75%}.column.is-two-thirds-desktop{flex:none;width:66.6666%}.column.is-half-desktop{flex:none;width:50%}.column.is-one-third-desktop{flex:none;width:33.3333%}.column.is-one-quarter-desktop{flex:none;width:25%}.column.is-one-fifth-desktop{flex:none;width:20%}.column.is-two-fifths-desktop{flex:none;width:40%}.column.is-three-fifths-desktop{flex:none;width:60%}.column.is-four-fifths-desktop{flex:none;width:80%}.column.is-offset-three-quarters-desktop{margin-left:75%}.column.is-offset-two-thirds-desktop{margin-left:66.6666%}.column.is-offset-half-desktop{margin-left:50%}.column.is-offset-one-third-desktop{margin-left:33.3333%}.column.is-offset-one-quarter-desktop{margin-left:25%}.column.is-offset-one-fifth-desktop{margin-left:20%}.column.is-offset-two-fifths-desktop{margin-left:40%}.column.is-offset-three-fifths-desktop{margin-left:60%}.column.is-offset-four-fifths-desktop{margin-left:80%}.column.is-0-desktop{flex:none;width:0%}.column.is-offset-0-desktop{margin-left:0}.column.is-1-desktop{flex:none;width:8.33333%}.column.is-offset-1-desktop{margin-left:8.33333%}.column.is-2-desktop{flex:none;width:16.66667%}.column.is-offset-2-desktop{margin-left:16.66667%}.column.is-3-desktop{flex:none;width:25%}.column.is-offset-3-desktop{margin-left:25%}.column.is-4-desktop{flex:none;width:33.33333%}.column.is-offset-4-desktop{margin-left:33.33333%}.column.is-5-desktop{flex:none;width:41.66667%}.column.is-offset-5-desktop{margin-left:41.66667%}.column.is-6-desktop{flex:none;width:50%}.column.is-offset-6-desktop{margin-left:50%}.column.is-7-desktop{flex:none;width:58.33333%}.column.is-offset-7-desktop{margin-left:58.33333%}.column.is-8-desktop{flex:none;width:66.66667%}.column.is-offset-8-desktop{margin-left:66.66667%}.column.is-9-desktop{flex:none;width:75%}.column.is-offset-9-desktop{margin-left:75%}.column.is-10-desktop{flex:none;width:83.33333%}.column.is-offset-10-desktop{margin-left:83.33333%}.column.is-11-desktop{flex:none;width:91.66667%}.column.is-offset-11-desktop{margin-left:91.66667%}.column.is-12-desktop{flex:none;width:100%}.column.is-offset-12-desktop{margin-left:100%}}@media screen and (min-width:1216px){.column.is-narrow-widescreen{flex:none;width:unset}.column.is-full-widescreen{flex:none;width:100%}.column.is-three-quarters-widescreen{flex:none;width:75%}.column.is-two-thirds-widescreen{flex:none;width:66.6666%}.column.is-half-widescreen{flex:none;width:50%}.column.is-one-third-widescreen{flex:none;width:33.3333%}.column.is-one-quarter-widescreen{flex:none;width:25%}.column.is-one-fifth-widescreen{flex:none;width:20%}.column.is-two-fifths-widescreen{flex:none;width:40%}.column.is-three-fifths-widescreen{flex:none;width:60%}.column.is-four-fifths-widescreen{flex:none;width:80%}.column.is-offset-three-quarters-widescreen{margin-left:75%}.column.is-offset-two-thirds-widescreen{margin-left:66.6666%}.column.is-offset-half-widescreen{margin-left:50%}.column.is-offset-one-third-widescreen{margin-left:33.3333%}.column.is-offset-one-quarter-widescreen{margin-left:25%}.column.is-offset-one-fifth-widescreen{margin-left:20%}.column.is-offset-two-fifths-widescreen{margin-left:40%}.column.is-offset-three-fifths-widescreen{margin-left:60%}.column.is-offset-four-fifths-widescreen{margin-left:80%}.column.is-0-widescreen{flex:none;width:0%}.column.is-offset-0-widescreen{margin-left:0}.column.is-1-widescreen{flex:none;width:8.33333%}.column.is-offset-1-widescreen{margin-left:8.33333%}.column.is-2-widescreen{flex:none;width:16.66667%}.column.is-offset-2-widescreen{margin-left:16.66667%}.column.is-3-widescreen{flex:none;width:25%}.column.is-offset-3-widescreen{margin-left:25%}.column.is-4-widescreen{flex:none;width:33.33333%}.column.is-offset-4-widescreen{margin-left:33.33333%}.column.is-5-widescreen{flex:none;width:41.66667%}.column.is-offset-5-widescreen{margin-left:41.66667%}.column.is-6-widescreen{flex:none;width:50%}.column.is-offset-6-widescreen{margin-left:50%}.column.is-7-widescreen{flex:none;width:58.33333%}.column.is-offset-7-widescreen{margin-left:58.33333%}.column.is-8-widescreen{flex:none;width:66.66667%}.column.is-offset-8-widescreen{margin-left:66.66667%}.column.is-9-widescreen{flex:none;width:75%}.column.is-offset-9-widescreen{margin-left:75%}.column.is-10-widescreen{flex:none;width:83.33333%}.column.is-offset-10-widescreen{margin-left:83.33333%}.column.is-11-widescreen{flex:none;width:91.66667%}.column.is-offset-11-widescreen{margin-left:91.66667%}.column.is-12-widescreen{flex:none;width:100%}.column.is-offset-12-widescreen{margin-left:100%}}@media screen and (min-width:1408px){.column.is-narrow-fullhd{flex:none;width:unset}.column.is-full-fullhd{flex:none;width:100%}.column.is-three-quarters-fullhd{flex:none;width:75%}.column.is-two-thirds-fullhd{flex:none;width:66.6666%}.column.is-half-fullhd{flex:none;width:50%}.column.is-one-third-fullhd{flex:none;width:33.3333%}.column.is-one-quarter-fullhd{flex:none;width:25%}.column.is-one-fifth-fullhd{flex:none;width:20%}.column.is-two-fifths-fullhd{flex:none;width:40%}.column.is-three-fifths-fullhd{flex:none;width:60%}.column.is-four-fifths-fullhd{flex:none;width:80%}.column.is-offset-three-quarters-fullhd{margin-left:75%}.column.is-offset-two-thirds-fullhd{margin-left:66.6666%}.column.is-offset-half-fullhd{margin-left:50%}.column.is-offset-one-third-fullhd{margin-left:33.3333%}.column.is-offset-one-quarter-fullhd{margin-left:25%}.column.is-offset-one-fifth-fullhd{margin-left:20%}.column.is-offset-two-fifths-fullhd{margin-left:40%}.column.is-offset-three-fifths-fullhd{margin-left:60%}.column.is-offset-four-fifths-fullhd{margin-left:80%}.column.is-0-fullhd{flex:none;width:0%}.column.is-offset-0-fullhd{margin-left:0}.column.is-1-fullhd{flex:none;width:8.33333%}.column.is-offset-1-fullhd{margin-left:8.33333%}.column.is-2-fullhd{flex:none;width:16.66667%}.column.is-offset-2-fullhd{margin-left:16.66667%}.column.is-3-fullhd{flex:none;width:25%}.column.is-offset-3-fullhd{margin-left:25%}.column.is-4-fullhd{flex:none;width:33.33333%}.column.is-offset-4-fullhd{margin-left:33.33333%}.column.is-5-fullhd{flex:none;width:41.66667%}.column.is-offset-5-fullhd{margin-left:41.66667%}.column.is-6-fullhd{flex:none;width:50%}.column.is-offset-6-fullhd{margin-left:50%}.column.is-7-fullhd{flex:none;width:58.33333%}.column.is-offset-7-fullhd{margin-left:58.33333%}.column.is-8-fullhd{flex:none;width:66.66667%}.column.is-offset-8-fullhd{margin-left:66.66667%}.column.is-9-fullhd{flex:none;width:75%}.column.is-offset-9-fullhd{margin-left:75%}.column.is-10-fullhd{flex:none;width:83.33333%}.column.is-offset-10-fullhd{margin-left:83.33333%}.column.is-11-fullhd{flex:none;width:91.66667%}.column.is-offset-11-fullhd{margin-left:91.66667%}.column.is-12-fullhd{flex:none;width:100%}.column.is-offset-12-fullhd{margin-left:100%}}.columns{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.columns:last-child{margin-bottom:-.75rem}.columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}.columns.is-centered{justify-content:center}.columns.is-gapless{margin-left:0;margin-right:0;margin-top:0}.columns.is-gapless>.column{margin:0;padding:0!important}.columns.is-gapless:not(:last-child){margin-bottom:1.5rem}.columns.is-gapless:last-child{margin-bottom:0}.columns.is-mobile{display:flex}.columns.is-multiline{flex-wrap:wrap}.columns.is-vcentered{align-items:center}@media screen and (min-width:769px),print{.columns:not(.is-desktop){display:flex}}@media screen and (min-width:1024px){.columns.is-desktop{display:flex}}.columns.is-variable{--columnGap:0.75rem;margin-left:calc(-1 * var(--columnGap));margin-right:calc(-1 * var(--columnGap))}.columns.is-variable>.column{padding-left:var(--columnGap);padding-right:var(--columnGap)}.columns.is-variable.is-0{--columnGap:0rem}@media screen and (max-width:768px){.columns.is-variable.is-0-mobile{--columnGap:0rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-0-tablet{--columnGap:0rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-0-tablet-only{--columnGap:0rem}}@media screen and (max-width:1023px){.columns.is-variable.is-0-touch{--columnGap:0rem}}@media screen and (min-width:1024px){.columns.is-variable.is-0-desktop{--columnGap:0rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-0-desktop-only{--columnGap:0rem}}@media screen and (min-width:1216px){.columns.is-variable.is-0-widescreen{--columnGap:0rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-0-widescreen-only{--columnGap:0rem}}@media screen and (min-width:1408px){.columns.is-variable.is-0-fullhd{--columnGap:0rem}}.columns.is-variable.is-1{--columnGap:0.25rem}@media screen and (max-width:768px){.columns.is-variable.is-1-mobile{--columnGap:0.25rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-1-tablet{--columnGap:0.25rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-1-tablet-only{--columnGap:0.25rem}}@media screen and (max-width:1023px){.columns.is-variable.is-1-touch{--columnGap:0.25rem}}@media screen and (min-width:1024px){.columns.is-variable.is-1-desktop{--columnGap:0.25rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-1-desktop-only{--columnGap:0.25rem}}@media screen and (min-width:1216px){.columns.is-variable.is-1-widescreen{--columnGap:0.25rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-1-widescreen-only{--columnGap:0.25rem}}@media screen and (min-width:1408px){.columns.is-variable.is-1-fullhd{--columnGap:0.25rem}}.columns.is-variable.is-2{--columnGap:0.5rem}@media screen and (max-width:768px){.columns.is-variable.is-2-mobile{--columnGap:0.5rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-2-tablet{--columnGap:0.5rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-2-tablet-only{--columnGap:0.5rem}}@media screen and (max-width:1023px){.columns.is-variable.is-2-touch{--columnGap:0.5rem}}@media screen and (min-width:1024px){.columns.is-variable.is-2-desktop{--columnGap:0.5rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-2-desktop-only{--columnGap:0.5rem}}@media screen and (min-width:1216px){.columns.is-variable.is-2-widescreen{--columnGap:0.5rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-2-widescreen-only{--columnGap:0.5rem}}@media screen and (min-width:1408px){.columns.is-variable.is-2-fullhd{--columnGap:0.5rem}}.columns.is-variable.is-3{--columnGap:0.75rem}@media screen and (max-width:768px){.columns.is-variable.is-3-mobile{--columnGap:0.75rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-3-tablet{--columnGap:0.75rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-3-tablet-only{--columnGap:0.75rem}}@media screen and (max-width:1023px){.columns.is-variable.is-3-touch{--columnGap:0.75rem}}@media screen and (min-width:1024px){.columns.is-variable.is-3-desktop{--columnGap:0.75rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-3-desktop-only{--columnGap:0.75rem}}@media screen and (min-width:1216px){.columns.is-variable.is-3-widescreen{--columnGap:0.75rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-3-widescreen-only{--columnGap:0.75rem}}@media screen and (min-width:1408px){.columns.is-variable.is-3-fullhd{--columnGap:0.75rem}}.columns.is-variable.is-4{--columnGap:1rem}@media screen and (max-width:768px){.columns.is-variable.is-4-mobile{--columnGap:1rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-4-tablet{--columnGap:1rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-4-tablet-only{--columnGap:1rem}}@media screen and (max-width:1023px){.columns.is-variable.is-4-touch{--columnGap:1rem}}@media screen and (min-width:1024px){.columns.is-variable.is-4-desktop{--columnGap:1rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-4-desktop-only{--columnGap:1rem}}@media screen and (min-width:1216px){.columns.is-variable.is-4-widescreen{--columnGap:1rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-4-widescreen-only{--columnGap:1rem}}@media screen and (min-width:1408px){.columns.is-variable.is-4-fullhd{--columnGap:1rem}}.columns.is-variable.is-5{--columnGap:1.25rem}@media screen and (max-width:768px){.columns.is-variable.is-5-mobile{--columnGap:1.25rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-5-tablet{--columnGap:1.25rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-5-tablet-only{--columnGap:1.25rem}}@media screen and (max-width:1023px){.columns.is-variable.is-5-touch{--columnGap:1.25rem}}@media screen and (min-width:1024px){.columns.is-variable.is-5-desktop{--columnGap:1.25rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-5-desktop-only{--columnGap:1.25rem}}@media screen and (min-width:1216px){.columns.is-variable.is-5-widescreen{--columnGap:1.25rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-5-widescreen-only{--columnGap:1.25rem}}@media screen and (min-width:1408px){.columns.is-variable.is-5-fullhd{--columnGap:1.25rem}}.columns.is-variable.is-6{--columnGap:1.5rem}@media screen and (max-width:768px){.columns.is-variable.is-6-mobile{--columnGap:1.5rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-6-tablet{--columnGap:1.5rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-6-tablet-only{--columnGap:1.5rem}}@media screen and (max-width:1023px){.columns.is-variable.is-6-touch{--columnGap:1.5rem}}@media screen and (min-width:1024px){.columns.is-variable.is-6-desktop{--columnGap:1.5rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-6-desktop-only{--columnGap:1.5rem}}@media screen and (min-width:1216px){.columns.is-variable.is-6-widescreen{--columnGap:1.5rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-6-widescreen-only{--columnGap:1.5rem}}@media screen and (min-width:1408px){.columns.is-variable.is-6-fullhd{--columnGap:1.5rem}}.columns.is-variable.is-7{--columnGap:1.75rem}@media screen and (max-width:768px){.columns.is-variable.is-7-mobile{--columnGap:1.75rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-7-tablet{--columnGap:1.75rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-7-tablet-only{--columnGap:1.75rem}}@media screen and (max-width:1023px){.columns.is-variable.is-7-touch{--columnGap:1.75rem}}@media screen and (min-width:1024px){.columns.is-variable.is-7-desktop{--columnGap:1.75rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-7-desktop-only{--columnGap:1.75rem}}@media screen and (min-width:1216px){.columns.is-variable.is-7-widescreen{--columnGap:1.75rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-7-widescreen-only{--columnGap:1.75rem}}@media screen and (min-width:1408px){.columns.is-variable.is-7-fullhd{--columnGap:1.75rem}}.columns.is-variable.is-8{--columnGap:2rem}@media screen and (max-width:768px){.columns.is-variable.is-8-mobile{--columnGap:2rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-8-tablet{--columnGap:2rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-8-tablet-only{--columnGap:2rem}}@media screen and (max-width:1023px){.columns.is-variable.is-8-touch{--columnGap:2rem}}@media screen and (min-width:1024px){.columns.is-variable.is-8-desktop{--columnGap:2rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-8-desktop-only{--columnGap:2rem}}@media screen and (min-width:1216px){.columns.is-variable.is-8-widescreen{--columnGap:2rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-8-widescreen-only{--columnGap:2rem}}@media screen and (min-width:1408px){.columns.is-variable.is-8-fullhd{--columnGap:2rem}}.tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:-webkit-min-content;min-height:-moz-min-content;min-height:min-content}.tile.is-ancestor{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.tile.is-ancestor:last-child{margin-bottom:-.75rem}.tile.is-ancestor:not(:last-child){margin-bottom:.75rem}.tile.is-child{margin:0!important}.tile.is-parent{padding:.75rem}.tile.is-vertical{flex-direction:column}.tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem!important}@media screen and (min-width:769px),print{.tile:not(.is-child){display:flex}.tile.is-1{flex:none;width:8.33333%}.tile.is-2{flex:none;width:16.66667%}.tile.is-3{flex:none;width:25%}.tile.is-4{flex:none;width:33.33333%}.tile.is-5{flex:none;width:41.66667%}.tile.is-6{flex:none;width:50%}.tile.is-7{flex:none;width:58.33333%}.tile.is-8{flex:none;width:66.66667%}.tile.is-9{flex:none;width:75%}.tile.is-10{flex:none;width:83.33333%}.tile.is-11{flex:none;width:91.66667%}.tile.is-12{flex:none;width:100%}}.has-text-white{color:#fff!important}a.has-text-white:focus,a.has-text-white:hover{color:#e6e6e6!important}.has-background-white{background-color:#fff!important}.has-text-black{color:#0a0a0a!important}a.has-text-black:focus,a.has-text-black:hover{color:#000!important}.has-background-black{background-color:#0a0a0a!important}.has-text-light{color:#f5f5f5!important}a.has-text-light:focus,a.has-text-light:hover{color:#dbdbdb!important}.has-background-light{background-color:#f5f5f5!important}.has-text-dark{color:#363636!important}a.has-text-dark:focus,a.has-text-dark:hover{color:#1c1c1c!important}.has-background-dark{background-color:#363636!important}.has-text-primary{color:#00d1b2!important}a.has-text-primary:focus,a.has-text-primary:hover{color:#009e86!important}.has-background-primary{background-color:#00d1b2!important}.has-text-primary-light{color:#ebfffc!important}a.has-text-primary-light:focus,a.has-text-primary-light:hover{color:#b8fff4!important}.has-background-primary-light{background-color:#ebfffc!important}.has-text-primary-dark{color:#00947e!important}a.has-text-primary-dark:focus,a.has-text-primary-dark:hover{color:#00c7a9!important}.has-background-primary-dark{background-color:#00947e!important}.has-text-link{color:#485fc7!important}a.has-text-link:focus,a.has-text-link:hover{color:#3449a8!important}.has-background-link{background-color:#485fc7!important}.has-text-link-light{color:#eff1fa!important}a.has-text-link-light:focus,a.has-text-link-light:hover{color:#c8cfee!important}.has-background-link-light{background-color:#eff1fa!important}.has-text-link-dark{color:#3850b7!important}a.has-text-link-dark:focus,a.has-text-link-dark:hover{color:#576dcb!important}.has-background-link-dark{background-color:#3850b7!important}.has-text-info{color:#3e8ed0!important}a.has-text-info:focus,a.has-text-info:hover{color:#2b74b1!important}.has-background-info{background-color:#3e8ed0!important}.has-text-info-light{color:#eff5fb!important}a.has-text-info-light:focus,a.has-text-info-light:hover{color:#c6ddf1!important}.has-background-info-light{background-color:#eff5fb!important}.has-text-info-dark{color:#296fa8!important}a.has-text-info-dark:focus,a.has-text-info-dark:hover{color:#368ace!important}.has-background-info-dark{background-color:#296fa8!important}.has-text-success{color:#48c78e!important}a.has-text-success:focus,a.has-text-success:hover{color:#34a873!important}.has-background-success{background-color:#48c78e!important}.has-text-success-light{color:#effaf5!important}a.has-text-success-light:focus,a.has-text-success-light:hover{color:#c8eedd!important}.has-background-success-light{background-color:#effaf5!important}.has-text-success-dark{color:#257953!important}a.has-text-success-dark:focus,a.has-text-success-dark:hover{color:#31a06e!important}.has-background-success-dark{background-color:#257953!important}.has-text-warning{color:#ffe08a!important}a.has-text-warning:focus,a.has-text-warning:hover{color:#ffd257!important}.has-background-warning{background-color:#ffe08a!important}.has-text-warning-light{color:#fffaeb!important}a.has-text-warning-light:focus,a.has-text-warning-light:hover{color:#ffecb8!important}.has-background-warning-light{background-color:#fffaeb!important}.has-text-warning-dark{color:#946c00!important}a.has-text-warning-dark:focus,a.has-text-warning-dark:hover{color:#c79200!important}.has-background-warning-dark{background-color:#946c00!important}.has-text-danger{color:#f14668!important}a.has-text-danger:focus,a.has-text-danger:hover{color:#ee1742!important}.has-background-danger{background-color:#f14668!important}.has-text-danger-light{color:#feecf0!important}a.has-text-danger-light:focus,a.has-text-danger-light:hover{color:#fabdc9!important}.has-background-danger-light{background-color:#feecf0!important}.has-text-danger-dark{color:#cc0f35!important}a.has-text-danger-dark:focus,a.has-text-danger-dark:hover{color:#ee2049!important}.has-background-danger-dark{background-color:#cc0f35!important}.has-text-black-bis{color:#121212!important}.has-background-black-bis{background-color:#121212!important}.has-text-black-ter{color:#242424!important}.has-background-black-ter{background-color:#242424!important}.has-text-grey-darker{color:#363636!important}.has-background-grey-darker{background-color:#363636!important}.has-text-grey-dark{color:#4a4a4a!important}.has-background-grey-dark{background-color:#4a4a4a!important}.has-text-grey{color:#7a7a7a!important}.has-background-grey{background-color:#7a7a7a!important}.has-text-grey-light{color:#b5b5b5!important}.has-background-grey-light{background-color:#b5b5b5!important}.has-text-grey-lighter{color:#dbdbdb!important}.has-background-grey-lighter{background-color:#dbdbdb!important}.has-text-white-ter{color:#f5f5f5!important}.has-background-white-ter{background-color:#f5f5f5!important}.has-text-white-bis{color:#fafafa!important}.has-background-white-bis{background-color:#fafafa!important}.is-flex-direction-row{flex-direction:row!important}.is-flex-direction-row-reverse{flex-direction:row-reverse!important}.is-flex-direction-column{flex-direction:column!important}.is-flex-direction-column-reverse{flex-direction:column-reverse!important}.is-flex-wrap-nowrap{flex-wrap:nowrap!important}.is-flex-wrap-wrap{flex-wrap:wrap!important}.is-flex-wrap-wrap-reverse{flex-wrap:wrap-reverse!important}.is-justify-content-flex-start{justify-content:flex-start!important}.is-justify-content-flex-end{justify-content:flex-end!important}.is-justify-content-center{justify-content:center!important}.is-justify-content-space-between{justify-content:space-between!important}.is-justify-content-space-around{justify-content:space-around!important}.is-justify-content-space-evenly{justify-content:space-evenly!important}.is-justify-content-start{justify-content:start!important}.is-justify-content-end{justify-content:end!important}.is-justify-content-left{justify-content:left!important}.is-justify-content-right{justify-content:right!important}.is-align-content-flex-start{align-content:flex-start!important}.is-align-content-flex-end{align-content:flex-end!important}.is-align-content-center{align-content:center!important}.is-align-content-space-between{align-content:space-between!important}.is-align-content-space-around{align-content:space-around!important}.is-align-content-space-evenly{align-content:space-evenly!important}.is-align-content-stretch{align-content:stretch!important}.is-align-content-start{align-content:start!important}.is-align-content-end{align-content:end!important}.is-align-content-baseline{align-content:baseline!important}.is-align-items-stretch{align-items:stretch!important}.is-align-items-flex-start{align-items:flex-start!important}.is-align-items-flex-end{align-items:flex-end!important}.is-align-items-center{align-items:center!important}.is-align-items-baseline{align-items:baseline!important}.is-align-items-start{align-items:start!important}.is-align-items-end{align-items:end!important}.is-align-items-self-start{align-items:self-start!important}.is-align-items-self-end{align-items:self-end!important}.is-align-self-auto{align-self:auto!important}.is-align-self-flex-start{align-self:flex-start!important}.is-align-self-flex-end{align-self:flex-end!important}.is-align-self-center{align-self:center!important}.is-align-self-baseline{align-self:baseline!important}.is-align-self-stretch{align-self:stretch!important}.is-flex-grow-0{flex-grow:0!important}.is-flex-grow-1{flex-grow:1!important}.is-flex-grow-2{flex-grow:2!important}.is-flex-grow-3{flex-grow:3!important}.is-flex-grow-4{flex-grow:4!important}.is-flex-grow-5{flex-grow:5!important}.is-flex-shrink-0{flex-shrink:0!important}.is-flex-shrink-1{flex-shrink:1!important}.is-flex-shrink-2{flex-shrink:2!important}.is-flex-shrink-3{flex-shrink:3!important}.is-flex-shrink-4{flex-shrink:4!important}.is-flex-shrink-5{flex-shrink:5!important}.is-clearfix::after{clear:both;content:" ";display:table}.is-pulled-left{float:left!important}.is-pulled-right{float:right!important}.is-radiusless{border-radius:0!important}.is-shadowless{box-shadow:none!important}.is-clickable{cursor:pointer!important;pointer-events:all!important}.is-clipped{overflow:hidden!important}.is-relative{position:relative!important}.is-marginless{margin:0!important}.is-paddingless{padding:0!important}.m-0{margin:0!important}.mt-0{margin-top:0!important}.mr-0{margin-right:0!important}.mb-0{margin-bottom:0!important}.ml-0{margin-left:0!important}.mx-0{margin-left:0!important;margin-right:0!important}.my-0{margin-top:0!important;margin-bottom:0!important}.m-1{margin:.25rem!important}.mt-1{margin-top:.25rem!important}.mr-1{margin-right:.25rem!important}.mb-1{margin-bottom:.25rem!important}.ml-1{margin-left:.25rem!important}.mx-1{margin-left:.25rem!important;margin-right:.25rem!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-2{margin:.5rem!important}.mt-2{margin-top:.5rem!important}.mr-2{margin-right:.5rem!important}.mb-2{margin-bottom:.5rem!important}.ml-2{margin-left:.5rem!important}.mx-2{margin-left:.5rem!important;margin-right:.5rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-3{margin:.75rem!important}.mt-3{margin-top:.75rem!important}.mr-3{margin-right:.75rem!important}.mb-3{margin-bottom:.75rem!important}.ml-3{margin-left:.75rem!important}.mx-3{margin-left:.75rem!important;margin-right:.75rem!important}.my-3{margin-top:.75rem!important;margin-bottom:.75rem!important}.m-4{margin:1rem!important}.mt-4{margin-top:1rem!important}.mr-4{margin-right:1rem!important}.mb-4{margin-bottom:1rem!important}.ml-4{margin-left:1rem!important}.mx-4{margin-left:1rem!important;margin-right:1rem!important}.my-4{margin-top:1rem!important;margin-bottom:1rem!important}.m-5{margin:1.5rem!important}.mt-5{margin-top:1.5rem!important}.mr-5{margin-right:1.5rem!important}.mb-5{margin-bottom:1.5rem!important}.ml-5{margin-left:1.5rem!important}.mx-5{margin-left:1.5rem!important;margin-right:1.5rem!important}.my-5{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-6{margin:3rem!important}.mt-6{margin-top:3rem!important}.mr-6{margin-right:3rem!important}.mb-6{margin-bottom:3rem!important}.ml-6{margin-left:3rem!important}.mx-6{margin-left:3rem!important;margin-right:3rem!important}.my-6{margin-top:3rem!important;margin-bottom:3rem!important}.m-auto{margin:auto!important}.mt-auto{margin-top:auto!important}.mr-auto{margin-right:auto!important}.mb-auto{margin-bottom:auto!important}.ml-auto{margin-left:auto!important}.mx-auto{margin-left:auto!important;margin-right:auto!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.p-0{padding:0!important}.pt-0{padding-top:0!important}.pr-0{padding-right:0!important}.pb-0{padding-bottom:0!important}.pl-0{padding-left:0!important}.px-0{padding-left:0!important;padding-right:0!important}.py-0{padding-top:0!important;padding-bottom:0!important}.p-1{padding:.25rem!important}.pt-1{padding-top:.25rem!important}.pr-1{padding-right:.25rem!important}.pb-1{padding-bottom:.25rem!important}.pl-1{padding-left:.25rem!important}.px-1{padding-left:.25rem!important;padding-right:.25rem!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-2{padding:.5rem!important}.pt-2{padding-top:.5rem!important}.pr-2{padding-right:.5rem!important}.pb-2{padding-bottom:.5rem!important}.pl-2{padding-left:.5rem!important}.px-2{padding-left:.5rem!important;padding-right:.5rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-3{padding:.75rem!important}.pt-3{padding-top:.75rem!important}.pr-3{padding-right:.75rem!important}.pb-3{padding-bottom:.75rem!important}.pl-3{padding-left:.75rem!important}.px-3{padding-left:.75rem!important;padding-right:.75rem!important}.py-3{padding-top:.75rem!important;padding-bottom:.75rem!important}.p-4{padding:1rem!important}.pt-4{padding-top:1rem!important}.pr-4{padding-right:1rem!important}.pb-4{padding-bottom:1rem!important}.pl-4{padding-left:1rem!important}.px-4{padding-left:1rem!important;padding-right:1rem!important}.py-4{padding-top:1rem!important;padding-bottom:1rem!important}.p-5{padding:1.5rem!important}.pt-5{padding-top:1.5rem!important}.pr-5{padding-right:1.5rem!important}.pb-5{padding-bottom:1.5rem!important}.pl-5{padding-left:1.5rem!important}.px-5{padding-left:1.5rem!important;padding-right:1.5rem!important}.py-5{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-6{padding:3rem!important}.pt-6{padding-top:3rem!important}.pr-6{padding-right:3rem!important}.pb-6{padding-bottom:3rem!important}.pl-6{padding-left:3rem!important}.px-6{padding-left:3rem!important;padding-right:3rem!important}.py-6{padding-top:3rem!important;padding-bottom:3rem!important}.p-auto{padding:auto!important}.pt-auto{padding-top:auto!important}.pr-auto{padding-right:auto!important}.pb-auto{padding-bottom:auto!important}.pl-auto{padding-left:auto!important}.px-auto{padding-left:auto!important;padding-right:auto!important}.py-auto{padding-top:auto!important;padding-bottom:auto!important}.is-size-1{font-size:3rem!important}.is-size-2{font-size:2.5rem!important}.is-size-3{font-size:2rem!important}.is-size-4{font-size:1.5rem!important}.is-size-5{font-size:1.25rem!important}.is-size-6{font-size:1rem!important}.is-size-7{font-size:.75rem!important}@media screen and (max-width:768px){.is-size-1-mobile{font-size:3rem!important}.is-size-2-mobile{font-size:2.5rem!important}.is-size-3-mobile{font-size:2rem!important}.is-size-4-mobile{font-size:1.5rem!important}.is-size-5-mobile{font-size:1.25rem!important}.is-size-6-mobile{font-size:1rem!important}.is-size-7-mobile{font-size:.75rem!important}}@media screen and (min-width:769px),print{.is-size-1-tablet{font-size:3rem!important}.is-size-2-tablet{font-size:2.5rem!important}.is-size-3-tablet{font-size:2rem!important}.is-size-4-tablet{font-size:1.5rem!important}.is-size-5-tablet{font-size:1.25rem!important}.is-size-6-tablet{font-size:1rem!important}.is-size-7-tablet{font-size:.75rem!important}}@media screen and (max-width:1023px){.is-size-1-touch{font-size:3rem!important}.is-size-2-touch{font-size:2.5rem!important}.is-size-3-touch{font-size:2rem!important}.is-size-4-touch{font-size:1.5rem!important}.is-size-5-touch{font-size:1.25rem!important}.is-size-6-touch{font-size:1rem!important}.is-size-7-touch{font-size:.75rem!important}}@media screen and (min-width:1024px){.is-size-1-desktop{font-size:3rem!important}.is-size-2-desktop{font-size:2.5rem!important}.is-size-3-desktop{font-size:2rem!important}.is-size-4-desktop{font-size:1.5rem!important}.is-size-5-desktop{font-size:1.25rem!important}.is-size-6-desktop{font-size:1rem!important}.is-size-7-desktop{font-size:.75rem!important}}@media screen and (min-width:1216px){.is-size-1-widescreen{font-size:3rem!important}.is-size-2-widescreen{font-size:2.5rem!important}.is-size-3-widescreen{font-size:2rem!important}.is-size-4-widescreen{font-size:1.5rem!important}.is-size-5-widescreen{font-size:1.25rem!important}.is-size-6-widescreen{font-size:1rem!important}.is-size-7-widescreen{font-size:.75rem!important}}@media screen and (min-width:1408px){.is-size-1-fullhd{font-size:3rem!important}.is-size-2-fullhd{font-size:2.5rem!important}.is-size-3-fullhd{font-size:2rem!important}.is-size-4-fullhd{font-size:1.5rem!important}.is-size-5-fullhd{font-size:1.25rem!important}.is-size-6-fullhd{font-size:1rem!important}.is-size-7-fullhd{font-size:.75rem!important}}.has-text-centered{text-align:center!important}.has-text-justified{text-align:justify!important}.has-text-left{text-align:left!important}.has-text-right{text-align:right!important}@media screen and (max-width:768px){.has-text-centered-mobile{text-align:center!important}}@media screen and (min-width:769px),print{.has-text-centered-tablet{text-align:center!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-centered-tablet-only{text-align:center!important}}@media screen and (max-width:1023px){.has-text-centered-touch{text-align:center!important}}@media screen and (min-width:1024px){.has-text-centered-desktop{text-align:center!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-centered-desktop-only{text-align:center!important}}@media screen and (min-width:1216px){.has-text-centered-widescreen{text-align:center!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-centered-widescreen-only{text-align:center!important}}@media screen and (min-width:1408px){.has-text-centered-fullhd{text-align:center!important}}@media screen and (max-width:768px){.has-text-justified-mobile{text-align:justify!important}}@media screen and (min-width:769px),print{.has-text-justified-tablet{text-align:justify!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-justified-tablet-only{text-align:justify!important}}@media screen and (max-width:1023px){.has-text-justified-touch{text-align:justify!important}}@media screen and (min-width:1024px){.has-text-justified-desktop{text-align:justify!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-justified-desktop-only{text-align:justify!important}}@media screen and (min-width:1216px){.has-text-justified-widescreen{text-align:justify!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-justified-widescreen-only{text-align:justify!important}}@media screen and (min-width:1408px){.has-text-justified-fullhd{text-align:justify!important}}@media screen and (max-width:768px){.has-text-left-mobile{text-align:left!important}}@media screen and (min-width:769px),print{.has-text-left-tablet{text-align:left!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-left-tablet-only{text-align:left!important}}@media screen and (max-width:1023px){.has-text-left-touch{text-align:left!important}}@media screen and (min-width:1024px){.has-text-left-desktop{text-align:left!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-left-desktop-only{text-align:left!important}}@media screen and (min-width:1216px){.has-text-left-widescreen{text-align:left!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-left-widescreen-only{text-align:left!important}}@media screen and (min-width:1408px){.has-text-left-fullhd{text-align:left!important}}@media screen and (max-width:768px){.has-text-right-mobile{text-align:right!important}}@media screen and (min-width:769px),print{.has-text-right-tablet{text-align:right!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-right-tablet-only{text-align:right!important}}@media screen and (max-width:1023px){.has-text-right-touch{text-align:right!important}}@media screen and (min-width:1024px){.has-text-right-desktop{text-align:right!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-right-desktop-only{text-align:right!important}}@media screen and (min-width:1216px){.has-text-right-widescreen{text-align:right!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-right-widescreen-only{text-align:right!important}}@media screen and (min-width:1408px){.has-text-right-fullhd{text-align:right!important}}.is-capitalized{text-transform:capitalize!important}.is-lowercase{text-transform:lowercase!important}.is-uppercase{text-transform:uppercase!important}.is-italic{font-style:italic!important}.is-underlined{text-decoration:underline!important}.has-text-weight-light{font-weight:300!important}.has-text-weight-normal{font-weight:400!important}.has-text-weight-medium{font-weight:500!important}.has-text-weight-semibold{font-weight:600!important}.has-text-weight-bold{font-weight:700!important}.is-family-primary{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif!important}.is-family-secondary{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif!important}.is-family-sans-serif{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif!important}.is-family-monospace{font-family:monospace!important}.is-family-code{font-family:monospace!important}.is-block{display:block!important}@media screen and (max-width:768px){.is-block-mobile{display:block!important}}@media screen and (min-width:769px),print{.is-block-tablet{display:block!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-block-tablet-only{display:block!important}}@media screen and (max-width:1023px){.is-block-touch{display:block!important}}@media screen and (min-width:1024px){.is-block-desktop{display:block!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-block-desktop-only{display:block!important}}@media screen and (min-width:1216px){.is-block-widescreen{display:block!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-block-widescreen-only{display:block!important}}@media screen and (min-width:1408px){.is-block-fullhd{display:block!important}}.is-flex{display:flex!important}@media screen and (max-width:768px){.is-flex-mobile{display:flex!important}}@media screen and (min-width:769px),print{.is-flex-tablet{display:flex!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-flex-tablet-only{display:flex!important}}@media screen and (max-width:1023px){.is-flex-touch{display:flex!important}}@media screen and (min-width:1024px){.is-flex-desktop{display:flex!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-flex-desktop-only{display:flex!important}}@media screen and (min-width:1216px){.is-flex-widescreen{display:flex!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-flex-widescreen-only{display:flex!important}}@media screen and (min-width:1408px){.is-flex-fullhd{display:flex!important}}.is-inline{display:inline!important}@media screen and (max-width:768px){.is-inline-mobile{display:inline!important}}@media screen and (min-width:769px),print{.is-inline-tablet{display:inline!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-inline-tablet-only{display:inline!important}}@media screen and (max-width:1023px){.is-inline-touch{display:inline!important}}@media screen and (min-width:1024px){.is-inline-desktop{display:inline!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-inline-desktop-only{display:inline!important}}@media screen and (min-width:1216px){.is-inline-widescreen{display:inline!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-inline-widescreen-only{display:inline!important}}@media screen and (min-width:1408px){.is-inline-fullhd{display:inline!important}}.is-inline-block{display:inline-block!important}@media screen and (max-width:768px){.is-inline-block-mobile{display:inline-block!important}}@media screen and (min-width:769px),print{.is-inline-block-tablet{display:inline-block!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-inline-block-tablet-only{display:inline-block!important}}@media screen and (max-width:1023px){.is-inline-block-touch{display:inline-block!important}}@media screen and (min-width:1024px){.is-inline-block-desktop{display:inline-block!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-inline-block-desktop-only{display:inline-block!important}}@media screen and (min-width:1216px){.is-inline-block-widescreen{display:inline-block!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-inline-block-widescreen-only{display:inline-block!important}}@media screen and (min-width:1408px){.is-inline-block-fullhd{display:inline-block!important}}.is-inline-flex{display:inline-flex!important}@media screen and (max-width:768px){.is-inline-flex-mobile{display:inline-flex!important}}@media screen and (min-width:769px),print{.is-inline-flex-tablet{display:inline-flex!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-inline-flex-tablet-only{display:inline-flex!important}}@media screen and (max-width:1023px){.is-inline-flex-touch{display:inline-flex!important}}@media screen and (min-width:1024px){.is-inline-flex-desktop{display:inline-flex!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-inline-flex-desktop-only{display:inline-flex!important}}@media screen and (min-width:1216px){.is-inline-flex-widescreen{display:inline-flex!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-inline-flex-widescreen-only{display:inline-flex!important}}@media screen and (min-width:1408px){.is-inline-flex-fullhd{display:inline-flex!important}}.is-hidden{display:none!important}.is-sr-only{border:none!important;clip:rect(0,0,0,0)!important;height:.01em!important;overflow:hidden!important;padding:0!important;position:absolute!important;white-space:nowrap!important;width:.01em!important}@media screen and (max-width:768px){.is-hidden-mobile{display:none!important}}@media screen and (min-width:769px),print{.is-hidden-tablet{display:none!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-hidden-tablet-only{display:none!important}}@media screen and (max-width:1023px){.is-hidden-touch{display:none!important}}@media screen and (min-width:1024px){.is-hidden-desktop{display:none!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-hidden-desktop-only{display:none!important}}@media screen and (min-width:1216px){.is-hidden-widescreen{display:none!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-hidden-widescreen-only{display:none!important}}@media screen and (min-width:1408px){.is-hidden-fullhd{display:none!important}}.is-invisible{visibility:hidden!important}@media screen and (max-width:768px){.is-invisible-mobile{visibility:hidden!important}}@media screen and (min-width:769px),print{.is-invisible-tablet{visibility:hidden!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-invisible-tablet-only{visibility:hidden!important}}@media screen and (max-width:1023px){.is-invisible-touch{visibility:hidden!important}}@media screen and (min-width:1024px){.is-invisible-desktop{visibility:hidden!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-invisible-desktop-only{visibility:hidden!important}}@media screen and (min-width:1216px){.is-invisible-widescreen{visibility:hidden!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-invisible-widescreen-only{visibility:hidden!important}}@media screen and (min-width:1408px){.is-invisible-fullhd{visibility:hidden!important}}.hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}.hero .navbar{background:0 0}.hero .tabs ul{border-bottom:none}.hero.is-white{background-color:#fff;color:#0a0a0a}.hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-white strong{color:inherit}.hero.is-white .title{color:#0a0a0a}.hero.is-white .subtitle{color:rgba(10,10,10,.9)}.hero.is-white .subtitle a:not(.button),.hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width:1023px){.hero.is-white .navbar-menu{background-color:#fff}}.hero.is-white .navbar-item,.hero.is-white .navbar-link{color:rgba(10,10,10,.7)}.hero.is-white .navbar-link.is-active,.hero.is-white .navbar-link:hover,.hero.is-white a.navbar-item.is-active,.hero.is-white a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.hero.is-white .tabs a{color:#0a0a0a;opacity:.9}.hero.is-white .tabs a:hover{opacity:1}.hero.is-white .tabs li.is-active a{color:#fff!important;opacity:1}.hero.is-white .tabs.is-boxed a,.hero.is-white .tabs.is-toggle a{color:#0a0a0a}.hero.is-white .tabs.is-boxed a:hover,.hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-white .tabs.is-boxed li.is-active a,.hero.is-white .tabs.is-boxed li.is-active a:hover,.hero.is-white .tabs.is-toggle li.is-active a,.hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.hero.is-white.is-bold{background-image:linear-gradient(141deg,#e6e6e6 0,#fff 71%,#fff 100%)}@media screen and (max-width:768px){.hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg,#e6e6e6 0,#fff 71%,#fff 100%)}}.hero.is-black{background-color:#0a0a0a;color:#fff}.hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-black strong{color:inherit}.hero.is-black .title{color:#fff}.hero.is-black .subtitle{color:rgba(255,255,255,.9)}.hero.is-black .subtitle a:not(.button),.hero.is-black .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-black .navbar-menu{background-color:#0a0a0a}}.hero.is-black .navbar-item,.hero.is-black .navbar-link{color:rgba(255,255,255,.7)}.hero.is-black .navbar-link.is-active,.hero.is-black .navbar-link:hover,.hero.is-black a.navbar-item.is-active,.hero.is-black a.navbar-item:hover{background-color:#000;color:#fff}.hero.is-black .tabs a{color:#fff;opacity:.9}.hero.is-black .tabs a:hover{opacity:1}.hero.is-black .tabs li.is-active a{color:#0a0a0a!important;opacity:1}.hero.is-black .tabs.is-boxed a,.hero.is-black .tabs.is-toggle a{color:#fff}.hero.is-black .tabs.is-boxed a:hover,.hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-black .tabs.is-boxed li.is-active a,.hero.is-black .tabs.is-boxed li.is-active a:hover,.hero.is-black .tabs.is-toggle li.is-active a,.hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.hero.is-black.is-bold{background-image:linear-gradient(141deg,#000 0,#0a0a0a 71%,#181616 100%)}@media screen and (max-width:768px){.hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg,#000 0,#0a0a0a 71%,#181616 100%)}}.hero.is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-light strong{color:inherit}.hero.is-light .title{color:rgba(0,0,0,.7)}.hero.is-light .subtitle{color:rgba(0,0,0,.9)}.hero.is-light .subtitle a:not(.button),.hero.is-light .subtitle strong{color:rgba(0,0,0,.7)}@media screen and (max-width:1023px){.hero.is-light .navbar-menu{background-color:#f5f5f5}}.hero.is-light .navbar-item,.hero.is-light .navbar-link{color:rgba(0,0,0,.7)}.hero.is-light .navbar-link.is-active,.hero.is-light .navbar-link:hover,.hero.is-light a.navbar-item.is-active,.hero.is-light a.navbar-item:hover{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.hero.is-light .tabs a{color:rgba(0,0,0,.7);opacity:.9}.hero.is-light .tabs a:hover{opacity:1}.hero.is-light .tabs li.is-active a{color:#f5f5f5!important;opacity:1}.hero.is-light .tabs.is-boxed a,.hero.is-light .tabs.is-toggle a{color:rgba(0,0,0,.7)}.hero.is-light .tabs.is-boxed a:hover,.hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-light .tabs.is-boxed li.is-active a,.hero.is-light .tabs.is-boxed li.is-active a:hover,.hero.is-light .tabs.is-toggle li.is-active a,.hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,.7);border-color:rgba(0,0,0,.7);color:#f5f5f5}.hero.is-light.is-bold{background-image:linear-gradient(141deg,#dfd8d9 0,#f5f5f5 71%,#fff 100%)}@media screen and (max-width:768px){.hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg,#dfd8d9 0,#f5f5f5 71%,#fff 100%)}}.hero.is-dark{background-color:#363636;color:#fff}.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-dark strong{color:inherit}.hero.is-dark .title{color:#fff}.hero.is-dark .subtitle{color:rgba(255,255,255,.9)}.hero.is-dark .subtitle a:not(.button),.hero.is-dark .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-dark .navbar-menu{background-color:#363636}}.hero.is-dark .navbar-item,.hero.is-dark .navbar-link{color:rgba(255,255,255,.7)}.hero.is-dark .navbar-link.is-active,.hero.is-dark .navbar-link:hover,.hero.is-dark a.navbar-item.is-active,.hero.is-dark a.navbar-item:hover{background-color:#292929;color:#fff}.hero.is-dark .tabs a{color:#fff;opacity:.9}.hero.is-dark .tabs a:hover{opacity:1}.hero.is-dark .tabs li.is-active a{color:#363636!important;opacity:1}.hero.is-dark .tabs.is-boxed a,.hero.is-dark .tabs.is-toggle a{color:#fff}.hero.is-dark .tabs.is-boxed a:hover,.hero.is-dark .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-dark .tabs.is-boxed li.is-active a,.hero.is-dark .tabs.is-boxed li.is-active a:hover,.hero.is-dark .tabs.is-toggle li.is-active a,.hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#363636}.hero.is-dark.is-bold{background-image:linear-gradient(141deg,#1f191a 0,#363636 71%,#46403f 100%)}@media screen and (max-width:768px){.hero.is-dark.is-bold .navbar-menu{background-image:linear-gradient(141deg,#1f191a 0,#363636 71%,#46403f 100%)}}.hero.is-primary{background-color:#00d1b2;color:#fff}.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-primary strong{color:inherit}.hero.is-primary .title{color:#fff}.hero.is-primary .subtitle{color:rgba(255,255,255,.9)}.hero.is-primary .subtitle a:not(.button),.hero.is-primary .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-primary .navbar-menu{background-color:#00d1b2}}.hero.is-primary .navbar-item,.hero.is-primary .navbar-link{color:rgba(255,255,255,.7)}.hero.is-primary .navbar-link.is-active,.hero.is-primary .navbar-link:hover,.hero.is-primary a.navbar-item.is-active,.hero.is-primary a.navbar-item:hover{background-color:#00b89c;color:#fff}.hero.is-primary .tabs a{color:#fff;opacity:.9}.hero.is-primary .tabs a:hover{opacity:1}.hero.is-primary .tabs li.is-active a{color:#00d1b2!important;opacity:1}.hero.is-primary .tabs.is-boxed a,.hero.is-primary .tabs.is-toggle a{color:#fff}.hero.is-primary .tabs.is-boxed a:hover,.hero.is-primary .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-primary .tabs.is-boxed li.is-active a,.hero.is-primary .tabs.is-boxed li.is-active a:hover,.hero.is-primary .tabs.is-toggle li.is-active a,.hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#00d1b2}.hero.is-primary.is-bold{background-image:linear-gradient(141deg,#009e6c 0,#00d1b2 71%,#00e7eb 100%)}@media screen and (max-width:768px){.hero.is-primary.is-bold .navbar-menu{background-image:linear-gradient(141deg,#009e6c 0,#00d1b2 71%,#00e7eb 100%)}}.hero.is-link{background-color:#485fc7;color:#fff}.hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-link strong{color:inherit}.hero.is-link .title{color:#fff}.hero.is-link .subtitle{color:rgba(255,255,255,.9)}.hero.is-link .subtitle a:not(.button),.hero.is-link .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-link .navbar-menu{background-color:#485fc7}}.hero.is-link .navbar-item,.hero.is-link .navbar-link{color:rgba(255,255,255,.7)}.hero.is-link .navbar-link.is-active,.hero.is-link .navbar-link:hover,.hero.is-link a.navbar-item.is-active,.hero.is-link a.navbar-item:hover{background-color:#3a51bb;color:#fff}.hero.is-link .tabs a{color:#fff;opacity:.9}.hero.is-link .tabs a:hover{opacity:1}.hero.is-link .tabs li.is-active a{color:#485fc7!important;opacity:1}.hero.is-link .tabs.is-boxed a,.hero.is-link .tabs.is-toggle a{color:#fff}.hero.is-link .tabs.is-boxed a:hover,.hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-link .tabs.is-boxed li.is-active a,.hero.is-link .tabs.is-boxed li.is-active a:hover,.hero.is-link .tabs.is-toggle li.is-active a,.hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#485fc7}.hero.is-link.is-bold{background-image:linear-gradient(141deg,#2959b3 0,#485fc7 71%,#5658d2 100%)}@media screen and (max-width:768px){.hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg,#2959b3 0,#485fc7 71%,#5658d2 100%)}}.hero.is-info{background-color:#3e8ed0;color:#fff}.hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-info strong{color:inherit}.hero.is-info .title{color:#fff}.hero.is-info .subtitle{color:rgba(255,255,255,.9)}.hero.is-info .subtitle a:not(.button),.hero.is-info .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-info .navbar-menu{background-color:#3e8ed0}}.hero.is-info .navbar-item,.hero.is-info .navbar-link{color:rgba(255,255,255,.7)}.hero.is-info .navbar-link.is-active,.hero.is-info .navbar-link:hover,.hero.is-info a.navbar-item.is-active,.hero.is-info a.navbar-item:hover{background-color:#3082c5;color:#fff}.hero.is-info .tabs a{color:#fff;opacity:.9}.hero.is-info .tabs a:hover{opacity:1}.hero.is-info .tabs li.is-active a{color:#3e8ed0!important;opacity:1}.hero.is-info .tabs.is-boxed a,.hero.is-info .tabs.is-toggle a{color:#fff}.hero.is-info .tabs.is-boxed a:hover,.hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-info .tabs.is-boxed li.is-active a,.hero.is-info .tabs.is-boxed li.is-active a:hover,.hero.is-info .tabs.is-toggle li.is-active a,.hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#3e8ed0}.hero.is-info.is-bold{background-image:linear-gradient(141deg,#208fbc 0,#3e8ed0 71%,#4d83db 100%)}@media screen and (max-width:768px){.hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg,#208fbc 0,#3e8ed0 71%,#4d83db 100%)}}.hero.is-success{background-color:#48c78e;color:#fff}.hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-success strong{color:inherit}.hero.is-success .title{color:#fff}.hero.is-success .subtitle{color:rgba(255,255,255,.9)}.hero.is-success .subtitle a:not(.button),.hero.is-success .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-success .navbar-menu{background-color:#48c78e}}.hero.is-success .navbar-item,.hero.is-success .navbar-link{color:rgba(255,255,255,.7)}.hero.is-success .navbar-link.is-active,.hero.is-success .navbar-link:hover,.hero.is-success a.navbar-item.is-active,.hero.is-success a.navbar-item:hover{background-color:#3abb81;color:#fff}.hero.is-success .tabs a{color:#fff;opacity:.9}.hero.is-success .tabs a:hover{opacity:1}.hero.is-success .tabs li.is-active a{color:#48c78e!important;opacity:1}.hero.is-success .tabs.is-boxed a,.hero.is-success .tabs.is-toggle a{color:#fff}.hero.is-success .tabs.is-boxed a:hover,.hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-success .tabs.is-boxed li.is-active a,.hero.is-success .tabs.is-boxed li.is-active a:hover,.hero.is-success .tabs.is-toggle li.is-active a,.hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#48c78e}.hero.is-success.is-bold{background-image:linear-gradient(141deg,#29b35e 0,#48c78e 71%,#56d2af 100%)}@media screen and (max-width:768px){.hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg,#29b35e 0,#48c78e 71%,#56d2af 100%)}}.hero.is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-warning strong{color:inherit}.hero.is-warning .title{color:rgba(0,0,0,.7)}.hero.is-warning .subtitle{color:rgba(0,0,0,.9)}.hero.is-warning .subtitle a:not(.button),.hero.is-warning .subtitle strong{color:rgba(0,0,0,.7)}@media screen and (max-width:1023px){.hero.is-warning .navbar-menu{background-color:#ffe08a}}.hero.is-warning .navbar-item,.hero.is-warning .navbar-link{color:rgba(0,0,0,.7)}.hero.is-warning .navbar-link.is-active,.hero.is-warning .navbar-link:hover,.hero.is-warning a.navbar-item.is-active,.hero.is-warning a.navbar-item:hover{background-color:#ffd970;color:rgba(0,0,0,.7)}.hero.is-warning .tabs a{color:rgba(0,0,0,.7);opacity:.9}.hero.is-warning .tabs a:hover{opacity:1}.hero.is-warning .tabs li.is-active a{color:#ffe08a!important;opacity:1}.hero.is-warning .tabs.is-boxed a,.hero.is-warning .tabs.is-toggle a{color:rgba(0,0,0,.7)}.hero.is-warning .tabs.is-boxed a:hover,.hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-warning .tabs.is-boxed li.is-active a,.hero.is-warning .tabs.is-boxed li.is-active a:hover,.hero.is-warning .tabs.is-toggle li.is-active a,.hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,.7);border-color:rgba(0,0,0,.7);color:#ffe08a}.hero.is-warning.is-bold{background-image:linear-gradient(141deg,#ffb657 0,#ffe08a 71%,#fff6a3 100%)}@media screen and (max-width:768px){.hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg,#ffb657 0,#ffe08a 71%,#fff6a3 100%)}}.hero.is-danger{background-color:#f14668;color:#fff}.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-danger strong{color:inherit}.hero.is-danger .title{color:#fff}.hero.is-danger .subtitle{color:rgba(255,255,255,.9)}.hero.is-danger .subtitle a:not(.button),.hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-danger .navbar-menu{background-color:#f14668}}.hero.is-danger .navbar-item,.hero.is-danger .navbar-link{color:rgba(255,255,255,.7)}.hero.is-danger .navbar-link.is-active,.hero.is-danger .navbar-link:hover,.hero.is-danger a.navbar-item.is-active,.hero.is-danger a.navbar-item:hover{background-color:#ef2e55;color:#fff}.hero.is-danger .tabs a{color:#fff;opacity:.9}.hero.is-danger .tabs a:hover{opacity:1}.hero.is-danger .tabs li.is-active a{color:#f14668!important;opacity:1}.hero.is-danger .tabs.is-boxed a,.hero.is-danger .tabs.is-toggle a{color:#fff}.hero.is-danger .tabs.is-boxed a:hover,.hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-danger .tabs.is-boxed li.is-active a,.hero.is-danger .tabs.is-boxed li.is-active a:hover,.hero.is-danger .tabs.is-toggle li.is-active a,.hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#f14668}.hero.is-danger.is-bold{background-image:linear-gradient(141deg,#fa0a62 0,#f14668 71%,#f7595f 100%)}@media screen and (max-width:768px){.hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg,#fa0a62 0,#f14668 71%,#f7595f 100%)}}.hero.is-small .hero-body{padding:1.5rem}@media screen and (min-width:769px),print{.hero.is-medium .hero-body{padding:9rem 4.5rem}}@media screen and (min-width:769px),print{.hero.is-large .hero-body{padding:18rem 6rem}}.hero.is-fullheight .hero-body,.hero.is-fullheight-with-navbar .hero-body,.hero.is-halfheight .hero-body{align-items:center;display:flex}.hero.is-fullheight .hero-body>.container,.hero.is-fullheight-with-navbar .hero-body>.container,.hero.is-halfheight .hero-body>.container{flex-grow:1;flex-shrink:1}.hero.is-halfheight{min-height:50vh}.hero.is-fullheight{min-height:100vh}.hero-video{overflow:hidden}.hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;transform:translate3d(-50%,-50%,0)}.hero-video.is-transparent{opacity:.3}@media screen and (max-width:768px){.hero-video{display:none}}.hero-buttons{margin-top:1.5rem}@media screen and (max-width:768px){.hero-buttons .button{display:flex}.hero-buttons .button:not(:last-child){margin-bottom:.75rem}}@media screen and (min-width:769px),print{.hero-buttons{display:flex;justify-content:center}.hero-buttons .button:not(:last-child){margin-right:1.5rem}}.hero-foot,.hero-head{flex-grow:0;flex-shrink:0}.hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}@media screen and (min-width:769px),print{.hero-body{padding:3rem 3rem}}.section{padding:3rem 1.5rem}@media screen and (min-width:1024px){.section{padding:3rem 3rem}.section.is-medium{padding:9rem 4.5rem}.section.is-large{padding:18rem 6rem}}.footer{background-color:#fafafa;padding:3rem 1.5rem 6rem} \ No newline at end of file diff --git a/pagetop/static/bulmix/css/bulma.min.css.map b/pagetop/static/bulmix/css/bulma.min.css.map new file mode 100644 index 00000000..fc794a72 --- /dev/null +++ b/pagetop/static/bulmix/css/bulma.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../bulma.sass","../sass/utilities/_all.sass","../sass/utilities/extends.sass","../sass/utilities/controls.sass","../sass/utilities/initial-variables.sass","bulma.css","../sass/utilities/mixins.sass","../sass/base/_all.sass","../sass/base/minireset.sass","../sass/base/generic.sass","../sass/utilities/derived-variables.sass","../sass/base/animations.sass","../sass/elements/_all.sass","../sass/elements/box.sass","../sass/elements/button.sass","../sass/utilities/functions.sass","../sass/elements/container.sass","../sass/elements/content.sass","../sass/elements/icon.sass","../sass/elements/image.sass","../sass/elements/notification.sass","../sass/elements/progress.sass","../sass/elements/table.sass","../sass/elements/tag.sass","../sass/elements/title.sass","../sass/elements/other.sass","../sass/form/_all.sass","../sass/form/shared.sass","../sass/form/input-textarea.sass","../sass/form/checkbox-radio.sass","../sass/form/select.sass","../sass/form/file.sass","../sass/form/tools.sass","../sass/components/_all.sass","../sass/components/breadcrumb.sass","../sass/components/card.sass","../sass/components/dropdown.sass","../sass/components/level.sass","../sass/components/media.sass","../sass/components/menu.sass","../sass/components/message.sass","../sass/components/modal.sass","../sass/components/navbar.sass","../sass/components/pagination.sass","../sass/components/panel.sass","../sass/components/tabs.sass","../sass/grid/_all.sass","../sass/grid/columns.sass","../sass/grid/tiles.sass","../sass/helpers/_all.sass","../sass/helpers/color.sass","../sass/helpers/flexbox.sass","../sass/helpers/float.sass","../sass/helpers/other.sass","../sass/helpers/overflow.sass","../sass/helpers/position.sass","../sass/helpers/spacing.sass","../sass/helpers/typography.sass","../sass/helpers/visibility.sass","../sass/layout/_all.sass","../sass/layout/hero.sass","../sass/layout/section.sass","../sass/layout/footer.sass"],"names":[],"mappings":"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,4BAA4B;EAC5B,sBLpC0B;ACkU5B;;AI5RA;EACE,cL7D4B;EK8D5B,cA1DkB;EA2DlB,gBL7BiB;EK8BjB,gBA1DoB;AJyVtB;;AI3RA;EACE,cLtDgC;EKuDhC,eAAe;EACf,qBAAqB;AJ8RvB;;AIjSA;EAKI,mBAAmB;AJgSvB;;AIrSA;EAOI,cL5E0B;AC8W9B;;AIhSA;EACE,4BLxE4B;EKyE5B,cCnBsB;EDoBtB,kBArEiB;EAsEjB,mBAvEkB;EAwElB,4BAzEgC;AJ4WlC;;AIjSA;EACE,4BL/E4B;EKgF5B,YAAY;EACZ,cAAc;EACd,WAxEa;EAyEb,gBAxEkB;AJ4WpB;;AIlSA;EACE,YAAY;EACZ,eAAe;AJqSjB;;AInSA;;EAEE,wBAAwB;AJsS1B;;AIpSA;EACE,kBAvFuB;AJ8XzB;;AIrSA;EACE,mBAAmB;EACnB,oBAAoB;AJwStB;;AItSA;EACE,cL5G4B;EK6G5B,gBLvEe;ACgXjB;;AIrSA;EACE,YAAY;AJwSd;;AItSA;EH5DE,iCAAiC;EG8DjC,4BL/G4B;EKgH5B,cLtH4B;EKuH5B,kBAjGqB;EAkGrB,gBAAgB;EAChB,uBAlG0B;EAmG1B,gBAAgB;EAChB,iBAAiB;AJySnB;;AIjTA;EAUI,6BAA6B;EAC7B,mBAAmB;EACnB,cAvGoB;EAwGpB,UAAU;AJ2Sd;;AIzSA;;EAGI,mBAAmB;AJ2SvB;;AI9SA;;EAKM,mBAAmB;AJ8SzB;;AInTA;EAOI,cL1I0B;AC0b9B;;AMhcA;EACE;IACE,uBAAuB;ENmczB;EMlcA;IACE,yBAAyB;ENoc3B;AACF;;AMzcA;EACE;IACE,uBAAuB;ENmczB;EMlcA;IACE,yBAAyB;ENoc3B;AACF;;AOzcA,mBAAA;ACWA;EAEE,uBTE6B;ESD7B,kBTwDgB;ESvDhB,0FTb2B;ESc3B,cTT4B;ESU5B,cAAc;EACd,gBAZmB;AR6crB;;AQ/bA;EAGI,yETD8B;ACiclC;;AQncA;EAKI,oETH8B;ACqclC;;AShaA;EAGE,uBV/C6B;EUgD7B,qBVrD4B;EUsD5B,iBX3DwB;EW4DxB,cV3D4B;EU4D5B,eAAe;EAGf,uBAAuB;EACvB,iCA5D6D;EA6D7D,iBA5D6B;EA6D7B,kBA7D6B;EA8D7B,8BA/D6D;EAgE7D,kBAAkB;EAClB,mBAAmB;AT+ZrB;;AS/aA;EAkBI,cAAc;ATialB;;ASnbA;EAwBM,aAAa;EACb,YAAY;AT+ZlB;;ASxbA;ERiGI,+BQtEsG;ERsEtG,oBQrEmE;ATiavE;;AS7bA;ERiGI,mBQnEmE;ERmEnE,gCQlEsG;ATma1G;;ASlcA;EAiCM,+BAAiF;EACjF,gCAAkF;ATqaxF;;ASvcA;EAsCI,qBVxF0B;EUyF1B,cV5F0B;ACigB9B;;AS5cA;EA0CI,qBV/E8B;EUgF9B,cVhG0B;ACsgB9B;;ASjdA;EA6CM,iDVlF4B;AC0flC;;ASrdA;EAgDI,qBVpG0B;EUqG1B,cVtG0B;AC+gB9B;;AS1dA;EAoDI,6BAA6B;EAC7B,yBAAyB;EACzB,cV1G0B;EU2G1B,0BAzF8B;ATmgBlC;;ASjeA;EA4DM,4BV1GwB;EU2GxB,cVlHwB;AC2hB9B;;ASteA;EAgEM,yBCd2B;EDe3B,cVtHwB;ACgiB9B;;AS3eA;;EAoEM,6BAA6B;EAC7B,yBAAyB;EACzB,gBAAgB;AT4atB;;ASlfA;EAwEI,gBAtG0B;EAuG1B,yBAtGmC;EAuGnC,cV/G8B;EUgH9B,qBAtG0B;ATohB9B;;ASzfA;EA8EM,cVnH4B;EUoH5B,0BAxGmC;ATuhBzC;;AS9fA;EAoFM,uBVhIyB;EUiIzB,yBAAyB;EACzB,cV/IuB;AC6jB7B;;ASpgBA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,cVpJqB;ACmkB7B;;AS1gBA;EA8FQ,yBAAyB;EACzB,cVxJqB;ACwkB7B;;AS/gBA;EAiGU,mDV7IqB;AC+jB/B;;ASnhBA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,cV/JqB;ACklB7B;;ASzhBA;;EAyGQ,uBVrJuB;EUsJvB,yBAAyB;EACzB,gBAAgB;ATqbxB;;AShiBA;EA6GQ,yBVtKqB;EUuKrB,YV1JuB;ACilB/B;;ASriBA;EAiHU,uBC/DuB;AVufjC;;ASziBA;;EAoHU,yBV7KmB;EU8KnB,yBAAyB;EACzB,gBAAgB;EAChB,YVnKqB;AC6lB/B;;ASjjBA;EA0HU,gEAA4E;AT2btF;;ASrjBA;EA4HQ,6BAA6B;EAC7B,mBVzKuB;EU0KvB,YV1KuB;ACumB/B;;AS3jBA;EAmIU,uBV/KqB;EUgLrB,mBVhLqB;EUiLrB,cV9LmB;AC0nB7B;;ASjkBA;EAwIY,4DAA8D;AT6b1E;;ASrkBA;EA8Ic,gEAA4E;AT2b1F;;ASzkBA;;EAiJU,6BAA6B;EAC7B,mBV9LqB;EU+LrB,gBAAgB;EAChB,YVhMqB;AC6nB/B;;ASjlBA;EAsJQ,6BAA6B;EAC7B,qBVhNqB;EUiNrB,cVjNqB;ACgpB7B;;ASvlBA;EA6JU,yBVtNmB;EUuNnB,YV1MqB;ACwoB/B;;AS5lBA;EAqKc,4DAA8D;AT2b5E;;AShmBA;;EAwKU,6BAA6B;EAC7B,qBVlOmB;EUmOnB,gBAAgB;EAChB,cVpOmB;ACiqB7B;;ASxmBA;EAoFM,yBV7IuB;EU8IvB,yBAAyB;EACzB,YVlIyB;AC0pB/B;;AS9mBA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,YVvIuB;ACgqB/B;;ASpnBA;EA8FQ,yBAAyB;EACzB,YV3IuB;ACqqB/B;;ASznBA;EAiGU,gDV1JmB;ACsrB7B;;AS7nBA;EAoGQ,uBClDyB;EDmDzB,yBAAyB;EACzB,YVlJuB;AC+qB/B;;ASnoBA;;EAyGQ,yBVlKqB;EUmKrB,yBAAyB;EACzB,gBAAgB;AT+hBxB;;AS1oBA;EA6GQ,uBVzJuB;EU0JvB,cVvKqB;ACwsB7B;;AS/oBA;EAiHU,yBC/DuB;AVimBjC;;ASnpBA;;EAoHU,uBVhKqB;EUiKrB,yBAAyB;EACzB,gBAAgB;EAChB,cVhLmB;ACotB7B;;AS3pBA;EA0HU,4DAA4E;ATqiBtF;;AS/pBA;EA4HQ,6BAA6B;EAC7B,qBVtLqB;EUuLrB,cVvLqB;AC8tB7B;;ASrqBA;EAmIU,yBV5LmB;EU6LnB,qBV7LmB;EU8LnB,YVjLqB;ACutB/B;;AS3qBA;EAwIY,gEAA8D;ATuiB1E;;AS/qBA;EA8Ic,4DAA4E;ATqiB1F;;ASnrBA;;EAiJU,6BAA6B;EAC7B,qBV3MmB;EU4MnB,gBAAgB;EAChB,cV7MmB;ACovB7B;;AS3rBA;EAsJQ,6BAA6B;EAC7B,mBVnMuB;EUoMvB,YVpMuB;AC6uB/B;;ASjsBA;EA6JU,uBVzMqB;EU0MrB,cVvNmB;AC+vB7B;;AStsBA;EAqKc,gEAA8D;ATqiB5E;;AS1sBA;;EAwKU,6BAA6B;EAC7B,mBVrNqB;EUsNrB,gBAAgB;EAChB,YVvNqB;AC8vB/B;;ASltBA;EAoFM,4BVlIwB;EUmIxB,yBAAyB;EACzB,yBCjEe;AVmsBrB;;ASxtBA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,yBCtEa;AVysBrB;;AS9tBA;EA8FQ,yBAAyB;EACzB,yBC1Ea;AV8sBrB;;ASnuBA;EAiGU,mDV/IoB;ACqxB9B;;ASvuBA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,yBCjFa;AVwtBrB;;AS7uBA;;EAyGQ,4BVvJsB;EUwJtB,yBAAyB;EACzB,gBAAgB;ATyoBxB;;ASpvBA;EA6GQ,oCCxFa;EDyFb,iBV5JsB;ACuyB9B;;ASzvBA;EAiHU,oCC/DuB;AV2sBjC;;AS7vBA;;EAoHU,oCC/FW;EDgGX,yBAAyB;EACzB,gBAAgB;EAChB,iBVrKoB;ACmzB9B;;ASrwBA;EA0HU,sFAA4E;AT+oBtF;;ASzwBA;EA4HQ,6BAA6B;EAC7B,wBV3KsB;EU4KtB,iBV5KsB;AC6zB9B;;AS/wBA;EAmIU,4BVjLoB;EUkLpB,wBVlLoB;EUmLpB,yBChHW;AVgwBrB;;ASrxBA;EAwIY,sEAA8D;ATipB1E;;ASzxBA;EA8Ic,sFAA4E;AT+oB1F;;AS7xBA;;EAiJU,6BAA6B;EAC7B,wBVhMoB;EUiMpB,gBAAgB;EAChB,iBVlMoB;ACm1B9B;;ASryBA;EAsJQ,6BAA6B;EAC7B,gCClIa;EDmIb,yBCnIa;AVsxBrB;;AS3yBA;EA6JU,oCCxIW;EDyIX,iBV5MoB;AC81B9B;;AShzBA;EAqKc,sEAA8D;AT+oB5E;;ASpzBA;;EAwKU,6BAA6B;EAC7B,gCCpJW;EDqJX,gBAAgB;EAChB,yBCtJW;AVuyBrB;;AS5zBA;EAoFM,yBVzIwB;EU0IxB,yBAAyB;EACzB,WC/DU;AV2yBhB;;ASl0BA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,WCpEQ;AVizBhB;;ASx0BA;EA8FQ,yBAAyB;EACzB,WCxEQ;AVszBhB;;AS70BA;EAiGU,gDVtJoB;ACs4B9B;;ASj1BA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,WC/EQ;AVg0BhB;;ASv1BA;;EAyGQ,yBV9JsB;EU+JtB,yBAAyB;EACzB,gBAAgB;ATmvBxB;;AS91BA;EA6GQ,sBCtFQ;EDuFR,cVnKsB;ACw5B9B;;ASn2BA;EAiHU,yBC/DuB;AVqzBjC;;ASv2BA;;EAoHU,sBC7FM;ED8FN,yBAAyB;EACzB,gBAAgB;EAChB,cV5KoB;ACo6B9B;;AS/2BA;EA0HU,0DAA4E;ATyvBtF;;ASn3BA;EA4HQ,6BAA6B;EAC7B,qBVlLsB;EUmLtB,cVnLsB;AC86B9B;;ASz3BA;EAmIU,yBVxLoB;EUyLpB,qBVzLoB;EU0LpB,WC9GM;AVw2BhB;;AS/3BA;EAwIY,gEAA8D;AT2vB1E;;ASn4BA;EA8Ic,0DAA4E;ATyvB1F;;ASv4BA;;EAiJU,6BAA6B;EAC7B,qBVvMoB;EUwMpB,gBAAgB;EAChB,cVzMoB;ACo8B9B;;AS/4BA;EAsJQ,6BAA6B;EAC7B,kBChIQ;EDiIR,WCjIQ;AV83BhB;;ASr5BA;EA6JU,sBCtIM;EDuIN,cVnNoB;AC+8B9B;;AS15BA;EAqKc,gEAA8D;ATyvB5E;;AS95BA;;EAwKU,6BAA6B;EAC7B,kBClJM;EDmJN,gBAAgB;EAChB,WCpJM;AV+4BhB;;ASt6BA;EAoFM,yBV3H4B;EU4H5B,yBAAyB;EACzB,WC/DU;AVq5BhB;;AS56BA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,WCpEQ;AV25BhB;;ASl7BA;EA8FQ,yBAAyB;EACzB,WCxEQ;AVg6BhB;;ASv7BA;EAiGU,iDVxIwB;ACk+BlC;;AS37BA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,WC/EQ;AV06BhB;;ASj8BA;;EAyGQ,yBVhJ0B;EUiJ1B,yBAAyB;EACzB,gBAAgB;AT61BxB;;ASx8BA;EA6GQ,sBCtFQ;EDuFR,cVrJ0B;ACo/BlC;;AS78BA;EAiHU,yBC/DuB;AV+5BjC;;ASj9BA;;EAoHU,sBC7FM;ED8FN,yBAAyB;EACzB,gBAAgB;EAChB,cV9JwB;ACggClC;;ASz9BA;EA0HU,0DAA4E;ATm2BtF;;AS79BA;EA4HQ,6BAA6B;EAC7B,qBVpK0B;EUqK1B,cVrK0B;AC0gClC;;ASn+BA;EAmIU,yBV1KwB;EU2KxB,qBV3KwB;EU4KxB,WC9GM;AVk9BhB;;ASz+BA;EAwIY,gEAA8D;ATq2B1E;;AS7+BA;EA8Ic,0DAA4E;ATm2B1F;;ASj/BA;;EAiJU,6BAA6B;EAC7B,qBVzLwB;EU0LxB,gBAAgB;EAChB,cV3LwB;ACgiClC;;ASz/BA;EAsJQ,6BAA6B;EAC7B,kBChIQ;EDiIR,WCjIQ;AVw+BhB;;AS//BA;EA6JU,sBCtIM;EDuIN,cVrMwB;AC2iClC;;ASpgCA;EAqKc,gEAA8D;ATm2B5E;;ASxgCA;;EAwKU,6BAA6B;EAC7B,kBClJM;EDmJN,gBAAgB;EAChB,WCpJM;AVy/BhB;;AShhCA;EAiLU,yBCnJsC;EDoJtC,cC3I2D;AV8+BrE;;ASrhCA;EAqLY,yBCnIqB;EDoIrB,yBAAyB;EACzB,cChJyD;AVo/BrE;;AS3hCA;EA0LY,yBCxIqB;EDyIrB,yBAAyB;EACzB,cCrJyD;AV0/BrE;;ASjiCA;EAoFM,yBVzH4B;EU0H5B,yBAAyB;EACzB,WC/DU;AVghChB;;ASviCA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,WCpEQ;AVshChB;;AS7iCA;EA8FQ,yBAAyB;EACzB,WCxEQ;AV2hChB;;ASljCA;EAiGU,iDVtIwB;AC2lClC;;AStjCA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,WC/EQ;AVqiChB;;AS5jCA;;EAyGQ,yBV9I0B;EU+I1B,yBAAyB;EACzB,gBAAgB;ATw9BxB;;ASnkCA;EA6GQ,sBCtFQ;EDuFR,cVnJ0B;AC6mClC;;ASxkCA;EAiHU,yBC/DuB;AV0hCjC;;AS5kCA;;EAoHU,sBC7FM;ED8FN,yBAAyB;EACzB,gBAAgB;EAChB,cV5JwB;ACynClC;;ASplCA;EA0HU,0DAA4E;AT89BtF;;ASxlCA;EA4HQ,6BAA6B;EAC7B,qBVlK0B;EUmK1B,cVnK0B;ACmoClC;;AS9lCA;EAmIU,yBVxKwB;EUyKxB,qBVzKwB;EU0KxB,WC9GM;AV6kChB;;ASpmCA;EAwIY,gEAA8D;ATg+B1E;;ASxmCA;EA8Ic,0DAA4E;AT89B1F;;AS5mCA;;EAiJU,6BAA6B;EAC7B,qBVvLwB;EUwLxB,gBAAgB;EAChB,cVzLwB;ACypClC;;ASpnCA;EAsJQ,6BAA6B;EAC7B,kBChIQ;EDiIR,WCjIQ;AVmmChB;;AS1nCA;EA6JU,sBCtIM;EDuIN,cVnMwB;ACoqClC;;AS/nCA;EAqKc,gEAA8D;AT89B5E;;ASnoCA;;EAwKU,6BAA6B;EAC7B,kBClJM;EDmJN,gBAAgB;EAChB,WCpJM;AVonChB;;AS3oCA;EAiLU,yBCnJsC;EDoJtC,cC3I2D;AVymCrE;;AShpCA;EAqLY,yBCnIqB;EDoIrB,yBAAyB;EACzB,cChJyD;AV+mCrE;;AStpCA;EA0LY,yBCxIqB;EDyIrB,yBAAyB;EACzB,cCrJyD;AVqnCrE;;AS5pCA;EAoFM,yBV1H4B;EU2H5B,yBAAyB;EACzB,WC/DU;AV2oChB;;ASlqCA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,WCpEQ;AVipChB;;ASxqCA;EA8FQ,yBAAyB;EACzB,WCxEQ;AVspChB;;AS7qCA;EAiGU,kDVvIwB;ACutClC;;ASjrCA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,WC/EQ;AVgqChB;;ASvrCA;;EAyGQ,yBV/I0B;EUgJ1B,yBAAyB;EACzB,gBAAgB;ATmlCxB;;AS9rCA;EA6GQ,sBCtFQ;EDuFR,cVpJ0B;ACyuClC;;ASnsCA;EAiHU,yBC/DuB;AVqpCjC;;ASvsCA;;EAoHU,sBC7FM;ED8FN,yBAAyB;EACzB,gBAAgB;EAChB,cV7JwB;ACqvClC;;AS/sCA;EA0HU,0DAA4E;ATylCtF;;ASntCA;EA4HQ,6BAA6B;EAC7B,qBVnK0B;EUoK1B,cVpK0B;AC+vClC;;ASztCA;EAmIU,yBVzKwB;EU0KxB,qBV1KwB;EU2KxB,WC9GM;AVwsChB;;AS/tCA;EAwIY,gEAA8D;AT2lC1E;;ASnuCA;EA8Ic,0DAA4E;ATylC1F;;ASvuCA;;EAiJU,6BAA6B;EAC7B,qBVxLwB;EUyLxB,gBAAgB;EAChB,cV1LwB;ACqxClC;;AS/uCA;EAsJQ,6BAA6B;EAC7B,kBChIQ;EDiIR,WCjIQ;AV8tChB;;ASrvCA;EA6JU,sBCtIM;EDuIN,cVpMwB;ACgyClC;;AS1vCA;EAqKc,gEAA8D;ATylC5E;;AS9vCA;;EAwKU,6BAA6B;EAC7B,kBClJM;EDmJN,gBAAgB;EAChB,WCpJM;AV+uChB;;AStwCA;EAiLU,yBCnJsC;EDoJtC,cC3I2D;AVouCrE;;AS3wCA;EAqLY,yBCnIqB;EDoIrB,yBAAyB;EACzB,cChJyD;AV0uCrE;;ASjxCA;EA0LY,yBCxIqB;EDyIrB,yBAAyB;EACzB,cCrJyD;AVgvCrE;;ASvxCA;EAoFM,yBV5H4B;EU6H5B,yBAAyB;EACzB,WC/DU;AVswChB;;AS7xCA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,WCpEQ;AV4wChB;;ASnyCA;EA8FQ,yBAAyB;EACzB,WCxEQ;AVixChB;;ASxyCA;EAiGU,kDVzIwB;ACo1ClC;;AS5yCA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,WC/EQ;AV2xChB;;ASlzCA;;EAyGQ,yBVjJ0B;EUkJ1B,yBAAyB;EACzB,gBAAgB;AT8sCxB;;ASzzCA;EA6GQ,sBCtFQ;EDuFR,cVtJ0B;ACs2ClC;;AS9zCA;EAiHU,yBC/DuB;AVgxCjC;;ASl0CA;;EAoHU,sBC7FM;ED8FN,yBAAyB;EACzB,gBAAgB;EAChB,cV/JwB;ACk3ClC;;AS10CA;EA0HU,0DAA4E;ATotCtF;;AS90CA;EA4HQ,6BAA6B;EAC7B,qBVrK0B;EUsK1B,cVtK0B;AC43ClC;;ASp1CA;EAmIU,yBV3KwB;EU4KxB,qBV5KwB;EU6KxB,WC9GM;AVm0ChB;;AS11CA;EAwIY,gEAA8D;ATstC1E;;AS91CA;EA8Ic,0DAA4E;ATotC1F;;ASl2CA;;EAiJU,6BAA6B;EAC7B,qBV1LwB;EU2LxB,gBAAgB;EAChB,cV5LwB;ACk5ClC;;AS12CA;EAsJQ,6BAA6B;EAC7B,kBChIQ;EDiIR,WCjIQ;AVy1ChB;;ASh3CA;EA6JU,sBCtIM;EDuIN,cVtMwB;AC65ClC;;ASr3CA;EAqKc,gEAA8D;ATotC5E;;ASz3CA;;EAwKU,6BAA6B;EAC7B,kBClJM;EDmJN,gBAAgB;EAChB,WCpJM;AV02ChB;;ASj4CA;EAiLU,yBCnJsC;EDoJtC,cC3I2D;AV+1CrE;;ASt4CA;EAqLY,yBCnIqB;EDoIrB,yBAAyB;EACzB,cChJyD;AVq2CrE;;AS54CA;EA0LY,yBCxIqB;EDyIrB,yBAAyB;EACzB,cCrJyD;AV22CrE;;ASl5CA;EAoFM,yBV7H4B;EU8H5B,yBAAyB;EACzB,yBCjEe;AVm4CrB;;ASx5CA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,yBCtEa;AVy4CrB;;AS95CA;EA8FQ,yBAAyB;EACzB,yBC1Ea;AV84CrB;;ASn6CA;EAiGU,mDV1IwB;ACg9ClC;;ASv6CA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,yBCjFa;AVw5CrB;;AS76CA;;EAyGQ,yBVlJ0B;EUmJ1B,yBAAyB;EACzB,gBAAgB;ATy0CxB;;ASp7CA;EA6GQ,oCCxFa;EDyFb,cVvJ0B;ACk+ClC;;ASz7CA;EAiHU,oCC/DuB;AV24CjC;;AS77CA;;EAoHU,oCC/FW;EDgGX,yBAAyB;EACzB,gBAAgB;EAChB,cVhKwB;AC8+ClC;;ASr8CA;EA0HU,sFAA4E;AT+0CtF;;ASz8CA;EA4HQ,6BAA6B;EAC7B,qBVtK0B;EUuK1B,cVvK0B;ACw/ClC;;AS/8CA;EAmIU,yBV5KwB;EU6KxB,qBV7KwB;EU8KxB,yBChHW;AVg8CrB;;ASr9CA;EAwIY,gEAA8D;ATi1C1E;;ASz9CA;EA8Ic,sFAA4E;AT+0C1F;;AS79CA;;EAiJU,6BAA6B;EAC7B,qBV3LwB;EU4LxB,gBAAgB;EAChB,cV7LwB;AC8gDlC;;ASr+CA;EAsJQ,6BAA6B;EAC7B,gCClIa;EDmIb,yBCnIa;AVs9CrB;;AS3+CA;EA6JU,oCCxIW;EDyIX,cVvMwB;ACyhDlC;;ASh/CA;EAqKc,gEAA8D;AT+0C5E;;ASp/CA;;EAwKU,6BAA6B;EAC7B,gCCpJW;EDqJX,gBAAgB;EAChB,yBCtJW;AVu+CrB;;AS5/CA;EAiLU,yBCnJsC;EDoJtC,cC3I2D;AV09CrE;;ASjgDA;EAqLY,yBCnIqB;EDoIrB,yBAAyB;EACzB,cChJyD;AVg+CrE;;ASvgDA;EA0LY,yBCxIqB;EDyIrB,yBAAyB;EACzB,cCrJyD;AVs+CrE;;AS7gDA;EAoFM,yBVvH2B;EUwH3B,yBAAyB;EACzB,WC/DU;AV4/ChB;;ASnhDA;EAyFQ,yBCvCyB;EDwCzB,yBAAyB;EACzB,WCpEQ;AVkgDhB;;ASzhDA;EA8FQ,yBAAyB;EACzB,WCxEQ;AVugDhB;;AS9hDA;EAiGU,kDVpIuB;ACqkDjC;;ASliDA;EAoGQ,yBClDyB;EDmDzB,yBAAyB;EACzB,WC/EQ;AVihDhB;;ASxiDA;;EAyGQ,yBV5IyB;EU6IzB,yBAAyB;EACzB,gBAAgB;ATo8CxB;;AS/iDA;EA6GQ,sBCtFQ;EDuFR,cVjJyB;ACulDjC;;ASpjDA;EAiHU,yBC/DuB;AVsgDjC;;ASxjDA;;EAoHU,sBC7FM;ED8FN,yBAAyB;EACzB,gBAAgB;EAChB,cV1JuB;ACmmDjC;;AShkDA;EA0HU,0DAA4E;AT08CtF;;ASpkDA;EA4HQ,6BAA6B;EAC7B,qBVhKyB;EUiKzB,cVjKyB;AC6mDjC;;AS1kDA;EAmIU,yBVtKuB;EUuKvB,qBVvKuB;EUwKvB,WC9GM;AVyjDhB;;AShlDA;EAwIY,gEAA8D;AT48C1E;;ASplDA;EA8Ic,0DAA4E;AT08C1F;;ASxlDA;;EAiJU,6BAA6B;EAC7B,qBVrLuB;EUsLvB,gBAAgB;EAChB,cVvLuB;ACmoDjC;;AShmDA;EAsJQ,6BAA6B;EAC7B,kBChIQ;EDiIR,WCjIQ;AV+kDhB;;AStmDA;EA6JU,sBCtIM;EDuIN,cVjMuB;AC8oDjC;;AS3mDA;EAqKc,gEAA8D;AT08C5E;;AS/mDA;;EAwKU,6BAA6B;EAC7B,kBClJM;EDmJN,gBAAgB;EAChB,WCpJM;AVgmDhB;;ASvnDA;EAiLU,yBCnJsC;EDoJtC,cC3I2D;AVqlDrE;;AS5nDA;EAqLY,yBCnIqB;EDoIrB,yBAAyB;EACzB,cChJyD;AV2lDrE;;ASloDA;EA0LY,yBCxIqB;EDyIrB,yBAAyB;EACzB,cCrJyD;AVimDrE;;ASxoDA;EARE,kBVbc;ACiqDhB;;AStpDE;EACE,kBVkBc;ACuoDlB;;AShpDA;EANE,eVhBW;AC0qDb;;ASppDA;EAJE,kBVnBc;AC+qDhB;;ASxpDA;EAFE,iBVtBa;ACorDf;;AS5pDA;;EAyMI,uBVrP2B;EUsP3B,qBV3P0B;EU4P1B,gBAhOyB;EAiOzB,YAhOyB;ATwrD7B;;ASpqDA;EA8MI,aAAa;EACb,WAAW;AT09Cf;;ASzqDA;EAiNI,6BAA6B;EAC7B,oBAAoB;AT49CxB;;AS9qDA;ERlDE,kBAAkB;EAKhB,6BAAmC;EACnC,4BAAkC;EQkQhC,6BAA6B;AT+9CnC;;ASrrDA;EAwNI,4BVtQ0B;EUuQ1B,qBV1Q0B;EU2Q1B,cV7Q0B;EU8Q1B,gBAAgB;EAChB,oBAAoB;ATi+CxB;;AS7rDA;EA8NI,qBVlNmB;EUmNnB,gCAA0D;EAC1D,iCAA2D;ATm+C/D;;ASj+CA;EACE,mBAAmB;EACnB,aAAa;EACb,eAAe;EACf,2BAA2B;ATo+C7B;;ASx+CA;EAMI,qBAAqB;ATs+CzB;;AS5+CA;ERjII,oBQyIwC;ATw+C5C;;ASh/CA;EAUI,sBAAsB;AT0+C1B;;ASp/CA;EAYI,mBAAmB;AT4+CvB;;ASx/CA;EA1OE,kBVbc;ACmvDhB;;ASxuDE;EACE,kBVkBc;ACytDlB;;AShgDA;EAtOE,kBVnBc;AC6vDhB;;ASpgDA;EApOE,iBVtBa;ACkwDf;;ASxgDA;EA0BQ,4BAA4B;EAC5B,yBAAyB;ATk/CjC;;AS7gDA;EA6BQ,6BAA6B;EAC7B,0BAA0B;ER/J9B,kBQgKwC;ATo/C5C;;ASnhDA;ERjII,eQkKqC;ATs/CzC;;ASvhDA;EAoCQ,UAAU;ATu/ClB;;AS3hDA;EA0CQ,UAAU;ATq/ClB;;AS/hDA;EA4CU,UAAU;ATu/CpB;;ASniDA;EA8CQ,YAAY;EACZ,cAAc;ATy/CtB;;ASxiDA;EAiDI,uBAAuB;AT2/C3B;;AS5iDA;EAoDQ,oBAAoB;EACpB,qBAAqB;AT4/C7B;;ASjjDA;EAuDI,yBAAyB;AT8/C7B;;ASrjDA;EA0DQ,oBAAoB;EACpB,qBAAqB;AT+/C7B;;AWl1DA;EACE,YAAY;EACZ,cAAc;EACd,kBAAkB;EAClB,WA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wB;EgBsCxB,WLsCU;AVovEhB;;Ae3zEA;EAgCM,yBhBvB4B;EgBwB5B,WLsCU;AVyvEhB;;Aeh0EA;EAuCU,yBLuCsC;EKtCtC,cL+C2D;AV8uErE;;Aer0EA;EAgCM,yBhBrB4B;EgBsB5B,WLsCU;AVmwEhB;;Ae10EA;EAuCU,yBLuCsC;EKtCtC,cL+C2D;AVwvErE;;Ae/0EA;EAgCM,yBhBtB4B;EgBuB5B,WLsCU;AV6wEhB;;Aep1EA;EAuCU,yBLuCsC;EKtCtC,cL+C2D;AVkwErE;;Aez1EA;EAgCM,yBhBxB4B;EgByB5B,WLsCU;AVuxEhB;;Ae91EA;EAuCU,yBLuCsC;EKtCtC,cL+C2D;AV4wErE;;Aen2EA;EAgCM,yBhBzB4B;EgB0B5B,yBLoCe;AVmyErB;;Aex2EA;EAuCU,yBLuCsC;EKtCtC,cL+C2D;AVsxErE;;Ae72EA;EAgCM,yBhBnB2B;EgBoB3B,WLsCU;AV2yEhB;;Ael3EA;EAuCU,yBLuCsC;EKtCtC,cL+C2D;AVgyErE;;AgBx3EA;EAEE,qBAAqB;EACrB,wBAAwB;EACxB,YAAY;EACZ,qBjBwDqB;EiBvDrB,cAAc;EACd,YjBoBW;EiBnBX,gBAAgB;EAChB,UAAU;EACV,WAAW;AhB03Eb;;AgBp4EA;EAYI,yBjBX2B;ACu4E/B;;AgBx4EA;EAcI,yBjBjB0B;AC+4E9B;;AgB54EA;EAgBI,yBjBnB0B;ACm5E9B;;AgBh5EA;EAkBI,yBjBrB0B;EiBsB1B,YAAY;AhBk4EhB;;AgBr5EA;EAyBQ,uBjBpBuB;ACo5E/B;;AgBz5EA;EA2BQ,uBjBtBuB;ACw5E/B;;AgB75EA;EA6BQ,uBjBxBuB;AC45E/B;;AgBj6EA;EA+BQ,mEAA2F;AhBs4EnG;;AgBr6EA;EAyBQ,yBjBjCqB;ACi7E7B;;AgBz6EA;EA2BQ,yBjBnCqB;ACq7E7B;;AgB76EA;EA6BQ,yBjBrCqB;ACy7E7B;;AgBj7EA;EA+BQ,qEAA2F;AhBs5EnG;;AgBr7EA;EAyBQ,4BjBtBsB;ACs7E9B;;AgBz7EA;EA2BQ,4BjBxBsB;AC07E9B;;AgB77EA;EA6BQ,4BjB1BsB;AC87E9B;;AgBj8EA;EA+BQ,wEAA2F;AhBs6EnG;;AgBr8EA;EAyBQ,yBjB7BsB;AC68E9B;;AgBz8EA;EA2BQ,yBjB/BsB;ACi9E9B;;AgB78EA;EA6BQ,yBjBjCsB;ACq9E9B;;AgBj9EA;EA+BQ,qEAA2F;AhBs7EnG;;AgBr9EA;EAyBQ,yBjBf0B;AC+8ElC;;AgBz9EA;EA2BQ,yBjBjB0B;ACm9ElC;;AgB79EA;EA6BQ,yBjBnB0B;ACu9ElC;;AgBj+EA;EA+BQ,qEAA2F;AhBs8EnG;;AgBr+EA;EAyBQ,yBjBb0B;AC69ElC;;AgBz+EA;EA2BQ,yBjBf0B;ACi+ElC;;AgB7+EA;EA6BQ,yBjBjB0B;ACq+ElC;;AgBj/EA;EA+BQ,qEAA2F;AhBs9EnG;;AgBr/EA;EAyBQ,yBjBd0B;AC8+ElC;;AgBz/EA;EA2BQ,yBjBhB0B;ACk/ElC;;AgB7/EA;EA6BQ,yBjBlB0B;ACs/ElC;;AgBjgFA;EA+BQ,qEAA2F;AhBs+EnG;;AgBrgFA;EAyBQ,yBjBhB0B;ACggFlC;;AgBzgFA;EA2BQ,yBjBlB0B;ACogFlC;;AgB7gFA;EA6BQ,yBjBpB0B;ACwgFlC;;AgBjhFA;EA+BQ,qEAA2F;AhBs/EnG;;AgBrhFA;EAyBQ,yBjBjB0B;ACihFlC;;AgBzhFA;EA2BQ,yBjBnB0B;ACqhFlC;;AgB7hFA;EA6BQ,yBjBrB0B;ACyhFlC;;AgBjiFA;EA+BQ,qEAA2F;AhBsgFnG;;AgBriFA;EAyBQ,yBjBXyB;AC2hFjC;;AgBziFA;EA2BQ,yBjBbyB;AC+hFjC;;AgB7iFA;EA6BQ,yBjBfyB;ACmiFjC;;AgBjjFA;EA+BQ,qEAA2F;AhBshFnG;;AgBrjFA;EAkCI,gCAtCkC;UAsClC,wBAtCkC;EAuClC,2CAAmC;UAAnC,mCAAmC;EACnC,yCAAiC;UAAjC,iCAAiC;EACjC,yCAAiC;UAAjC,iCAAiC;EACjC,yBjBrC2B;EiBsC3B,qEAA0F;EAC1F,6BAA6B;EAC7B,4BAA4B;EAC5B,0BAA0B;AhBuhF9B;;AgBjkFA;EA4CM,6BAA6B;AhByhFnC;;AgBrkFA;EA8CM,6BAA6B;AhB2hFnC;;AgBzkFA;EAgDM,oBAAoB;AhB6hF1B;;AgB7kFA;EAoDI,ejBxBY;ACqjFhB;;AgBjlFA;EAsDI,ejB5BY;AC2jFhB;;AgBrlFA;EAwDI,cjB/BW;ACgkFf;;AgB/hFA;EACE;IACE,2BAA2B;EhBkiF7B;EgBjiFA;IACE,4BAA4B;EhBmiF9B;AACF;;AgBxiFA;EACE;IACE,2BAA2B;EhBkiF7B;EgBjiFA;IACE,4BAA4B;EhBmiF9B;AACF;;AiB/kFA;EAEE,uBlBhB6B;EkBiB7B,clB1B4B;AC2mF9B;;AiBplFA;;EAMI,yBlBzB0B;EkB0B1B,qBA9B6B;EA+B7B,qBA9B6B;EA+B7B,mBAAmB;AjBmlFvB;;AiB5lFA;;EAeQ,uBlB7BuB;EkB8BvB,mBlB9BuB;EkB+BvB,clB5CqB;AC8nF7B;;AiBnmFA;;EAeQ,yBlB1CqB;EkB2CrB,qBlB3CqB;EkB4CrB,YlB/BuB;ACwnF/B;;AiB1mFA;;EAeQ,4BlB/BsB;EkBgCtB,wBlBhCsB;EkBiCtB,yBPkCa;AV8jFrB;;AiBjnFA;;EAeQ,yBlBtCsB;EkBuCtB,qBlBvCsB;EkBwCtB,WPoCQ;AVmkFhB;;AiBxnFA;;EAeQ,yBlBxB0B;EkByB1B,qBlBzB0B;EkB0B1B,WPoCQ;AV0kFhB;;AiB/nFA;;EAeQ,yBlBtB0B;EkBuB1B,qBlBvB0B;EkBwB1B,WPoCQ;AVilFhB;;AiBtoFA;;EAeQ,yBlBvB0B;EkBwB1B,qBlBxB0B;EkByB1B,WPoCQ;AVwlFhB;;AiB7oFA;;EAeQ,yBlBzB0B;EkB0B1B,qBlB1B0B;EkB2B1B,WPoCQ;AV+lFhB;;AiBppFA;;EAeQ,yBlB1B0B;EkB2B1B,qBlB3B0B;EkB4B1B,yBPkCa;AVwmFrB;;AiB3pFA;;EAeQ,yBlBpByB;EkBqBzB,qBlBrByB;EkBsBzB,WPoCQ;AV6mFhB;;AiBlqFA;;EAoBM,mBAAmB;EACnB,SAAS;AjBmpFf;;AiBxqFA;;EAuBM,yBlBhC4B;EkBiC5B,WP6BU;AVynFhB;;AiB9qFA;;;;EA2BQ,mBAAmB;AjB0pF3B;;AiBrrFA;;EA6BM,sBAAsB;AjB6pF5B;;AiB1rFA;EA+BI,clBtD0B;ACqtF9B;;AiB9rFA;EAiCM,mBAAmB;AjBiqFzB;;AiBlsFA;EAoCM,yBlB7C4B;EkB8C5B,WPgBU;AVkpFhB;;AiBvsFA;;EAwCQ,mBAAmB;AjBoqF3B;;AiB5sFA;;EA2CQ,kBPUQ;EOTR,mBAAmB;AjBsqF3B;;AiBltFA;EA8CI,6BA5DqC;AjBouFzC;;AiBttFA;;EAiDM,qBApEgC;EAqEhC,clBzEwB;ACmvF9B;;AiB5tFA;EAoDI,6BAhEqC;AjB4uFzC;;AiBhuFA;;EAuDM,qBAxEgC;EAyEhC,clB/EwB;AC6vF9B;;AiBtuFA;EA0DI,6BAvEqC;AjBuvFzC;;AiB1uFA;;EA+DU,sBAAsB;AjBgrFhC;;AiB/uFA;;EAoEM,iBAAiB;AjBgrFvB;;AiBpvFA;;EAyEU,wBAAwB;AjBgrFlC;;AiBzvFA;EA2EI,WAAW;AjBkrFf;;AiB7vFA;EAgFU,yBlB/FoB;ACgxF9B;;AiBjwFA;EAqFY,yBlBpGkB;ACoxF9B;;AiBrwFA;EAuFc,4BlBvGgB;ACyxF9B;;AiBzwFA;;EA2FM,qBAAqB;AjBmrF3B;;AiB9wFA;EAgGU,yBlB/GoB;ACiyF9B;;AiBhrFA;EhBjEE,iCAAiC;EgBoEjC,cAAc;EACd,kBAAkB;EAClB,eAAe;AjBkrFjB;;AkB7yFA;EACE,mBAAmB;EACnB,aAAa;EACb,eAAe;EACf,2BAA2B;AlBgzF7B;;AkBpzFA;EAMI,qBAAqB;AlBkzFzB;;AkBxzFA;EjBmJI,oBiB3IwC;AlBozF5C;;AkB5zFA;EAUI,sBAAsB;AlBszF1B;;AkBh0FA;EAYI,mBAAmB;AlBwzFvB;;AkBp0FA;EAgBM,enBYO;AC4yFb;;AkBx0FA;EAmBM,kBnBQU;ACizFhB;;AkB50FA;EAqBI,uBAAuB;AlB2zF3B;;AkBh1FA;EAuBM,qBAAqB;EACrB,oBAAoB;AlB6zF1B;;AkBr1FA;EA0BI,yBAAyB;AlB+zF7B;;AkBz1FA;EA6BQ,mBAAmB;AlBg0F3B;;AkB71FA;EA+BQ,eAAe;AlBk0FvB;;AkBj2FA;EjBmJI,eiBjHmC;AlBm0FvC;;AkBr2FA;EjBmJI,ciB/GqC;EAE/B,yBAAyB;EACzB,4BAA4B;AlBo0FtC;;AkB32FA;EA6CU,0BAA0B;EAC1B,6BAA6B;AlBk0FvC;;AkB7zFA;EACE,mBAAmB;EACnB,4BnBjD4B;EmBkD5B,kBnBMU;EmBLV,cnBzD4B;EmB0D5B,oBAAoB;EACpB,kBnB5Bc;EmB6Bd,WAAW;EACX,uBAAuB;EACvB,gBAAgB;EAChB,oBAAoB;EACpB,qBAAqB;EACrB,mBAAmB;AlBg0FrB;;AkB50FA;EjBgGI,oBiBlFuC;EjBkFvC,uBiBjFyC;AlBk0F7C;;AkBj1FA;EAqBM,uBnBlEyB;EmBmEzB,cnBhFuB;ACg5F7B;;AkBt1FA;EAqBM,yBnB/EuB;EmBgFvB,YnBnEyB;ACw4F/B;;AkB31FA;EAqBM,4BnBpEwB;EmBqExB,yBRFe;AV40FrB;;AkBh2FA;EAqBM,yBnB3EwB;EmB4ExB,WRAU;AV+0FhB;;AkBr2FA;EAqBM,yBnB7D4B;EmB8D5B,WRAU;AVo1FhB;;AkB12FA;EA4BU,yBRCsC;EQAtC,cRS2D;AVy0FrE;;AkB/2FA;EAqBM,yBnB3D4B;EmB4D5B,WRAU;AV81FhB;;AkBp3FA;EA4BU,yBRCsC;EQAtC,cRS2D;AVm1FrE;;AkBz3FA;EAqBM,yBnB5D4B;EmB6D5B,WRAU;AVw2FhB;;AkB93FA;EA4BU,yBRCsC;EQAtC,cRS2D;AV61FrE;;AkBn4FA;EAqBM,yBnB9D4B;EmB+D5B,WRAU;AVk3FhB;;AkBx4FA;EA4BU,yBRCsC;EQAtC,cRS2D;AVu2FrE;;AkB74FA;EAqBM,yBnB/D4B;EmBgE5B,yBRFe;AV83FrB;;AkBl5FA;EA4BU,yBRCsC;EQAtC,cRS2D;AVi3FrE;;AkBv5FA;EAqBM,yBnBzD2B;EmB0D3B,WRAU;AVs4FhB;;AkB55FA;EA4BU,yBRCsC;EQAtC,cRS2D;AV23FrE;;AkBj6FA;EAgCI,kBnBtDY;AC27FhB;;AkBr6FA;EAkCI,enBzDS;ACg8Fb;;AkBz6FA;EAoCI,kBnB5DY;ACq8FhB;;AkB76FA;EjBgGI,qBiBzD0C;EjByD1C,sBiBxD0C;AlB04F9C;;AkBl7FA;EjBgGI,qBiBtD0C;EjBsD1C,sBiBrD0C;AlB44F9C;;AkBv7FA;EjBgGI,qBiBnD0C;EjBmD1C,sBiBlD0C;AlB84F9C;;AkB57FA;EjBgGI,gBiBvJmB;EAyGnB,UAAU;EACV,kBAAkB;EAClB,UAAU;AlB+4Fd;;AkBn8FA;EAuDM,8BAA8B;EAC9B,WAAW;EACX,cAAc;EACd,SAAS;EACT,kBAAkB;EAClB,QAAQ;EACR,0DAA0D;EAC1D,+BAA+B;AlBg5FrC;;AkB98FA;EAgEM,WAAW;EACX,UAAU;AlBk5FhB;;AkBn9FA;EAmEM,WAAW;EACX,UAAU;AlBo5FhB;;AkBx9FA;EAuEM,yBAAmD;AlBq5FzD;;AkB59FA;EAyEM,yBAAoD;AlBu5F1D;;AkBh+FA;EA2EI,qBnBhEmB;ACy9FvB;;AkBv5FA;EAEI,0BAA0B;AlBy5F9B;;AmB/gGA;;EAGE,sBAAsB;AnBihGxB;;AmBphGA;;;;EAMI,oBAAoB;AnBqhGxB;;AmB3hGA;;EAQI,iBApBmB;AnB4iGvB;;AmBhiGA;;EAUI,iBArBmB;AnBgjGvB;;AmBriGA;;EAYI,sBAAsB;AnB8hG1B;;AmB5hGA;EACE,cpB9B4B;EoBiC5B,epBLW;EoBMX,gBpBGmB;EoBFnB,kBAnCuB;AnBgkGzB;;AmBniGA;EAQI,cApCwB;EAqCxB,oBApCyB;AnBmkG7B;;AmBxiGA;EAWI,oBA3B+B;AnB4jGnC;;AmB5iGA;EAgBM,epBnBO;ACmjGb;;AmBhjGA;EAgBM,iBpBlBS;ACsjGf;;AmBpjGA;EAgBM,epBjBO;ACyjGb;;AmBxjGA;EAgBM,iBpBhBS;AC4jGf;;AmB5jGA;EAgBM,kBpBfU;AC+jGhB;;AmBhkGA;EAgBM,epBdO;ACkkGb;;AmBpkGA;EAgBM,kBpBbU;ACqkGhB;;AmBtjGA;EACE,cpB/C4B;EoBkD5B,kBpBrBc;EoBsBd,gBpBjBiB;EoBkBjB,iBA3CyB;AnBkmG3B;;AmB7jGA;EAQI,cpBvD0B;EoBwD1B,gBpBnBiB;AC4kGrB;;AmBlkGA;EAWI,oBA7C+B;AnBwmGnC;;AmBtkGA;EAgBM,epBrCO;AC+lGb;;AmB1kGA;EAgBM,iBpBpCS;ACkmGf;;AmB9kGA;EAgBM,epBnCO;ACqmGb;;AmBllGA;EAgBM,iBpBlCS;ACwmGf;;AmBtlGA;EAgBM,kBpBjCU;AC2mGhB;;AmB1lGA;EAgBM,epBhCO;AC8mGb;;AmB9lGA;EAgBM,kBpB/BU;ACinGhB;;AoB/oGA;EACE,cAAc;EACd,eAAe;EACf,mBAAmB;EACnB,kBAAkB;EAClB,yBAAyB;ApBkpG3B;;AoB7oGA;EACE,mBAAmB;EACnB,4BrBP4B;EqBQ5B,qBrBkDqB;EqBjDrB,oBAAoB;EACpB,kBrBac;EqBZd,WAAW;EACX,uBAAuB;EACvB,oBAAoB;EACpB,gBAAgB;EAChB,uBAAuB;EACvB,kBAAkB;EAClB,mBAAmB;ApBgpGrB;;AqB9qGA,eAAA;AC0DA;EAxBE,uBvBnB6B;EuBoB7B,qBvBzB4B;EuB0B5B,kBvBiCU;EuBhCV,cvB/B4B;ACgrG9B;;ACnnGI;EqB5BA,4BvBjC0B;ACorG9B;;ACvnGI;EqB5BA,4BvBjC0B;ACwrG9B;;AC3nGI;EqB5BA,4BvBjC0B;AC4rG9B;;AC/nGI;EqB5BA,4BvBjC0B;ACgsG9B;;AsB9pGE;EAEE,qBvBjC0B;ACisG9B;;AsB/pGE;EAIE,qBvBzB8B;EuB0B9B,iDvB1B8B;ACyrGlC;;AsB9pGE;;;;;EAEE,4BvBtC0B;EuBuC1B,wBvBvC0B;EuBwC1B,gBAAgB;EAChB,cvB9C0B;ACktG9B;;ACvpGI;;;;;EqBXE,+BvBhDwB;AC0tG9B;;AC/pGI;;;;;EqBXE,+BvBhDwB;ACkuG9B;;ACvqGI;;;;;EqBXE,+BvBhDwB;AC0uG9B;;AC/qGI;;;;;EqBXE,+BvBhDwB;ACkvG9B;;AuBpvGA;EAEE,2DxBN2B;EwBO3B,eAAe;EACf,WAAW;AvBsvGb;;AuBrvGE;EACE,gBAAgB;AvBwvGpB;;AuBpvGI;EACE,mBxBFyB;ACyvG/B;;AuBxvGK;EAMG,mDxBPuB;AC6vG/B;;AuB5vGI;EACE,qBxBfuB;AC8wG7B;;AuBhwGK;EAMG,gDxBpBqB;ACkxG7B;;AuBpwGI;EACE,wBxBJwB;AC2wG9B;;AuBxwGK;EAMG,mDxBTsB;AC+wG9B;;AuB5wGI;EACE,qBxBXwB;AC0xG9B;;AuBhxGK;EAMG,gDxBhBsB;AC8xG9B;;AuBpxGI;EACE,qBxBG4B;ACoxGlC;;AuBxxGK;EAMG,iDxBF0B;ACwxGlC;;AuB5xGI;EACE,qBxBK4B;AC0xGlC;;AuBhyGK;EAMG,iDxBA0B;AC8xGlC;;AuBpyGI;EACE,qBxBI4B;ACmyGlC;;AuBxyGK;EAMG,kDxBD0B;ACuyGlC;;AuB5yGI;EACE,qBxBE4B;AC6yGlC;;AuBhzGK;EAMG,kDxBH0B;ACizGlC;;AuBpzGI;EACE,qBxBC4B;ACszGlC;;AuBxzGK;EAMG,mDxBJ0B;AC0zGlC;;AuB5zGI;EACE,qBxBO2B;ACwzGjC;;AuBh0GK;EAMG,kDxBEyB;AC4zGjC;;AuB5zGE;EzBmBA,kBCyBgB;EDxBhB,kBCNc;ACmzGhB;;AuB/zGE;EzBoBA,kBCVc;ACyzGhB;;AuBj0GE;EzBoBA,iBCba;AC8zGf;;AuBl0GE;EACE,cAAc;EACd,WAAW;AvBq0Gf;;AuBp0GE;EACE,eAAe;EACf,WAAW;AvBu0Gf;;AuBr0GA;EAGI,qBxB8BmB;EwB7BnB,gDAA4D;EAC5D,iDAA6D;AvBs0GjE;;AuB30GA;EAOI,6BAA6B;EAC7B,yBAAyB;EACzB,gBAAgB;EAChB,eAAe;EACf,gBAAgB;AvBw0GpB;;AuBt0GA;EAEE,cAAc;EACd,eAAe;EACf,eAAe;EACf,2BzB7CkE;EyB8ClE,gBAAgB;AvBw0GlB;;AuB90GA;EAQI,gBA1DsB;EA2DtB,eA1DqB;AvBo4GzB;;AuBn1GA;EAWI,eAAe;AvB40GnB;;AuBv1GA;EAcI,YAAY;AvB60GhB;;AwB94GA;EACE,eAAe;EACf,qBAAqB;EACrB,iBAAiB;EACjB,kBAAkB;AxBi5GpB;;AwBh5GE;EACE,eAAe;AxBm5GnB;;AwBl5GE;EACE,czBF0B;ACu5G9B;;AwBp5GE;;;;;EAGE,czBJ0B;EyBK1B,mBAAmB;AxBy5GvB;;AwBp5GA;EvB0II,kBuBvIqC;AxBq5GzC;;AyBx6GA;EACE,qBAAqB;EACrB,eAAe;EACf,kBAAkB;EAClB,mBAAmB;AzB26GrB;;AyB/6GA;EAMI,a3BDkB;AE86GtB;;AyBn7GA;EAUM,qB1BU4B;EE8I9B,cwBvJ+B;EAC7B,UAAU;AzB66GhB;;AyBz7GA;EAeM,qB1BsDiB;EEqFnB,iBwB1IsC;AzB86G1C;;AyB97GA;EAmBI,eAAe;EACf,cAAc;EACd,cAAc;EACd,eAAe;EACf,aAAa;AzB+6GjB;;AyBt8GA;EAyBM,aAAa;AzBi7GnB;;AyB18GA;;EA4BM,wB1BjBwB;ACo8G9B;;AyB/8GA;ExB0JI,oBwB5HwC;AzBq7G5C;;AyBn9GA;EAgCM,YAAY;EACZ,UAAU;AzBu7GhB;;AyBx9GA;EAmCQ,kBAAkB;AzBy7G1B;;AyB59GA;EAuCM,qB1BnCwB;AC49G9B;;AyBh+GA;EA6CQ,mB1BhCuB;ACu9G/B;;AyBp+GA;EA+CQ,mB1BlCuB;AC29G/B;;AyBx+GA;EAkDU,qBfyDuB;AVi4GjC;;AyB5+GA;EAuDU,mD1B1CqB;ACm+G/B;;AyBh/GA;EA6CQ,qB1B7CqB;ACo/G7B;;AyBp/GA;EA+CQ,qB1B/CqB;ACw/G7B;;AyBx/GA;EAkDU,mBfyDuB;AVi5GjC;;AyB5/GA;EAuDU,gD1BvDmB;ACggH7B;;AyBhgHA;EA6CQ,wB1BlCsB;ACy/G9B;;AyBpgHA;EA+CQ,wB1BpCsB;AC6/G9B;;AyBxgHA;EAkDU,qBfyDuB;AVi6GjC;;AyB5gHA;EAuDU,mD1B5CoB;ACqgH9B;;AyBhhHA;EA6CQ,qB1BzCsB;ACghH9B;;AyBphHA;EA+CQ,qB1B3CsB;ACohH9B;;AyBxhHA;EAkDU,qBfyDuB;AVi7GjC;;AyB5hHA;EAuDU,gD1BnDoB;AC4hH9B;;AyBhiHA;EA6CQ,qB1B3B0B;ACkhHlC;;AyBpiHA;EA+CQ,qB1B7B0B;ACshHlC;;AyBxiHA;EAkDU,qBfyDuB;AVi8GjC;;AyB5iHA;EAuDU,iD1BrCwB;AC8hHlC;;AyBhjHA;EA6CQ,qB1BzB0B;ACgiHlC;;AyBpjHA;EA+CQ,qB1B3B0B;ACoiHlC;;AyBxjHA;EAkDU,qBfyDuB;AVi9GjC;;AyB5jHA;EAuDU,iD1BnCwB;AC4iHlC;;AyBhkHA;EA6CQ,qB1B1B0B;ACijHlC;;AyBpkHA;EA+CQ,qB1B5B0B;ACqjHlC;;AyBxkHA;EAkDU,qBfyDuB;AVi+GjC;;AyB5kHA;EAuDU,kD1BpCwB;AC6jHlC;;AyBhlHA;EA6CQ,qB1B5B0B;ACmkHlC;;AyBplHA;EA+CQ,qB1B9B0B;ACukHlC;;AyBxlHA;EAkDU,qBfyDuB;AVi/GjC;;AyB5lHA;EAuDU,kD1BtCwB;AC+kHlC;;AyBhmHA;EA6CQ,qB1B7B0B;AColHlC;;AyBpmHA;EA+CQ,qB1B/B0B;ACwlHlC;;AyBxmHA;EAkDU,qBfyDuB;AVigHjC;;AyB5mHA;EAuDU,mD1BvCwB;ACgmHlC;;AyBhnHA;EA6CQ,qB1BvByB;AC8lHjC;;AyBpnHA;EA+CQ,qB1BzByB;ACkmHjC;;AyBxnHA;EAkDU,qBfyDuB;AVihHjC;;AyB5nHA;EAuDU,kD1BjCuB;AC0mHjC;;AyBhoHA;E3ByCE,kBCyBgB;EDxBhB,kBCNc;ACimHhB;;AyBroHA;E3B4CE,kBCVc;ACumHhB;;AyBzoHA;E3B8CE,iBCba;AC4mHf;;AyB7oHA;EAkEM,qB1B5DwB;AC2oH9B;;AyBjpHA;EAoEI,WAAW;AzBilHf;;AyBrpHA;EAsEM,WAAW;AzBmlHjB;;AyBzpHA;EA0EM,aAAa;EACb,kBAAkB;ExBuFpB,cwBtF+B;EAC7B,YAAY;EACZ,eAAe;AzBmlHrB;;AyBjqHA;EAgFM,kB1B5CU;ACioHhB;;AyBrqHA;EAkFM,kB1BhDU;ACuoHhB;;AyBzqHA;EAoFM,iB1BnDS;AC4oHf;;A0BhqHA;EAEE,oBAAoB;EACpB,aAAa;EACb,2BAA2B;EAC3B,kBAAkB;A1BkqHpB;;A0BvqHA;EAYQ,uB3BZuB;E2BavB,yBAAyB;EACzB,c3B3BqB;AC0rH7B;;A0B7qHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,c3BjCmB;ACgsH7B;;A0BnrHA;EAwBU,yBAAyB;EACzB,+C3BzBqB;E2B0BrB,c3BvCmB;ACssH7B;;A0BzrHA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,c3B7CmB;AC4sH7B;;A0B/rHA;EAYQ,yB3BzBqB;E2B0BrB,yBAAyB;EACzB,Y3BduB;ACqsH/B;;A0BrsHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,Y3BpBqB;AC2sH/B;;A0B3sHA;EAwBU,yBAAyB;EACzB,4C3BtCmB;E2BuCnB,Y3B1BqB;ACitH/B;;A0BjtHA;EA8BU,uBhBgEuB;EgB/DvB,yBAAyB;EACzB,Y3BhCqB;ACutH/B;;A0BvtHA;EAYQ,4B3BdsB;E2BetB,yBAAyB;EACzB,yBhBmDa;AV4pHrB;;A0B7tHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,yBhB6CW;AVkqHrB;;A0BnuHA;EAwBU,yBAAyB;EACzB,+C3B3BoB;E2B4BpB,yBhBuCW;AVwqHrB;;A0BzuHA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,yBhBiCW;AV8qHrB;;A0B/uHA;EAYQ,yB3BrBsB;E2BsBtB,yBAAyB;EACzB,WhBqDQ;AVkrHhB;;A0BrvHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,WhB+CM;AVwrHhB;;A0B3vHA;EAwBU,yBAAyB;EACzB,4C3BlCoB;E2BmCpB,WhByCM;AV8rHhB;;A0BjwHA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,WhBmCM;AVosHhB;;A0BvwHA;EAYQ,yB3BP0B;E2BQ1B,yBAAyB;EACzB,WhBqDQ;AV0sHhB;;A0B7wHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,WhB+CM;AVgtHhB;;A0BnxHA;EAwBU,yBAAyB;EACzB,6C3BpBwB;E2BqBxB,WhByCM;AVstHhB;;A0BzxHA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,WhBmCM;AV4tHhB;;A0B/xHA;EAYQ,yB3BL0B;E2BM1B,yBAAyB;EACzB,WhBqDQ;AVkuHhB;;A0BryHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,WhB+CM;AVwuHhB;;A0B3yHA;EAwBU,yBAAyB;EACzB,6C3BlBwB;E2BmBxB,WhByCM;AV8uHhB;;A0BjzHA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,WhBmCM;AVovHhB;;A0BvzHA;EAYQ,yB3BN0B;E2BO1B,yBAAyB;EACzB,WhBqDQ;AV0vHhB;;A0B7zHA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,WhB+CM;AVgwHhB;;A0Bn0HA;EAwBU,yBAAyB;EACzB,8C3BnBwB;E2BoBxB,WhByCM;AVswHhB;;A0Bz0HA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,WhBmCM;AV4wHhB;;A0B/0HA;EAYQ,yB3BR0B;E2BS1B,yBAAyB;EACzB,WhBqDQ;AVkxHhB;;A0Br1HA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,WhB+CM;AVwxHhB;;A0B31HA;EAwBU,yBAAyB;EACzB,8C3BrBwB;E2BsBxB,WhByCM;AV8xHhB;;A0Bj2HA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,WhBmCM;AVoyHhB;;A0Bv2HA;EAYQ,yB3BT0B;E2BU1B,yBAAyB;EACzB,yBhBmDa;AV4yHrB;;A0B72HA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,yBhB6CW;AVkzHrB;;A0Bn3HA;EAwBU,yBAAyB;EACzB,+C3BtBwB;E2BuBxB,yBhBuCW;AVwzHrB;;A0Bz3HA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,yBhBiCW;AV8zHrB;;A0B/3HA;EAYQ,yB3BHyB;E2BIzB,yBAAyB;EACzB,WhBqDQ;AVk0HhB;;A0Br4HA;EAkBU,yBhB4EuB;EgB3EvB,yBAAyB;EACzB,WhB+CM;AVw0HhB;;A0B34HA;EAwBU,yBAAyB;EACzB,8C3BhBuB;E2BiBvB,WhByCM;AV80HhB;;A0Bj5HA;EA8BU,yBhBgEuB;EgB/DvB,yBAAyB;EACzB,WhBmCM;AVo1HhB;;A0Bv5HA;EAmCI,kB3BZY;ACo4HhB;;A0B35HA;EAqCI,e3BfS;ACy4Hb;;A0B/5HA;EAuCI,kB3BlBY;AC84HhB;;A0Bn6HA;EA0CQ,eAAe;A1B63HvB;;A0Bv6HA;EA4CI,iB3BxBW;ACu5Hf;;A0B36HA;EA+CQ,eAAe;A1Bg4HvB;;A0B/6HA;EAmDM,6BAA6B;EAC7B,0BAA0B;A1Bg4HhC;;A0Bp7HA;EAsDM,4BAA4B;EAC5B,yBAAyB;A1Bk4H/B;;A0Bz7HA;EA0DQ,kB3BJI;ACu4HZ;;A0B77HA;EA4DQ,aAAa;A1Bq4HrB;;A0Bj8HA;EA+DM,sBAAsB;A1Bs4H5B;;A0Br8HA;EAiEM,sBAAsB;EACtB,YAAY;EACZ,gBAAgB;A1Bw4HtB;;A0B38HA;EAqEM,uBAAuB;A1B04H7B;;A0B/8HA;EAuEM,aAAa;EACb,YAAY;A1B44HlB;;A0Bp9HA;EA0EQ,eAAe;A1B84HvB;;A0Bx9HA;EA6EQ,eAAe;A1B+4HvB;;A0B59HA;EAgFQ,eAAe;A1Bg5HvB;;A0Bh+HA;EAmFQ,eAAe;A1Bi5HvB;;A0Bp+HA;EAsFQ,0BAA4C;A1Bk5HpD;;A0Bx+HA;EAwFQ,0B3BlCI;E2BmCJ,uBAAuB;A1Bo5H/B;;A0B7+HA;EA2FI,uBAAuB;A1Bs5H3B;;A0Bj/HA;EA8FM,WAAW;A1Bu5HjB;;A0Br/HA;EAgGM,YAAY;EACZ,eAAe;A1By5HrB;;A0B1/HA;EAmGI,yBAAyB;A1B25H7B;;A0B9/HA;EAqGM,0BAA4C;A1B65HlD;;A0BlgIA;EAuGM,0B3BjDM;E2BkDN,2BAA2B;EAC3B,SAAS;A1B+5Hf;;A0B75HA;EACE,oBAAoB;EACpB,aAAa;EACb,eAAe;EACf,2BAA2B;EAC3B,gBAAgB;EAChB,kBAAkB;A1Bg6HpB;;A0Bt6HA;EASM,yBhBtB2B;EgBuB3B,c3B9HwB;AC+hI9B;;A0B36HA;EAYM,qBhBzB2B;AV47HjC;;A0B/6HA;EAeM,yBhB5B2B;EgB6B3B,c3BpIwB;ACwiI9B;;A0Bp7HA;EAkBM,qBhB/B2B;AVq8HjC;;A0Bp6HA;EACE,YAAY;EACZ,OAAO;EACP,UAAU;EACV,aAAa;EACb,kBAAkB;EAClB,MAAM;EACN,WAAW;A1Bu6Hb;;A0Br6HA;;EAGE,qB3BhJ4B;E2BiJ5B,kB3BtFU;E2BuFV,cAAc;EACd,iBAAiB;EACjB,kBAAkB;EAClB,mBAAmB;A1Bu6HrB;;A0Br6HA;EACE,4B3BrJ4B;E2BsJ5B,c3B5J4B;ACokI9B;;A0Bt6HA;EACE,qB3B5J4B;E2B6J5B,mBA9J4B;EA+J5B,2BA9JoC;EA+JpC,cAAc;EACd,eA/JwB;EAgKxB,gBAAgB;EAChB,mBAAmB;EACnB,uBAAuB;A1By6HzB;;A0Bv6HA;EACE,mBAAmB;EACnB,aAAa;EACb,WAAW;EACX,uBAAuB;EzBvBrB,mByBwBmC;EACrC,UAAU;A1B06HZ;;A0Bh7HA;EAQI,eAAe;A1B46HnB;;A2B5lIA;EACE,c5BF4B;E4BG5B,cAAc;EACd,e5B2BW;E4B1BX,gB5BiCe;AC8jIjB;;A2BnmIA;EAMI,oBAAoB;A3BimIxB;;A2BvmIA;EASI,kB5BsBY;AC4kIhB;;A2B3mIA;EAWI,kB5BkBY;ACklIhB;;A2B/mIA;EAaI,iB5BeW;ACulIf;;A2BpmIA;EACE,cAAc;EACd,kB5Bcc;E4Bbd,mBAAmB;A3BumIrB;;A2B1mIA;EAOM,Y5BdyB;ACqnI/B;;A2B9mIA;EAOM,c5B3BuB;ACsoI7B;;A2BlnIA;EAOM,iB5BhBwB;AC+nI9B;;A2BtnIA;EAOM,c5BvBwB;AC0oI9B;;A2B1nIA;EAOM,c5BT4B;ACgoIlC;;A2B9nIA;EAOM,c5BP4B;ACkoIlC;;A2BloIA;EAOM,c5BR4B;ACuoIlC;;A2BtoIA;EAOM,c5BV4B;AC6oIlC;;A2B1oIA;EAOM,c5BX4B;ACkpIlC;;A2B9oIA;EAOM,c5BL2B;ACgpIjC;;A2BvoIA;EAEI,sBAAsB;A3ByoI1B;;A2B3oIA;EAKI,aAAa;EACb,2BAA2B;A3B0oI/B;;A2BhpIA;E1B2HI,kB0BlHwC;A3B2oI5C;;A2BppIA;;;EAcU,gBAAgB;A3B4oI1B;;A2B1pIA;;;EAoBY,6BAA6B;EAC7B,0BAA0B;A3B4oItC;;A2BjqIA;;;EA8BY,4BAA4B;EAC5B,yBAAyB;A3ByoIrC;;A2BxqIA;;;;;EAyCY,UAAU;A3BuoItB;;A2BhrIA;;;;;;;;;EA8CY,UAAU;A3B8oItB;;A2B5rIA;;;;;;;;;EAgDc,UAAU;A3BwpIxB;;A2BxsIA;EAkDQ,YAAY;EACZ,cAAc;A3B0pItB;;A2B7sIA;EAqDM,uBAAuB;A3B4pI7B;;A2BjtIA;EAuDM,yBAAyB;A3B8pI/B;;A2BrtIA;EA0DQ,YAAY;EACZ,cAAc;A3B+pItB;;A2B1tIA;EA6DI,aAAa;EACb,2BAA2B;A3BiqI/B;;A2B/tIA;EAgEM,cAAc;A3BmqIpB;;A2BnuIA;EAkEQ,gBAAgB;E1ByDpB,qB0BxD2C;A3BqqI/C;;A2BxuIA;EAqEQ,YAAY;EACZ,cAAc;A3BuqItB;;A2B7uIA;EAwEM,uBAAuB;A3ByqI7B;;A2BjvIA;EA0EM,yBAAyB;A3B2qI/B;;A2BrvIA;EA4EM,eAAe;A3B6qIrB;;A2BzvIA;EAgFU,sBAAsB;A3B6qIhC;;A2B7vIA;EAkFQ,uBAAuB;A3B+qI/B;;A2BjwIA;EAoFQ,gBAAgB;A3BirIxB;;ACrsIE;E0BhEF;IAuFM,aAAa;E3BmrIjB;AACF;;A2BlrIA;EAEI,kBAAkB;A3BorItB;;ACntIE;E0B6BF;IAII,qBAAqB;E3BurIvB;AACF;;ACrtIE;E0ByBF;IAMI,aAAa;IACb,YAAY;IACZ,cAAc;I1B0Bd,oB0BzBsC;IACtC,iBAAiB;E3B2rInB;E2BrsIF;IAYM,kB5BhGU;I4BiGV,oBAAoB;E3B4rIxB;E2BzsIF;IAeM,oBAAoB;E3B6rIxB;E2B5sIF;IAiBM,kB5BvGU;I4BwGV,oBAAoB;E3B8rIxB;E2BhtIF;IAoBM,iB5B3GS;I4B4GT,oBAAoB;E3B+rIxB;AACF;;A2B9rIA;EAEI,gBAAgB;A3BgsIpB;;AClvIE;E0BgDF;IAII,aAAa;IACb,aAAa;IACb,YAAY;IACZ,cAAc;E3BmsIhB;E2B1sIF;IASM,gBAAgB;E3BosIpB;E2B7sIF;IAWM,cAAc;E3BqsIlB;E2BhtIF;IAaQ,YAAY;E3BssIlB;E2BntIF;I1BWI,qB0BI2C;E3BusI7C;AACF;;A2BtsIA;EACE,sBAAsB;EACtB,WAAW;EACX,e5BhIW;E4BiIX,kBAAkB;EAClB,mBAAmB;A3BysIrB;;A2B9sIA;;;EAaU,c5BxKoB;AC+2I9B;;A2BptIA;;;EAeQ,kB5B3IQ;ACs1IhB;;A2B1tIA;;;EAiBQ,kB5B/IQ;AC81IhB;;A2BhuIA;;;EAmBQ,iB5BlJO;ACq2If;;A2BtuIA;EAqBM,c5B7KwB;E4B8KxB,a7BjLgB;E6BkLhB,oBAAoB;EACpB,kBAAkB;EAClB,MAAM;EACN,Y7BrLgB;E6BsLhB,UAAU;A3BqtIhB;;A2BhvIA;;EA+BM,mB7B1LgB;AEg5ItB;;A2BrvIA;EAiCM,OAAO;A3BwtIb;;A2BzvIA;;EAqCM,oB7BhMgB;AEy5ItB;;A2B9vIA;EAuCM,QAAQ;A3B2tId;;A2BlwIA;EA2CM,6BAA6B;E1BzC/B,c0B0C+B;EAC7B,YAAY;EACZ,UAAU;A3B2tIhB;;A2BzwIA;EAgDM,kB5B5KU;ACy4IhB;;A2B7wIA;EAkDM,kB5BhLU;AC+4IhB;;A2BjxIA;EAoDM,iB5BnLS;ACo5If;;A4Bv7IA,qBAAA;ACWA;EAGE,e9BuBW;E8BtBX,mBAAmB;A7B86IrB;;A6Bl7IA;EAMI,mBAAmB;EACnB,c9BI8B;E8BH9B,aAAa;EACb,uBAAuB;EACvB,iBAduC;A7B87I3C;;A6B17IA;EAYM,c9BjBwB;ACm8I9B;;A6B97IA;EAcI,mBAAmB;EACnB,aAAa;A7Bo7IjB;;A6Bn8IA;E5BiJI,e4BhIoC;A7Bs7IxC;;A6Bv8IA;EAoBQ,c9BzBsB;E8B0BtB,eAAe;EACf,oBAAoB;A7Bu7I5B;;A6B78IA;EAwBM,c9B1BwB;E8B2BxB,iBAAiB;A7By7IvB;;A6Bl9IA;;EA4BI,uBAAuB;EACvB,aAAa;EACb,eAAe;EACf,2BAA2B;A7B27I/B;;A6B19IA;E5BiJI,mB4B/GuC;A7B47I3C;;A6B99IA;E5BiJI,kB4B7GuC;A7B87I3C;;A6Bl+IA;;EAyCM,uBAAuB;A7B87I7B;;A6Bv+IA;;EA6CM,yBAAyB;A7B+7I/B;;A6B5+IA;EAgDI,kB9BrBY;ACq9IhB;;A6Bh/IA;EAkDI,kB9BzBY;AC29IhB;;A6Bp/IA;EAoDI,iB9B5BW;ACg+If;;A6Bx/IA;EAwDM,iBAAiB;A7Bo8IvB;;A6B5/IA;EA2DM,iBAAiB;A7Bq8IvB;;A6BhgJA;EA8DM,iBAAiB;A7Bs8IvB;;A6BpgJA;EAiEM,iBAAiB;A7Bu8IvB;;A8B7/IA;EACE,uB/BR6B;E+BS7B,sBAnBmB;EAoBnB,0F/BvB2B;E+BwB3B,c/BnB4B;E+BoB5B,eAAe;EACf,kBAAkB;A9BggJpB;;A8B7/IE;EACE,+BA3BiB;EA4BjB,gCA5BiB;A9B4hJrB;;A8B//IE;EACE,kCA9BiB;EA+BjB,mCA/BiB;A9BiiJrB;;A8BhgJA;EAEE,6BAjCwC;EAkCxC,oBAAoB;EACpB,kD/BxC2B;E+ByC3B,aAAa;A9BkgJf;;A8BhgJA;EACE,mBAAmB;EACnB,c/BzC4B;E+B0C5B,aAAa;EACb,YAAY;EACZ,gB/BNe;E+BOf,qBA1CgC;A9B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;;AiCp0JA;EAgBQ,kBAlBsB;AjC00J9B;;AiCx0JA;EAkBI,8ClCnB0B;EkCoB1B,gBA1BgB;EA2BhB,iBA3BgB;AjCq1JpB;;AiC90JA;EAwBM,kBA9BsB;EA+BtB,mBA/BsB;AjCy1J5B;;AiCxzJA;;EAEE,gBAAgB;EAChB,YAAY;EACZ,cAAc;AjC2zJhB;;AiCzzJA;EhCgHI,kBgCxJgB;AjCq2JpB;;AiC1zJA;EhC6GI,iBgCxJgB;AjCy2JpB;;AiC3zJA;EACE,gBAAgB;EAChB,YAAY;EACZ,cAAc;EACd,mBAAmB;AjC8zJrB;;ACvxJE;EgC3CF;IAQI,gBAAgB;EjC+zJlB;AACF;;AkCt2JA;EACE,enCgBW;ACy1Jb;;AkC12JA;EAII,kBnCcY;AC41JhB;;AkC92JA;EAMI,kBnCUY;ACk2JhB;;AkCl3JA;EAQI,iBnCOW;ACu2Jf;;AkC52JA;EACE,iBArB0B;AlCo4J5B;;AkCh3JA;EAGI,kBnCmCc;EmClCd,cnC3B0B;EmC4B1B,cAAc;EACd,qBAzBiC;AlC04JrC;;AkCv3JA;EAQM,4BnCzBwB;EmC0BxB,cnCjCwB;ACo5J9B;;AkC53JA;EAYM,yBnCpB4B;EmCqB5B,WxBuCU;AV60JhB;;AkCj4JA;EjC8HI,8BFlJ0B;EmCqCxB,cAnC0B;EjCgJ5B,oBiC/IkC;AlCw5JtC;;AkCn3JA;EACE,cnC3C4B;EmC4C5B,iBApC2B;EAqC3B,qBApC+B;EAqC/B,yBAAyB;AlCs3J3B;;AkC13JA;EAMI,eAtCoB;AlC85JxB;;AkC93JA;EAQI,kBAxCoB;AlCk6JxB;;AmC75JA;EAEE,4BpCZ4B;EoCa5B,kBpC2CU;EoC1CV,epCUW;ACq5Jb;;AmCn6JA;EAMI,mBAAmB;AnCi6JvB;;AmCv6JA;EAQI,mBAAmB;EACnB,0BAA0B;AnCm6J9B;;AmC56JA;EAYI,kBpCGY;ACi6JhB;;AmCh7JA;EAcI,kBpCDY;ACu6JhB;;AmCp7JA;EAgBI,iBpCJW;AC46Jf;;AmCx7JA;EAsCM,uBAH+C;AnCy5JrD;;AmC57JA;EAwCQ,uBpChDuB;EoCiDvB,cpC9DqB;ACs9J7B;;AmCj8JA;EA2CQ,mBpCnDuB;AC68J/B;;AmCr8JA;EAsCM,yBAH+C;AnCs6JrD;;AmCz8JA;EAwCQ,yBpC7DqB;EoC8DrB,YpCjDuB;ACs9J/B;;AmC98JA;EA2CQ,qBpChEqB;ACu+J7B;;AmCl9JA;EAsCM,yBAH+C;AnCm7JrD;;AmCt9JA;EAwCQ,4BpClDsB;EoCmDtB,yBzBgBa;AVk6JrB;;AmC39JA;EA2CQ,wBpCrDsB;ACy+J9B;;AmC/9JA;EAsCM,yBAH+C;AnCg8JrD;;AmCn+JA;EAwCQ,yBpCzDsB;EoC0DtB,WzBkBQ;AV66JhB;;AmCx+JA;EA2CQ,qBpC5DsB;AC6/J9B;;AmC5+JA;EAsCM,yBzB4B0C;AV86JhD;;AmCh/JA;EAwCQ,yBpC3C0B;EoC4C1B,WzBkBQ;AV07JhB;;AmCr/JA;EA2CQ,qBpC9C0B;EoC+C1B,czB+B6D;AV+6JrE;;AmC1/JA;EAsCM,yBzB4B0C;AV47JhD;;AmC9/JA;EAwCQ,yBpCzC0B;EoC0C1B,WzBkBQ;AVw8JhB;;AmCngKA;EA2CQ,qBpC5C0B;EoC6C1B,czB+B6D;AV67JrE;;AmCxgKA;EAsCM,yBzB4B0C;AV08JhD;;AmC5gKA;EAwCQ,yBpC1C0B;EoC2C1B,WzBkBQ;AVs9JhB;;AmCjhKA;EA2CQ,qBpC7C0B;EoC8C1B,czB+B6D;AV28JrE;;AmCthKA;EAsCM,yBzB4B0C;AVw9JhD;;AmC1hKA;EAwCQ,yBpC5C0B;EoC6C1B,WzBkBQ;AVo+JhB;;AmC/hKA;EA2CQ,qBpC/C0B;EoCgD1B,czB+B6D;AVy9JrE;;AmCpiKA;EAsCM,yBzB4B0C;AVs+JhD;;AmCxiKA;EAwCQ,yBpC7C0B;EoC8C1B,yBzBgBa;AVo/JrB;;AmC7iKA;EA2CQ,qBpChD0B;EoCiD1B,czB+B6D;AVu+JrE;;AmCljKA;EAsCM,yBzB4B0C;AVo/JhD;;AmCtjKA;EAwCQ,yBpCvCyB;EoCwCzB,WzBkBQ;AVggKhB;;AmC3jKA;EA2CQ,qBpC1CyB;EoC2CzB,czB+B6D;AVq/JrE;;AmClhKA;EACE,mBAAmB;EACnB,yBpChE4B;EoCiE5B,0BAAgE;EAChE,WzBSc;EyBRd,aAAa;EACb,gBpC/Be;EoCgCf,8BAA8B;EAC9B,iBAAiB;EACjB,mBAtEiC;EAuEjC,kBAAkB;AnCqhKpB;;AmC/hKA;EAYI,YAAY;EACZ,cAAc;ElC0Ed,mBkCzEsC;AnCuhK1C;;AmCriKA;EAgBI,eAjEgC;EAkEhC,yBAAyB;EACzB,0BAA0B;AnCyhK9B;;AmCvhKA;EACE,qBpChF4B;EoCiF5B,kBpCtBU;EoCuBV,mBAAmB;EACnB,uBAjFmC;EAkFnC,cpCvF4B;EoCwF5B,qBAjFiC;AnC2mKnC;;AmChiKA;;EASI,uBpCnF2B;AC+mK/B;;AmCriKA;EAWI,6BAlFgD;AnCgnKpD;;AoChmKA;EAEE,mBAAmB;EACnB,aAAa;EACb,sBAAsB;EACtB,uBAAuB;EACvB,gBAAgB;EAChB,eAAe;EACf,WAxCU;ApC0oKZ;;AoC1mKA;EAWI,aAAa;ApCmmKjB;;AoCjmKA;EAEE,wCrC/C2B;ACkpK7B;;AoCjmKA;;EAEE,cA9CgC;EA+ChC,+BAA0D;EAC1D,cAAc;EACd,kBAAkB;EAClB,WAAW;ApComKb;;ACxkKE;EmClCF;;IASI,cAAc;IACd,8BAA0D;IAC1D,YAxDuB;EpC+pKzB;AACF;;AoCtmKA;EAEE,gBAAgB;EAChB,YAxD2B;EAyD3B,eAAe;EnCgGb,WmCxJoB;EA0DtB,SAzDoB;EA0DpB,WA5D2B;ApCoqK7B;;AoCtmKA;EACE,aAAa;EACb,sBAAsB;EACtB,8BAAgD;EAChD,gBAAgB;EAChB,uBAAuB;ApCymKzB;;AoCvmKA;;EAEE,mBAAmB;EACnB,4BrCtE4B;EqCuE5B,aAAa;EACb,cAAc;EACd,2BAA2B;EAC3B,aApE4B;EAqE5B,kBAAkB;ApC0mKpB;;AoCxmKA;EACE,gCrCjF4B;EqCkF5B,2BrCtBgB;EqCuBhB,4BrCvBgB;ACkoKlB;;AoCzmKA;EACE,crC1F4B;EqC2F5B,YAAY;EACZ,cAAc;EACd,iBrChEa;EqCiEb,cA7E8B;ApCyrKhC;;AoC1mKA;EACE,8BrCjCgB;EqCkChB,+BrClCgB;EqCmChB,6BrC/F4B;AC4sK9B;;AoChnKA;EnCsDI,mBmChDuC;ApC8mK3C;;AoC5mKA;EnChDE,iCAAiC;EmCkDjC,uBrCjG6B;EqCkG7B,YAAY;EACZ,cAAc;EACd,cAAc;EACd,aAtF4B;ApCqsK9B;;AqCzqKA;EACE,uBtC5C6B;EsC6C7B,mBAvDqB;EAwDrB,kBAAkB;EAClB,WAtDW;ArCkuKb;;AqChrKA;EASM,uBtCpDyB;EsCqDzB,ctClEuB;AC6uK7B;;AqCrrKA;;EAcU,ctCtEmB;ACkvK7B;;AqC1rKA;;;;EAoBY,yB3B+BqB;E2B9BrB,ctC7EiB;AC0vK7B;;AqClsKA;EAwBY,qBtChFiB;AC8vK7B;;AqCtsKA;EA0BQ,ctClFqB;ACkwK7B;;AC/qKE;EoC3BF;;;;IAgCY,ctCxFiB;EC0wK3B;EqCltKF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,ctC/Fe;ECuxK3B;EqC/tKF;;IA0Cc,qBtClGe;EC2xK3B;EqCnuKF;;;IA8CU,yB3BKuB;I2BJvB,ctCvGmB;ECiyK3B;EqCzuKF;IAmDc,uBtC9FiB;IsC+FjB,ctC5Ge;ECqyK3B;AACF;;AqC9uKA;EASM,yBtCjEuB;EsCkEvB,YtCrDyB;AC8xK/B;;AqCnvKA;;EAcU,YtCzDqB;ACmyK/B;;AqCxvKA;;;;EAoBY,uB3B+BqB;E2B9BrB,YtChEmB;AC2yK/B;;AqChwKA;EAwBY,mBtCnEmB;AC+yK/B;;AqCpwKA;EA0BQ,YtCrEuB;ACmzK/B;;AC7uKE;EoC3BF;;;;IAgCY,YtC3EmB;EC2zK7B;EqChxKF;;;;;;;;;;IAsCc,uB3BamB;I2BZnB,YtClFiB;ECw0K7B;EqC7xKF;;IA0Cc,mBtCrFiB;EC40K7B;EqCjyKF;;;IA8CU,uB3BKuB;I2BJvB,YtC1FqB;ECk1K7B;EqCvyKF;IAmDc,yBtC3Ge;IsC4Gf,YtC/FiB;ECs1K7B;AACF;;AqC5yKA;EASM,4BtCtDwB;EsCuDxB,yB3BYe;AV2xKrB;;AqCjzKA;;EAcU,yB3BQW;AVgyKrB;;AqCtzKA;;;;EAoBY,yB3B+BqB;E2B9BrB,yB3BCS;AVwyKrB;;AqC9zKA;EAwBY,gC3BFS;AV4yKrB;;AqCl0KA;EA0BQ,yB3BJa;AVgzKrB;;AC3yKE;EoC3BF;;;;IAgCY,yB3BVS;EVwzKnB;EqC90KF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,yB3BjBO;EVq0KnB;EqC31KF;;IA0Cc,gC3BpBO;EVy0KnB;EqC/1KF;;;IA8CU,yB3BKuB;I2BJvB,yB3BzBW;EV+0KnB;EqCr2KF;IAmDc,4BtChGgB;IsCiGhB,yB3B9BO;EVm1KnB;AACF;;AqC12KA;EASM,yBtC7DwB;EsC8DxB,W3BcU;AVu1KhB;;AqC/2KA;;EAcU,W3BUM;AV41KhB;;AqCp3KA;;;;EAoBY,yB3B+BqB;E2B9BrB,W3BGI;AVo2KhB;;AqC53KA;EAwBY,kB3BAI;AVw2KhB;;AqCh4KA;EA0BQ,W3BFQ;AV42KhB;;ACz2KE;EoC3BF;;;;IAgCY,W3BRI;EVo3Kd;EqC54KF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,W3BfE;EVi4Kd;EqCz5KF;;IA0Cc,kB3BlBE;EVq4Kd;EqC75KF;;;IA8CU,yB3BKuB;I2BJvB,W3BvBM;EV24Kd;EqCn6KF;IAmDc,yBtCvGgB;IsCwGhB,W3B5BE;EV+4Kd;AACF;;AqCx6KA;EASM,yBtC/C4B;EsCgD5B,W3BcU;AVq5KhB;;AqC76KA;;EAcU,W3BUM;AV05KhB;;AqCl7KA;;;;EAoBY,yB3B+BqB;E2B9BrB,W3BGI;AVk6KhB;;AqC17KA;EAwBY,kB3BAI;AVs6KhB;;AqC97KA;EA0BQ,W3BFQ;AV06KhB;;ACv6KE;EoC3BF;;;;IAgCY,W3BRI;EVk7Kd;EqC18KF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,W3BfE;EV+7Kd;EqCv9KF;;IA0Cc,kB3BlBE;EVm8Kd;EqC39KF;;;IA8CU,yB3BKuB;I2BJvB,W3BvBM;EVy8Kd;EqCj+KF;IAmDc,yBtCzFoB;IsC0FpB,W3B5BE;EV68Kd;AACF;;AqCt+KA;EASM,yBtC7C4B;EsC8C5B,W3BcU;AVm9KhB;;AqC3+KA;;EAcU,W3BUM;AVw9KhB;;AqCh/KA;;;;EAoBY,yB3B+BqB;E2B9BrB,W3BGI;AVg+KhB;;AqCx/KA;EAwBY,kB3BAI;AVo+KhB;;AqC5/KA;EA0BQ,W3BFQ;AVw+KhB;;ACr+KE;EoC3BF;;;;IAgCY,W3BRI;EVg/Kd;EqCxgLF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,W3BfE;EV6/Kd;EqCrhLF;;IA0Cc,kB3BlBE;EVigLd;EqCzhLF;;;IA8CU,yB3BKuB;I2BJvB,W3BvBM;EVugLd;EqC/hLF;IAmDc,yBtCvFoB;IsCwFpB,W3B5BE;EV2gLd;AACF;;AqCpiLA;EASM,yBtC9C4B;EsC+C5B,W3BcU;AVihLhB;;AqCziLA;;EAcU,W3BUM;AVshLhB;;AqC9iLA;;;;EAoBY,yB3B+BqB;E2B9BrB,W3BGI;AV8hLhB;;AqCtjLA;EAwBY,kB3BAI;AVkiLhB;;AqC1jLA;EA0BQ,W3BFQ;AVsiLhB;;ACniLE;EoC3BF;;;;IAgCY,W3BRI;EV8iLd;EqCtkLF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,W3BfE;EV2jLd;EqCnlLF;;IA0Cc,kB3BlBE;EV+jLd;EqCvlLF;;;IA8CU,yB3BKuB;I2BJvB,W3BvBM;EVqkLd;EqC7lLF;IAmDc,yBtCxFoB;IsCyFpB,W3B5BE;EVykLd;AACF;;AqClmLA;EASM,yBtChD4B;EsCiD5B,W3BcU;AV+kLhB;;AqCvmLA;;EAcU,W3BUM;AVolLhB;;AqC5mLA;;;;EAoBY,yB3B+BqB;E2B9BrB,W3BGI;AV4lLhB;;AqCpnLA;EAwBY,kB3BAI;AVgmLhB;;AqCxnLA;EA0BQ,W3BFQ;AVomLhB;;ACjmLE;EoC3BF;;;;IAgCY,W3BRI;EV4mLd;EqCpoLF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,W3BfE;EVynLd;EqCjpLF;;IA0Cc,kB3BlBE;EV6nLd;EqCrpLF;;;IA8CU,yB3BKuB;I2BJvB,W3BvBM;EVmoLd;EqC3pLF;IAmDc,yBtC1FoB;IsC2FpB,W3B5BE;EVuoLd;AACF;;AqChqLA;EASM,yBtCjD4B;EsCkD5B,yB3BYe;AV+oLrB;;AqCrqLA;;EAcU,yB3BQW;AVopLrB;;AqC1qLA;;;;EAoBY,yB3B+BqB;E2B9BrB,yB3BCS;AV4pLrB;;AqClrLA;EAwBY,gC3BFS;AVgqLrB;;AqCtrLA;EA0BQ,yB3BJa;AVoqLrB;;AC/pLE;EoC3BF;;;;IAgCY,yB3BVS;EV4qLnB;EqClsLF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,yB3BjBO;EVyrLnB;EqC/sLF;;IA0Cc,gC3BpBO;EV6rLnB;EqCntLF;;;IA8CU,yB3BKuB;I2BJvB,yB3BzBW;EVmsLnB;EqCztLF;IAmDc,yBtC3FoB;IsC4FpB,yB3B9BO;EVusLnB;AACF;;AqC9tLA;EASM,yBtC3C2B;EsC4C3B,W3BcU;AV2sLhB;;AqCnuLA;;EAcU,W3BUM;AVgtLhB;;AqCxuLA;;;;EAoBY,yB3B+BqB;E2B9BrB,W3BGI;AVwtLhB;;AqChvLA;EAwBY,kB3BAI;AV4tLhB;;AqCpvLA;EA0BQ,W3BFQ;AVguLhB;;AC7tLE;EoC3BF;;;;IAgCY,W3BRI;EVwuLd;EqChwLF;;;;;;;;;;IAsCc,yB3BamB;I2BZnB,W3BfE;EVqvLd;EqC7wLF;;IA0Cc,kB3BlBE;EVyvLd;EqCjxLF;;;IA8CU,yB3BKuB;I2BJvB,W3BvBM;EV+vLd;EqCvxLF;IAmDc,yBtCrFmB;IsCsFnB,W3B5BE;EVmwLd;AACF;;AqC5xLA;EAsDI,oBAAoB;EACpB,aAAa;EACb,mBA7GmB;EA8GnB,WAAW;ArC0uLf;;AqCnyLA;EA2DI,gCtCxG0B;ACo1L9B;;AqCvyLA;EALE,OAAO;EACP,eAAe;EACf,QAAQ;EACR,WA/CiB;ArC+1LnB;;AqC9yLA;EAgEI,SAAS;ArCkvLb;;AqClzLA;EAkEM,iCtC/GwB;ACm2L9B;;AqCtzLA;EAoEI,MAAM;ArCsvLV;;AqCpvLA;;EAGI,oBA9HmB;ArCo3LvB;;AqCzvLA;;EAKI,uBAhImB;ArCy3LvB;;AqCvvLA;;EAEE,oBAAoB;EACpB,aAAa;EACb,cAAc;EACd,mBAvIqB;ArCi4LvB;;AqCxvLA;EAIM,6BAA6B;ArCwvLnC;;AqCtvLA;EpCtFE,iCAAiC;EoCwFjC,gBAAgB;EAChB,gBAAgB;EAChB,kBAAkB;ArCyvLpB;;AqCvvLA;EAEE,ctCrJ4B;EEoB5B,eAAe;EACf,cAAc;EACd,eoCxBqB;EpCyBrB,kBAAkB;EAClB,coC1BqB;EpCuJnB,iBoCEkC;ArC6vLtC;;AC33LE;EACE,8BAA8B;EAC9B,cAAc;EACd,WAAW;EACX,qBAAqB;EACrB,kBAAkB;EAClB,wBAAwB;EACxB,yBFiCQ;EEhCR,yDAAyD;EACzD,oCF0Ba;EEzBb,WAAW;AD83Lf;;AC73LI;EACE,oBAAoB;ADg4L1B;;AC/3LI;EACE,oBAAoB;ADk4L1B;;ACj4LI;EACE,oBAAoB;ADo4L1B;;ACn4LE;EACE,qCAAiC;ADs4LrC;;ACl4LM;EACE,wCAAwC;ADq4LhD;;ACp4LM;EACE,UAAU;ADu4LlB;;ACt4LM;EACE,0CAA0C;ADy4LlD;;AqCpyLA;EACE,aAAa;ArCuyLf;;AqCryLA;;EAEE,ctC9J4B;EsC+J5B,cAAc;EACd,gBAAgB;EAChB,uBAAuB;EACvB,kBAAkB;ArCwyLpB;;AqC9yLA;;EASM,qBAAqB;EACrB,sBAAsB;ArC0yL5B;;AqCxyLA;;EAEE,eAAe;ArC2yLjB;;AqC7yLA;;;;;EAOI,yBtCxK0B;EsCyK1B,ctCjK8B;AC+8LlC;;AqC5yLA;EACE,YAAY;EACZ,cAAc;ArC+yLhB;;AqCjzLA;EAII,mBA7KgC;ArC89LpC;;AqCrzLA;EAMI,UAAU;ArCmzLd;;AqCzzLA;EAQI,YAAY;EACZ,cAAc;ArCqzLlB;;AqC9zLA;EAWI,oCAAoC;EACpC,mBAhMmB;EAiMnB,kCAAkC;ArCuzLtC;;AqCp0LA;EAgBM,6BArLyC;EAsLzC,4BtCpL4B;AC4+LlC;;AqCz0LA;EAmBM,6BArL0C;EAsL1C,4BtCvL4B;EsCwL5B,0BArLuC;EAsLvC,wBArLqC;EAsLrC,ctC1L4B;EsC2L5B,kCAAwE;ArC0zL9E;;AqCxzLA;EACE,YAAY;EACZ,cAAc;ArC2zLhB;;AqCzzLA;EpC3DI,oBoC4DoC;ArC4zLxC;;AqC7zLA;EAII,qBtCrM8B;EsCsM9B,oBAAoB;EpCxDpB,coCyD6B;ArC6zLjC;;AqC3zLA;EACE,mBAAmB;EACnB,sBAAsB;EACtB,mBAAmB;ArC8zLrB;;AqCj0LA;EAKI,oBAAoB;EACpB,qBAAqB;ArCg0LzB;;AqC9zLA;EACE,4BtC3N4B;EsC4N5B,YAAY;EACZ,aAAa;EACb,WA/LyB;EAgMzB,gBAAgB;ArCi0LlB;;ACp9LE;EoC/BF;IAsLI,cAAc;ErCk0LhB;EqCj0LA;;IAGI,mBAAmB;IACnB,aAAa;ErCk0LjB;EqCj0LA;IAEI,aAAa;ErCk0LjB;EqC15LF;IA0FI,uBtC3O2B;IsC4O3B,4CtCzPyB;IsC0PzB,iBAAiB;ErCm0LnB;EqCt0LA;IAKI,cAAc;ErCo0LlB;EqCl0LA;IA3MA,OAAO;IACP,eAAe;IACf,QAAQ;IACR,WA/CiB;ErC+jMjB;EqCx0LA;IAKI,SAAS;ErCs0Lb;EqC30LA;IAOM,4CtCrQqB;EC4kM3B;EqC90LA;IASI,MAAM;ErCw0LV;EqCj1LA;IpClMA,iCAAiC;IoCgN3B,iCAA2C;IAC3C,cAAc;ErCu0LpB;EqCt0LA;;IAGI,oBA9QiB;ErCqlMrB;EqC10LA;;IAKI,uBAhRiB;ErCylMrB;AACF;;AC1gME;EoCmMA;;;;IAIE,oBAAoB;IACpB,aAAa;ErC20Lf;EqC9iMF;IAqOI,mBA1RmB;ErCsmMrB;EqC70LA;IAGI,kBA1R0B;ErCumM9B;EqCh1LA;;IAMM,mBAAmB;ErC80LzB;EqCp1LA;;IASM,kBtClOI;ECijMV;EqCx1LA;;;;IAgBQ,wCAAwC;ErC80LhD;EqC91LA;IAuBU,wCAAwC;ErC00LlD;EqCj2LA;IA4BU,4BtC7SkB;IsC8SlB,ctCzTiB;ECioM3B;EqCr2LA;IA+BU,4BtChTkB;IsCiTlB,ctCxSsB;ECinMhC;EqC7+LF;IAsKI,aAAa;ErC00Lf;EqCv+LF;;IAgKI,mBAAmB;IACnB,aAAa;ErC20Lf;EqCt9LF;IA8IM,oBAAoB;ErC20LxB;EqC70LA;IAKM,oDAAoD;ErC20L1D;EqCh1LA;IAOM,gCtClUsB;IsCmUtB,0BAAkE;IAClE,gBAAgB;IAChB,YAAY;IACZ,4CtC9UqB;IsC+UrB,SAAS;ErC40Lf;EqCx1LA;IAkBM,cAAc;ErCy0LpB;EqCx0LM;IAEE,UAAU;IACV,oBAAoB;IACpB,wBAAwB;ErCy0LhC;EqCrgMF;IA8LI,YAAY;IACZ,cAAc;ErC00LhB;EqCz0LA;IACE,2BAA2B;IpCrM3B,kBoCsMoC;ErC20LtC;EqC10LA;IACE,yBAAyB;IpCxMzB,iBoCyMoC;ErC40LtC;EqCl9LF;IAwII,uBtCxV2B;IsCyV3B,8BtClSc;IsCmSd,+BtCnSc;IsCoSd,6BtChW0B;IsCiW1B,2CtCzWyB;IsC0WzB,aAAa;IACb,mBAAmB;IpCzMnB,OoC0MuB;IACvB,eAAe;IACf,kBAAkB;IAClB,SAAS;IACT,WAjVkB;ErC8pMpB;EqCh+LF;IAqJM,sBAAsB;IACtB,mBAAmB;ErC80LvB;EqC71LA;IpC1ME,mBoC2NuC;ErC+0LzC;EqCh2LA;IAoBM,4BtC7WsB;IsC8WtB,ctCzXqB;ECwsM3B;EqCp2LA;IAuBM,4BtChXsB;IsCiXtB,ctCxW0B;ECwrMhC;EqC/0LE;IAEE,kBtC3TY;IsC4TZ,gBAAgB;IAChB,4EtCjYuB;IsCkYvB,cAAc;IACd,UAAU;IACV,oBAAoB;IACpB,wBAA8C;IAC9C,2BAA2B;IAC3B,yBtCjUM;IsCkUN,uCAAuC;ErCg1L3C;EqCp3LA;IAsCI,UAAU;IACV,QAAQ;ErCi1LZ;EqCv/LF;IAwKI,cAAc;ErCk1LhB;EqCj1LA;;IpCpPE,qBoCuPyC;ErCk1L3C;EqCr1LA;;IpCpPE,sBoCyPyC;ErCo1L3C;EqCl1LA;IAlWA,OAAO;IACP,eAAe;IACf,QAAQ;IACR,WA/CiB;ErCsuMjB;EqCx1LA;IAKI,SAAS;ErCs1Lb;EqC31LA;IAOM,4CtC5ZqB;ECmvM3B;EqC91LA;IASI,MAAM;ErCw1LV;EqCv1LA;;IAGI,oBA/ZiB;ErCuvMrB;EqC31LA;;IAKI,uBAjaiB;ErC2vMrB;EqC/1LA;;IAOI,oBAA4D;ErC41LhE;EqCn2LA;;IASI,uBAA+D;ErC81LnE;EqC51LA;;IAGI,ctC7auB;EC0wM3B;EqCh2LA;;IAKI,6BAla2C;ErCiwM/C;EqC91LA;IAKM,yBtCzasB;ECqwM5B;AACF;;AqCz1LA;EAEI,iCAA2C;ArC21L/C;;AsCnvMA;EAEE,evCFW;EuCGX,gBAnC0B;AtCwxM5B;;AsCxvMA;EAMI,kBvCLY;AC2vMhB;;AsC5vMA;EAQI,kBvCTY;ACiwMhB;;AsChwMA;EAUI,iBvCZW;ACswMf;;AsCpwMA;;EAcM,iBAAiB;EACjB,kBAAkB;EAClB,qBvCkBiB;ACyuMvB;;AsC3wMA;EAkBM,qBvCgBiB;AC6uMvB;;AsC3vMA;;EAEE,mBAAmB;EACnB,aAAa;EACb,uBAAuB;EACvB,kBAAkB;AtC8vMpB;;AsC5vMA;;;;EAME,cA9D6B;EA+D7B,uBAAuB;EACvB,eA/D8B;EAgE9B,mBA/DkC;EAgElC,oBA/DmC;EAgEnC,kBAAkB;AtC6vMpB;;AsC3vMA;;;EAGE,qBvCtE4B;EuCuE5B,cvC3E4B;EuC4E5B,gBxC3EoB;AEy0MtB;;AsCnwMA;;;EAOI,qBvC3E0B;EuC4E1B,cvC/E0B;ACi1M9B;;AsC1wMA;;;EAUI,qBvCjE8B;ACu0MlC;;AsChxMA;;;EAYI,iDvCvFyB;ACi2M7B;;AsCtxMA;;;EAcI,yBvCjF0B;EuCkF1B,qBvClF0B;EuCmF1B,gBAAgB;EAChB,cvCtF0B;EuCuF1B,YAAY;AtC8wMhB;;AsC5wMA;;EAEE,oBAtFkC;EAuFlC,qBAtFmC;EAuFnC,mBAAmB;AtC+wMrB;;AsC7wMA;EAEI,yBvCnF8B;EuCoF9B,qBvCpF8B;EuCqF9B,W5BzBY;AVwyMhB;;AsC7wMA;EACE,cvCrG4B;EuCsG5B,oBAAoB;AtCgxMtB;;AsC9wMA;EACE,eAAe;AtCixMjB;;AsClxMA;EAGI,gBAAgB;AtCmxMpB;;AC1yME;EqCxDF;IAmFI,eAAe;EtCoxMjB;EsC3yMF;;IA0BI,YAAY;IACZ,cAAc;EtCqxMhB;EsChyMF;IAcM,YAAY;IACZ,cAAc;EtCqxMlB;AACF;;ACrzME;EqCgBF;IAmBI,YAAY;IACZ,cAAc;IACd,2BAA2B;IAC3B,QAAQ;EtCuxMV;EsC91MF;;;;IA4EI,gBAAgB;IAChB,aAAa;EtCwxMf;EsCvxMA;IACE,QAAQ;EtCyxMV;EsCxxMA;IACE,QAAQ;EtC0xMV;EsCt4MF;IA8GI,8BAA8B;IAC9B,gBAAgB;IAChB,aAAa;EtC2xMf;EsC9xMA;IAMM,QAAQ;EtC2xMd;EsCjyMA;IAQM,uBAAuB;IACvB,QAAQ;EtC4xMd;EsCryMA;IAWM,QAAQ;EtC6xMd;EsCxyMA;IAcM,QAAQ;EtC6xMd;EsC3yMA;IAgBM,QAAQ;EtC8xMd;EsC9yMA;IAkBM,yBAAyB;IACzB,QAAQ;EtC+xMd;AACF;;AuCr6MA;EACE,kBxCqCgB;EwCpChB,0FxChC2B;EwCiC3B,exCEW;ACs6Mb;;AuC36MA;EAKI,qBxCWkB;AC+5MtB;;AuC/6MA;EAYQ,uBxC7BuB;EwC8BvB,cxC3CqB;ACk9M7B;;AuCp7MA;EAeQ,0BxChCuB;ACy8M/B;;AuCx7MA;EAiBQ,YxClCuB;AC68M/B;;AuC57MA;EAYQ,yBxC1CqB;EwC2CrB,YxC9BuB;ACk9M/B;;AuCj8MA;EAeQ,4BxC7CqB;ACm+M7B;;AuCr8MA;EAiBQ,cxC/CqB;ACu+M7B;;AuCz8MA;EAYQ,4BxC/BsB;EwCgCtB,yB7BmCa;AV85MrB;;AuC98MA;EAeQ,+BxClCsB;ACq+M9B;;AuCl9MA;EAiBQ,iBxCpCsB;ACy+M9B;;AuCt9MA;EAYQ,yBxCtCsB;EwCuCtB,W7BqCQ;AVy6MhB;;AuC39MA;EAeQ,4BxCzCsB;ACy/M9B;;AuC/9MA;EAiBQ,cxC3CsB;AC6/M9B;;AuCn+MA;EAYQ,yBxCxB0B;EwCyB1B,W7BqCQ;AVs7MhB;;AuCx+MA;EAeQ,4BxC3B0B;ACw/MlC;;AuC5+MA;EAiBQ,cxC7B0B;AC4/MlC;;AuCh/MA;EAYQ,yBxCtB0B;EwCuB1B,W7BqCQ;AVm8MhB;;AuCr/MA;EAeQ,4BxCzB0B;ACmgNlC;;AuCz/MA;EAiBQ,cxC3B0B;ACugNlC;;AuC7/MA;EAYQ,yBxCvB0B;EwCwB1B,W7BqCQ;AVg9MhB;;AuClgNA;EAeQ,4BxC1B0B;ACihNlC;;AuCtgNA;EAiBQ,cxC5B0B;ACqhNlC;;AuC1gNA;EAYQ,yBxCzB0B;EwC0B1B,W7BqCQ;AV69MhB;;AuC/gNA;EAeQ,4BxC5B0B;ACgiNlC;;AuCnhNA;EAiBQ,cxC9B0B;ACoiNlC;;AuCvhNA;EAYQ,yBxC1B0B;EwC2B1B,yB7BmCa;AV4+MrB;;AuC5hNA;EAeQ,4BxC7B0B;AC8iNlC;;AuChiNA;EAiBQ,cxC/B0B;ACkjNlC;;AuCpiNA;EAYQ,yBxCpByB;EwCqBzB,W7BqCQ;AVu/MhB;;AuCziNA;EAeQ,4BxCvByB;ACqjNjC;;AuC7iNA;EAiBQ,cxCzByB;ACyjNjC;;AuC9hNA;;EAGI,gCxC3C2B;AC2kN/B;;AuC9hNA;EACE,yBxC9C6B;EwC+C7B,0BAA8C;EAC9C,cxCrD4B;EwCsD5B,iBAhDyB;EAiDzB,gBxCjBe;EwCkBf,iBArD8B;EAsD9B,mBArDgC;AvCslNlC;;AuC/hNA;EACE,qBAAqB;EACrB,aAAa;EACb,kBArD4B;EAsD5B,uBAAuB;AvCkiNzB;;AuCtiNA;EAMI,gCxC7D0B;EwC8D1B,mBAAmB;EACnB,cAAc;AvCoiNlB;;AuC5iNA;EAWM,4BxCrEwB;EwCsExB,cxCvEwB;AC4mN9B;;AuCniNA;EAEI,cxC1E0B;AC+mN9B;;AuCviNA;EAIM,cxC7D4B;AComNlC;;AuCriNA;EACE,mBAAmB;EACnB,cxCjF4B;EwCkF5B,aAAa;EACb,2BAA2B;EAC3B,qBAAqB;AvCwiNvB;;AuC7iNA;EtCuEI,oBsChEsC;AvC0iN1C;;AuCjjNA;EASI,YAAY;EACZ,cAAc;EACd,WAAW;AvC4iNf;;AuCvjNA;EAaI,eAAe;AvC8iNnB;;AuC3jNA;EAeI,0BxC9E8B;EwC+E9B,cxC/F0B;AC+oN9B;;AuChkNA;EAkBM,cxCjF4B;ACmoNlC;;AuCpkNA;EAoBI,8BxCnCc;EwCoCd,+BxCpCc;ACwlNlB;;AuCljNA;;EAEE,eAAe;AvCqjNjB;;AuCvjNA;;EAII,4BxCnG0B;AC2pN9B;;AuCtjNA;EtChGE,qBAAqB;EACrB,esCgGgB;EtC/FhB,WsC+FqB;EtC9FrB,gBsC8FqB;EtC7FrB,kBAAkB;EAClB,mBAAmB;EACnB,UsC2FqB;EACrB,cxC5G4B;EEoJ1B,oBsCvCoC;AvC+jNxC;;AuClkNA;EAKI,kBAAkB;EAClB,oBAAoB;AvCikNxB;;AwC3pNA;EvCgCE,iCAAiC;EuC5BjC,oBAAoB;EACpB,aAAa;EACb,ezCCW;EyCAX,8BAA8B;EAC9B,gBAAgB;EAChB,gBAAgB;EAChB,mBAAmB;AxC4pNrB;;AwCtqNA;EAYI,mBAAmB;EACnB,4BzCjC0B;EyCkC1B,0BAzC4B;EA0C5B,wBAzC0B;EA0C1B,czCvC0B;EyCwC1B,aAAa;EACb,uBAAuB;EACvB,mBAA6C;EAC7C,kBAxCyB;EAyCzB,mBAAmB;AxC8pNvB;;AwCnrNA;EAuBM,4BzC/CwB;EyCgDxB,czChDwB;ACgtN9B;;AwCxrNA;EA0BI,cAAc;AxCkqNlB;;AwC5rNA;EA6BQ,4BzCrC0B;EyCsC1B,czCtC0B;ACysNlC;;AwCjsNA;EAgCI,mBAAmB;EACnB,4BzCrD0B;EyCsD1B,0BA7D4B;EA8D5B,wBA7D0B;EA8D1B,aAAa;EACb,YAAY;EACZ,cAAc;EACd,2BAA2B;AxCqqN/B;;AwC5sNA;EAyCM,qBAAqB;AxCuqN3B;;AwChtNA;EA2CM,UAAU;EACV,uBAAuB;EACvB,oBAAoB;EACpB,qBAAqB;AxCyqN3B;;AwCvtNA;EAgDM,yBAAyB;EACzB,oBAAoB;AxC2qN1B;;AwC5tNA;EvC8HI,mBuC1EuC;AxC4qN3C;;AwChuNA;EvC8HI,kBuCxEuC;AxC8qN3C;;AwCpuNA;EA0DM,uBAAuB;AxC8qN7B;;AwCxuNA;EA6DM,yBAAyB;AxC+qN/B;;AwC5uNA;EAiEM,6BAA6B;EAE3B,0BAAkE;AxC8qN1E;;AwCjvNA;EAuEQ,4BzCxFsB;EyCyFtB,4BzC5FsB;AC0wN9B;;AwCtvNA;EA4EU,uBzC3FqB;EyC4FrB,qBzCjGoB;EyCkGpB,2CAA2E;AxC8qNrF;;AwC5vNA;EAiFM,YAAY;EACZ,cAAc;AxC+qNpB;;AwCjwNA;EAqFM,qBzCzGwB;EyC0GxB,mBA/F+B;EAgG/B,iBA/F6B;EAgG7B,gBAAgB;EAChB,kBAAkB;AxCgrNxB;;AwCzwNA;EA2FQ,4BzC5GsB;EyC6GtB,qBzCjHsB;EyCkHtB,UAAU;AxCkrNlB;;AwC/wNA;EvC8HI,iBuC9BuE;AxCmrN3E;;AwCnxNA;EAmGU,2BzC5DE;EyC6DF,8BzC7DE;ACivNZ;;AwCxxNA;EA0GU,4BzCnEE;EyCoEF,+BzCpEE;ACsvNZ;;AwC7xNA;EAiHU,yBzCzHwB;EyC0HxB,qBzC1HwB;EyC2HxB,W9B/DM;E8BgEN,UAAU;AxCgrNpB;;AwCpyNA;EAsHM,mBAAmB;AxCkrNzB;;AwCxyNA;EA2HY,iCzClFW;EyCmFX,8BzCnFW;EyCoFX,oBAAoB;AxCirNhC;;AwC9yNA;EAoIY,kCzC3FW;EyC4FX,+BzC5FW;EyC6FX,qBAAqB;AxC8qNjC;;AwCpzNA;EA6II,kBzCrIY;ACgzNhB;;AwCxzNA;EA+II,kBzCzIY;ACszNhB;;AwC5zNA;EAiJI,iBzC5IW;AC2zNf;;AyC91NA,eAAA;ACIA;EACE,cAAc;EACd,aAAa;EACb,YAAY;EACZ,cAAc;EACd,gBAPkB;A1Cq2NpB;;A0C71NE;EACE,UAAU;EACV,YAAY;A1Cg2NhB;;A0C/1NE;EACE,UAAU;EACV,WAAW;A1Ck2Nf;;A0Cj2NE;EACE,UAAU;EACV,UAAU;A1Co2Nd;;A0Cn2NE;EACE,UAAU;EACV,eAAe;A1Cs2NnB;;A0Cr2NE;EACE,UAAU;EACV,UAAU;A1Cw2Nd;;A0Cv2NE;EACE,UAAU;EACV,eAAe;A1C02NnB;;A0Cz2NE;EACE,UAAU;EACV,UAAU;A1C42Nd;;A0C32NE;EACE,UAAU;EACV,UAAU;A1C82Nd;;A0C72NE;EACE,UAAU;EACV,UAAU;A1Cg3Nd;;A0C/2NE;EACE,UAAU;EACV,UAAU;A1Ck3Nd;;A0Cj3NE;EACE,UAAU;EACV,UAAU;A1Co3Nd;;A0Cn3NE;EzCiHE,gByChHmC;A1Cs3NvC;;A0Cr3NE;EzC+GE,qByC9GwC;A1Cw3N5C;;A0Cv3NE;EzC6GE,gByC5GmC;A1C03NvC;;A0Cz3NE;EzC2GE,qByC1GwC;A1C43N5C;;A0C33NE;EzCyGE,gByCxGmC;A1C83NvC;;A0C73NE;EzCuGE,gByCtGmC;A1Cg4NvC;;A0C/3NE;EzCqGE,gByCpGmC;A1Ck4NvC;;A0Cj4NE;EzCmGE,gByClGmC;A1Co4NvC;;A0Cn4NE;EzCiGE,gByChGmC;A1Cs4NvC;;A0Cp4NI;EACE,UAAU;EACV,SAAiC;A1Cu4NvC;;A0Ct4NI;EzC2FA,eyC1F4D;A1Cy4NhE;;A0C74NI;EACE,UAAU;EACV,eAAiC;A1Cg5NvC;;A0C/4NI;EzC2FA,qByC1F4D;A1Ck5NhE;;A0Ct5NI;EACE,UAAU;EACV,gBAAiC;A1Cy5NvC;;A0Cx5NI;EzC2FA,sByC1F4D;A1C25NhE;;A0C/5NI;EACE,UAAU;EACV,UAAiC;A1Ck6NvC;;A0Cj6NI;EzC2FA,gByC1F4D;A1Co6NhE;;A0Cx6NI;EACE,UAAU;EACV,gBAAiC;A1C26NvC;;A0C16NI;EzC2FA,sByC1F4D;A1C66NhE;;A0Cj7NI;EACE,UAAU;EACV,gBAAiC;A1Co7NvC;;A0Cn7NI;EzC2FA,sByC1F4D;A1Cs7NhE;;A0C17NI;EACE,UAAU;EACV,UAAiC;A1C67NvC;;A0C57NI;EzC2FA,gByC1F4D;A1C+7NhE;;A0Cn8NI;EACE,UAAU;EACV,gBAAiC;A1Cs8NvC;;A0Cr8NI;EzC2FA,sByC1F4D;A1Cw8NhE;;A0C58NI;EACE,UAAU;EACV,gBAAiC;A1C+8NvC;;A0C98NI;EzC2FA,sByC1F4D;A1Ci9NhE;;A0Cr9NI;EACE,UAAU;EACV,UAAiC;A1Cw9NvC;;A0Cv9NI;EzC2FA,gByC1F4D;A1C09NhE;;A0C99NI;EACE,UAAU;EACV,gBAAiC;A1Ci+NvC;;A0Ch+NI;EzC2FA,sByC1F4D;A1Cm+NhE;;A0Cv+NI;EACE,UAAU;EACV,gBAAiC;A1C0+NvC;;A0Cz+NI;EzC2FA,sByC1F4D;A1C4+NhE;;A0Ch/NI;EACE,UAAU;EACV,WAAiC;A1Cm/NvC;;A0Cl/NI;EzC2FA,iByC1F4D;A1Cq/NhE;;AC19NE;EyCzFF;IAiEM,UAAU;IACV,YAAY;E1Cu/NhB;E0CzjOF;IAoEM,UAAU;IACV,WAAW;E1Cw/Nf;E0C7jOF;IAuEM,UAAU;IACV,UAAU;E1Cy/Nd;E0CjkOF;IA0EM,UAAU;IACV,eAAe;E1C0/NnB;E0CrkOF;IA6EM,UAAU;IACV,UAAU;E1C2/Nd;E0CzkOF;IAgFM,UAAU;IACV,eAAe;E1C4/NnB;E0C7kOF;IAmFM,UAAU;IACV,UAAU;E1C6/Nd;E0CjlOF;IAsFM,UAAU;IACV,UAAU;E1C8/Nd;E0CrlOF;IAyFM,UAAU;IACV,UAAU;E1C+/Nd;E0CzlOF;IA4FM,UAAU;IACV,UAAU;E1CggOd;E0C7lOF;IA+FM,UAAU;IACV,UAAU;E1CigOd;E0CjmOF;IzCwJI,gByCtDqC;E1CkgOvC;E0CpmOF;IzCwJI,qByCpD0C;E1CmgO5C;E0CvmOF;IzCwJI,gByClDqC;E1CogOvC;E0C1mOF;IzCwJI,qByChD0C;E1CqgO5C;E0C7mOF;IzCwJI,gByC9CqC;E1CsgOvC;E0ChnOF;IzCwJI,gByC5CqC;E1CugOvC;E0CnnOF;IzCwJI,gByC1CqC;E1CwgOvC;E0CtnOF;IzCwJI,gByCxCqC;E1CygOvC;E0CznOF;IzCwJI,gByCtCqC;E1C0gOvC;E0C5nOF;IAqHQ,UAAU;IACV,SAAiC;E1C0gOvC;E0ChoOF;IzCwJI,eyChC8D;E1C2gOhE;E0CnoOF;IAqHQ,UAAU;IACV,eAAiC;E1CihOvC;E0CvoOF;IzCwJI,qByChC8D;E1CkhOhE;E0C1oOF;IAqHQ,UAAU;IACV,gBAAiC;E1CwhOvC;E0C9oOF;IzCwJI,sByChC8D;E1CyhOhE;E0CjpOF;IAqHQ,UAAU;IACV,UAAiC;E1C+hOvC;E0CrpOF;IzCwJI,gByChC8D;E1CgiOhE;E0CxpOF;IAqHQ,UAAU;IACV,gBAAiC;E1CsiOvC;E0C5pOF;IzCwJI,sByChC8D;E1CuiOhE;E0C/pOF;IAqHQ,UAAU;IACV,gBAAiC;E1C6iOvC;E0CnqOF;IzCwJI,sByChC8D;E1C8iOhE;E0CtqOF;IAqHQ,UAAU;IACV,UAAiC;E1CojOvC;E0C1qOF;IzCwJI,gByChC8D;E1CqjOhE;E0C7qOF;IAqHQ,UAAU;IACV,gBAAiC;E1C2jOvC;E0CjrOF;IzCwJI,sByChC8D;E1C4jOhE;E0CprOF;IAqHQ,UAAU;IACV,gBAAiC;E1CkkOvC;E0CxrOF;IzCwJI,sByChC8D;E1CmkOhE;E0C3rOF;IAqHQ,UAAU;IACV,UAAiC;E1CykOvC;E0C/rOF;IzCwJI,gByChC8D;E1C0kOhE;E0ClsOF;IAqHQ,UAAU;IACV,gBAAiC;E1CglOvC;E0CtsOF;IzCwJI,sByChC8D;E1CilOhE;E0CzsOF;IAqHQ,UAAU;IACV,gBAAiC;E1CulOvC;E0C7sOF;IzCwJI,sByChC8D;E1CwlOhE;E0ChtOF;IAqHQ,UAAU;IACV,WAAiC;E1C8lOvC;E0CptOF;IzCwJI,iByChC8D;E1C+lOhE;AACF;;AC3nOE;EyC7FF;IA4HM,UAAU;IACV,YAAY;E1CimOhB;E0C9tOF;IAgIM,UAAU;IACV,WAAW;E1CimOf;E0CluOF;IAoIM,UAAU;IACV,UAAU;E1CimOd;E0CtuOF;IAwIM,UAAU;IACV,eAAe;E1CimOnB;E0C1uOF;IA4IM,UAAU;IACV,UAAU;E1CimOd;E0C9uOF;IAgJM,UAAU;IACV,eAAe;E1CimOnB;E0ClvOF;IAoJM,UAAU;IACV,UAAU;E1CimOd;E0CtvOF;IAwJM,UAAU;IACV,UAAU;E1CimOd;E0C1vOF;IA4JM,UAAU;IACV,UAAU;E1CimOd;E0C9vOF;IAgKM,UAAU;IACV,UAAU;E1CimOd;E0ClwOF;IAoKM,UAAU;IACV,UAAU;E1CimOd;E0CtwOF;IzCwJI,gByCgBqC;E1CimOvC;E0CzwOF;IzCwJI,qByCmB0C;E1CimO5C;E0C5wOF;IzCwJI,gByCsBqC;E1CimOvC;E0C/wOF;IzCwJI,qByCyB0C;E1CimO5C;E0ClxOF;IzCwJI,gByC4BqC;E1CimOvC;E0CrxOF;IzCwJI,gByC+BqC;E1CimOvC;E0CxxOF;IzCwJI,gByCkCqC;E1CimOvC;E0C3xOF;IzCwJI,gByCqCqC;E1CimOvC;E0C9xOF;IzCwJI,gByCwCqC;E1CimOvC;E0CjyOF;IAoMQ,UAAU;IACV,SAAiC;E1CgmOvC;E0CryOF;IzCwJI,eyCgD8D;E1CgmOhE;E0CxyOF;IAoMQ,UAAU;IACV,eAAiC;E1CumOvC;E0C5yOF;IzCwJI,qByCgD8D;E1CumOhE;E0C/yOF;IAoMQ,UAAU;IACV,gBAAiC;E1C8mOvC;E0CnzOF;IzCwJI,sByCgD8D;E1C8mOhE;E0CtzOF;IAoMQ,UAAU;IACV,UAAiC;E1CqnOvC;E0C1zOF;IzCwJI,gByCgD8D;E1CqnOhE;E0C7zOF;IAoMQ,UAAU;IACV,gBAAiC;E1C4nOvC;E0Cj0OF;IzCwJI,sByCgD8D;E1C4nOhE;E0Cp0OF;IAoMQ,UAAU;IACV,gBAAiC;E1CmoOvC;E0Cx0OF;IzCwJI,sByCgD8D;E1CmoOhE;E0C30OF;IAoMQ,UAAU;IACV,UAAiC;E1C0oOvC;E0C/0OF;IzCwJI,gByCgD8D;E1C0oOhE;E0Cl1OF;IAoMQ,UAAU;IACV,gBAAiC;E1CipOvC;E0Ct1OF;IzCwJI,sByCgD8D;E1CipOhE;E0Cz1OF;IAoMQ,UAAU;IACV,gBAAiC;E1CwpOvC;E0C71OF;IzCwJI,sByCgD8D;E1CwpOhE;E0Ch2OF;IAoMQ,UAAU;IACV,UAAiC;E1C+pOvC;E0Cp2OF;IzCwJI,gByCgD8D;E1C+pOhE;E0Cv2OF;IAoMQ,UAAU;IACV,gBAAiC;E1CsqOvC;E0C32OF;IzCwJI,sByCgD8D;E1CsqOhE;E0C92OF;IAoMQ,UAAU;IACV,gBAAiC;E1C6qOvC;E0Cl3OF;IzCwJI,sByCgD8D;E1C6qOhE;E0Cr3OF;IAoMQ,UAAU;IACV,WAAiC;E1CorOvC;E0Cz3OF;IzCwJI,iByCgD8D;E1CorOhE;AACF;;ACxxOE;EyCrGF;IA2MM,UAAU;IACV,YAAY;E1CurOhB;E0Cn4OF;IA8MM,UAAU;IACV,WAAW;E1CwrOf;E0Cv4OF;IAiNM,UAAU;IACV,UAAU;E1CyrOd;E0C34OF;IAoNM,UAAU;IACV,eAAe;E1C0rOnB;E0C/4OF;IAuNM,UAAU;IACV,UAAU;E1C2rOd;E0Cn5OF;IA0NM,UAAU;IACV,eAAe;E1C4rOnB;E0Cv5OF;IA6NM,UAAU;IACV,UAAU;E1C6rOd;E0C35OF;IAgOM,UAAU;IACV,UAAU;E1C8rOd;E0C/5OF;IAmOM,UAAU;IACV,UAAU;E1C+rOd;E0Cn6OF;IAsOM,UAAU;IACV,UAAU;E1CgsOd;E0Cv6OF;IAyOM,UAAU;IACV,UAAU;E1CisOd;E0C36OF;IzCwJI,gByCoFqC;E1CksOvC;E0C96OF;IzCwJI,qByCsF0C;E1CmsO5C;E0Cj7OF;IzCwJI,gByCwFqC;E1CosOvC;E0Cp7OF;IzCwJI,qByC0F0C;E1CqsO5C;E0Cv7OF;IzCwJI,gByC4FqC;E1CssOvC;E0C17OF;IzCwJI,gByC8FqC;E1CusOvC;E0C77OF;IzCwJI,gByCgGqC;E1CwsOvC;E0Ch8OF;IzCwJI,gByCkGqC;E1CysOvC;E0Cn8OF;IzCwJI,gByCoGqC;E1C0sOvC;E0Ct8OF;IA+PQ,UAAU;IACV,SAAiC;E1C0sOvC;E0C18OF;IzCwJI,eyC0G8D;E1C2sOhE;E0C78OF;IA+PQ,UAAU;IACV,eAAiC;E1CitOvC;E0Cj9OF;IzCwJI,qByC0G8D;E1CktOhE;E0Cp9OF;IA+PQ,UAAU;IACV,gBAAiC;E1CwtOvC;E0Cx9OF;IzCwJI,sByC0G8D;E1CytOhE;E0C39OF;IA+PQ,UAAU;IACV,UAAiC;E1C+tOvC;E0C/9OF;IzCwJI,gByC0G8D;E1CguOhE;E0Cl+OF;IA+PQ,UAAU;IACV,gBAAiC;E1CsuOvC;E0Ct+OF;IzCwJI,sByC0G8D;E1CuuOhE;E0Cz+OF;IA+PQ,UAAU;IACV,gBAAiC;E1C6uOvC;E0C7+OF;IzCwJI,sByC0G8D;E1C8uOhE;E0Ch/OF;IA+PQ,UAAU;IACV,UAAiC;E1CovOvC;E0Cp/OF;IzCwJI,gByC0G8D;E1CqvOhE;E0Cv/OF;IA+PQ,UAAU;IACV,gBAAiC;E1C2vOvC;E0C3/OF;IzCwJI,sByC0G8D;E1C4vOhE;E0C9/OF;IA+PQ,UAAU;IACV,gBAAiC;E1CkwOvC;E0ClgPF;IzCwJI,sByC0G8D;E1CmwOhE;E0CrgPF;IA+PQ,UAAU;IACV,UAAiC;E1CywOvC;E0CzgPF;IzCwJI,gByC0G8D;E1C0wOhE;E0C5gPF;IA+PQ,UAAU;IACV,gBAAiC;E1CgxOvC;E0ChhPF;IzCwJI,sByC0G8D;E1CixOhE;E0CnhPF;IA+PQ,UAAU;IACV,gBAAiC;E1CuxOvC;E0CvhPF;IzCwJI,sByC0G8D;E1CwxOhE;E0C1hPF;IA+PQ,UAAU;IACV,WAAiC;E1C8xOvC;E0C9hPF;IzCwJI,iByC0G8D;E1C+xOhE;AACF;;ACz7OE;EyCzGF;IAqQM,UAAU;IACV,YAAY;E1CkyOhB;E0CxiPF;IAwQM,UAAU;IACV,WAAW;E1CmyOf;E0C5iPF;IA2QM,UAAU;IACV,UAAU;E1CoyOd;E0ChjPF;IA8QM,UAAU;IACV,eAAe;E1CqyOnB;E0CpjPF;IAiRM,UAAU;IACV,UAAU;E1CsyOd;E0CxjPF;IAoRM,UAAU;IACV,eAAe;E1CuyOnB;E0C5jPF;IAuRM,UAAU;IACV,UAAU;E1CwyOd;E0ChkPF;IA0RM,UAAU;IACV,UAAU;E1CyyOd;E0CpkPF;IA6RM,UAAU;IACV,UAAU;E1C0yOd;E0CxkPF;IAgSM,UAAU;IACV,UAAU;E1C2yOd;E0C5kPF;IAmSM,UAAU;IACV,UAAU;E1C4yOd;E0ChlPF;IzCwJI,gByC8IqC;E1C6yOvC;E0CnlPF;IzCwJI,qByCgJ0C;E1C8yO5C;E0CtlPF;IzCwJI,gByCkJqC;E1C+yOvC;E0CzlPF;IzCwJI,qByCoJ0C;E1CgzO5C;E0C5lPF;IzCwJI,gByCsJqC;E1CizOvC;E0C/lPF;IzCwJI,gByCwJqC;E1CkzOvC;E0ClmPF;IzCwJI,gByC0JqC;E1CmzOvC;E0CrmPF;IzCwJI,gByC4JqC;E1CozOvC;E0CxmPF;IzCwJI,gByC8JqC;E1CqzOvC;E0C3mPF;IAyTQ,UAAU;IACV,SAAiC;E1CqzOvC;E0C/mPF;IzCwJI,eyCoK8D;E1CszOhE;E0ClnPF;IAyTQ,UAAU;IACV,eAAiC;E1C4zOvC;E0CtnPF;IzCwJI,qByCoK8D;E1C6zOhE;E0CznPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cm0OvC;E0C7nPF;IzCwJI,sByCoK8D;E1Co0OhE;E0ChoPF;IAyTQ,UAAU;IACV,UAAiC;E1C00OvC;E0CpoPF;IzCwJI,gByCoK8D;E1C20OhE;E0CvoPF;IAyTQ,UAAU;IACV,gBAAiC;E1Ci1OvC;E0C3oPF;IzCwJI,sByCoK8D;E1Ck1OhE;E0C9oPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cw1OvC;E0ClpPF;IzCwJI,sByCoK8D;E1Cy1OhE;E0CrpPF;IAyTQ,UAAU;IACV,UAAiC;E1C+1OvC;E0CzpPF;IzCwJI,gByCoK8D;E1Cg2OhE;E0C5pPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cs2OvC;E0ChqPF;IzCwJI,sByCoK8D;E1Cu2OhE;E0CnqPF;IAyTQ,UAAU;IACV,gBAAiC;E1C62OvC;E0CvqPF;IzCwJI,sByCoK8D;E1C82OhE;E0C1qPF;IAyTQ,UAAU;IACV,UAAiC;E1Co3OvC;E0C9qPF;IzCwJI,gByCoK8D;E1Cq3OhE;E0CjrPF;IAyTQ,UAAU;IACV,gBAAiC;E1C23OvC;E0CrrPF;IzCwJI,sByCoK8D;E1C43OhE;E0CxrPF;IAyTQ,UAAU;IACV,gBAAiC;E1Ck4OvC;E0C5rPF;IzCwJI,sByCoK8D;E1Cm4OhE;E0C/rPF;IAyTQ,UAAU;IACV,WAAiC;E1Cy4OvC;E0CnsPF;IzCwJI,iByCoK8D;E1C04OhE;AACF;;AC/kPI;EyCxHJ;IA+TM,UAAU;IACV,YAAY;E1C64OhB;E0C7sPF;IAkUM,UAAU;IACV,WAAW;E1C84Of;E0CjtPF;IAqUM,UAAU;IACV,UAAU;E1C+4Od;E0CrtPF;IAwUM,UAAU;IACV,eAAe;E1Cg5OnB;E0CztPF;IA2UM,UAAU;IACV,UAAU;E1Ci5Od;E0C7tPF;IA8UM,UAAU;IACV,eAAe;E1Ck5OnB;E0CjuPF;IAiVM,UAAU;IACV,UAAU;E1Cm5Od;E0CruPF;IAoVM,UAAU;IACV,UAAU;E1Co5Od;E0CzuPF;IAuVM,UAAU;IACV,UAAU;E1Cq5Od;E0C7uPF;IA0VM,UAAU;IACV,UAAU;E1Cs5Od;E0CjvPF;IA6VM,UAAU;IACV,UAAU;E1Cu5Od;E0CrvPF;IzCwJI,gByCwMqC;E1Cw5OvC;E0CxvPF;IzCwJI,qByC0M0C;E1Cy5O5C;E0C3vPF;IzCwJI,gByC4MqC;E1C05OvC;E0C9vPF;IzCwJI,qByC8M0C;E1C25O5C;E0CjwPF;IzCwJI,gByCgNqC;E1C45OvC;E0CpwPF;IzCwJI,gByCkNqC;E1C65OvC;E0CvwPF;IzCwJI,gByCoNqC;E1C85OvC;E0C1wPF;IzCwJI,gByCsNqC;E1C+5OvC;E0C7wPF;IzCwJI,gByCwNqC;E1Cg6OvC;E0ChxPF;IAmXQ,UAAU;IACV,SAAiC;E1Cg6OvC;E0CpxPF;IzCwJI,eyC8N8D;E1Ci6OhE;E0CvxPF;IAmXQ,UAAU;IACV,eAAiC;E1Cu6OvC;E0C3xPF;IzCwJI,qByC8N8D;E1Cw6OhE;E0C9xPF;IAmXQ,UAAU;IACV,gBAAiC;E1C86OvC;E0ClyPF;IzCwJI,sByC8N8D;E1C+6OhE;E0CryPF;IAmXQ,UAAU;IACV,UAAiC;E1Cq7OvC;E0CzyPF;IzCwJI,gByC8N8D;E1Cs7OhE;E0C5yPF;IAmXQ,UAAU;IACV,gBAAiC;E1C47OvC;E0ChzPF;IzCwJI,sByC8N8D;E1C67OhE;E0CnzPF;IAmXQ,UAAU;IACV,gBAAiC;E1Cm8OvC;E0CvzPF;IzCwJI,sByC8N8D;E1Co8OhE;E0C1zPF;IAmXQ,UAAU;IACV,UAAiC;E1C08OvC;E0C9zPF;IzCwJI,gByC8N8D;E1C28OhE;E0Cj0PF;IAmXQ,UAAU;IACV,gBAAiC;E1Ci9OvC;E0Cr0PF;IzCwJI,sByC8N8D;E1Ck9OhE;E0Cx0PF;IAmXQ,UAAU;IACV,gBAAiC;E1Cw9OvC;E0C50PF;IzCwJI,sByC8N8D;E1Cy9OhE;E0C/0PF;IAmXQ,UAAU;IACV,UAAiC;E1C+9OvC;E0Cn1PF;IzCwJI,gByC8N8D;E1Cg+OhE;E0Ct1PF;IAmXQ,UAAU;IACV,gBAAiC;E1Cs+OvC;E0C11PF;IzCwJI,sByC8N8D;E1Cu+OhE;E0C71PF;IAmXQ,UAAU;IACV,gBAAiC;E1C6+OvC;E0Cj2PF;IzCwJI,sByC8N8D;E1C8+OhE;E0Cp2PF;IAmXQ,UAAU;IACV,WAAiC;E1Co/OvC;E0Cx2PF;IzCwJI,iByC8N8D;E1Cq/OhE;AACF;;ACruPI;EyCvIJ;IAyXM,UAAU;IACV,YAAY;E1Cw/OhB;E0Cl3PF;IA4XM,UAAU;IACV,WAAW;E1Cy/Of;E0Ct3PF;IA+XM,UAAU;IACV,UAAU;E1C0/Od;E0C13PF;IAkYM,UAAU;IACV,eAAe;E1C2/OnB;E0C93PF;IAqYM,UAAU;IACV,UAAU;E1C4/Od;E0Cl4PF;IAwYM,UAAU;IACV,eAAe;E1C6/OnB;E0Ct4PF;IA2YM,UAAU;IACV,UAAU;E1C8/Od;E0C14PF;IA8YM,UAAU;IACV,UAAU;E1C+/Od;E0C94PF;IAiZM,UAAU;IACV,UAAU;E1CggPd;E0Cl5PF;IAoZM,UAAU;IACV,UAAU;E1CigPd;E0Ct5PF;IAuZM,UAAU;IACV,UAAU;E1CkgPd;E0C15PF;IzCwJI,gByCkQqC;E1CmgPvC;E0C75PF;IzCwJI,qByCoQ0C;E1CogP5C;E0Ch6PF;IzCwJI,gByCsQqC;E1CqgPvC;E0Cn6PF;IzCwJI,qByCwQ0C;E1CsgP5C;E0Ct6PF;IzCwJI,gByC0QqC;E1CugPvC;E0Cz6PF;IzCwJI,gByC4QqC;E1CwgPvC;E0C56PF;IzCwJI,gByC8QqC;E1CygPvC;E0C/6PF;IzCwJI,gByCgRqC;E1C0gPvC;E0Cl7PF;IzCwJI,gByCkRqC;E1C2gPvC;E0Cr7PF;IA6aQ,UAAU;IACV,SAAiC;E1C2gPvC;E0Cz7PF;IzCwJI,eyCwR8D;E1C4gPhE;E0C57PF;IA6aQ,UAAU;IACV,eAAiC;E1CkhPvC;E0Ch8PF;IzCwJI,qByCwR8D;E1CmhPhE;E0Cn8PF;IA6aQ,UAAU;IACV,gBAAiC;E1CyhPvC;E0Cv8PF;IzCwJI,sByCwR8D;E1C0hPhE;E0C18PF;IA6aQ,UAAU;IACV,UAAiC;E1CgiPvC;E0C98PF;IzCwJI,gByCwR8D;E1CiiPhE;E0Cj9PF;IA6aQ,UAAU;IACV,gBAAiC;E1CuiPvC;E0Cr9PF;IzCwJI,sByCwR8D;E1CwiPhE;E0Cx9PF;IA6aQ,UAAU;IACV,gBAAiC;E1C8iPvC;E0C59PF;IzCwJI,sByCwR8D;E1C+iPhE;E0C/9PF;IA6aQ,UAAU;IACV,UAAiC;E1CqjPvC;E0Cn+PF;IzCwJI,gByCwR8D;E1CsjPhE;E0Ct+PF;IA6aQ,UAAU;IACV,gBAAiC;E1C4jPvC;E0C1+PF;IzCwJI,sByCwR8D;E1C6jPhE;E0C7+PF;IA6aQ,UAAU;IACV,gBAAiC;E1CmkPvC;E0Cj/PF;IzCwJI,sByCwR8D;E1CokPhE;E0Cp/PF;IA6aQ,UAAU;IACV,UAAiC;E1C0kPvC;E0Cx/PF;IzCwJI,gByCwR8D;E1C2kPhE;E0C3/PF;IA6aQ,UAAU;IACV,gBAAiC;E1CilPvC;E0C//PF;IzCwJI,sByCwR8D;E1CklPhE;E0ClgQF;IA6aQ,UAAU;IACV,gBAAiC;E1CwlPvC;E0CtgQF;IzCwJI,sByCwR8D;E1CylPhE;E0CzgQF;IA6aQ,UAAU;IACV,WAAiC;E1C+lPvC;E0C7gQF;IzCwJI,iByCwR8D;E1CgmPhE;AACF;;A0C/lPA;EzC1RI,qByC1JgB;EzC0JhB,sByC1JgB;EAublB,oBAvbkB;A1CyhQpB;;A0CrmPA;EAKI,uBAzbgB;A1C6hQpB;;A0CzmPA;EAOI,qCAA4C;A1CsmPhD;;A0C7mPA;EAUI,uBAAuB;A1CumP3B;;A0CjnPA;EzC1RI,cyCsSiC;EzCtSjC,eyCuSiC;EACjC,aAAa;A1CymPjB;;A0CvnPA;EAgBM,SAAS;EACT,qBAAqB;A1C2mP3B;;A0C5nPA;EAmBM,qBAAqB;A1C6mP3B;;A0ChoPA;EAqBM,gBAAgB;A1C+mPtB;;A0CpoPA;EAuBI,aAAa;A1CinPjB;;A0CxoPA;EAyBI,eAAe;A1CmnPnB;;A0C5oPA;EA2BI,mBAAmB;A1CqnPvB;;ACr+PE;EyCqVF;IA+BM,aAAa;E1CsnPjB;AACF;;AC/9PE;EyCyUF;IAmCM,aAAa;E1CwnPjB;AACF;;A0CtnPE;EACE,oBAAY;EzCjUZ,wCyCkU2D;EzClU3D,yCyCmU2D;A1CynP/D;;A0C5nPE;EAKI,8BAA8B;EAC9B,+BAA+B;A1C2nPrC;;A0CjoPE;EASM,iBAAY;A1C4nPpB;;ACpgQE;EyC+XA;IAYQ,iBAAY;E1C8nPpB;AACF;;ACtgQE;EyC2XA;IAeQ,iBAAY;E1CioPpB;AACF;;ACxgQE;EyCuXA;IAkBQ,iBAAY;E1CooPpB;AACF;;AC1gQE;EyCmXA;IAqBQ,iBAAY;E1CuoPpB;AACF;;AC5gQE;EyC+WA;IAwBQ,iBAAY;E1C0oPpB;AACF;;AC7gQI;EyC0WF;IA2BQ,iBAAY;E1C6oPpB;AACF;;ACzgQI;EyCgWF;IA8BQ,iBAAY;E1CgpPpB;AACF;;AC1gQI;EyC2VF;IAiCQ,iBAAY;E1CmpPpB;AACF;;ACtgQI;EyCiVF;IAoCQ,iBAAY;E1CspPpB;AACF;;A0C3rPE;EASM,oBAAY;A1CsrPpB;;AC9jQE;EyC+XA;IAYQ,oBAAY;E1CwrPpB;AACF;;AChkQE;EyC2XA;IAeQ,oBAAY;E1C2rPpB;AACF;;AClkQE;EyCuXA;IAkBQ,oBAAY;E1C8rPpB;AACF;;ACpkQE;EyCmXA;IAqBQ,oBAAY;E1CisPpB;AACF;;ACtkQE;EyC+WA;IAwBQ,oBAAY;E1CosPpB;AACF;;ACvkQI;EyC0WF;IA2BQ,oBAAY;E1CusPpB;AACF;;ACnkQI;EyCgWF;IA8BQ,oBAAY;E1C0sPpB;AACF;;ACpkQI;EyC2VF;IAiCQ,oBAAY;E1C6sPpB;AACF;;AChkQI;EyCiVF;IAoCQ,oBAAY;E1CgtPpB;AACF;;A0CrvPE;EASM,mBAAY;A1CgvPpB;;ACxnQE;EyC+XA;IAYQ,mBAAY;E1CkvPpB;AACF;;AC1nQE;EyC2XA;IAeQ,mBAAY;E1CqvPpB;AACF;;AC5nQE;EyCuXA;IAkBQ,mBAAY;E1CwvPpB;AACF;;AC9nQE;EyCmXA;IAqBQ,mBAAY;E1C2vPpB;AACF;;AChoQE;EyC+WA;IAwBQ,mBAAY;E1C8vPpB;AACF;;ACjoQI;EyC0WF;IA2BQ,mBAAY;E1CiwPpB;AACF;;AC7nQI;EyCgWF;IA8BQ,mBAAY;E1CowPpB;AACF;;AC9nQI;EyC2VF;IAiCQ,mBAAY;E1CuwPpB;AACF;;AC1nQI;EyCiVF;IAoCQ,mBAAY;E1C0wPpB;AACF;;A0C/yPE;EASM,oBAAY;A1C0yPpB;;AClrQE;EyC+XA;IAYQ,oBAAY;E1C4yPpB;AACF;;ACprQE;EyC2XA;IAeQ,oBAAY;E1C+yPpB;AACF;;ACtrQE;EyCuXA;IAkBQ,oBAAY;E1CkzPpB;AACF;;ACxrQE;EyCmXA;IAqBQ,oBAAY;E1CqzPpB;AACF;;AC1rQE;EyC+WA;IAwBQ,oBAAY;E1CwzPpB;AACF;;AC3rQI;EyC0WF;IA2BQ,oBAAY;E1C2zPpB;AACF;;ACvrQI;EyCgWF;IA8BQ,oBAAY;E1C8zPpB;AACF;;ACxrQI;EyC2VF;IAiCQ,oBAAY;E1Ci0PpB;AACF;;ACprQI;EyCiVF;IAoCQ,oBAAY;E1Co0PpB;AACF;;A0Cz2PE;EASM,iBAAY;A1Co2PpB;;AC5uQE;EyC+XA;IAYQ,iBAAY;E1Cs2PpB;AACF;;AC9uQE;EyC2XA;IAeQ,iBAAY;E1Cy2PpB;AACF;;AChvQE;EyCuXA;IAkBQ,iBAAY;E1C42PpB;AACF;;AClvQE;EyCmXA;IAqBQ,iBAAY;E1C+2PpB;AACF;;ACpvQE;EyC+WA;IAwBQ,iBAAY;E1Ck3PpB;AACF;;ACrvQI;EyC0WF;IA2BQ,iBAAY;E1Cq3PpB;AACF;;ACjvQI;EyCgWF;IA8BQ,iBAAY;E1Cw3PpB;AACF;;AClvQI;EyC2VF;IAiCQ,iBAAY;E1C23PpB;AACF;;AC9uQI;EyCiVF;IAoCQ,iBAAY;E1C83PpB;AACF;;A0Cn6PE;EASM,oBAAY;A1C85PpB;;ACtyQE;EyC+XA;IAYQ,oBAAY;E1Cg6PpB;AACF;;ACxyQE;EyC2XA;IAeQ,oBAAY;E1Cm6PpB;AACF;;AC1yQE;EyCuXA;IAkBQ,oBAAY;E1Cs6PpB;AACF;;AC5yQE;EyCmXA;IAqBQ,oBAAY;E1Cy6PpB;AACF;;AC9yQE;EyC+WA;IAwBQ,oBAAY;E1C46PpB;AACF;;AC/yQI;EyC0WF;IA2BQ,oBAAY;E1C+6PpB;AACF;;AC3yQI;EyCgWF;IA8BQ,oBAAY;E1Ck7PpB;AACF;;AC5yQI;EyC2VF;IAiCQ,oBAAY;E1Cq7PpB;AACF;;ACxyQI;EyCiVF;IAoCQ,oBAAY;E1Cw7PpB;AACF;;A0C79PE;EASM,mBAAY;A1Cw9PpB;;ACh2QE;EyC+XA;IAYQ,mBAAY;E1C09PpB;AACF;;ACl2QE;EyC2XA;IAeQ,mBAAY;E1C69PpB;AACF;;ACp2QE;EyCuXA;IAkBQ,mBAAY;E1Cg+PpB;AACF;;ACt2QE;EyCmXA;IAqBQ,mBAAY;E1Cm+PpB;AACF;;ACx2QE;EyC+WA;IAwBQ,mBAAY;E1Cs+PpB;AACF;;ACz2QI;EyC0WF;IA2BQ,mBAAY;E1Cy+PpB;AACF;;ACr2QI;EyCgWF;IA8BQ,mBAAY;E1C4+PpB;AACF;;ACt2QI;EyC2VF;IAiCQ,mBAAY;E1C++PpB;AACF;;ACl2QI;EyCiVF;IAoCQ,mBAAY;E1Ck/PpB;AACF;;A0CvhQE;EASM,oBAAY;A1CkhQpB;;AC15QE;EyC+XA;IAYQ,oBAAY;E1CohQpB;AACF;;AC55QE;EyC2XA;IAeQ,oBAAY;E1CuhQpB;AACF;;AC95QE;EyCuXA;IAkBQ,oBAAY;E1C0hQpB;AACF;;ACh6QE;EyCmXA;IAqBQ,oBAAY;E1C6hQpB;AACF;;ACl6QE;EyC+WA;IAwBQ,oBAAY;E1CgiQpB;AACF;;ACn6QI;EyC0WF;IA2BQ,oBAAY;E1CmiQpB;AACF;;AC/5QI;EyCgWF;IA8BQ,oBAAY;E1CsiQpB;AACF;;ACh6QI;EyC2VF;IAiCQ,oBAAY;E1CyiQpB;AACF;;AC55QI;EyCiV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B;A7C+zRnC;;A6C9zRI;EAGI,yBAAgD;A7C+zRxD;;A6C9zRI;EACE,oCAAwC;A7Ci0R9C;;A6C71RE;EACE,yBAAwB;A7Cg2R5B;;A6C/1RE;EAGI,yBAA0C;A7Cg2RhD;;A6C/1RE;EACE,oCAAmC;A7Ck2RvC;;A6C71RI;EACE,yBAA8B;A7Cg2RpC;;A6C/1RI;EAGI,yBAAgD;A7Cg2RxD;;A6C/1RI;EACE,oCAAyC;A7Ck2R/C;;A6Ch2RI;EACE,yBAA6B;A7Cm2RnC;;A6Cl2RI;EAGI,yBAAgD;A7Cm2RxD;;A6Cl2RI;EACE,oCAAwC;A7Cq2R9C;;A6Cj4RE;EACE,yBAAwB;A7Co4R5B;;A6Cn4RE;EAGI,yBAA0C;A7Co4RhD;;A6Cn4RE;EACE,oCAAmC;A7Cs4RvC;;A6Cj4RI;EACE,yBAA8B;A7Co4RpC;;A6Cn4RI;EAGI,yBAAgD;A7Co4RxD;;A6Cn4RI;EACE,oCAAyC;A7Cs4R/C;;A6Cp4RI;EACE,yBAA6B;A7Cu4RnC;;A6Ct4RI;EAGI,yBAAgD;A7Cu4RxD;;A6Ct4RI;EACE,oCAAwC;A7Cy4R9C;;A6Cr6RE;EACE,yBAAwB;A7Cw6R5B;;A6Cv6RE;EAGI,yBAA0C;A7Cw6RhD;;A6Cv6RE;EACE,oCAAmC;A7C06RvC;;A6Cr6RI;EACE,yBAA8B;A7Cw6RpC;;A6Cv6RI;EAGI,yBAAgD;A7Cw6RxD;;A6Cv6RI;EACE,oCAAyC;A7C06R/C;;A6Cx6RI;EACE,yBAA6B;A7C26RnC;;A6C16RI;EAGI,yBAAgD;A7C26RxD;;A6C16RI;EACE,oCAAwC;A7C66R9C;;A6C16RE;EACE,yBAAwB;A7C66R5B;;A6C56RE;EACE,oCAAmC;A7C+6RvC;;A6Cl7RE;EACE,yBAAwB;A7Cq7R5B;;A6Cp7RE;EACE,oCAAmC;A7Cu7RvC;;A6C17RE;EACE,yBAAwB;A7C67R5B;;A6C57RE;EACE,oCAAmC;A7C+7RvC;;A6Cl8RE;EACE,yBAAwB;A7Cq8R5B;;A6Cp8RE;EACE,oCAAmC;A7Cu8RvC;;A6C18RE;EACE,yBAAwB;A7C68R5B;;A6C58RE;EACE,oCAAmC;A7C+8RvC;;A6Cl9RE;EACE,yBAAwB;A7Cq9R5B;;A6Cp9RE;EACE,oCAAmC;A7Cu9RvC;;A6C19RE;EACE,yBAAwB;A7C69R5B;;A6C59RE;EACE,oCAAmC;A7C+9RvC;;A6Cl+RE;EACE,4BAAwB;A7Cq+R5B;;A6Cp+RE;EACE,uCAAmC;A7Cu+RvC;;A6C1+RE;EACE,yBAAwB;A7C6+R5B;;A6C5+RE;EACE,oCAAmC;A7C++RvC;;A8CnhSE;EACE,8BAAiC;A9CshSrC;;A8CvhSE;EACE,sCAAiC;A9C0hSrC;;A8C3hSE;EACE,iCAAiC;A9C8hSrC;;A8C/hSE;EACE,yCAAiC;A9CkiSrC;;A8C9hSE;EACE,4BAA4B;A9CiiShC;;A8CliSE;EACE,0BAA4B;A9CqiShC;;A8CtiSE;EACE,kCAA4B;A9CyiShC;;A8CriSE;EACE,sCAAkC;A9CwiStC;;A8CziSE;EACE,oCAAkC;A9C4iStC;;A8C7iSE;EACE,kCAAkC;A9CgjStC;;A8CjjSE;EACE,yCAAkC;A9CojStC;;A8CrjSE;EACE,wCAAkC;A9CwjStC;;A8CzjSE;EACE,wCAAkC;A9C4jStC;;A8C7jSE;EACE,iCAAkC;A9CgkStC;;A8CjkSE;EACE,+BAAkC;A9CokStC;;A8CrkSE;EACE,gCAAkC;A9CwkStC;;A8CzkSE;EACE,iCAAkC;A9C4kStC;;A8CxkSE;EACE,oCAAgC;A9C2kSpC;;A8C5kSE;EACE,kCAAgC;A9C+kSpC;;A8ChlSE;EACE,gCAAgC;A9CmlSpC;;A8CplSE;EACE,uCAAgC;A9CulSpC;;A8CxlSE;EACE,sCAAgC;A9C2lSpC;;A8C5lSE;EACE,sCAAgC;A9C+lSpC;;A8ChmSE;EACE,iCAAgC;A9CmmSpC;;A8CpmSE;EACE,+BAAgC;A9CumSpC;;A8CxmSE;EACE,6BAAgC;A9C2mSpC;;A8C5mSE;EACE,kCAAgC;A9C+mSpC;;A8C3mSE;EACE,+BAA8B;A9C8mSlC;;A8C/mSE;EACE,kCAA8B;A9CknSlC;;A8CnnSE;EACE,gCAA8B;A9CsnSlC;;A8CvnSE;EACE,8BAA8B;A9C0nSlC;;A8C3nSE;EACE,gCAA8B;A9C8nSlC;;A8C/nSE;EACE,6BAA8B;A9CkoSlC;;A8CnoSE;EACE,2BAA8B;A9CsoSlC;;A8CvoSE;EACE,kCAA8B;A9C0oSlC;;A8C3oSE;EACE,gCAA8B;A9C8oSlC;;A8C1oSE;EACE,2BAA6B;A9C6oSjC;;A8C9oSE;EACE,iCAA6B;A9CipSjC;;A8ClpSE;EACE,+BAA6B;A9CqpSjC;;A8CtpSE;EACE,6BAA6B;A9CypSjC;;A8C1pSE;EACE,+BAA6B;A9C6pSjC;;A8C9pSE;EACE,8BAA6B;A9CiqSjC;;A8C5pSI;EACE,uBAAqC;A9C+pS3C;;A8ChqSI;EACE,uBAAqC;A9CmqS3C;;A8CpqSI;EACE,uBAAqC;A9CuqS3C;;A8CxqSI;EACE,uBAAqC;A9C2qS3C;;A8C5qSI;EACE,uBAAqC;A9C+qS3C;;A8ChrSI;EACE,uBAAqC;A9CmrS3C;;A8CprSI;EACE,yBAAqC;A9CurS3C;;A8CxrSI;EACE,yBAAqC;A9C2rS3C;;A8C5rSI;EACE,yBAAqC;A9C+rS3C;;A8ChsSI;EACE,yBAAqC;A9CmsS3C;;A8CpsSI;EACE,yBAAqC;A9CusS3C;;A8CxsSI;EACE,yBAAqC;A9C2sS3C;;AC1uSE;EACE,WAAW;EACX,YAAY;EACZ,cAAc;AD6uSlB;;A+C9uSA;EACE,sBAAsB;A/CivSxB;;A+C/uSA;EACE,uBAAuB;A/CkvSzB;;AgDzvSA;EACE,2BAA2B;AhD4vS7B;;AgD1vSA;EACE,2BAA2B;AhD6vS7B;;AgD3vSA;EACE,0BAA0B;EAC1B,8BAA8B;AhD8vShC;;AiDxwSA;EACE,2BAA2B;AjD2wS7B;;AkDvwSA;EACE,6BAA6B;AlD0wS/B;;AmDhxSA;EACE,oBAAoB;AnDmxStB;;AmDjxSA;EACE,qBAAqB;AnDoxSvB;;AmDzwSI;EACE,oBAA+B;AnD4wSrC;;AmDzwSM;EACE,wBAA8C;AnD4wStD;;AmD7wSM;EACE,0BAA8C;AnDgxStD;;AmDjxSM;EACE,2BAA8C;AnDoxStD;;AmDrxSM;EACE,yBAA8C;AnDwxStD;;AmDrxSM;EACE,yBAAyC;EACzC,0BAA2C;AnDwxSnD;;AmDrxSM;EACE,wBAAuC;EACvC,2BAA6C;AnDwxSrD;;AmDvySI;EACE,0BAA+B;AnD0ySrC;;AmDvySM;EACE,8BAA8C;AnD0yStD;;AmD3ySM;EACE,gCAA8C;AnD8yStD;;AmD/ySM;EACE,iCAA8C;AnDkzStD;;AmDnzSM;EACE,+BAA8C;AnDszStD;;AmDnzSM;EACE,+BAAyC;EACzC,gCAA2C;AnDszSnD;;AmDnzSM;EACE,8BAAuC;EACvC,iCAA6C;AnDszSrD;;AmDr0SI;EACE,yBAA+B;AnDw0SrC;;AmDr0SM;EACE,6BAA8C;AnDw0StD;;AmDz0SM;EACE,+BAA8C;AnD40StD;;AmD70SM;EACE,gCAA8C;AnDg1StD;;AmDj1SM;EACE,8BAA8C;AnDo1StD;;AmDj1SM;EACE,8BAAyC;EACzC,+BAA2C;AnDo1SnD;;AmDj1SM;EACE,6BAAuC;EACvC,gCAA6C;AnDo1SrD;;AmDn2SI;EACE,0BAA+B;AnDs2SrC;;AmDn2SM;EACE,8BAA8C;AnDs2StD;;AmDv2SM;EACE,gCAA8C;AnD02StD;;AmD32SM;EACE,iCAA8C;AnD82StD;;AmD/2SM;EACE,+BAA8C;AnDk3StD;;AmD/2SM;EACE,+BAAyC;EACzC,gCAA2C;AnDk3SnD;;AmD/2SM;EACE,8BAAuC;EACvC,iCAA6C;AnDk3SrD;;AmDj4SI;EACE,uBAA+B;AnDo4SrC;;AmDj4SM;EACE,2BAA8C;AnDo4StD;;AmDr4SM;EACE,6BAA8C;AnDw4StD;;AmDz4SM;EACE,8BAA8C;AnD44StD;;AmD74SM;EACE,4BAA8C;AnDg5StD;;AmD74SM;EACE,4BAAyC;EACzC,6BAA2C;AnDg5SnD;;AmD74SM;EACE,2BAAuC;EACvC,8BAA6C;AnDg5SrD;;AmD/5SI;EACE,yBAA+B;AnDk6SrC;;AmD/5SM;EACE,6BAA8C;AnDk6StD;;AmDn6SM;EACE,+BAA8C;AnDs6StD;;AmDv6SM;EACE,gCAA8C;AnD06StD;;AmD36SM;EACE,8BAA8C;AnD86StD;;AmD36SM;EACE,8BAAyC;EACzC,+BAA2C;AnD86SnD;;AmD36SM;EACE,6BAAuC;EACvC,gCAA6C;AnD86SrD;;AmD77SI;EACE,uBAA+B;AnDg8SrC;;AmD77SM;EACE,2BAA8C;AnDg8StD;;AmDj8SM;EACE,6BAA8C;AnDo8StD;;AmDr8SM;EACE,8BAA8C;AnDw8StD;;AmDz8SM;EACE,4BAA8C;AnD48StD;;AmDz8SM;EACE,4BAAyC;EACzC,6BAA2C;AnD48SnD;;AmDz8SM;EACE,2BAAuC;EACvC,8BAA6C;AnD48SrD;;AmD39SI;EACE,uBAA+B;AnD89SrC;;AmD39SM;EACE,2BAA8C;AnD89StD;;AmD/9SM;EACE,6BAA8C;AnDk+StD;;AmDn+SM;EACE,8BAA8C;AnDs+StD;;AmDv+SM;EACE,4BAA8C;AnD0+StD;;AmDv+SM;EACE,4BAAyC;EACzC,6BAA2C;AnD0+SnD;;AmDv+SM;EACE,2BAAuC;EACvC,8BAA6C;AnD0+SrD;;AmDz/SI;EACE,qBAA+B;AnD4/SrC;;AmDz/SM;EACE,yBAA8C;AnD4/StD;;AmD7/SM;EACE,2BAA8C;AnDggTtD;;AmDjgTM;EACE,4BAA8C;AnDogTtD;;AmDrgTM;EACE,0BAA8C;AnDwgTtD;;AmDrgTM;EACE,0BAAyC;EACzC,2BAA2C;AnDwgTnD;;AmDrgTM;EACE,yBAAuC;EACvC,4BAA6C;AnDwgTrD;;AmDvhTI;EACE,2BAA+B;AnD0hTrC;;AmDvhTM;EACE,+BAA8C;AnD0hTtD;;AmD3hTM;EACE,iCAA8C;AnD8hTtD;;AmD/hTM;EACE,kCAA8C;AnDkiTtD;;AmDniTM;EACE,gCAA8C;AnDsiTtD;;AmDniTM;EACE,gCAAyC;EACzC,iCAA2C;AnDsiTnD;;AmDniTM;EACE,+BAAuC;EACvC,kCAA6C;AnDsiTrD;;AmDrjTI;EACE,0BAA+B;AnDwjTrC;;AmDrjTM;EACE,8BAA8C;AnDwjTtD;;AmDzjTM;EACE,gCAA8C;AnD4jTtD;;AmD7jTM;EACE,iCAA8C;AnDgkTtD;;AmDjkTM;EACE,+BAA8C;AnDokTtD;;AmDjkTM;EACE,+BAAyC;EACzC,gCAA2C;AnDokTnD;;AmDjkTM;EACE,8BAAuC;EACvC,iCAA6C;AnDokTrD;;AmDnlTI;EACE,2BAA+B;AnDslTrC;;AmDnlTM;EACE,+BAA8C;AnDslTtD;;AmDvlTM;EACE,iCAA8C;AnD0lTtD;;AmD3lTM;EACE,kCAA8C;AnD8lTtD;;AmD/lTM;EACE,gCAA8C;AnDkmTtD;;AmD/lTM;EACE,gCAAyC;EACzC,iCAA2C;AnDkmTnD;;AmD/lTM;EACE,+BAAuC;EACvC,kCAA6C;AnDkmTrD;;AmDjnTI;EACE,wBAA+B;AnDonTrC;;AmDjnTM;EACE,4BAA8C;AnDonTtD;;AmDrnTM;EACE,8BAA8C;AnDwnTtD;;AmDznTM;EACE,+BAA8C;AnD4nTtD;;AmD7nTM;EACE,6BAA8C;AnDgoTtD;;AmD7nTM;EACE,6BAAyC;EACzC,8BAA2C;AnDgoTnD;;AmD7nTM;EACE,4BAAuC;EACvC,+BAA6C;AnDgoTrD;;AmD/oTI;EACE,0BAA+B;AnDkpTrC;;AmD/oTM;EACE,8BAA8C;AnDkpTtD;;AmDnpTM;EACE,gCAA8C;AnDspTtD;;AmDvpTM;EACE,iCAA8C;AnD0pTtD;;AmD3pTM;EACE,+BAA8C;AnD8pTtD;;AmD3pTM;EACE,+BAAyC;EACzC,gCAA2C;AnD8pTnD;;AmD3pTM;EACE,8BAAuC;EACvC,iCAA6C;AnD8pTrD;;AmD7qTI;EACE,wBAA+B;AnDgrTrC;;AmD7qTM;EACE,4BAA8C;AnDgrTtD;;AmDjrTM;EACE,8BAA8C;AnDorTtD;;AmDrrTM;EACE,+BAA8C;AnDwrTtD;;AmDzrTM;EACE,6BAA8C;AnD4rTtD;;AmDzrTM;EACE,6BAAyC;EACzC,8BAA2C;AnD4rTnD;;AmDzrTM;EACE,4BAAuC;EACvC,+BAA6C;AnD4rTrD;;AmD3sTI;EACE,wBAA+B;AnD8sTrC;;AmD3sTM;EACE,4BAA8C;AnD8sTtD;;AmD/sTM;EACE,8BAA8C;AnDktTtD;;AmDntTM;EACE,+BAA8C;AnDstTtD;;AmDvtTM;EACE,6BAA8C;AnD0tTtD;;AmDvtTM;EACE,6BAAyC;EACzC,8BAA2C;AnD0tTnD;;AmDvtTM;EACE,4BAAuC;EACvC,+BAA6C;AnD0tTrD;;AoDnvTI;EACE,0BAA2B;ApDsvTjC;;AoDvvTI;EACE,4BAA2B;ApD0vTjC;;AoD3vTI;EACE,0BAA2B;ApD8vTjC;;AoD/vTI;EACE,4BAA2B;ApDkwTjC;;AoDnwTI;EACE,6BAA2B;ApDswTjC;;AoDvwTI;EACE,0BAA2B;ApD0wTjC;;AoD3wTI;EACE,6BAA2B;ApD8wTjC;;ACvrTE;EmDxFE;IACE,0BAA2B;EpDmxT/B;EoDpxTE;IACE,4BAA2B;EpDsxT/B;EoDvxTE;IACE,0BAA2B;EpDyxT/B;EoD1xTE;IACE,4BAA2B;EpD4xT/B;EoD7xTE;IACE,6BAA2B;EpD+xT/B;EoDhyTE;IACE,0BAA2B;EpDkyT/B;EoDnyTE;IACE,6BAA2B;EpDqyT/B;AACF;;AC3sTE;EmD5FE;IACE,0BAA2B;EpD2yT/B;EoD5yTE;IACE,4BAA2B;EpD8yT/B;EoD/yTE;IACE,0BAA2B;EpDizT/B;EoDlzTE;IACE,4BAA2B;EpDozT/B;EoDrzTE;IACE,6BAA2B;EpDuzT/B;EoDxzTE;IACE,0BAA2B;EpD0zT/B;EoD3zTE;IACE,6BAA2B;EpD6zT/B;AACF;;AC3tTE;EmDpGE;IACE,0BAA2B;EpDm0T/B;EoDp0TE;IACE,4BAA2B;EpDs0T/B;EoDv0TE;IACE,0BAA2B;EpDy0T/B;EoD10TE;IACE,4BAA2B;EpD40T/B;EoD70TE;IACE,6BAA2B;EpD+0T/B;EoDh1TE;IACE,0BAA2B;EpDk1T/B;EoDn1TE;IACE,6BAA2B;EpDq1T/B;AACF;;AC/uTE;EmDxGE;IACE,0BAA2B;EpD21T/B;EoD51TE;IACE,4BAA2B;EpD81T/B;EoD/1TE;IACE,0BAA2B;EpDi2T/B;EoDl2TE;IACE,4BAA2B;EpDo2T/B;EoDr2TE;IACE,6BAA2B;EpDu2T/B;EoDx2TE;IACE,0BAA2B;EpD02T/B;EoD32TE;IACE,6BAA2B;EpD62T/B;AACF;;ACxvTI;EmDvHA;IACE,0BAA2B;EpDm3T/B;EoDp3TE;IACE,4BAA2B;EpDs3T/B;EoDv3TE;IACE,0BAA2B;EpDy3T/B;EoD13TE;IACE,4BAA2B;EpD43T/B;EoD73TE;IACE,6BAA2B;EpD+3T/B;EoDh4TE;IACE,0BAA2B;EpDk4T/B;EoDn4TE;IACE,6BAA2B;EpDq4T/B;AACF;;ACjwTI;EmDtIA;IACE,0BAA2B;EpD24T/B;EoD54TE;IACE,4BAA2B;EpD84T/B;EoD/4TE;IACE,0BAA2B;EpDi5T/B;EoDl5TE;IACE,4BAA2B;EpDo5T/B;EoDr5TE;IACE,6BAA2B;EpDu5T/B;EoDx5TE;IACE,0BAA2B;EpD05T/B;EoD35TE;IACE,6BAA2B;EpD65T/B;AACF;;AoDr4TE;EACE,6BAAqC;ApDw4TzC;;AoDz4TE;EACE,8BAAqC;ApD44TzC;;AoD74TE;EACE,2BAAqC;ApDg5TzC;;AoDj5TE;EACE,4BAAqC;ApDo5TzC;;ACv1TE;EmDzDE;IACE,6BAAqC;EpDo5TzC;AACF;;ACz1TE;EmD1DE;IACE,6BAAqC;EpDu5TzC;AACF;;AC31TE;EmD3DE;IACE,6BAAqC;EpD05TzC;AACF;;AC71TE;EmD5DE;IACE,6BAAqC;EpD65TzC;AACF;;AC/1TE;EmD7DE;IACE,6BAAqC;EpDg6TzC;AACF;;ACh2TI;EmD/DA;IACE,6BAAqC;EpDm6TzC;AACF;;AC51TI;EmDtEA;IACE,6BAAqC;EpDs6TzC;AACF;;AC71TI;EmDxEA;IACE,6BAAqC;EpDy6TzC;AACF;;ACz1TI;EmD/EA;IACE,6BAAqC;EpD46TzC;AACF;;AC74TE;EmDzDE;IACE,8BAAqC;EpD08TzC;AACF;;AC/4TE;EmD1DE;IACE,8BAAqC;EpD68TzC;AACF;;ACj5TE;EmD3DE;IACE,8BAAqC;EpDg9TzC;AACF;;ACn5TE;EmD5DE;IACE,8BAAqC;EpDm9TzC;AACF;;ACr5TE;EmD7DE;IACE,8BAAqC;EpDs9TzC;AACF;;ACt5TI;EmD/DA;IACE,8BAAqC;EpDy9TzC;AACF;;ACl5TI;EmDtEA;IACE,8BAAqC;EpD49TzC;AACF;;ACn5TI;EmDxEA;IACE,8BAAqC;EpD+9TzC;AACF;;AC/4TI;EmD/EA;IACE,8BAAqC;EpDk+TzC;AACF;;ACn8TE;EmDzDE;IACE,2BAAqC;EpDggUzC;AACF;;ACr8TE;EmD1DE;IACE,2BAAqC;EpDmgUzC;AACF;;ACv8TE;EmD3DE;IACE,2BAAqC;EpDsgUzC;AACF;;ACz8TE;EmD5DE;IACE,2BAAqC;EpDygUzC;AACF;;AC38TE;EmD7DE;IACE,2BAAqC;EpD4gUzC;AACF;;AC58TI;EmD/DA;IACE,2BAAqC;EpD+gUzC;AACF;;ACx8TI;EmDtEA;IACE,2BAAqC;EpDkhUzC;AACF;;ACz8TI;EmDxEA;IACE,2BAAqC;EpDqhUzC;AACF;;ACr8TI;EmD/EA;IACE,2BAAqC;EpDwhUzC;AACF;;ACz/TE;EmDzDE;IACE,4BAAqC;EpDsjUzC;AACF;;AC3/TE;EmD1DE;IACE,4BAAqC;EpDyjUzC;AACF;;AC7/TE;EmD3DE;IACE,4BAAqC;EpD4jUzC;AACF;;AC//TE;EmD5DE;IACE,4BAAqC;EpD+jUzC;AACF;;ACjgUE;EmD7DE;IACE,4BAAqC;EpDkkUzC;AACF;;AClgUI;EmD/DA;IACE,4BAAqC;EpDqkUzC;AACF;;AC9/TI;EmDtEA;IACE,4BAAqC;EpDwkUzC;AACF;;AC//TI;EmDxEA;IACE,4BAAqC;EpD2kUzC;AACF;;AC3/TI;EmD/EA;IACE,4BAAqC;EpD8kUzC;AACF;;AoD7kUA;EACE,qCAAqC;ApDglUvC;;AoD9kUA;EACE,oCAAoC;ApDilUtC;;AoD/kUA;EACE,oCAAoC;ApDklUtC;;AoDhlUA;EACE,6BAA6B;ApDmlU/B;;AoDjlUA;EACE,qCAAqC;ApDolUvC;;AoDllUA;EACE,2BAAqC;ApDqlUvC;;AoDplUA;EACE,2BAAsC;ApDulUxC;;AoDtlUA;EACE,2BAAsC;ApDylUxC;;AoDxlUA;EACE,2BAAwC;ApD2lU1C;;AoD1lUA;EACE,2BAAoC;ApD6lUtC;;AoD3lUA;EACE,+LAAuC;ApD8lUzC;;AoD5lUA;EACE,+LAAyC;ApD+lU3C;;AoD7lUA;EACE,+LAA0C;ApDgmU5C;;AoD9lUA;EACE,iCAAyC;ApDimU3C;;AoD/lUA;EACE,iCAAoC;ApDkmUtC;;AqDnsUE;EACE,yBAA+B;ArDssUnC;;AC/mUE;EoDrFE;IACE,yBAA+B;ErDwsUnC;AACF;;ACjnUE;EoDtFE;IACE,yBAA+B;ErD2sUnC;AACF;;ACnnUE;EoDvFE;IACE,yBAA+B;ErD8sUnC;AACF;;ACrnUE;EoDxFE;IACE,yBAA+B;ErDitUnC;AACF;;ACvnUE;EoDzFE;IACE,yBAA+B;ErDotUnC;AACF;;ACxnUI;EoD3FA;IACE,yBAA+B;ErDutUnC;AACF;;ACpnUI;EoDlGA;IACE,yBAA+B;ErD0tUnC;AACF;;ACrnUI;EoDpGA;IACE,yBAA+B;ErD6tUnC;AACF;;ACjnUI;EoD3GA;IACE,yBAA+B;ErDguUnC;AACF;;AqD7vUE;EACE,wBAA+B;ArDgwUnC;;ACzqUE;EoDrFE;IACE,wBAA+B;ErDkwUnC;AACF;;AC3qUE;EoDtFE;IACE,wBAA+B;ErDqwUnC;AACF;;AC7qUE;EoDvFE;IACE,wBAA+B;ErDwwUnC;AACF;;AC/qUE;EoDxFE;IACE,wBAA+B;ErD2wUnC;AACF;;ACjrUE;EoDzFE;IACE,wBAA+B;ErD8wUnC;AACF;;AClrUI;EoD3FA;IACE,wBAA+B;ErDixUnC;AACF;;AC9qUI;EoDlGA;IACE,wBAA+B;ErDoxUnC;AACF;;AC/qUI;EoDpGA;IACE,wBAA+B;ErDuxUnC;AACF;;AC3qUI;EoD3GA;IACE,wBAA+B;ErD0xUnC;AACF;;AqDvzUE;EACE,0BAA+B;ArD0zUnC;;ACnuUE;EoDrFE;IACE,0BAA+B;ErD4zUnC;AACF;;ACruUE;EoDtFE;IACE,0BAA+B;ErD+zUnC;AACF;;ACvuUE;EoDvFE;IACE,0BAA+B;ErDk0UnC;AACF;;ACzuUE;EoDxFE;IACE,0BAA+B;ErDq0UnC;AACF;;AC3uUE;EoDzFE;IACE,0BAA+B;ErDw0UnC;AACF;;AC5uUI;EoD3FA;IACE,0BAA+B;ErD20UnC;AACF;;ACxuUI;EoDlGA;IACE,0BAA+B;ErD80UnC;AACF;;ACzuUI;EoDpGA;IACE,0BAA+B;ErDi1UnC;AACF;;ACruUI;EoD3GA;IACE,0BAA+B;ErDo1UnC;AACF;;AqDj3UE;EACE,gCAA+B;ArDo3UnC;;AC7xUE;EoDrFE;IACE,gCAA+B;ErDs3UnC;AACF;;AC/xUE;EoDtFE;IACE,gCAA+B;ErDy3UnC;AACF;;ACjyUE;EoDvFE;IACE,gCAA+B;ErD43UnC;AACF;;ACnyUE;EoDxFE;IACE,gCAA+B;ErD+3UnC;AACF;;ACryUE;EoDzFE;IACE,gCAA+B;ErDk4UnC;AACF;;ACtyUI;EoD3FA;IACE,gCAA+B;ErDq4UnC;AACF;;AClyUI;EoDlGA;IACE,gCAA+B;ErDw4UnC;AACF;;ACnyUI;EoDpGA;IACE,gCAA+B;ErD24UnC;AACF;;AC/xUI;EoD3GA;IACE,gCAA+B;ErD84UnC;AACF;;AqD36UE;EACE,+BAA+B;ArD86UnC;;ACv1UE;EoDrFE;IACE,+BAA+B;ErDg7UnC;AACF;;ACz1UE;EoDtFE;IACE,+BAA+B;ErDm7UnC;AACF;;AC31UE;EoDvFE;IACE,+BAA+B;ErDs7UnC;AACF;;AC71UE;EoDxFE;IACE,+BAA+B;ErDy7UnC;AACF;;AC/1UE;EoDzFE;IACE,+BAA+B;ErD47UnC;AACF;;ACh2UI;EoD3FA;IACE,+BAA+B;ErD+7UnC;AACF;;AC51UI;EoDlGA;IACE,+BAA+B;ErDk8UnC;AACF;;AC71UI;EoDpGA;IACE,+BAA+B;ErDq8UnC;AACF;;ACz1UI;EoD3GA;IACE,+BAA+B;ErDw8UnC;AACF;;AqDv8UA;EACE,wBAAwB;ArD08U1B;;AqDx8UA;EACE,uBAAuB;EACvB,iCAAiC;EACjC,yBAAyB;EACzB,2BAA2B;EAC3B,qBAAqB;EACrB,6BAA6B;EAC7B,8BAA8B;EAC9B,wBAAwB;ArD28U1B;;AC55UE;EoD5CA;IACE,wBAAwB;ErD48U1B;AACF;;AC95UE;EoD5CA;IACE,wBAAwB;ErD88U1B;AACF;;ACh6UE;EoD5CA;IACE,wBAAwB;ErDg9U1B;AACF;;ACl6UE;EoD5CA;IACE,wBAAwB;ErDk9U1B;AACF;;ACp6UE;EoD5CA;IACE,wBAAwB;ErDo9U1B;AACF;;ACr6UI;EoD7CF;IACE,wBAAwB;ErDs9U1B;AACF;;ACj6UI;EoDnDF;IACE,wBAAwB;ErDw9U1B;AACF;;ACl6UI;EoDpDF;IACE,wBAAwB;ErD09U1B;AACF;;AC95UI;EoD1DF;IACE,wBAAwB;ErD49U1B;AACF;;AqD39UA;EACE,6BAA6B;ArD89U/B;;ACt9UE;EoDLA;IACE,6BAA6B;ErD+9U/B;AACF;;ACx9UE;EoDLA;IACE,6BAA6B;ErDi+U/B;AACF;;AC19UE;EoDLA;IACE,6BAA6B;ErDm+U/B;AACF;;AC59UE;EoDLA;IACE,6BAA6B;ErDq+U/B;AACF;;AC99UE;EoDLA;IACE,6BAA6B;ErDu+U/B;AACF;;AC/9UI;EoDNF;IACE,6BAA6B;ErDy+U/B;AACF;;AC39UI;EoDZF;IACE,6BAA6B;ErD2+U/B;AACF;;AC59UI;EoDbF;IACE,6BAA6B;ErD6+U/B;AACF;;ACx9UI;EoDnBF;IACE,6BAA6B;ErD++U/B;AACF;;AsDzmVA,iBAAA;ACWA;EACE,oBAAoB;EACpB,aAAa;EACb,sBAAsB;EACtB,8BAA8B;AvDkmVhC;;AuDtmVA;EAMI,gBAAgB;AvDomVpB;;AuD1mVA;EASM,mBAAmB;AvDqmVzB;;AuD9mVA;EAeM,uBxDXyB;EwDYzB,cxDzBuB;AC4nV7B;;AuDnnVA;;EAmBQ,cAAc;AvDqmVtB;;AuDxnVA;EAqBQ,cxD9BqB;ACqoV7B;;AuD5nVA;EAuBQ,4BxDhCqB;ACyoV7B;;AuDhoVA;;EA0BU,cxDnCmB;AC8oV7B;;ACviVE;EsD9FF;IA6BU,uBxDzBqB;ECsoV7B;AACF;;AuD3oVA;;EAgCQ,4BxDzCqB;ACypV7B;;AuDhpVA;;;EAqCU,yB7C6DuB;E6C5DvB,cxD/CmB;ACgqV7B;;AuDvpVA;EAyCU,cxDlDmB;EwDmDnB,YAAY;AvDknVtB;;AuD5pVA;EA4CY,UAAU;AvDonVtB;;AuDhqVA;EA+CY,uBAAwB;EACxB,UAAU;AvDqnVtB;;AuDrqVA;EAoDY,cxD7DiB;ACkrV7B;;AuDzqVA;EAsDc,uCxD/De;ACsrV7B;;AuD7qVA;EA0Dc,yBxDnEe;EwDoEf,qBxDpEe;EwDqEf,YxDxDiB;AC+qV/B;;AuDnrVA;EAkEU,4EAAyG;AvDqnVnH;;ACrmVE;EsDlFF;IAqEc,4EAAyG;EvDunVrH;AACF;;AuD7rVA;EAeM,yBxDxBuB;EwDyBvB,YxDZyB;AC8rV/B;;AuDlsVA;;EAmBQ,cAAc;AvDorVtB;;AuDvsVA;EAqBQ,YxDjBuB;ACusV/B;;AuD3sVA;EAuBQ,+BxDnBuB;AC2sV/B;;AuD/sVA;;EA0BU,YxDtBqB;ACgtV/B;;ACtnVE;EsD9FF;IA6BU,yBxDtCmB;ECkuV3B;AACF;;AuD1tVA;;EAgCQ,+BxD5BuB;AC2tV/B;;AuD/tVA;;;EAqCU,uB7C6DuB;E6C5DvB,YxDlCqB;ACkuV/B;;AuDtuVA;EAyCU,YxDrCqB;EwDsCrB,YAAY;AvDisVtB;;AuD3uVA;EA4CY,UAAU;AvDmsVtB;;AuD/uVA;EA+CY,yBAAwB;EACxB,UAAU;AvDosVtB;;AuDpvVA;EAoDY,YxDhDmB;ACovV/B;;AuDxvVA;EAsDc,uCxD/De;ACqwV7B;;AuD5vVA;EA0Dc,uBxDtDiB;EwDuDjB,mBxDvDiB;EwDwDjB,cxDrEe;AC2wV7B;;AuDlwVA;EAkEU,8EAAyG;AvDosVnH;;ACprVE;EsDlFF;IAqEc,8EAAyG;EvDssVrH;AACF;;AuD5wVA;EAeM,4BxDbwB;EwDcxB,yB7CqDe;AV4sVrB;;AuDjxVA;;EAmBQ,cAAc;AvDmwVtB;;AuDtxVA;EAqBQ,yB7CgDa;AVqtVrB;;AuD1xVA;EAuBQ,yB7C8Ca;AVytVrB;;AuD9xVA;;EA0BU,yB7C2CW;AV8tVrB;;ACrsVE;EsD9FF;IA6BU,4BxD3BoB;ECsyV5B;AACF;;AuDzyVA;;EAgCQ,yB7CqCa;AVyuVrB;;AuD9yVA;;;EAqCU,yB7C6DuB;E6C5DvB,yB7C+BW;AVgvVrB;;AuDrzVA;EAyCU,yB7C4BW;E6C3BX,YAAY;AvDgxVtB;;AuD1zVA;EA4CY,UAAU;AvDkxVtB;;AuD9zVA;EA+CY,4BAAwB;EACxB,UAAU;AvDmxVtB;;AuDn0VA;EAoDY,yB7CiBS;AVkwVrB;;AuDv0VA;EAsDc,uCxD/De;ACo1V7B;;AuD30VA;EA0Dc,oC7CWO;E6CVP,gC7CUO;E6CTP,iBxD1DgB;AC+0V9B;;AuDj1VA;EAkEU,iFAAyG;AvDmxVnH;;ACnwVE;EsDlFF;IAqEc,iFAAyG;EvDqxVrH;AACF;;AuD31VA;EAeM,yBxDpBwB;EwDqBxB,W7CuDU;AVyxVhB;;AuDh2VA;;EAmBQ,cAAc;AvDk1VtB;;AuDr2VA;EAqBQ,W7CkDQ;AVkyVhB;;AuDz2VA;EAuBQ,+B7CgDQ;AVsyVhB;;AuD72VA;;EA0BU,W7C6CM;AV2yVhB;;ACpxVE;EsD9FF;IA6BU,yBxDlCoB;EC43V5B;AACF;;AuDx3VA;;EAgCQ,+B7CuCQ;AVszVhB;;AuD73VA;;;EAqCU,yB7C6DuB;E6C5DvB,W7CiCM;AV6zVhB;;AuDp4VA;EAyCU,W7C8BM;E6C7BN,YAAY;AvD+1VtB;;AuDz4VA;EA4CY,UAAU;AvDi2VtB;;AuD74VA;EA+CY,yBAAwB;EACxB,UAAU;AvDk2VtB;;AuDl5VA;EAoDY,W7CmBI;AV+0VhB;;AuDt5VA;EAsDc,uCxD/De;ACm6V7B;;AuD15VA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDjEgB;ACq6V9B;;AuDh6VA;EAkEU,gFAAyG;AvDk2VnH;;ACl1VE;EsDlFF;IAqEc,gFAAyG;EvDo2VrH;AACF;;AuD16VA;EAeM,yBxDN4B;EwDO5B,W7CuDU;AVw2VhB;;AuD/6VA;;EAmBQ,cAAc;AvDi6VtB;;AuDp7VA;EAqBQ,W7CkDQ;AVi3VhB;;AuDx7VA;EAuBQ,+B7CgDQ;AVq3VhB;;AuD57VA;;EA0BU,W7C6CM;AV03VhB;;ACn2VE;EsD9FF;IA6BU,yBxDpBwB;EC67VhC;AACF;;AuDv8VA;;EAgCQ,+B7CuCQ;AVq4VhB;;AuD58VA;;;EAqCU,yB7C6DuB;E6C5DvB,W7CiCM;AV44VhB;;AuDn9VA;EAyCU,W7C8BM;E6C7BN,YAAY;AvD86VtB;;AuDx9VA;EA4CY,UAAU;AvDg7VtB;;AuD59VA;EA+CY,yBAAwB;EACxB,UAAU;AvDi7VtB;;AuDj+VA;EAoDY,W7CmBI;AV85VhB;;AuDr+VA;EAsDc,uCxD/De;ACk/V7B;;AuDz+VA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDnDoB;ACs+VlC;;AuD/+VA;EAkEU,gFAAyG;AvDi7VnH;;ACj6VE;EsDlFF;IAqEc,gFAAyG;EvDm7VrH;AACF;;AuDz/VA;EAeM,yBxDJ4B;EwDK5B,W7CuDU;AVu7VhB;;AuD9/VA;;EAmBQ,cAAc;AvDg/VtB;;AuDngWA;EAqBQ,W7CkDQ;AVg8VhB;;AuDvgWA;EAuBQ,+B7CgDQ;AVo8VhB;;AuD3gWA;;EA0BU,W7C6CM;AVy8VhB;;ACl7VE;EsD9FF;IA6BU,yBxDlBwB;EC0gWhC;AACF;;AuDthWA;;EAgCQ,+B7CuCQ;AVo9VhB;;AuD3hWA;;;EAqCU,yB7C6DuB;E6C5DvB,W7CiCM;AV29VhB;;AuDliWA;EAyCU,W7C8BM;E6C7BN,YAAY;AvD6/VtB;;AuDviWA;EA4CY,UAAU;AvD+/VtB;;AuD3iWA;EA+CY,yBAAwB;EACxB,UAAU;AvDggWtB;;AuDhjWA;EAoDY,W7CmBI;AV6+VhB;;AuDpjWA;EAsDc,uCxD/De;ACikW7B;;AuDxjWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDjDoB;ACmjWlC;;AuD9jWA;EAkEU,gFAAyG;AvDggWnH;;ACh/VE;EsDlFF;IAqEc,gFAAyG;EvDkgWrH;AACF;;AuDxkWA;EAeM,yBxDL4B;EwDM5B,W7CuDU;AVsgWhB;;AuD7kWA;;EAmBQ,cAAc;AvD+jWtB;;AuDllWA;EAqBQ,W7CkDQ;AV+gWhB;;AuDtlWA;EAuBQ,+B7CgDQ;AVmhWhB;;AuD1lWA;;EA0BU,W7C6CM;AVwhWhB;;ACjgWE;EsD9FF;IA6BU,yBxDnBwB;EC0lWhC;AACF;;AuDrmWA;;EAgCQ,+B7CuCQ;AVmiWhB;;AuD1mWA;;;EAqCU,yB7C6DuB;E6C5DvB,W7CiCM;AV0iWhB;;AuDjnWA;EAyCU,W7C8BM;E6C7BN,YAAY;AvD4kWtB;;AuDtnWA;EA4CY,UAAU;AvD8kWtB;;AuD1nWA;EA+CY,yBAAwB;EACxB,UAAU;AvD+kWtB;;AuD/nWA;EAoDY,W7CmBI;AV4jWhB;;AuDnoWA;EAsDc,uCxD/De;ACgpW7B;;AuDvoWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDlDoB;ACmoWlC;;AuD7oWA;EAkEU,gFAAyG;AvD+kWnH;;AC/jWE;EsDlFF;IAqEc,gFAAyG;EvDilWrH;AACF;;AuDvpWA;EAeM,yBxDP4B;EwDQ5B,W7CuDU;AVqlWhB;;AuD5pWA;;EAmBQ,cAAc;AvD8oWtB;;AuDjqWA;EAqBQ,W7CkDQ;AV8lWhB;;AuDrqWA;EAuBQ,+B7CgDQ;AVkmWhB;;AuDzqWA;;EA0BU,W7C6CM;AVumWhB;;AChlWE;EsD9FF;IA6BU,yBxDrBwB;EC2qWhC;AACF;;AuDprWA;;EAgCQ,+B7CuCQ;AVknWhB;;AuDzrWA;;;EAqCU,yB7C6DuB;E6C5DvB,W7CiCM;AVynWhB;;AuDhsWA;EAyCU,W7C8BM;E6C7BN,YAAY;AvD2pWtB;;AuDrsWA;EA4CY,UAAU;AvD6pWtB;;AuDzsWA;EA+CY,yBAAwB;EACxB,UAAU;AvD8pWtB;;AuD9sWA;EAoDY,W7CmBI;AV2oWhB;;AuDltWA;EAsDc,uCxD/De;AC+tW7B;;AuDttWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDpDoB;ACotWlC;;AuD5tWA;EAkEU,gFAAyG;AvD8pWnH;;AC9oWE;EsDlFF;IAqEc,gFAAyG;EvDgqWrH;AACF;;AuDtuWA;EAeM,yBxDR4B;EwDS5B,yB7CqDe;AVsqWrB;;AuD3uWA;;EAmBQ,cAAc;AvD6tWtB;;AuDhvWA;EAqBQ,yB7CgDa;AV+qWrB;;AuDpvWA;EAuBQ,yB7C8Ca;AVmrWrB;;AuDxvWA;;EA0BU,yB7C2CW;AVwrWrB;;AC/pWE;EsD9FF;IA6BU,yBxDtBwB;EC2vWhC;AACF;;AuDnwWA;;EAgCQ,yB7CqCa;AVmsWrB;;AuDxwWA;;;EAqCU,yB7C6DuB;E6C5DvB,yB7C+BW;AV0sWrB;;AuD/wWA;EAyCU,yB7C4BW;E6C3BX,YAAY;AvD0uWtB;;AuDpxWA;EA4CY,UAAU;AvD4uWtB;;AuDxxWA;EA+CY,yBAAwB;EACxB,UAAU;AvD6uWtB;;AuD7xWA;EAoDY,yB7CiBS;AV4tWrB;;AuDjyWA;EAsDc,uCxD/De;AC8yW7B;;AuDryWA;EA0Dc,oC7CWO;E6CVP,gC7CUO;E6CTP,cxDrDoB;ACoyWlC;;AuD3yWA;EAkEU,gFAAyG;AvD6uWnH;;AC7tWE;EsDlFF;IAqEc,gFAAyG;EvD+uWrH;AACF;;AuDrzWA;EAeM,yBxDF2B;EwDG3B,W7CuDU;AVmvWhB;;AuD1zWA;;EAmBQ,cAAc;AvD4yWtB;;AuD/zWA;EAqBQ,W7CkDQ;AV4vWhB;;AuDn0WA;EAuBQ,+B7CgDQ;AVgwWhB;;AuDv0WA;;EA0BU,W7C6CM;AVqwWhB;;AC9uWE;EsD9FF;IA6BU,yBxDhBuB;ECo0W/B;AACF;;AuDl1WA;;EAgCQ,+B7CuCQ;AVgxWhB;;AuDv1WA;;;EAqCU,yB7C6DuB;E6C5DvB,W7CiCM;AVuxWhB;;AuD91WA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDyzWtB;;AuDn2WA;EA4CY,UAAU;AvD2zWtB;;AuDv2WA;EA+CY,yBAAwB;EACxB,UAAU;AvD4zWtB;;AuD52WA;EAoDY,W7CmBI;AVyyWhB;;AuDh3WA;EAsDc,uCxD/De;AC63W7B;;AuDp3WA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxD/CmB;AC62WjC;;AuD13WA;EAkEU,gFAAyG;AvD4zWnH;;AC5yWE;EsDlFF;IAqEc,gFAAyG;EvD8zWrH;AACF;;AuDp4WA;EAyEM,eAhF0B;AvD+4WhC;;AClzWE;EsDtFF;IA6EQ,oBAnF8B;EvDm5WpC;AACF;;ACxzWE;EsDtFF;IAiFQ,mBAtF4B;EvDw5WlC;AACF;;AuDp5WA;EAsFM,mBAAmB;EACnB,aAAa;AvDk0WnB;;AuDz5WA;EAyFQ,YAAY;EACZ,cAAc;AvDo0WtB;;AuD95WA;EA4FI,gBAAgB;AvDs0WpB;;AuDl6WA;EA8FI,iBAAiB;AvDw0WrB;;AuDp0WA;EAEE,gBAAgB;AvDs0WlB;;AuDx0WA;EAII,SAAS;EACT,gBAAgB;EAChB,eAAe;EACf,kBAAkB;EAClB,QAAQ;EACR,qCAAqC;AvDw0WzC;;AuDj1WA;EAYI,YAAY;AvDy0WhB;;ACr2WE;EsDgBF;IAeI,aAAa;EvD20Wf;AACF;;AuD10WA;EACE,kBAAkB;AvD60WpB;;AC/2WE;EsDiCF;IAKM,aAAa;EvD80WjB;EuDn1WF;IAOQ,sBAAsB;EvD+0W5B;AACF;;ACp3WE;EsD6BF;IASI,aAAa;IACb,uBAAuB;EvDm1WzB;EuD71WF;ItD8BI,oBsDlBwC;EvDo1W1C;AACF;;AuDj1WA;;EAEE,YAAY;EACZ,cAAc;AvDo1WhB;;AuDl1WA;EACE,YAAY;EACZ,cAAc;EACd,oBApJ6B;AvDy+W/B;;AC14WE;EsDkDF;IAKI,kBArJgC;EvD6+WlC;AACF;;AwD1+WA;EACE,oBAN2B;AxDm/W7B;;ACx4WE;EuDtGF;IAII,kBAR+B;ExDu/WjC;EwDn/WF;IAOM,oBAV8B;ExDy/WlC;EwDt/WF;IASM,mBAX4B;ExD2/WhC;AACF;;AyD3/WA;EACE,yB1DO4B;E0DN5B,yBAJ+B;AzDkgXjC","file":"bulma.css"} \ No newline at end of file From 68d79f60901f90fe31c6d53fdcbc3b73c8d92805 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 29 Mar 2022 22:53:17 +0200 Subject: [PATCH 041/244] Modifica el renderizado de componentes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La función default_render() se implementa usando llamadas a funciones, nunca usando campos internos de la estructura. Esto es así para dar las mismas opciones a los temas que alteren el render de un componente dado. --- pagetop-user/src/lib.rs | 2 +- pagetop/src/base/component/block.rs | 22 ++-- pagetop/src/base/component/chunck.rs | 6 +- pagetop/src/base/component/container.rs | 42 +++++--- pagetop/src/base/component/form/button.rs | 49 +++++---- pagetop/src/base/component/form/date.rs | 100 +++++++++---------- pagetop/src/base/component/form/form.rs | 47 +++++---- pagetop/src/base/component/form/hidden.rs | 30 +++--- pagetop/src/base/component/form/input.rs | 116 +++++++++++----------- pagetop/src/base/component/form/mod.rs | 4 +- pagetop/src/base/component/grid/column.rs | 18 +++- pagetop/src/base/component/grid/row.rs | 18 +++- pagetop/src/base/component/image.rs | 19 ++-- pagetop/src/base/component/menu.rs | 53 +++++----- pagetop/src/base/component/mod.rs | 4 +- pagetop/src/base/module/demopage/mod.rs | 2 +- pagetop/src/html/optattr.rs | 11 -- pagetop/src/html/optiden.rs | 11 -- pagetop/src/lib.rs | 9 +- pagetop/src/prelude.rs | 1 + pagetop/src/response/page/assets.rs | 27 ++--- pagetop/src/response/page/page.rs | 18 ++-- pagetop/src/theme/definition.rs | 21 ++-- 23 files changed, 335 insertions(+), 295 deletions(-) diff --git a/pagetop-user/src/lib.rs b/pagetop-user/src/lib.rs index 7ef2ecf3..dd0b362b 100644 --- a/pagetop-user/src/lib.rs +++ b/pagetop-user/src/lib.rs @@ -40,7 +40,7 @@ fn form_login() -> impl PageComponent { .with_help_text(t("username_help", &args![ "app" => SETTINGS.app.name.to_owned() ]).as_str()) - .autofocus(true) + .with_autofocus(true) ) .add(form::Input::password() .with_name("pass") diff --git a/pagetop/src/base/component/block.rs b/pagetop/src/base/component/block.rs index 5e5a7159..976c27bc 100644 --- a/pagetop/src/base/component/block.rs +++ b/pagetop/src/base/component/block.rs @@ -31,15 +31,15 @@ impl PageComponent for Block { } fn default_render(&self, assets: &mut PageAssets) -> Markup { - let id = assets.serial_id(self.name(), self.id.value()); - let title = self.title.value(); + let id = assets.serial_id(self.name(), self.id()); html! { div id=(id) class="block" { - @if !title.is_empty() { - h2 class="block-title" { (title) } + @match self.title() { + Some(title) => h2 class="block-title" { (title) }, + None => {} } div class="block-body" { - @for html in self.html.iter() { + @for html in self.html().iter() { (*html) } } @@ -88,12 +88,16 @@ impl Block { // Block GETTERS. - pub fn id(&self) -> &str { - self.id.value() + pub fn id(&self) -> &Option<String> { + self.id.option() } - pub fn title(&self) -> &str { - self.title.value() + pub fn title(&self) -> &Option<String> { + self.title.option() + } + + pub fn html(&self) -> &Vec<Markup> { + &self.html } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/chunck.rs b/pagetop/src/base/component/chunck.rs index b03ac0c8..532584fc 100644 --- a/pagetop/src/base/component/chunck.rs +++ b/pagetop/src/base/component/chunck.rs @@ -28,7 +28,7 @@ impl PageComponent for Chunck { fn default_render(&self, _: &mut PageAssets) -> Markup { html! { - @for html in self.html.iter() { + @for html in self.html().iter() { (*html) } } @@ -65,6 +65,10 @@ impl Chunck { // Chunck GETTERS. + pub fn html(&self) -> &Vec<Markup> { + &self.html + } + pub fn template(&self) -> &str { self.template.as_str() } diff --git a/pagetop/src/base/component/container.rs b/pagetop/src/base/component/container.rs index e76b48b4..cba905d6 100644 --- a/pagetop/src/base/component/container.rs +++ b/pagetop/src/base/component/container.rs @@ -1,12 +1,12 @@ use crate::prelude::*; -enum ContainerType { Header, Footer, Main, Section, Wrapper } +pub enum ContainerType { Header, Footer, Main, Section, Wrapper } pub struct Container { renderable: fn() -> bool, weight : i8, - id : OptIden, container : ContainerType, + id : OptIden, components: PageContainer, template : String, } @@ -17,8 +17,8 @@ impl PageComponent for Container { Container { renderable: always, weight : 0, - id : OptIden::none(), container : ContainerType::Wrapper, + id : OptIden::none(), components: PageContainer::new(), template : "default".to_owned(), } @@ -33,38 +33,38 @@ impl PageComponent for Container { } fn default_render(&self, assets: &mut PageAssets) -> Markup { - match self.container { + match self.container_type() { ContainerType::Header => html! { - header id=[&self.id.option()] class="header" { + header id=[self.id()] class="header" { div class="container" { - (self.components.render(assets)) + (self.render_components(assets)) } } }, ContainerType::Footer => html! { - footer id=[&self.id.option()] class="footer" { + footer id=[self.id()] class="footer" { div class="container" { - (self.components.render(assets)) + (self.render_components(assets)) } } }, ContainerType::Main => html! { - main id=[&self.id.option()] class="main" { + main id=[self.id()] class="main" { div class="container" { - (self.components.render(assets)) + (self.render_components(assets)) } } }, ContainerType::Section => html! { - section id=[&self.id.option()] class="section" { + section id=[self.id()] class="section" { div class="container" { - (self.components.render(assets)) + (self.render_components(assets)) } } }, _ => html! { - div id=[&self.id.option()] class="container" { - (self.components.render(assets)) + div id=[self.id()] class="container" { + (self.render_components(assets)) } } } @@ -126,13 +126,23 @@ impl Container { // Container GETTERS. - pub fn id(&self) -> &str { - self.id.value() + pub fn container_type(&self) -> &ContainerType { + &self.container + } + + pub fn id(&self) -> &Option<String> { + self.id.option() } pub fn template(&self) -> &str { self.template.as_str() } + + // Container EXTRAS. + + pub fn render_components(&self, assets: &mut PageAssets) -> Markup { + html! { (self.components.render(assets)) } + } } fn always() -> bool { diff --git a/pagetop/src/base/component/form/button.rs b/pagetop/src/base/component/form/button.rs index fa9794f2..fbe25738 100644 --- a/pagetop/src/base/component/form/button.rs +++ b/pagetop/src/base/component/form/button.rs @@ -1,6 +1,6 @@ use crate::prelude::*; -enum ButtonType {Button, Reset, Submit} +pub enum ButtonType {Button, Reset, Submit} pub struct Button { renderable : fn() -> bool, @@ -37,26 +37,29 @@ impl PageComponent for Button { } fn default_render(&self, _: &mut PageAssets) -> Markup { - let (button_type, button_class) = match &self.button_type { + let (button_type, button_class) = match self.button_type() { ButtonType::Button => ("button", "btn btn-primary form-button"), ButtonType::Reset => ("reset", "btn btn-primary form-reset" ), - ButtonType::Submit => ("submit", "btn btn-primary form-submit") + ButtonType::Submit => ("submit", "btn btn-primary form-submit"), }; - let id = match &self.name.option() { - Some(name) => Some(format!("edit-{}", name)), + let id = match self.name() { + Some(name) => Some(concat_string!("edit-", name)), _ => None }; html! { button type=(button_type) - id=[&id] + id=[id] class=(button_class) - name=[&self.name.option()] - value=[&self.value.option()] - autofocus=[&self.autofocus.option()] - disabled=[&self.disabled.option()] + name=[self.name()] + value=[self.value()] + autofocus=[self.autofocus()] + disabled=[self.disabled()] { - (self.value.value()) + @match self.value() { + Some(value) => { (value) }, + None => {}, + } } } } @@ -102,7 +105,7 @@ impl Button { self } - pub fn autofocus(mut self, toggle: bool) -> Self { + pub fn with_autofocus(mut self, toggle: bool) -> Self { self.autofocus.with_value(match toggle { true => "autofocus", false => "", @@ -110,7 +113,7 @@ impl Button { self } - pub fn disabled(mut self, toggle: bool) -> Self { + pub fn with_disabled(mut self, toggle: bool) -> Self { self.disabled.with_value(match toggle { true => "disabled", false => "", @@ -125,20 +128,24 @@ impl Button { // Button GETTERS. - pub fn name(&self) -> &str { - self.name.value() + pub fn button_type(&self) -> &ButtonType { + &self.button_type } - pub fn value(&self) -> &str { - self.value.value() + pub fn name(&self) -> &Option<String> { + self.name.option() } - pub fn has_autofocus(&self) -> bool { - self.autofocus.has_value() + pub fn value(&self) -> &Option<String> { + self.value.option() } - pub fn is_disabled(&self) -> bool { - self.disabled.has_value() + pub fn autofocus(&self) -> &Option<String> { + self.autofocus.option() + } + + pub fn disabled(&self) -> &Option<String> { + self.disabled.option() } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/form/date.rs b/pagetop/src/base/component/form/date.rs index 5e42bc6b..906f5bbc 100644 --- a/pagetop/src/base/component/form/date.rs +++ b/pagetop/src/base/component/form/date.rs @@ -45,10 +45,10 @@ impl PageComponent for Date { } fn default_render(&self, _: &mut PageAssets) -> Markup { - let (class, id) = match self.name.option() { + let (class, id) = match self.name() { Some(name) => ( - format!("form-item form-item-{} form-type-date", name), - Some(format!("edit-{}", name)) + concat_string!("form-item form-item-", name, " form-type-date"), + Some(concat_string!("edit-", name)) ), None => ( "form-item form-type-date".to_owned(), @@ -57,35 +57,33 @@ impl PageComponent for Date { }; html! { div class=(class) { - @if self.label.has_value() { - label class="form-label" for=[&id] { - (self.label.value()) " " - @if self.required.has_value() { - span + @match self.label() { + Some(label) => label class="form-label" for=[&id] { + (label) " " + @match self.required() { + Some(_) => span class="form-required" - title="Este campo es obligatorio." - { - "*" - } " " + title="Este campo es obligatorio." { "*" } " ", + None => {} } - } + }, + None => {} } input type="date" - id=[&id] + id=[id] class="form-control" - name=[&self.name.option()] - value=[&self.value.option()] - placeholder=[&self.placeholder.option()] - autofocus=[&self.autofocus.option()] - autocomplete=[&self.autocomplete.option()] - readonly=[&self.readonly.option()] - required=[&self.required.option()] - disabled=[&self.disabled.option()]; - @if self.help_text.has_value() { - div class="form-text" { - (self.help_text.value()) - } + name=[self.name()] + value=[self.value()] + placeholder=[self.placeholder()] + autofocus=[self.autofocus()] + autocomplete=[self.autocomplete()] + readonly=[self.readonly()] + required=[self.required()] + disabled=[self.disabled()]; + @match self.help_text() { + Some(help_text) => div class="form-text" { (help_text) }, + None => {} } } } @@ -126,7 +124,7 @@ impl Date { self } - pub fn autofocus(mut self, toggle: bool) -> Self { + pub fn with_autofocus(mut self, toggle: bool) -> Self { self.autofocus.with_value(match toggle { true => "autofocus", false => "", @@ -134,7 +132,7 @@ impl Date { self } - pub fn autocomplete(mut self, toggle: bool) -> Self { + pub fn with_autocomplete(mut self, toggle: bool) -> Self { self.autocomplete.with_value(match toggle { true => "", false => "off", @@ -142,7 +140,7 @@ impl Date { self } - pub fn disabled(mut self, toggle: bool) -> Self { + pub fn with_disabled(mut self, toggle: bool) -> Self { self.disabled.with_value(match toggle { true => "disabled", false => "", @@ -150,7 +148,7 @@ impl Date { self } - pub fn readonly(mut self, toggle: bool) -> Self { + pub fn with_readonly(mut self, toggle: bool) -> Self { self.readonly.with_value(match toggle { true => "readonly", false => "", @@ -158,7 +156,7 @@ impl Date { self } - pub fn required(mut self, toggle: bool) -> Self { + pub fn with_required(mut self, toggle: bool) -> Self { self.required.with_value(match toggle { true => "required", false => "", @@ -178,44 +176,44 @@ impl Date { // Date GETTERS. - pub fn name(&self) -> &str { - self.name.value() + pub fn name(&self) -> &Option<String> { + self.name.option() } - pub fn value(&self) -> &str { - self.value.value() + pub fn value(&self) -> &Option<String> { + self.value.option() } - pub fn label(&self) -> &str { - self.label.value() + pub fn label(&self) -> &Option<String> { + self.label.option() } - pub fn placeholder(&self) -> &str { - self.placeholder.value() + pub fn placeholder(&self) -> &Option<String> { + self.placeholder.option() } - pub fn has_autofocus(&self) -> bool { - self.autofocus.has_value() + pub fn autofocus(&self) -> &Option<String> { + self.autofocus.option() } - pub fn has_autocomplete(&self) -> bool { - !self.autocomplete.has_value() + pub fn autocomplete(&self) -> &Option<String> { + self.autocomplete.option() } - pub fn is_disabled(&self) -> bool { - self.disabled.has_value() + pub fn disabled(&self) -> &Option<String> { + self.disabled.option() } - pub fn is_readonly(&self) -> bool { - self.readonly.has_value() + pub fn readonly(&self) -> &Option<String> { + self.readonly.option() } - pub fn is_required(&self) -> bool { - self.required.has_value() + pub fn required(&self) -> &Option<String> { + self.required.option() } - pub fn help_text(&self) -> &str { - self.help_text.value() + pub fn help_text(&self) -> &Option<String> { + self.help_text.option() } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/form/form.rs b/pagetop/src/base/component/form/form.rs index 385dd369..5ecea5e0 100644 --- a/pagetop/src/base/component/form/form.rs +++ b/pagetop/src/base/component/form/form.rs @@ -7,8 +7,8 @@ pub struct Form { weight : i8, id : OptIden, action : OptAttr, - method : FormMethod, charset : OptAttr, + method : FormMethod, elements : PageContainer, template : String, } @@ -21,8 +21,8 @@ impl PageComponent for Form { weight : 0, id : OptIden::none(), action : OptAttr::none(), - method : FormMethod::Post, charset : OptAttr::some("UTF-8"), + method : FormMethod::Post, elements : PageContainer::new(), template : "default".to_owned(), } @@ -37,19 +37,19 @@ impl PageComponent for Form { } fn default_render(&self, assets: &mut PageAssets) -> Markup { - let method = match self.method { + let method = match self.method() { FormMethod::Get => None, FormMethod::Post => Some("post".to_owned()) }; html! { form - id=[&self.id.option()] - action=[&self.action.option()] + id=[self.id()] + action=[self.action()] method=[method] - accept-charset=[&self.charset.option()] + accept-charset=[self.charset()] { div { - (self.elements.render(assets)) + (self.render_elements(assets)) } } } @@ -80,13 +80,13 @@ impl Form { self } - pub fn with_method(mut self, method: FormMethod) -> Self { - self.method = method; + pub fn with_charset(mut self, charset: &str) -> Self { + self.charset.with_value(charset); self } - pub fn with_charset(mut self, charset: &str) -> Self { - self.charset.with_value(charset); + pub fn with_method(mut self, method: FormMethod) -> Self { + self.method = method; self } @@ -102,28 +102,31 @@ impl Form { // Form GETTERS. - pub fn id(&self) -> &str { - self.id.value() + pub fn id(&self) -> &Option<String> { + self.id.option() } - pub fn action(&self) -> &str { - self.action.value() + pub fn action(&self) -> &Option<String> { + self.action.option() } - pub fn method(&self) -> &str { - match &self.method { - FormMethod::Get => "get", - FormMethod::Post => "post" - } + pub fn charset(&self) -> &Option<String> { + self.charset.option() } - pub fn charset(&self) -> &str { - self.charset.value() + pub fn method(&self) -> &FormMethod { + &self.method } pub fn template(&self) -> &str { self.template.as_str() } + + // Form EXTRAS. + + pub fn render_elements(&self, assets: &mut PageAssets) -> Markup { + html! { (self.elements.render(assets)) } + } } fn always() -> bool { diff --git a/pagetop/src/base/component/form/hidden.rs b/pagetop/src/base/component/form/hidden.rs index b7eca015..636d034e 100644 --- a/pagetop/src/base/component/form/hidden.rs +++ b/pagetop/src/base/component/form/hidden.rs @@ -1,18 +1,18 @@ use crate::prelude::*; pub struct Hidden { - weight : i8, - name : OptIden, - value : OptAttr, + weight: i8, + name : OptIden, + value : OptAttr, } impl PageComponent for Hidden { fn new() -> Self { Hidden { - weight : 0, - name : OptIden::none(), - value : OptAttr::none(), + weight: 0, + name : OptIden::none(), + value : OptAttr::none(), } } @@ -21,16 +21,12 @@ impl PageComponent for Hidden { } fn default_render(&self, _: &mut PageAssets) -> Markup { - let id = match self.name.option() { - Some(name) => Some(format!("value-{}", name)), + let id = match self.name() { + Some(name) => Some(concat_string!("value-", name)), _ => None }; html! { - input - type="hidden" - id=[&id] - name=[&self.name.option()] - value=[&self.value.option()]; + input type="hidden" id=[id] name=[self.name()] value=[self.value()]; } } } @@ -60,11 +56,11 @@ impl Hidden { // Hidden GETTERS. - pub fn name(&self) -> &str { - self.name.value() + pub fn name(&self) -> &Option<String> { + self.name.option() } - pub fn value(&self) -> &str { - self.value.value() + pub fn value(&self) -> &Option<String> { + self.value.option() } } diff --git a/pagetop/src/base/component/form/input.rs b/pagetop/src/base/component/form/input.rs index 7622fd08..7dded20f 100644 --- a/pagetop/src/base/component/form/input.rs +++ b/pagetop/src/base/component/form/input.rs @@ -1,6 +1,6 @@ use crate::prelude::*; -enum InputType {Email, Password, Search, Telephone, Textfield, Url} +pub enum InputType {Email, Password, Search, Telephone, Textfield, Url} pub struct Input { renderable : fn() -> bool, @@ -55,7 +55,7 @@ impl PageComponent for Input { } fn default_render(&self, _: &mut PageAssets) -> Markup { - let (type_input, type_class) = match &self.input_type { + let (type_input, type_class) = match self.input_type() { InputType::Email => ("email", "form-type-email"), InputType::Password => ("password", "form-type-password"), InputType::Search => ("search", "form-type-search"), @@ -63,50 +63,48 @@ impl PageComponent for Input { InputType::Textfield => ("text", "form-type-textfield"), InputType::Url => ("url", "form-type-url") }; - let (class, id) = match &self.name.option() { + let (class, id) = match self.name() { Some(name) => ( - format!("form-item form-item-{} {}", name, type_class), - Some(format!("edit-{}", name)) + concat_string!("form-item form-item-", name, " ", type_class), + Some(concat_string!("edit-", name)) ), None => ( - format!("form-item {}", type_class), + concat_string!("form-item ", type_class), None ) }; html! { div class=(class) { - @if self.label.has_value() { - label class="form-label" for=[&id] { - (self.label.value()) " " - @if self.required.has_value() { - span + @match self.label() { + Some(label) => label class="form-label" for=[&id] { + (label) " " + @match self.required() { + Some(_) => span class="form-required" - title="Este campo es obligatorio." - { - "*" - } " " + title="Este campo es obligatorio." { "*" } " ", + None => {} } - } + }, + None => {} } input type=(type_input) - id=[&id] + id=[id] class="form-control" - name=[&self.name.option()] - value=[&self.value.option()] - size=[self.size] - minlength=[self.minlength] - maxlength=[self.maxlength] - placeholder=[&self.placeholder.option()] - autofocus=[&self.autofocus.option()] - autocomplete=[&self.autocomplete.option()] - readonly=[&self.readonly.option()] - required=[&self.required.option()] - disabled=[&self.disabled.option()]; - @if self.help_text.has_value() { - div class="form-text" { - (self.help_text.value()) - } + name=[self.name()] + value=[self.value()] + size=[self.size()] + minlength=[self.minlength()] + maxlength=[self.maxlength()] + placeholder=[self.placeholder()] + autofocus=[self.autofocus()] + autocomplete=[self.autocomplete()] + readonly=[self.readonly()] + required=[self.required()] + disabled=[self.disabled()]; + @match self.help_text() { + Some(help_text) => div class="form-text" { (help_text) }, + None => {} } } } @@ -196,7 +194,7 @@ impl Input { self } - pub fn autofocus(mut self, toggle: bool) -> Self { + pub fn with_autofocus(mut self, toggle: bool) -> Self { self.autofocus.with_value(match toggle { true => "autofocus", false => "", @@ -204,7 +202,7 @@ impl Input { self } - pub fn autocomplete(mut self, toggle: bool) -> Self { + pub fn with_autocomplete(mut self, toggle: bool) -> Self { self.autocomplete.with_value(match toggle { true => "", false => "off", @@ -212,7 +210,7 @@ impl Input { self } - pub fn disabled(mut self, toggle: bool) -> Self { + pub fn with_disabled(mut self, toggle: bool) -> Self { self.disabled.with_value(match toggle { true => "disabled", false => "", @@ -220,7 +218,7 @@ impl Input { self } - pub fn readonly(mut self, toggle: bool) -> Self { + pub fn with_readonly(mut self, toggle: bool) -> Self { self.readonly.with_value(match toggle { true => "readonly", false => "", @@ -228,7 +226,7 @@ impl Input { self } - pub fn required(mut self, toggle: bool) -> Self { + pub fn with_required(mut self, toggle: bool) -> Self { self.required.with_value(match toggle { true => "required", false => "", @@ -248,16 +246,20 @@ impl Input { // Input GETTERS. - pub fn name(&self) -> &str { - self.name.value() + pub fn input_type(&self) -> &InputType { + &self.input_type } - pub fn value(&self) -> &str { - self.value.value() + pub fn name(&self) -> &Option<String> { + self.name.option() } - pub fn label(&self) -> &str { - self.label.value() + pub fn value(&self) -> &Option<String> { + self.value.option() + } + + pub fn label(&self) -> &Option<String> { + self.label.option() } pub fn size(&self) -> Option<u16> { @@ -272,32 +274,32 @@ impl Input { self.maxlength } - pub fn placeholder(&self) -> &str { - self.placeholder.value() + pub fn placeholder(&self) -> &Option<String> { + self.placeholder.option() } - pub fn has_autofocus(&self) -> bool { - self.autofocus.has_value() + pub fn autofocus(&self) -> &Option<String> { + self.autofocus.option() } - pub fn has_autocomplete(&self) -> bool { - !self.autocomplete.has_value() + pub fn autocomplete(&self) -> &Option<String> { + self.autocomplete.option() } - pub fn is_disabled(&self) -> bool { - self.disabled.has_value() + pub fn disabled(&self) -> &Option<String> { + self.disabled.option() } - pub fn is_readonly(&self) -> bool { - self.readonly.has_value() + pub fn readonly(&self) -> &Option<String> { + self.readonly.option() } - pub fn is_required(&self) -> bool { - self.required.has_value() + pub fn required(&self) -> &Option<String> { + self.required.option() } - pub fn help_text(&self) -> &str { - self.help_text.value() + pub fn help_text(&self) -> &Option<String> { + self.help_text.option() } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/form/mod.rs b/pagetop/src/base/component/form/mod.rs index 4e10d476..23b965e9 100644 --- a/pagetop/src/base/component/form/mod.rs +++ b/pagetop/src/base/component/form/mod.rs @@ -2,10 +2,10 @@ mod form; pub use form::{Form, FormMethod}; mod input; -pub use input::Input; +pub use input::{Input, InputType}; mod hidden; pub use hidden::Hidden; mod date; pub use date::Date; mod button; -pub use button::Button; +pub use button::{Button, ButtonType}; diff --git a/pagetop/src/base/component/grid/column.rs b/pagetop/src/base/component/grid/column.rs index 19eb577b..6d3a7b19 100644 --- a/pagetop/src/base/component/grid/column.rs +++ b/pagetop/src/base/component/grid/column.rs @@ -32,8 +32,8 @@ impl PageComponent for Column { fn default_render(&self, assets: &mut PageAssets) -> Markup { html! { - div id=[&self.id.option()] class=[&self.classes.option()] { - (self.components.render(assets)) + div id=[self.id()] class=[self.classes()] { + (self.render_components(assets)) } } } @@ -75,13 +75,23 @@ impl Column { // Column GETTERS. - pub fn id(&self) -> &str { - self.id.value() + pub fn id(&self) -> &Option<String> { + self.id.option() + } + + pub fn classes(&self) -> &Option<String> { + self.classes.option() } pub fn template(&self) -> &str { self.template.as_str() } + + // Column EXTRAS. + + pub fn render_components(&self, assets: &mut PageAssets) -> Markup { + html! { (self.components.render(assets)) } + } } fn always() -> bool { diff --git a/pagetop/src/base/component/grid/row.rs b/pagetop/src/base/component/grid/row.rs index 53719e3f..b1bb2c24 100644 --- a/pagetop/src/base/component/grid/row.rs +++ b/pagetop/src/base/component/grid/row.rs @@ -32,8 +32,8 @@ impl PageComponent for Row { fn default_render(&self, assets: &mut PageAssets) -> Markup { html! { - div id=[&self.id.option()] class=[&self.classes.option()] { - (self.columns.render(assets)) + div id=[self.id()] class=[self.classes()] { + (self.render_columns(assets)) } } } @@ -75,13 +75,23 @@ impl Row { // Row GETTERS. - pub fn id(&self) -> &str { - self.id.value() + pub fn id(&self) -> &Option<String> { + self.id.option() + } + + pub fn classes(&self) -> &Option<String> { + self.classes.option() } pub fn template(&self) -> &str { self.template.as_str() } + + // Row EXTRAS. + + pub fn render_columns(&self, assets: &mut PageAssets) -> Markup { + html! { (self.columns.render(assets)) } + } } fn always() -> bool { diff --git a/pagetop/src/base/component/image.rs b/pagetop/src/base/component/image.rs index b330b374..799aab63 100644 --- a/pagetop/src/base/component/image.rs +++ b/pagetop/src/base/component/image.rs @@ -3,7 +3,7 @@ use crate::prelude::*; pub struct Image { renderable: fn() -> bool, weight : i8, - source : Option<String>, + source : OptAttr, template : String, } @@ -13,7 +13,7 @@ impl PageComponent for Image { Image { renderable: always, weight : 0, - source : None, + source : OptAttr::none(), template : "default".to_owned(), } } @@ -28,7 +28,7 @@ impl PageComponent for Image { fn default_render(&self, _: &mut PageAssets) -> Markup { html! { - img src=[&self.source] class="img-fluid" {} + img src=[self.source()] class="img-fluid"; } } } @@ -36,9 +36,7 @@ impl PageComponent for Image { impl Image { pub fn image(source: &str) -> Self { - let mut i = Image::new(); - i.source = Some(source.to_owned()); - i + Image::new().with_source(source) } // Image BUILDER. @@ -53,6 +51,11 @@ impl Image { self } + pub fn with_source(mut self, source: &str) -> Self { + self.source.with_value(source); + self + } + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self @@ -60,6 +63,10 @@ impl Image { // Image GETTERS. + pub fn source(&self) -> &Option<String> { + self.source.option() + } + pub fn template(&self) -> &str { self.template.as_str() } diff --git a/pagetop/src/base/component/menu.rs b/pagetop/src/base/component/menu.rs index 0f529874..253cd3d8 100644 --- a/pagetop/src/base/component/menu.rs +++ b/pagetop/src/base/component/menu.rs @@ -1,12 +1,13 @@ use crate::prelude::*; -enum MenuItemType { +pub enum MenuItemType { Label(String), Link(String, String), LinkBlank(String, String), Html(Markup), Separator, Submenu(String, Menu), + Void, } // ----------------------------------------------------------------------------- @@ -16,7 +17,7 @@ enum MenuItemType { pub struct MenuItem { renderable: fn() -> bool, weight : i8, - item_type : Option<MenuItemType>, + item_type : MenuItemType, } impl PageComponent for MenuItem { @@ -25,7 +26,7 @@ impl PageComponent for MenuItem { MenuItem { renderable: always, weight : 0, - item_type : None, + item_type : MenuItemType::Void, } } @@ -38,22 +39,22 @@ impl PageComponent for MenuItem { } fn default_render(&self, assets: &mut PageAssets) -> Markup { - match &self.item_type { - Some(MenuItemType::Label(label)) => html! { + match self.item_type() { + MenuItemType::Label(label) => html! { li class="label" { a href="#" { (label) } } }, - Some(MenuItemType::Link(label, path)) => html! { + MenuItemType::Link(label, path) => html! { li class="link" { a href=(path) { (label) } } }, - Some(MenuItemType::LinkBlank(label, path)) => html! { + MenuItemType::LinkBlank(label, path) => html! { li class="link_blank" { a href=(path) target="_blank" { (label) } } }, - Some(MenuItemType::Html(html)) => html! { + MenuItemType::Html(html) => html! { li class="html" { (*html) } }, - Some(MenuItemType::Submenu(label, menu)) => html! { + MenuItemType::Submenu(label, menu) => html! { li class="submenu" { a href="#" { (label) } ul { @@ -61,10 +62,10 @@ impl PageComponent for MenuItem { } } }, - Some(MenuItemType::Separator) => html! { + MenuItemType::Separator => html! { li class="separator" { } }, - None => html! {} + MenuItemType::Void => html! {}, } } } @@ -75,7 +76,7 @@ impl MenuItem { MenuItem { renderable: always, weight : 0, - item_type : Some(MenuItemType::Label(label.to_owned())), + item_type : MenuItemType::Label(label.to_owned()), } } @@ -83,10 +84,10 @@ impl MenuItem { MenuItem { renderable: always, weight : 0, - item_type : Some(MenuItemType::Link( + item_type : MenuItemType::Link( label.to_owned(), path.to_owned(), - )), + ), } } @@ -94,10 +95,10 @@ impl MenuItem { MenuItem { renderable: always, weight : 0, - item_type : Some(MenuItemType::LinkBlank( + item_type : MenuItemType::LinkBlank( label.to_owned(), path.to_owned(), - )), + ), } } @@ -105,7 +106,7 @@ impl MenuItem { MenuItem { renderable: always, weight : 0, - item_type : Some(MenuItemType::Html(html)), + item_type : MenuItemType::Html(html), } } @@ -113,7 +114,7 @@ impl MenuItem { MenuItem { renderable: always, weight : 0, - item_type : Some(MenuItemType::Separator), + item_type : MenuItemType::Separator, } } @@ -121,10 +122,10 @@ impl MenuItem { MenuItem { renderable: always, weight : 0, - item_type : Some(MenuItemType::Submenu( + item_type : MenuItemType::Submenu( label.to_owned(), menu - )), + ), } } @@ -139,6 +140,12 @@ impl MenuItem { self.weight = weight; self } + + // MenuItem GETTERS. + + pub fn item_type(&self) -> &MenuItemType { + &self.item_type + } } // ----------------------------------------------------------------------------- @@ -186,7 +193,7 @@ impl PageComponent for Menu { )) .add_jquery(); - let id = assets.serial_id(self.name(), self.id.value()); + let id = assets.serial_id(self.name(), self.id()); html! { ul id=(id) class="sm sm-clean" { (self.render_items(assets)) @@ -232,8 +239,8 @@ impl Menu { // Menu GETTERS. - pub fn id(&self) -> &str { - self.id.value() + pub fn id(&self) -> &Option<String> { + self.id.option() } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/mod.rs b/pagetop/src/base/component/mod.rs index 4619c937..b4e646b9 100644 --- a/pagetop/src/base/component/mod.rs +++ b/pagetop/src/base/component/mod.rs @@ -1,5 +1,5 @@ mod container; -pub use container::Container; +pub use container::{Container, ContainerType}; pub mod grid; @@ -10,7 +10,7 @@ pub use block::Block; mod image; pub use image::Image; mod menu; -pub use menu::{Menu, MenuItem}; +pub use menu::{Menu, MenuItem, MenuItemType}; pub mod form; pub use form::{Form, FormMethod}; diff --git a/pagetop/src/base/module/demopage/mod.rs b/pagetop/src/base/module/demopage/mod.rs index c9fc9cc0..489b6d3b 100644 --- a/pagetop/src/base/module/demopage/mod.rs +++ b/pagetop/src/base/module/demopage/mod.rs @@ -140,7 +140,7 @@ fn just_visiting() -> Chunck { span { (l("visiting_title")) } - br {} + br; (l("visiting_subtitle")) } p { (l("visiting_text1")) } diff --git a/pagetop/src/html/optattr.rs b/pagetop/src/html/optattr.rs index 3eed9aab..a76f33b7 100644 --- a/pagetop/src/html/optattr.rs +++ b/pagetop/src/html/optattr.rs @@ -19,17 +19,6 @@ impl OptAttr { }; } - pub fn value(&self) -> &str { - match &self.0 { - Some(value) => value.as_str(), - None => "", - } - } - - pub fn has_value(&self) -> bool { - self.0 != None - } - pub fn option(&self) -> &Option<String> { &self.0 } diff --git a/pagetop/src/html/optiden.rs b/pagetop/src/html/optiden.rs index 93caf18a..ec46acf1 100644 --- a/pagetop/src/html/optiden.rs +++ b/pagetop/src/html/optiden.rs @@ -19,17 +19,6 @@ impl OptIden { }; } - pub fn value(&self) -> &str { - match &self.0 { - Some(id) => id.as_str(), - None => "", - } - } - - pub fn has_value(&self) -> bool { - self.0 != None - } - pub fn option(&self) -> &Option<String> { &self.0 } diff --git a/pagetop/src/lib.rs b/pagetop/src/lib.rs index 731271d3..42ad192a 100644 --- a/pagetop/src/lib.rs +++ b/pagetop/src/lib.rs @@ -1,8 +1,11 @@ +// Exports. + +pub use concat_string::concat_string; +pub use doc_comment::doc_comment; +pub use once_cell::sync::Lazy; + // Local. -pub(crate) use concat_string::concat_string; -pub(crate) use doc_comment::doc_comment; -pub(crate) use once_cell::sync::Lazy; pub(crate) use futures::executor::block_on as run_now; // ----------------------------------------------------------------------------- diff --git a/pagetop/src/prelude.rs b/pagetop/src/prelude.rs index 7c2e9ef3..429c9449 100644 --- a/pagetop/src/prelude.rs +++ b/pagetop/src/prelude.rs @@ -3,6 +3,7 @@ // Macros. pub use crate::{ args, + concat_string, theme_static_files, }; diff --git a/pagetop/src/response/page/assets.rs b/pagetop/src/response/page/assets.rs index ffc566ea..3d42a06f 100644 --- a/pagetop/src/response/page/assets.rs +++ b/pagetop/src/response/page/assets.rs @@ -1,4 +1,4 @@ -use crate::{Lazy, base}; +use crate::{Lazy, base, concat_string}; use crate::config::SETTINGS; use crate::html::{Markup, PreEscaped, html}; use crate::theme::*; @@ -289,18 +289,19 @@ impl PageAssets { // Assets EXTRAS. - pub fn serial_id(&mut self, prefix: &str, id: &str) -> String { - if id.is_empty() { - let prefix = prefix.trim().replace(" ", "_").to_lowercase(); - let prefix = if prefix.is_empty() { - "prefix".to_owned() - } else { - prefix - }; - self.id_counter += 1; - [prefix, self.id_counter.to_string()].join("-") - } else { - id.to_owned() + pub fn serial_id(&mut self, prefix: &str, id: &Option<String>) -> String { + match id { + Some(id) => id.to_string(), + None => { + let prefix = prefix.trim().replace(" ", "_").to_lowercase(); + let prefix = if prefix.is_empty() { + "prefix".to_owned() + } else { + prefix + }; + self.id_counter += 1; + concat_string!(prefix, "-", self.id_counter.to_string()) + } } } } diff --git a/pagetop/src/response/page/page.rs b/pagetop/src/response/page/page.rs index fedf05e4..50ff3040 100644 --- a/pagetop/src/response/page/page.rs +++ b/pagetop/src/response/page/page.rs @@ -122,20 +122,20 @@ impl<'a> Page<'a> { // Page GETTERS. - pub fn language(&self) -> &str { - self.language.value() + pub fn language(&self) -> &Option<String> { + self.language.option() } - pub fn direction(&self) -> &str { - self.direction.value() + pub fn direction(&self) -> &Option<String> { + self.direction.option() } - pub fn title(&self) -> &str { - self.title.value() + pub fn title(&self) -> &Option<String> { + self.title.option() } - pub fn description(&self) -> &str { - self.description.value() + pub fn description(&self) -> &Option<String> { + self.description.option() } pub fn body_classes(&mut self) -> &str { @@ -165,7 +165,7 @@ impl<'a> Page<'a> { // Finalmente, renderizar la página. return Ok(html! { (DOCTYPE) - html lang=[&self.language.option()] dir=[&self.direction.option()] { + html lang=[self.language()] dir=[self.direction()] { (head) (body) } diff --git a/pagetop/src/theme/definition.rs b/pagetop/src/theme/definition.rs index 15f6566e..51b1d4c8 100644 --- a/pagetop/src/theme/definition.rs +++ b/pagetop/src/theme/definition.rs @@ -1,4 +1,4 @@ -use crate::app; +use crate::{app, concat_string}; use crate::config::SETTINGS; use crate::html::{Markup, html}; use crate::response::page::{Favicon, Page, PageAssets, PageComponent}; @@ -28,22 +28,21 @@ pub trait ThemeTrait: Send + Sync { } fn render_page_head(&self, page: &mut Page) -> Markup { - let title = page.title(); - let title = if title.is_empty() { - SETTINGS.app.name.to_owned() - } else { - [SETTINGS.app.name.to_string(), title.to_string()].join(" | ") - }; - let description = page.description(); let viewport = "width=device-width, initial-scale=1, shrink-to-fit=no"; html! { head { meta charset="utf-8"; - title { (title) } + @match page.title() { + Some(t) => title { + (concat_string!(SETTINGS.app.name, " | ", t)) + }, + None => title { (SETTINGS.app.name) } + } - @if !description.is_empty() { - meta name="description" content=(description); + @match page.description() { + Some(d) => meta name="description" content=(d);, + None => {} } meta http-equiv="X-UA-Compatible" content="IE=edge"; From 363cec7a75d0479bf89df8c71a1060b703178084 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 30 Mar 2022 23:48:11 +0200 Subject: [PATCH 042/244] =?UTF-8?q?Libera=20la=20versi=C3=B3n=20de=20desar?= =?UTF-8?q?rollo=200.0.6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pagetop/Cargo.toml | 2 +- pagetop/src/base/component/block.rs | 40 ++++++++++++++------ pagetop/src/base/component/container.rs | 34 ++++++++++++----- pagetop/src/base/component/form/button.rs | 18 ++++++++- pagetop/src/base/component/form/date.rs | 20 +++++++++- pagetop/src/base/component/form/form.rs | 39 ++++++++++++++------ pagetop/src/base/component/form/input.rs | 16 ++++++++ pagetop/src/base/component/grid/column.rs | 29 ++++++++++----- pagetop/src/base/component/grid/row.rs | 29 ++++++++++----- pagetop/src/base/component/image.rs | 32 +++++++++++++++- pagetop/src/base/component/menu.rs | 26 ++++++++++--- pagetop/src/base/theme/bulmix/mod.rs | 26 +++++++++++++ pagetop/src/html/classes.rs | 45 +++++------------------ pagetop/src/html/optattr.rs | 5 ++- pagetop/src/html/optiden.rs | 5 ++- pagetop/src/response/page/page.rs | 27 ++++++++------ pagetop/src/theme/definition.rs | 6 +-- 17 files changed, 284 insertions(+), 115 deletions(-) diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index 01eb60ec..8598de96 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.5" +version = "0.0.6" edition = "2021" authors = [ diff --git a/pagetop/src/base/component/block.rs b/pagetop/src/base/component/block.rs index 976c27bc..fdf9922d 100644 --- a/pagetop/src/base/component/block.rs +++ b/pagetop/src/base/component/block.rs @@ -3,9 +3,10 @@ use crate::prelude::*; pub struct Block { renderable: fn() -> bool, weight : i8, - id : OptIden, title : OptAttr, html : Vec<Markup>, + id : OptIden, + classes : Classes, template : String, } @@ -15,9 +16,10 @@ impl PageComponent for Block { Block { renderable: always, weight : 0, - id : OptIden::none(), title : OptAttr::none(), html : Vec::new(), + id : OptIden::none(), + classes : Classes::none(), template : "default".to_owned(), } } @@ -33,7 +35,7 @@ impl PageComponent for Block { fn default_render(&self, assets: &mut PageAssets) -> Markup { let id = assets.serial_id(self.name(), self.id()); html! { - div id=(id) class="block" { + div id=(id) class=[self.classes("block")] { @match self.title() { Some(title) => h2 class="block-title" { (title) }, None => {} @@ -66,11 +68,6 @@ impl Block { self } - pub fn with_id(mut self, id: &str) -> Self { - self.id.with_value(id); - self - } - pub fn with_title(mut self, title: &str) -> Self { self.title.with_value(title); self @@ -81,6 +78,21 @@ impl Block { self } + pub fn with_id(mut self, id: &str) -> Self { + self.id.with_value(id); + self + } + + pub fn set_classes(mut self, classes: &str) -> Self { + self.classes.set_classes(classes); + self + } + + pub fn add_classes(mut self, classes: &str) -> Self { + self.classes.add_classes(classes); + self + } + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self @@ -88,10 +100,6 @@ impl Block { // Block GETTERS. - pub fn id(&self) -> &Option<String> { - self.id.option() - } - pub fn title(&self) -> &Option<String> { self.title.option() } @@ -100,6 +108,14 @@ impl Block { &self.html } + pub fn id(&self) -> &Option<String> { + self.id.option() + } + + pub fn classes(&self, default: &str) -> Option<String> { + self.classes.option(default) + } + pub fn template(&self) -> &str { self.template.as_str() } diff --git a/pagetop/src/base/component/container.rs b/pagetop/src/base/component/container.rs index cba905d6..94003ae0 100644 --- a/pagetop/src/base/component/container.rs +++ b/pagetop/src/base/component/container.rs @@ -6,8 +6,9 @@ pub struct Container { renderable: fn() -> bool, weight : i8, container : ContainerType, - id : OptIden, components: PageContainer, + id : OptIden, + classes : Classes, template : String, } @@ -18,8 +19,9 @@ impl PageComponent for Container { renderable: always, weight : 0, container : ContainerType::Wrapper, - id : OptIden::none(), components: PageContainer::new(), + id : OptIden::none(), + classes : Classes::none(), template : "default".to_owned(), } } @@ -35,35 +37,35 @@ impl PageComponent for Container { fn default_render(&self, assets: &mut PageAssets) -> Markup { match self.container_type() { ContainerType::Header => html! { - header id=[self.id()] class="header" { + header id=[self.id()] class=[self.classes("header")] { div class="container" { (self.render_components(assets)) } } }, ContainerType::Footer => html! { - footer id=[self.id()] class="footer" { + footer id=[self.id()] class=[self.classes("footer")] { div class="container" { (self.render_components(assets)) } } }, ContainerType::Main => html! { - main id=[self.id()] class="main" { + main id=[self.id()] class=[self.classes("main")] { div class="container" { (self.render_components(assets)) } } }, ContainerType::Section => html! { - section id=[self.id()] class="section" { + section id=[self.id()] class=[self.classes("section")] { div class="container" { (self.render_components(assets)) } } }, _ => html! { - div id=[self.id()] class="container" { + div id=[self.id()] class=[self.classes("container")] { (self.render_components(assets)) } } @@ -109,13 +111,23 @@ impl Container { self } + pub fn add(mut self, component: impl PageComponent) -> Self { + self.components.add(component); + self + } + pub fn with_id(mut self, id: &str) -> Self { self.id.with_value(id); self } - pub fn add(mut self, component: impl PageComponent) -> Self { - self.components.add(component); + pub fn set_classes(mut self, classes: &str) -> Self { + self.classes.set_classes(classes); + self + } + + pub fn add_classes(mut self, classes: &str) -> Self { + self.classes.add_classes(classes); self } @@ -134,6 +146,10 @@ impl Container { self.id.option() } + pub fn classes(&self, default: &str) -> Option<String> { + self.classes.option(default) + } + pub fn template(&self) -> &str { self.template.as_str() } diff --git a/pagetop/src/base/component/form/button.rs b/pagetop/src/base/component/form/button.rs index fbe25738..b2f59609 100644 --- a/pagetop/src/base/component/form/button.rs +++ b/pagetop/src/base/component/form/button.rs @@ -10,6 +10,7 @@ pub struct Button { value : OptAttr, autofocus : OptAttr, disabled : OptAttr, + classes : Classes, template : String, } @@ -24,6 +25,7 @@ impl PageComponent for Button { value : OptAttr::none(), autofocus : OptAttr::none(), disabled : OptAttr::none(), + classes : Classes::none(), template : "default".to_owned(), } } @@ -50,7 +52,7 @@ impl PageComponent for Button { button type=(button_type) id=[id] - class=(button_class) + class=[self.classes(button_class)] name=[self.name()] value=[self.value()] autofocus=[self.autofocus()] @@ -121,6 +123,16 @@ impl Button { self } + pub fn set_classes(mut self, classes: &str) -> Self { + self.classes.set_classes(classes); + self + } + + pub fn add_classes(mut self, classes: &str) -> Self { + self.classes.add_classes(classes); + self + } + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self @@ -148,6 +160,10 @@ impl Button { self.disabled.option() } + pub fn classes(&self, default: &str) -> Option<String> { + self.classes.option(default) + } + pub fn template(&self) -> &str { self.template.as_str() } diff --git a/pagetop/src/base/component/form/date.rs b/pagetop/src/base/component/form/date.rs index 906f5bbc..f1270a82 100644 --- a/pagetop/src/base/component/form/date.rs +++ b/pagetop/src/base/component/form/date.rs @@ -13,6 +13,7 @@ pub struct Date { readonly : OptAttr, required : OptAttr, help_text : OptAttr, + classes : Classes, template : String, } @@ -32,6 +33,7 @@ impl PageComponent for Date { readonly : OptAttr::none(), required : OptAttr::none(), help_text : OptAttr::none(), + classes : Classes::none(), template : "default".to_owned(), } } @@ -45,7 +47,7 @@ impl PageComponent for Date { } fn default_render(&self, _: &mut PageAssets) -> Markup { - let (class, id) = match self.name() { + let (classes, id) = match self.name() { Some(name) => ( concat_string!("form-item form-item-", name, " form-type-date"), Some(concat_string!("edit-", name)) @@ -56,7 +58,7 @@ impl PageComponent for Date { ) }; html! { - div class=(class) { + div class=[self.classes(classes.as_str())] { @match self.label() { Some(label) => label class="form-label" for=[&id] { (label) " " @@ -169,6 +171,16 @@ impl Date { self } + pub fn set_classes(mut self, classes: &str) -> Self { + self.classes.set_classes(classes); + self + } + + pub fn add_classes(mut self, classes: &str) -> Self { + self.classes.add_classes(classes); + self + } + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self @@ -216,6 +228,10 @@ impl Date { self.help_text.option() } + pub fn classes(&self, default: &str) -> Option<String> { + self.classes.option(default) + } + pub fn template(&self) -> &str { self.template.as_str() } diff --git a/pagetop/src/base/component/form/form.rs b/pagetop/src/base/component/form/form.rs index 5ecea5e0..c4d8e206 100644 --- a/pagetop/src/base/component/form/form.rs +++ b/pagetop/src/base/component/form/form.rs @@ -5,11 +5,12 @@ pub enum FormMethod {Get, Post} pub struct Form { renderable: fn() -> bool, weight : i8, - id : OptIden, action : OptAttr, charset : OptAttr, method : FormMethod, elements : PageContainer, + id : OptIden, + classes : Classes, template : String, } @@ -19,11 +20,12 @@ impl PageComponent for Form { Form { renderable: always, weight : 0, - id : OptIden::none(), action : OptAttr::none(), charset : OptAttr::some("UTF-8"), method : FormMethod::Post, elements : PageContainer::new(), + id : OptIden::none(), + classes : Classes::none(), template : "default".to_owned(), } } @@ -44,6 +46,7 @@ impl PageComponent for Form { html! { form id=[self.id()] + class=[self.classes("form")] action=[self.action()] method=[method] accept-charset=[self.charset()] @@ -70,11 +73,6 @@ impl Form { self } - pub fn with_id(mut self, id: &str) -> Self { - self.id.with_value(id); - self - } - pub fn with_action(mut self, action: &str) -> Self { self.action.with_value(action); self @@ -95,6 +93,21 @@ impl Form { self } + pub fn with_id(mut self, id: &str) -> Self { + self.id.with_value(id); + self + } + + pub fn set_classes(mut self, classes: &str) -> Self { + self.classes.set_classes(classes); + self + } + + pub fn add_classes(mut self, classes: &str) -> Self { + self.classes.add_classes(classes); + self + } + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self @@ -102,10 +115,6 @@ impl Form { // Form GETTERS. - pub fn id(&self) -> &Option<String> { - self.id.option() - } - pub fn action(&self) -> &Option<String> { self.action.option() } @@ -118,6 +127,14 @@ impl Form { &self.method } + pub fn id(&self) -> &Option<String> { + self.id.option() + } + + pub fn classes(&self, default: &str) -> Option<String> { + self.classes.option(default) + } + pub fn template(&self) -> &str { self.template.as_str() } diff --git a/pagetop/src/base/component/form/input.rs b/pagetop/src/base/component/form/input.rs index 7dded20f..2e1af61d 100644 --- a/pagetop/src/base/component/form/input.rs +++ b/pagetop/src/base/component/form/input.rs @@ -19,6 +19,7 @@ pub struct Input { readonly : OptAttr, required : OptAttr, help_text : OptAttr, + classes : Classes, template : String, } @@ -42,6 +43,7 @@ impl PageComponent for Input { readonly : OptAttr::none(), required : OptAttr::none(), help_text : OptAttr::none(), + classes : Classes::none(), template : "default".to_owned(), } } @@ -239,6 +241,16 @@ impl Input { self } + pub fn set_classes(mut self, classes: &str) -> Self { + self.classes.set_classes(classes); + self + } + + pub fn add_classes(mut self, classes: &str) -> Self { + self.classes.add_classes(classes); + self + } + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self @@ -302,6 +314,10 @@ impl Input { self.help_text.option() } + pub fn classes(&self, default: &str) -> Option<String> { + self.classes.option(default) + } + pub fn template(&self) -> &str { self.template.as_str() } diff --git a/pagetop/src/base/component/grid/column.rs b/pagetop/src/base/component/grid/column.rs index 6d3a7b19..f5bc4669 100644 --- a/pagetop/src/base/component/grid/column.rs +++ b/pagetop/src/base/component/grid/column.rs @@ -3,9 +3,9 @@ use crate::prelude::*; pub struct Column { renderable: fn() -> bool, weight : i8, + components: PageContainer, id : OptIden, classes : Classes, - components: PageContainer, template : String, } @@ -15,13 +15,17 @@ impl PageComponent for Column { Column { renderable: always, weight : 0, - id : OptIden::none(), - classes : Classes::some(vec!["col"]), components: PageContainer::new(), + id : OptIden::none(), + classes : Classes::none(), template : "default".to_owned(), } } + fn name(&self) -> &'static str { + "GridColumn" + } + fn is_renderable(&self) -> bool { (self.renderable)() } @@ -32,7 +36,7 @@ impl PageComponent for Column { fn default_render(&self, assets: &mut PageAssets) -> Markup { html! { - div id=[self.id()] class=[self.classes()] { + div id=[self.id()] class=[self.classes("col")] { (self.render_components(assets)) } } @@ -53,18 +57,23 @@ impl Column { self } + pub fn add(mut self, component: impl PageComponent) -> Self { + self.components.add(component); + self + } + pub fn with_id(mut self, id: &str) -> Self { self.id.with_value(id); self } - pub fn add_classes(mut self, classes: Vec<&str>) -> Self { - self.classes.add_classes(classes); + pub fn set_classes(mut self, classes: &str) -> Self { + self.classes.set_classes(classes); self } - pub fn add(mut self, component: impl PageComponent) -> Self { - self.components.add(component); + pub fn add_classes(mut self, classes: &str) -> Self { + self.classes.add_classes(classes); self } @@ -79,8 +88,8 @@ impl Column { self.id.option() } - pub fn classes(&self) -> &Option<String> { - self.classes.option() + pub fn classes(&self, default: &str) -> Option<String> { + self.classes.option(default) } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/grid/row.rs b/pagetop/src/base/component/grid/row.rs index b1bb2c24..8437c1fe 100644 --- a/pagetop/src/base/component/grid/row.rs +++ b/pagetop/src/base/component/grid/row.rs @@ -3,9 +3,9 @@ use crate::prelude::*; pub struct Row { renderable: fn() -> bool, weight : i8, + columns : PageContainer, id : OptIden, classes : Classes, - columns : PageContainer, template : String, } @@ -15,13 +15,17 @@ impl PageComponent for Row { Row { renderable: always, weight : 0, - id : OptIden::none(), - classes : Classes::some(vec!["row"]), columns : PageContainer::new(), + id : OptIden::none(), + classes : Classes::none(), template : "default".to_owned(), } } + fn name(&self) -> &'static str { + "GridRow" + } + fn is_renderable(&self) -> bool { (self.renderable)() } @@ -32,7 +36,7 @@ impl PageComponent for Row { fn default_render(&self, assets: &mut PageAssets) -> Markup { html! { - div id=[self.id()] class=[self.classes()] { + div id=[self.id()] class=[self.classes("row")] { (self.render_columns(assets)) } } @@ -53,18 +57,23 @@ impl Row { self } + pub fn add_column(mut self, column: grid::Column) -> Self { + self.columns.add(column); + self + } + pub fn with_id(mut self, id: &str) -> Self { self.id.with_value(id); self } - pub fn add_classes(mut self, classes: Vec<&str>) -> Self { - self.classes.add_classes(classes); + pub fn set_classes(mut self, classes: &str) -> Self { + self.classes.set_classes(classes); self } - pub fn add_column(mut self, column: grid::Column) -> Self { - self.columns.add(column); + pub fn add_classes(mut self, classes: &str) -> Self { + self.classes.add_classes(classes); self } @@ -79,8 +88,8 @@ impl Row { self.id.option() } - pub fn classes(&self) -> &Option<String> { - self.classes.option() + pub fn classes(&self, default: &str) -> Option<String> { + self.classes.option(default) } pub fn template(&self) -> &str { diff --git a/pagetop/src/base/component/image.rs b/pagetop/src/base/component/image.rs index 799aab63..c324782a 100644 --- a/pagetop/src/base/component/image.rs +++ b/pagetop/src/base/component/image.rs @@ -4,6 +4,8 @@ pub struct Image { renderable: fn() -> bool, weight : i8, source : OptAttr, + id : OptIden, + classes : Classes, template : String, } @@ -14,6 +16,8 @@ impl PageComponent for Image { renderable: always, weight : 0, source : OptAttr::none(), + id : OptIden::none(), + classes : Classes::none(), template : "default".to_owned(), } } @@ -28,7 +32,10 @@ impl PageComponent for Image { fn default_render(&self, _: &mut PageAssets) -> Markup { html! { - img src=[self.source()] class="img-fluid"; + img + src=[self.source()] + id=[self.id()] + class=[self.classes("img-fluid")]; } } } @@ -56,6 +63,21 @@ impl Image { self } + pub fn with_id(mut self, id: &str) -> Self { + self.id.with_value(id); + self + } + + pub fn set_classes(mut self, classes: &str) -> Self { + self.classes.set_classes(classes); + self + } + + pub fn add_classes(mut self, classes: &str) -> Self { + self.classes.add_classes(classes); + self + } + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self @@ -67,6 +89,14 @@ impl Image { self.source.option() } + pub fn id(&self) -> &Option<String> { + self.id.option() + } + + pub fn classes(&self, default: &str) -> Option<String> { + self.classes.option(default) + } + pub fn template(&self) -> &str { self.template.as_str() } diff --git a/pagetop/src/base/component/menu.rs b/pagetop/src/base/component/menu.rs index 253cd3d8..91881908 100644 --- a/pagetop/src/base/component/menu.rs +++ b/pagetop/src/base/component/menu.rs @@ -155,8 +155,9 @@ impl MenuItem { pub struct Menu { renderable: fn() -> bool, weight : i8, - id : OptIden, items : PageContainer, + id : OptIden, + classes : Classes, template : String, } @@ -166,8 +167,9 @@ impl PageComponent for Menu { Menu { renderable: always, weight : 0, - id : OptIden::none(), items : PageContainer::new(), + id : OptIden::none(), + classes : Classes::none(), template : "default".to_owned(), } } @@ -195,7 +197,7 @@ impl PageComponent for Menu { let id = assets.serial_id(self.name(), self.id()); html! { - ul id=(id) class="sm sm-clean" { + ul id=(id) class=[self.classes("sm sm-clean")] { (self.render_items(assets)) } script type="text/javascript" defer { @@ -222,13 +224,23 @@ impl Menu { self } + pub fn add(mut self, item: MenuItem) -> Self { + self.items.add(item); + self + } + pub fn with_id(mut self, id: &str) -> Self { self.id.with_value(id); self } - pub fn add(mut self, item: MenuItem) -> Self { - self.items.add(item); + pub fn set_classes(mut self, classes: &str) -> Self { + self.classes.set_classes(classes); + self + } + + pub fn add_classes(mut self, classes: &str) -> Self { + self.classes.add_classes(classes); self } @@ -243,6 +255,10 @@ impl Menu { self.id.option() } + pub fn classes(&self, default: &str) -> Option<String> { + self.classes.option(default) + } + pub fn template(&self) -> &str { self.template.as_str() } diff --git a/pagetop/src/base/theme/bulmix/mod.rs b/pagetop/src/base/theme/bulmix/mod.rs index b8d57ba7..0e8a4d9b 100644 --- a/pagetop/src/base/theme/bulmix/mod.rs +++ b/pagetop/src/base/theme/bulmix/mod.rs @@ -31,4 +31,30 @@ impl ThemeTrait for BulmixTheme { ) .add_jquery(); } + + fn render_component( + &self, + component: &dyn PageComponent, + assets: &mut PageAssets + ) -> Option<Markup> { + match component.name() { + "GridRow" => { + let row = component.downcast_ref::<grid::Row>().unwrap(); + Some(html! { + div id=[row.id()] class=[row.classes("columns")] { + (row.render_columns(assets)) + } + }) + }, + "GridColumn" => { + let col = component.downcast_ref::<grid::Column>().unwrap(); + Some(html! { + div id=[col.id()] class=[col.classes("column")] { + (col.render_components(assets)) + } + }) + }, + _ => None + } + } } diff --git a/pagetop/src/html/classes.rs b/pagetop/src/html/classes.rs index c2a35984..6c41aafb 100644 --- a/pagetop/src/html/classes.rs +++ b/pagetop/src/html/classes.rs @@ -1,48 +1,23 @@ use crate::concat_string; -pub struct Classes(Option<String>); +pub struct Classes(String); impl Classes { pub fn none() -> Self { - Classes(None) + Classes("".to_owned()) } - pub fn some(classes: Vec<&str>) -> Self { - let mut c = Classes::none(); - c.add_classes(classes); - c + pub fn set_classes(&mut self, classes: &str) -> &mut Self { + self.0 = classes.to_owned(); + self } - pub fn add_classes(&mut self, classes: Vec<&str>) { - for class in classes.iter() { - self.add_class(class); - } + pub fn add_classes(&mut self, classes: &str) -> &mut Self { + self.0 = concat_string!(self.0, " ", classes).trim().to_owned(); + self } - fn add_class(&mut self, class: &str) { - let class = class.trim().replace(" ", "_"); - if !class.is_empty() { - match &self.0 { - None => self.0 = Some(class), - Some(classes) => if !classes.split(" ").any(|c| *c == class) { - self.0 = Some(concat_string!(classes, " ", class)) - } - } - } - } - - pub fn classes(&self) -> &str { - match &self.0 { - Some(classes) => classes.as_str(), - None => "", - } - } - - pub fn has_classes(&self) -> bool { - self.0 != None - } - - pub fn option(&self) -> &Option<String> { - &self.0 + pub fn option(&self, default: &str) -> Option<String> { + Some(concat_string!(default.to_owned(), " ", self.0).trim().to_owned()) } } diff --git a/pagetop/src/html/optattr.rs b/pagetop/src/html/optattr.rs index a76f33b7..d009e32e 100644 --- a/pagetop/src/html/optattr.rs +++ b/pagetop/src/html/optattr.rs @@ -6,17 +6,18 @@ impl OptAttr { } pub fn some(value: &str) -> Self { - let mut o = OptAttr::none(); + let mut o = OptAttr(None); o.with_value(value); o } - pub fn with_value(&mut self, value: &str) { + pub fn with_value(&mut self, value: &str) -> &mut Self { let value = value.trim(); self.0 = match value.is_empty() { true => None, false => Some(value.to_owned()), }; + self } pub fn option(&self) -> &Option<String> { diff --git a/pagetop/src/html/optiden.rs b/pagetop/src/html/optiden.rs index ec46acf1..52a65c10 100644 --- a/pagetop/src/html/optiden.rs +++ b/pagetop/src/html/optiden.rs @@ -6,17 +6,18 @@ impl OptIden { } pub fn some(id: &str) -> Self { - let mut o = OptIden::none(); + let mut o = OptIden(None); o.with_value(id); o } - pub fn with_value(&mut self, id: &str) { + pub fn with_value(&mut self, id: &str) -> &mut Self { let id = id.trim(); self.0 = match id.is_empty() { true => None, false => Some(id.replace(" ", "_")), }; + self } pub fn option(&self) -> &Option<String> { diff --git a/pagetop/src/response/page/page.rs b/pagetop/src/response/page/page.rs index 50ff3040..cb561626 100644 --- a/pagetop/src/response/page/page.rs +++ b/pagetop/src/response/page/page.rs @@ -45,8 +45,8 @@ pub struct Page<'a> { title : OptAttr, description : OptAttr, assets : PageAssets, - body_classes: Classes, regions : HashMap<&'a str, PageContainer>, + body_classes: Classes, template : String, } @@ -64,9 +64,9 @@ impl<'a> Page<'a> { }, title : OptAttr::none(), description : OptAttr::none(), - body_classes: Classes::some(vec!["body"]), assets : PageAssets::new(), regions : COMPONENTS.read().unwrap().clone(), + body_classes: Classes::none(), template : "default".to_owned(), } } @@ -97,11 +97,6 @@ impl<'a> Page<'a> { self } - pub fn add_body_classes(&mut self, classes: Vec<&str>) -> &mut Self { - self.body_classes.add_classes(classes); - self - } - pub fn add_to( &mut self, region: &'a str, @@ -115,6 +110,16 @@ impl<'a> Page<'a> { self } + pub fn set_body_classes(&mut self, classes: &str) -> &mut Self { + self.body_classes.set_classes(classes); + self + } + + pub fn add_body_classes(&mut self, classes: &str) -> &mut Self { + self.body_classes.add_classes(classes); + self + } + pub fn using_template(&mut self, template: &str) -> &mut Self { self.template = template.to_owned(); self @@ -138,14 +143,14 @@ impl<'a> Page<'a> { self.description.option() } - pub fn body_classes(&mut self) -> &str { - self.body_classes.classes() - } - pub fn assets(&mut self) -> &mut PageAssets { &mut self.assets } + pub fn body_classes(&self, default: &str) -> Option<String> { + self.body_classes.option(default) + } + pub fn template(&self) -> &str { self.template.as_str() } diff --git a/pagetop/src/theme/definition.rs b/pagetop/src/theme/definition.rs index 51b1d4c8..acc30f47 100644 --- a/pagetop/src/theme/definition.rs +++ b/pagetop/src/theme/definition.rs @@ -55,7 +55,7 @@ pub trait ThemeTrait: Send + Sync { fn render_page_body(&self, page: &mut Page) -> Markup { html! { - body class=(page.body_classes()) { + body class=[page.body_classes("body")] { @match page.template() { "admin" => { @for region in &["top-menu", "side-menu", "content"] { @@ -85,8 +85,8 @@ pub trait ThemeTrait: Send + Sync { Cómo usarlo: match component.name() { - "block" => { - let block = component.downcast_mut::<Block>().unwrap(); + "Block" => { + let block = component.downcast_ref::<Block>().unwrap(); match block.template() { "default" => Some(block_default(block)), _ => None From 48fa9e9db9b4c3b5f564c828bb33891e30fd7842 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 31 Mar 2022 00:50:53 +0200 Subject: [PATCH 043/244] Modifica el renderizado de contenedores internos --- pagetop/src/base/component/container.rs | 20 +++++++++----------- pagetop/src/base/component/form/form.rs | 14 +++++--------- pagetop/src/base/component/menu.rs | 14 ++++++-------- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/pagetop/src/base/component/container.rs b/pagetop/src/base/component/container.rs index 94003ae0..24172d00 100644 --- a/pagetop/src/base/component/container.rs +++ b/pagetop/src/base/component/container.rs @@ -39,34 +39,34 @@ impl PageComponent for Container { ContainerType::Header => html! { header id=[self.id()] class=[self.classes("header")] { div class="container" { - (self.render_components(assets)) + (self.components().render(assets)) } } }, ContainerType::Footer => html! { footer id=[self.id()] class=[self.classes("footer")] { div class="container" { - (self.render_components(assets)) + (self.components().render(assets)) } } }, ContainerType::Main => html! { main id=[self.id()] class=[self.classes("main")] { div class="container" { - (self.render_components(assets)) + (self.components().render(assets)) } } }, ContainerType::Section => html! { section id=[self.id()] class=[self.classes("section")] { div class="container" { - (self.render_components(assets)) + (self.components().render(assets)) } } }, _ => html! { div id=[self.id()] class=[self.classes("container")] { - (self.render_components(assets)) + (self.components().render(assets)) } } } @@ -142,6 +142,10 @@ impl Container { &self.container } + pub fn components(&self) -> &PageContainer { + &self.components + } + pub fn id(&self) -> &Option<String> { self.id.option() } @@ -153,12 +157,6 @@ impl Container { pub fn template(&self) -> &str { self.template.as_str() } - - // Container EXTRAS. - - pub fn render_components(&self, assets: &mut PageAssets) -> Markup { - html! { (self.components.render(assets)) } - } } fn always() -> bool { diff --git a/pagetop/src/base/component/form/form.rs b/pagetop/src/base/component/form/form.rs index c4d8e206..2d88d141 100644 --- a/pagetop/src/base/component/form/form.rs +++ b/pagetop/src/base/component/form/form.rs @@ -51,9 +51,7 @@ impl PageComponent for Form { method=[method] accept-charset=[self.charset()] { - div { - (self.render_elements(assets)) - } + div { (self.elements().render(assets)) } } } } @@ -127,6 +125,10 @@ impl Form { &self.method } + pub fn elements(&self) -> &PageContainer { + &self.elements + } + pub fn id(&self) -> &Option<String> { self.id.option() } @@ -138,12 +140,6 @@ impl Form { pub fn template(&self) -> &str { self.template.as_str() } - - // Form EXTRAS. - - pub fn render_elements(&self, assets: &mut PageAssets) -> Markup { - html! { (self.elements.render(assets)) } - } } fn always() -> bool { diff --git a/pagetop/src/base/component/menu.rs b/pagetop/src/base/component/menu.rs index 91881908..85b9007e 100644 --- a/pagetop/src/base/component/menu.rs +++ b/pagetop/src/base/component/menu.rs @@ -58,7 +58,7 @@ impl PageComponent for MenuItem { li class="submenu" { a href="#" { (label) } ul { - (menu.render_items(assets)) + (menu.items().render(assets)) } } }, @@ -198,7 +198,7 @@ impl PageComponent for Menu { let id = assets.serial_id(self.name(), self.id()); html! { ul id=(id) class=[self.classes("sm sm-clean")] { - (self.render_items(assets)) + (self.items().render(assets)) } script type="text/javascript" defer { "jQuery(function(){jQuery('#" (id) "').smartmenus({" @@ -251,6 +251,10 @@ impl Menu { // Menu GETTERS. + pub fn items(&self) -> &PageContainer { + &self.items + } + pub fn id(&self) -> &Option<String> { self.id.option() } @@ -262,12 +266,6 @@ impl Menu { pub fn template(&self) -> &str { self.template.as_str() } - - // Menu EXTRAS. - - pub fn render_items(&self, assets: &mut PageAssets) -> Markup { - html! { (self.items.render(assets)) } - } } fn always() -> bool { From cc579add5fecee236702fc9cab63b5ae5b9fb84c Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 31 Mar 2022 21:05:54 +0200 Subject: [PATCH 044/244] Corrige API del grid --- pagetop/src/base/component/grid/column.rs | 12 +++++------- pagetop/src/base/component/grid/row.rs | 12 +++++------- pagetop/src/base/theme/bulmix/mod.rs | 4 ++-- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/pagetop/src/base/component/grid/column.rs b/pagetop/src/base/component/grid/column.rs index f5bc4669..da1a76a9 100644 --- a/pagetop/src/base/component/grid/column.rs +++ b/pagetop/src/base/component/grid/column.rs @@ -37,7 +37,7 @@ impl PageComponent for Column { fn default_render(&self, assets: &mut PageAssets) -> Markup { html! { div id=[self.id()] class=[self.classes("col")] { - (self.render_components(assets)) + (self.components().render(assets)) } } } @@ -84,6 +84,10 @@ impl Column { // Column GETTERS. + pub fn components(&self) -> &PageContainer { + &self.components + } + pub fn id(&self) -> &Option<String> { self.id.option() } @@ -95,12 +99,6 @@ impl Column { pub fn template(&self) -> &str { self.template.as_str() } - - // Column EXTRAS. - - pub fn render_components(&self, assets: &mut PageAssets) -> Markup { - html! { (self.components.render(assets)) } - } } fn always() -> bool { diff --git a/pagetop/src/base/component/grid/row.rs b/pagetop/src/base/component/grid/row.rs index 8437c1fe..f4a5b6a5 100644 --- a/pagetop/src/base/component/grid/row.rs +++ b/pagetop/src/base/component/grid/row.rs @@ -37,7 +37,7 @@ impl PageComponent for Row { fn default_render(&self, assets: &mut PageAssets) -> Markup { html! { div id=[self.id()] class=[self.classes("row")] { - (self.render_columns(assets)) + (self.columns().render(assets)) } } } @@ -84,6 +84,10 @@ impl Row { // Row GETTERS. + pub fn columns(&self) -> &PageContainer { + &self.columns + } + pub fn id(&self) -> &Option<String> { self.id.option() } @@ -95,12 +99,6 @@ impl Row { pub fn template(&self) -> &str { self.template.as_str() } - - // Row EXTRAS. - - pub fn render_columns(&self, assets: &mut PageAssets) -> Markup { - html! { (self.columns.render(assets)) } - } } fn always() -> bool { diff --git a/pagetop/src/base/theme/bulmix/mod.rs b/pagetop/src/base/theme/bulmix/mod.rs index 0e8a4d9b..284353c1 100644 --- a/pagetop/src/base/theme/bulmix/mod.rs +++ b/pagetop/src/base/theme/bulmix/mod.rs @@ -42,7 +42,7 @@ impl ThemeTrait for BulmixTheme { let row = component.downcast_ref::<grid::Row>().unwrap(); Some(html! { div id=[row.id()] class=[row.classes("columns")] { - (row.render_columns(assets)) + (row.columns().render(assets)) } }) }, @@ -50,7 +50,7 @@ impl ThemeTrait for BulmixTheme { let col = component.downcast_ref::<grid::Column>().unwrap(); Some(html! { div id=[col.id()] class=[col.classes("column")] { - (col.render_components(assets)) + (col.components().render(assets)) } }) }, From 69139f2a624545c5959bd748dd9f4cad757f47f2 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 1 Apr 2022 19:15:01 +0200 Subject: [PATCH 045/244] =?UTF-8?q?Libera=20la=20versi=C3=B3n=20de=20desar?= =?UTF-8?q?rollo=200.0.7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pagetop/src/base/component/block.rs | 2 -- pagetop/src/base/component/chunck.rs | 2 -- pagetop/src/base/component/container.rs | 2 -- pagetop/src/base/component/form/button.rs | 2 -- pagetop/src/base/component/form/date.rs | 1 - pagetop/src/base/component/form/form.rs | 1 - pagetop/src/base/component/form/hidden.rs | 2 -- pagetop/src/base/component/form/input.rs | 2 -- pagetop/src/base/component/grid/column.rs | 1 - pagetop/src/base/component/grid/row.rs | 1 - pagetop/src/base/component/image.rs | 2 -- pagetop/src/base/component/menu.rs | 3 --- 12 files changed, 21 deletions(-) diff --git a/pagetop/src/base/component/block.rs b/pagetop/src/base/component/block.rs index fdf9922d..a1bf8745 100644 --- a/pagetop/src/base/component/block.rs +++ b/pagetop/src/base/component/block.rs @@ -11,7 +11,6 @@ pub struct Block { } impl PageComponent for Block { - fn new() -> Self { Block { renderable: always, @@ -51,7 +50,6 @@ impl PageComponent for Block { } impl Block { - pub fn with(html: Markup) -> Self { Block::new().add(html) } diff --git a/pagetop/src/base/component/chunck.rs b/pagetop/src/base/component/chunck.rs index 532584fc..dc909a89 100644 --- a/pagetop/src/base/component/chunck.rs +++ b/pagetop/src/base/component/chunck.rs @@ -8,7 +8,6 @@ pub struct Chunck { } impl PageComponent for Chunck { - fn new() -> Self { Chunck { renderable: always, @@ -36,7 +35,6 @@ impl PageComponent for Chunck { } impl Chunck { - pub fn with(html: Markup) -> Self { Chunck::new().add(html) } diff --git a/pagetop/src/base/component/container.rs b/pagetop/src/base/component/container.rs index 24172d00..b85288af 100644 --- a/pagetop/src/base/component/container.rs +++ b/pagetop/src/base/component/container.rs @@ -13,7 +13,6 @@ pub struct Container { } impl PageComponent for Container { - fn new() -> Self { Container { renderable: always, @@ -74,7 +73,6 @@ impl PageComponent for Container { } impl Container { - pub fn header() -> Self { let mut c = Container::new(); c.container = ContainerType::Header; diff --git a/pagetop/src/base/component/form/button.rs b/pagetop/src/base/component/form/button.rs index b2f59609..f99f06d3 100644 --- a/pagetop/src/base/component/form/button.rs +++ b/pagetop/src/base/component/form/button.rs @@ -15,7 +15,6 @@ pub struct Button { } impl PageComponent for Button { - fn new() -> Self { Button { renderable : always, @@ -68,7 +67,6 @@ impl PageComponent for Button { } impl Button { - pub fn button(value: &str) -> Self { Button::new().with_value(value) } diff --git a/pagetop/src/base/component/form/date.rs b/pagetop/src/base/component/form/date.rs index f1270a82..40c2f784 100644 --- a/pagetop/src/base/component/form/date.rs +++ b/pagetop/src/base/component/form/date.rs @@ -18,7 +18,6 @@ pub struct Date { } impl PageComponent for Date { - fn new() -> Self { Date { renderable : always, diff --git a/pagetop/src/base/component/form/form.rs b/pagetop/src/base/component/form/form.rs index 2d88d141..e5169ff3 100644 --- a/pagetop/src/base/component/form/form.rs +++ b/pagetop/src/base/component/form/form.rs @@ -15,7 +15,6 @@ pub struct Form { } impl PageComponent for Form { - fn new() -> Self { Form { renderable: always, diff --git a/pagetop/src/base/component/form/hidden.rs b/pagetop/src/base/component/form/hidden.rs index 636d034e..f4734ba0 100644 --- a/pagetop/src/base/component/form/hidden.rs +++ b/pagetop/src/base/component/form/hidden.rs @@ -7,7 +7,6 @@ pub struct Hidden { } impl PageComponent for Hidden { - fn new() -> Self { Hidden { weight: 0, @@ -32,7 +31,6 @@ impl PageComponent for Hidden { } impl Hidden { - pub fn set(name: &str, value: &str) -> Self { Hidden::new().with_name(name).with_value(value) } diff --git a/pagetop/src/base/component/form/input.rs b/pagetop/src/base/component/form/input.rs index 2e1af61d..9d6e1afd 100644 --- a/pagetop/src/base/component/form/input.rs +++ b/pagetop/src/base/component/form/input.rs @@ -24,7 +24,6 @@ pub struct Input { } impl PageComponent for Input { - fn new() -> Self { Input { renderable : always, @@ -114,7 +113,6 @@ impl PageComponent for Input { } impl Input { - pub fn textfield() -> Self { Input::new() } diff --git a/pagetop/src/base/component/grid/column.rs b/pagetop/src/base/component/grid/column.rs index da1a76a9..c8594642 100644 --- a/pagetop/src/base/component/grid/column.rs +++ b/pagetop/src/base/component/grid/column.rs @@ -10,7 +10,6 @@ pub struct Column { } impl PageComponent for Column { - fn new() -> Self { Column { renderable: always, diff --git a/pagetop/src/base/component/grid/row.rs b/pagetop/src/base/component/grid/row.rs index f4a5b6a5..03a39e39 100644 --- a/pagetop/src/base/component/grid/row.rs +++ b/pagetop/src/base/component/grid/row.rs @@ -10,7 +10,6 @@ pub struct Row { } impl PageComponent for Row { - fn new() -> Self { Row { renderable: always, diff --git a/pagetop/src/base/component/image.rs b/pagetop/src/base/component/image.rs index c324782a..1384f4df 100644 --- a/pagetop/src/base/component/image.rs +++ b/pagetop/src/base/component/image.rs @@ -10,7 +10,6 @@ pub struct Image { } impl PageComponent for Image { - fn new() -> Self { Image { renderable: always, @@ -41,7 +40,6 @@ impl PageComponent for Image { } impl Image { - pub fn image(source: &str) -> Self { Image::new().with_source(source) } diff --git a/pagetop/src/base/component/menu.rs b/pagetop/src/base/component/menu.rs index 85b9007e..daabdd60 100644 --- a/pagetop/src/base/component/menu.rs +++ b/pagetop/src/base/component/menu.rs @@ -21,7 +21,6 @@ pub struct MenuItem { } impl PageComponent for MenuItem { - fn new() -> Self { MenuItem { renderable: always, @@ -71,7 +70,6 @@ impl PageComponent for MenuItem { } impl MenuItem { - pub fn label(label: &str) -> Self { MenuItem { renderable: always, @@ -162,7 +160,6 @@ pub struct Menu { } impl PageComponent for Menu { - fn new() -> Self { Menu { renderable: always, From 53dd1f24c7cffe369be70aa71b90e8fe44d64f6f Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 2 Apr 2022 09:21:43 +0200 Subject: [PATCH 046/244] =?UTF-8?q?A=C3=B1ade=20la=20funci=C3=B3n=20arc()?= =?UTF-8?q?=20para=20capturar=20el=20componente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recibe un componente mutable que podría modificarse justo antes de ser añadido a un contenedor. Es una posible solución para poder desarrollar un mecanismo aceptable de Triggers/Hooks/Actions (THA) para PageTop. --- pagetop-admin/src/summary.rs | 7 +++--- pagetop-user/src/lib.rs | 8 +++++-- pagetop/src/base/component/container.rs | 2 +- pagetop/src/base/component/form/form.rs | 2 +- pagetop/src/base/component/grid/column.rs | 2 +- pagetop/src/base/component/grid/row.rs | 2 +- pagetop/src/base/component/menu.rs | 2 +- pagetop/src/base/module/demopage/mod.rs | 28 ++++++++++++----------- pagetop/src/base/theme/bootsier/mod.rs | 2 +- pagetop/src/response/page/component.rs | 9 ++++++++ pagetop/src/response/page/container.rs | 12 ++++------ pagetop/src/response/page/mod.rs | 2 +- pagetop/src/response/page/page.rs | 6 ++--- pagetop/src/theme/definition.rs | 2 +- 14 files changed, 50 insertions(+), 36 deletions(-) diff --git a/pagetop-admin/src/summary.rs b/pagetop-admin/src/summary.rs index b91b97fa..6e6f2158 100644 --- a/pagetop-admin/src/summary.rs +++ b/pagetop-admin/src/summary.rs @@ -38,17 +38,18 @@ pub async fn summary() -> app::Result<Markup> { .with_title("Admin") - .add_to("top-menu", top_menu) + .add_to("top-menu", top_menu.arc()) .add_to("content", grid::Row::new() .add_column(grid::Column::new() - .add(side_menu) + .add(side_menu.arc()) ) .add_column(grid::Column::new() .add(Chunck::with(html! { p { "Columna 2"} - })) + }).arc()) ) + .arc() ) diff --git a/pagetop-user/src/lib.rs b/pagetop-user/src/lib.rs index dd0b362b..414fb3e4 100644 --- a/pagetop-user/src/lib.rs +++ b/pagetop-user/src/lib.rs @@ -31,7 +31,7 @@ impl ModuleTrait for UserModule { } } -fn form_login() -> impl PageComponent { +fn form_login() -> ArcComponent { Form::new() .with_id("user-login") .add(form::Input::textfield() @@ -41,13 +41,16 @@ fn form_login() -> impl PageComponent { "app" => SETTINGS.app.name.to_owned() ]).as_str()) .with_autofocus(true) + .arc() ) .add(form::Input::password() .with_name("pass") .with_label(l("password").as_str()) .with_help_text(l("password_help").as_str()) + .arc() ) - .add(form::Button::submit(l("login").as_str())) + .add(form::Button::submit(l("login").as_str()).arc()) + .arc() } async fn login() -> app::Result<Markup> { @@ -58,6 +61,7 @@ async fn login() -> app::Result<Markup> { .add_to("content", Container::new() .with_id("welcome") .add(form_login()) + .arc() ) .render() } diff --git a/pagetop/src/base/component/container.rs b/pagetop/src/base/component/container.rs index b85288af..2e48ba10 100644 --- a/pagetop/src/base/component/container.rs +++ b/pagetop/src/base/component/container.rs @@ -109,7 +109,7 @@ impl Container { self } - pub fn add(mut self, component: impl PageComponent) -> Self { + pub fn add(mut self, component: ArcComponent) -> Self { self.components.add(component); self } diff --git a/pagetop/src/base/component/form/form.rs b/pagetop/src/base/component/form/form.rs index e5169ff3..9317f9eb 100644 --- a/pagetop/src/base/component/form/form.rs +++ b/pagetop/src/base/component/form/form.rs @@ -85,7 +85,7 @@ impl Form { self } - pub fn add(mut self, element: impl PageComponent) -> Self { + pub fn add(mut self, element: ArcComponent) -> Self { self.elements.add(element); self } diff --git a/pagetop/src/base/component/grid/column.rs b/pagetop/src/base/component/grid/column.rs index c8594642..a007c83b 100644 --- a/pagetop/src/base/component/grid/column.rs +++ b/pagetop/src/base/component/grid/column.rs @@ -56,7 +56,7 @@ impl Column { self } - pub fn add(mut self, component: impl PageComponent) -> Self { + pub fn add(mut self, component: ArcComponent) -> Self { self.components.add(component); self } diff --git a/pagetop/src/base/component/grid/row.rs b/pagetop/src/base/component/grid/row.rs index 03a39e39..2a185894 100644 --- a/pagetop/src/base/component/grid/row.rs +++ b/pagetop/src/base/component/grid/row.rs @@ -57,7 +57,7 @@ impl Row { } pub fn add_column(mut self, column: grid::Column) -> Self { - self.columns.add(column); + self.columns.add(column.arc()); self } diff --git a/pagetop/src/base/component/menu.rs b/pagetop/src/base/component/menu.rs index daabdd60..3f2b4ff4 100644 --- a/pagetop/src/base/component/menu.rs +++ b/pagetop/src/base/component/menu.rs @@ -222,7 +222,7 @@ impl Menu { } pub fn add(mut self, item: MenuItem) -> Self { - self.items.add(item); + self.items.add(item.arc()); self } diff --git a/pagetop/src/base/module/demopage/mod.rs b/pagetop/src/base/module/demopage/mod.rs index 489b6d3b..d71c7176 100644 --- a/pagetop/src/base/module/demopage/mod.rs +++ b/pagetop/src/base/module/demopage/mod.rs @@ -35,7 +35,7 @@ async fn demo() -> app::Result<Markup> { .render() } -fn hello_world() -> Container { +fn hello_world() -> ArcComponent { Container::header() .add(grid::Row::new() .add_column(grid::Column::new() @@ -68,15 +68,17 @@ fn hello_world() -> Container { i class="fas fa-paper-plane" {} "Get quote" } - })) + }).arc()) ) .add_column(grid::Column::new() - .add(Image::image("/bootsier/images/demo-header.svg")) + .add(Image::image("/bootsier/images/demo-header.svg").arc()) ) + .arc() ) + .arc() } -fn hello_world_original() -> Chunck { +fn hello_world_original() -> ArcComponent { Chunck::with(html! { header id="header" class="header" { div class="container" { @@ -121,10 +123,10 @@ fn hello_world_original() -> Chunck { } } } - }) + }).arc() } -fn just_visiting() -> Chunck { +fn just_visiting() -> ArcComponent { Chunck::with(html! { div id="details" class="basic-1" { div class="container" { @@ -151,10 +153,10 @@ fn just_visiting() -> Chunck { } } } - }) + }).arc() } -fn about_pagetop() -> Chunck { +fn about_pagetop() -> ArcComponent { Chunck::with(html! { div id="pagetop" class="basic-2" { div class="container" { @@ -175,10 +177,10 @@ fn about_pagetop() -> Chunck { } } } - }) + }).arc() } -fn promo_pagetop() -> Chunck { +fn promo_pagetop() -> ArcComponent { Chunck::with(html! { div id="promo" class="basic-3" { div class="container" { @@ -200,10 +202,10 @@ fn promo_pagetop() -> Chunck { } } } - }) + }).arc() } -fn reporting_problems() -> Chunck { +fn reporting_problems() -> ArcComponent { Chunck::with(html! { div id="reporting" class="basic-4" { div class="container" { @@ -223,5 +225,5 @@ fn reporting_problems() -> Chunck { } } } - }) + }).arc() } diff --git a/pagetop/src/base/theme/bootsier/mod.rs b/pagetop/src/base/theme/bootsier/mod.rs index 90111723..b169351d 100644 --- a/pagetop/src/base/theme/bootsier/mod.rs +++ b/pagetop/src/base/theme/bootsier/mod.rs @@ -77,7 +77,7 @@ impl ThemeTrait for BootsierTheme { } } } - })) + }).arc()) .render() } } diff --git a/pagetop/src/response/page/component.rs b/pagetop/src/response/page/component.rs index 630b8a9b..b9a920d3 100644 --- a/pagetop/src/response/page/component.rs +++ b/pagetop/src/response/page/component.rs @@ -3,8 +3,11 @@ use crate::response::page::PageAssets; use downcast_rs::{Downcast, impl_downcast}; +use std::sync::Arc; use std::any::type_name; +pub type ArcComponent = Arc<dyn PageComponent>; + pub trait PageComponent: Downcast + Send + Sync { fn new() -> Self where Self: Sized; @@ -33,6 +36,12 @@ pub trait PageComponent: Downcast + Send + Sync { 0 } + #[allow(unused_mut)] + fn arc(mut self) -> ArcComponent where Self: Sized { + let component = self; + Arc::new(component) + } + #[allow(unused_variables)] fn default_render(&self, assets: &mut PageAssets) -> Markup { html! {} diff --git a/pagetop/src/response/page/container.rs b/pagetop/src/response/page/container.rs index 72287560..7e5d4953 100644 --- a/pagetop/src/response/page/container.rs +++ b/pagetop/src/response/page/container.rs @@ -1,24 +1,22 @@ use crate::html::{Markup, html}; -use crate::response::page::{PageAssets, PageComponent, render_component}; - -use std::sync::Arc; +use crate::response::page::{ArcComponent, PageAssets, render_component}; #[derive(Clone)] -pub struct PageContainer(Vec<Arc<dyn PageComponent>>); +pub struct PageContainer(Vec<ArcComponent>); impl PageContainer { pub fn new() -> Self { PageContainer(Vec::new()) } - pub fn new_with(component: impl PageComponent) -> Self { + pub fn new_with(component: ArcComponent) -> Self { let mut container = PageContainer::new(); container.add(component); container } - pub fn add(&mut self, component: impl PageComponent) { - self.0.push(Arc::new(component)); + pub fn add(&mut self, component: ArcComponent) { + self.0.push(component); } pub fn render(&self, assets: &mut PageAssets) -> Markup { diff --git a/pagetop/src/response/page/mod.rs b/pagetop/src/response/page/mod.rs index f34070e2..63c19a47 100644 --- a/pagetop/src/response/page/mod.rs +++ b/pagetop/src/response/page/mod.rs @@ -7,7 +7,7 @@ pub use assets::{ }; mod component; -pub use component::PageComponent; +pub use component::{ArcComponent, PageComponent}; mod container; pub use container::PageContainer; diff --git a/pagetop/src/response/page/page.rs b/pagetop/src/response/page/page.rs index cb561626..5cbe80cb 100644 --- a/pagetop/src/response/page/page.rs +++ b/pagetop/src/response/page/page.rs @@ -1,7 +1,7 @@ use crate::{Lazy, app, trace}; use crate::config::SETTINGS; use crate::html::{Classes, DOCTYPE, Markup, OptAttr, html}; -use crate::response::page::{PageAssets, PageComponent, PageContainer}; +use crate::response::page::*; use std::sync::RwLock; use std::collections::HashMap; @@ -100,7 +100,7 @@ impl<'a> Page<'a> { pub fn add_to( &mut self, region: &'a str, - component: impl PageComponent + component: ArcComponent ) -> &mut Self { if let Some(regions) = self.regions.get_mut(region) { regions.add(component); @@ -205,7 +205,7 @@ pub fn render_component( } } -pub fn add_component_to(region: &'static str, component: impl PageComponent) { +pub fn add_component_to(region: &'static str, component: ArcComponent) { let mut hmap = COMPONENTS.write().unwrap(); if let Some(regions) = hmap.get_mut(region) { regions.add(component); diff --git a/pagetop/src/theme/definition.rs b/pagetop/src/theme/definition.rs index acc30f47..db4c0e37 100644 --- a/pagetop/src/theme/definition.rs +++ b/pagetop/src/theme/definition.rs @@ -104,7 +104,7 @@ pub trait ThemeTrait: Send + Sync { div { h1 { (s) } } - })) + }).arc()) .render() } } From 4dd57eab4360f56a57f1caac1a4f2e69a2108cfa Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 4 Apr 2022 20:32:37 +0200 Subject: [PATCH 047/244] =?UTF-8?q?A=C3=B1ade=20referencias=20a=20todos=20?= =?UTF-8?q?los=20m=C3=A9todos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit El proyecto compila, pendiente de una solución para los contenedores. --- pagetop-user/src/lib.rs | 8 ++--- pagetop/src/base/component/block.rs | 20 +++++++------ pagetop/src/base/component/chunck.rs | 12 ++++---- pagetop/src/base/component/container.rs | 12 ++++---- pagetop/src/base/component/form/button.rs | 28 ++++++++++-------- pagetop/src/base/component/form/date.rs | 30 +++++++++---------- pagetop/src/base/component/form/form.rs | 18 ++++++------ pagetop/src/base/component/form/hidden.rs | 11 ++++--- pagetop/src/base/component/form/input.rs | 36 +++++++++++------------ pagetop/src/base/component/grid/column.rs | 12 ++++---- pagetop/src/base/component/grid/row.rs | 12 ++++---- pagetop/src/base/component/image.rs | 18 +++++++----- 12 files changed, 115 insertions(+), 102 deletions(-) diff --git a/pagetop-user/src/lib.rs b/pagetop-user/src/lib.rs index 414fb3e4..06b0dd1a 100644 --- a/pagetop-user/src/lib.rs +++ b/pagetop-user/src/lib.rs @@ -32,7 +32,7 @@ impl ModuleTrait for UserModule { } fn form_login() -> ArcComponent { - Form::new() + Form::new()/* .with_id("user-login") .add(form::Input::textfield() .with_name("name") @@ -49,7 +49,7 @@ fn form_login() -> ArcComponent { .with_help_text(l("password_help").as_str()) .arc() ) - .add(form::Button::submit(l("login").as_str()).arc()) + .add(form::Button::submit(l("login").as_str()).arc())*/ .arc() } @@ -57,11 +57,11 @@ async fn login() -> app::Result<Markup> { Page::new() .with_title( "Identificación del usuario" - ) + )/* .add_to("content", Container::new() .with_id("welcome") .add(form_login()) .arc() - ) + )*/ .render() } diff --git a/pagetop/src/base/component/block.rs b/pagetop/src/base/component/block.rs index a1bf8745..64dd8d7c 100644 --- a/pagetop/src/base/component/block.rs +++ b/pagetop/src/base/component/block.rs @@ -51,47 +51,49 @@ impl PageComponent for Block { impl Block { pub fn with(html: Markup) -> Self { - Block::new().add(html) + let mut block = Block::new(); + block.add(html); + block } // Block BUILDER. - pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { self.renderable = renderable; self } - pub fn with_weight(mut self, weight: i8) -> Self { + pub fn with_weight(&mut self, weight: i8) -> &Self { self.weight = weight; self } - pub fn with_title(mut self, title: &str) -> Self { + pub fn with_title(&mut self, title: &str) -> &Self { self.title.with_value(title); self } - pub fn add(mut self, html: Markup) -> Self { + pub fn add(&mut self, html: Markup) -> &Self { self.html.push(html); self } - pub fn with_id(mut self, id: &str) -> Self { + pub fn with_id(&mut self, id: &str) -> &Self { self.id.with_value(id); self } - pub fn set_classes(mut self, classes: &str) -> Self { + pub fn set_classes(&mut self, classes: &str) -> &Self { self.classes.set_classes(classes); self } - pub fn add_classes(mut self, classes: &str) -> Self { + pub fn add_classes(&mut self, classes: &str) -> &Self { self.classes.add_classes(classes); self } - pub fn using_template(mut self, template: &str) -> Self { + pub fn using_template(&mut self, template: &str) -> &Self { self.template = template.to_owned(); self } diff --git a/pagetop/src/base/component/chunck.rs b/pagetop/src/base/component/chunck.rs index dc909a89..7589ea4a 100644 --- a/pagetop/src/base/component/chunck.rs +++ b/pagetop/src/base/component/chunck.rs @@ -36,27 +36,29 @@ impl PageComponent for Chunck { impl Chunck { pub fn with(html: Markup) -> Self { - Chunck::new().add(html) + let mut chunck = Chunck::new(); + chunck.add(html); + chunck } // Chunck BUILDER. - pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { self.renderable = renderable; self } - pub fn with_weight(mut self, weight: i8) -> Self { + pub fn with_weight(&mut self, weight: i8) -> &Self { self.weight = weight; self } - pub fn add(mut self, html: Markup) -> Self { + pub fn add(&mut self, html: Markup) -> &Self { self.html.push(html); self } - pub fn using_template(mut self, template: &str) -> Self { + pub fn using_template(&mut self, template: &str) -> &Self { self.template = template.to_owned(); self } diff --git a/pagetop/src/base/component/container.rs b/pagetop/src/base/component/container.rs index 2e48ba10..79f9b7a5 100644 --- a/pagetop/src/base/component/container.rs +++ b/pagetop/src/base/component/container.rs @@ -99,12 +99,12 @@ impl Container { // Container BUILDER. - pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { self.renderable = renderable; self } - pub fn with_weight(mut self, weight: i8) -> Self { + pub fn with_weight(&mut self, weight: i8) -> &Self { self.weight = weight; self } @@ -114,22 +114,22 @@ impl Container { self } - pub fn with_id(mut self, id: &str) -> Self { + pub fn with_id(&mut self, id: &str) -> &Self { self.id.with_value(id); self } - pub fn set_classes(mut self, classes: &str) -> Self { + pub fn set_classes(&mut self, classes: &str) -> &Self { self.classes.set_classes(classes); self } - pub fn add_classes(mut self, classes: &str) -> Self { + pub fn add_classes(&mut self, classes: &str) -> &Self { self.classes.add_classes(classes); self } - pub fn using_template(mut self, template: &str) -> Self { + pub fn using_template(&mut self, template: &str) -> &Self { self.template = template.to_owned(); self } diff --git a/pagetop/src/base/component/form/button.rs b/pagetop/src/base/component/form/button.rs index f99f06d3..f6fd474d 100644 --- a/pagetop/src/base/component/form/button.rs +++ b/pagetop/src/base/component/form/button.rs @@ -68,44 +68,48 @@ impl PageComponent for Button { impl Button { pub fn button(value: &str) -> Self { - Button::new().with_value(value) + let mut button = Button::new(); + button.with_value(value); + button } pub fn reset(value: &str) -> Self { - let mut button = Button::new().with_value(value); + let mut button = Button::new(); + button.with_value(value); button.button_type = ButtonType::Reset; button } pub fn submit(value: &str) -> Self { - let mut button = Button::new().with_value(value); + let mut button = Button::new(); + button.with_value(value); button.button_type = ButtonType::Submit; button } // Button BUILDER. - pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { self.renderable = renderable; self } - pub fn with_weight(mut self, weight: i8) -> Self { + pub fn with_weight(&mut self, weight: i8) -> &Self { self.weight = weight; self } - pub fn with_name(mut self, name: &str) -> Self { + pub fn with_name(&mut self, name: &str) -> &Self { self.name.with_value(name); self } - pub fn with_value(mut self, value: &str) -> Self { + pub fn with_value(&mut self, value: &str) -> &Self { self.value.with_value(value); self } - pub fn with_autofocus(mut self, toggle: bool) -> Self { + pub fn with_autofocus(&mut self, toggle: bool) -> &Self { self.autofocus.with_value(match toggle { true => "autofocus", false => "", @@ -113,7 +117,7 @@ impl Button { self } - pub fn with_disabled(mut self, toggle: bool) -> Self { + pub fn with_disabled(&mut self, toggle: bool) -> &Self { self.disabled.with_value(match toggle { true => "disabled", false => "", @@ -121,17 +125,17 @@ impl Button { self } - pub fn set_classes(mut self, classes: &str) -> Self { + pub fn set_classes(&mut self, classes: &str) -> &Self { self.classes.set_classes(classes); self } - pub fn add_classes(mut self, classes: &str) -> Self { + pub fn add_classes(&mut self, classes: &str) -> &Self { self.classes.add_classes(classes); self } - pub fn using_template(mut self, template: &str) -> Self { + pub fn using_template(&mut self, template: &str) -> &Self { self.template = template.to_owned(); self } diff --git a/pagetop/src/base/component/form/date.rs b/pagetop/src/base/component/form/date.rs index 40c2f784..bc355a2a 100644 --- a/pagetop/src/base/component/form/date.rs +++ b/pagetop/src/base/component/form/date.rs @@ -95,37 +95,37 @@ impl Date { // Date BUILDER. - pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { self.renderable = renderable; self } - pub fn with_weight(mut self, weight: i8) -> Self { + pub fn with_weight(&mut self, weight: i8) -> &Self { self.weight = weight; self } - pub fn with_name(mut self, name: &str) -> Self { + pub fn with_name(&mut self, name: &str) -> &Self { self.name.with_value(name); self } - pub fn with_value(mut self, value: &str) -> Self { + pub fn with_value(&mut self, value: &str) -> &Self { self.value.with_value(value); self } - pub fn with_label(mut self, label: &str) -> Self { + pub fn with_label(&mut self, label: &str) -> &Self { self.label.with_value(label); self } - pub fn with_placeholder(mut self, placeholder: &str) -> Self { + pub fn with_placeholder(&mut self, placeholder: &str) -> &Self { self.placeholder.with_value(placeholder); self } - pub fn with_autofocus(mut self, toggle: bool) -> Self { + pub fn with_autofocus(&mut self, toggle: bool) -> &Self { self.autofocus.with_value(match toggle { true => "autofocus", false => "", @@ -133,7 +133,7 @@ impl Date { self } - pub fn with_autocomplete(mut self, toggle: bool) -> Self { + pub fn with_autocomplete(&mut self, toggle: bool) -> &Self { self.autocomplete.with_value(match toggle { true => "", false => "off", @@ -141,7 +141,7 @@ impl Date { self } - pub fn with_disabled(mut self, toggle: bool) -> Self { + pub fn with_disabled(&mut self, toggle: bool) -> &Self { self.disabled.with_value(match toggle { true => "disabled", false => "", @@ -149,7 +149,7 @@ impl Date { self } - pub fn with_readonly(mut self, toggle: bool) -> Self { + pub fn with_readonly(&mut self, toggle: bool) -> &Self { self.readonly.with_value(match toggle { true => "readonly", false => "", @@ -157,7 +157,7 @@ impl Date { self } - pub fn with_required(mut self, toggle: bool) -> Self { + pub fn with_required(&mut self, toggle: bool) -> &Self { self.required.with_value(match toggle { true => "required", false => "", @@ -165,22 +165,22 @@ impl Date { self } - pub fn with_help_text(mut self, help_text: &str) -> Self { + pub fn with_help_text(&mut self, help_text: &str) -> &Self { self.help_text.with_value(help_text); self } - pub fn set_classes(mut self, classes: &str) -> Self { + pub fn set_classes(&mut self, classes: &str) -> &Self { self.classes.set_classes(classes); self } - pub fn add_classes(mut self, classes: &str) -> Self { + pub fn add_classes(&mut self, classes: &str) -> &Self { self.classes.add_classes(classes); self } - pub fn using_template(mut self, template: &str) -> Self { + pub fn using_template(&mut self, template: &str) -> &Self { self.template = template.to_owned(); self } diff --git a/pagetop/src/base/component/form/form.rs b/pagetop/src/base/component/form/form.rs index 9317f9eb..3685d9a1 100644 --- a/pagetop/src/base/component/form/form.rs +++ b/pagetop/src/base/component/form/form.rs @@ -60,27 +60,27 @@ impl Form { // Form BUILDER. - pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { self.renderable = renderable; self } - pub fn with_weight(mut self, weight: i8) -> Self { + pub fn with_weight(&mut self, weight: i8) -> &Self { self.weight = weight; self } - pub fn with_action(mut self, action: &str) -> Self { + pub fn with_action(&mut self, action: &str) -> &Self { self.action.with_value(action); self } - pub fn with_charset(mut self, charset: &str) -> Self { + pub fn with_charset(&mut self, charset: &str) -> &Self { self.charset.with_value(charset); self } - pub fn with_method(mut self, method: FormMethod) -> Self { + pub fn with_method(&mut self, method: FormMethod) -> &Self { self.method = method; self } @@ -90,22 +90,22 @@ impl Form { self } - pub fn with_id(mut self, id: &str) -> Self { + pub fn with_id(&mut self, id: &str) -> &Self { self.id.with_value(id); self } - pub fn set_classes(mut self, classes: &str) -> Self { + pub fn set_classes(&mut self, classes: &str) -> &Self { self.classes.set_classes(classes); self } - pub fn add_classes(mut self, classes: &str) -> Self { + pub fn add_classes(&mut self, classes: &str) -> &Self { self.classes.add_classes(classes); self } - pub fn using_template(mut self, template: &str) -> Self { + pub fn using_template(&mut self, template: &str) -> &Self { self.template = template.to_owned(); self } diff --git a/pagetop/src/base/component/form/hidden.rs b/pagetop/src/base/component/form/hidden.rs index f4734ba0..0e6e56c3 100644 --- a/pagetop/src/base/component/form/hidden.rs +++ b/pagetop/src/base/component/form/hidden.rs @@ -32,22 +32,25 @@ impl PageComponent for Hidden { impl Hidden { pub fn set(name: &str, value: &str) -> Self { - Hidden::new().with_name(name).with_value(value) + let mut hidden = Hidden::new(); + hidden.with_name(name); + hidden.with_value(value); + hidden } // Hidden BUILDER. - pub fn with_weight(mut self, weight: i8) -> Self { + pub fn with_weight(&mut self, weight: i8) -> &Self { self.weight = weight; self } - pub fn with_name(mut self, name: &str) -> Self { + pub fn with_name(&mut self, name: &str) -> &Self { self.name.with_value(name); self } - pub fn with_value(mut self, value: &str) -> Self { + pub fn with_value(&mut self, value: &str) -> &Self { self.value.with_value(value); self } diff --git a/pagetop/src/base/component/form/input.rs b/pagetop/src/base/component/form/input.rs index 9d6e1afd..c468cdfe 100644 --- a/pagetop/src/base/component/form/input.rs +++ b/pagetop/src/base/component/form/input.rs @@ -149,52 +149,52 @@ impl Input { // Input BUILDER. - pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { self.renderable = renderable; self } - pub fn with_weight(mut self, weight: i8) -> Self { + pub fn with_weight(&mut self, weight: i8) -> &Self { self.weight = weight; self } - pub fn with_name(mut self, name: &str) -> Self { + pub fn with_name(&mut self, name: &str) -> &Self { self.name.with_value(name); self } - pub fn with_value(mut self, value: &str) -> Self { + pub fn with_value(&mut self, value: &str) -> &Self { self.value.with_value(value); self } - pub fn with_label(mut self, label: &str) -> Self { + pub fn with_label(&mut self, label: &str) -> &Self { self.label.with_value(label); self } - pub fn with_size(mut self, size: Option<u16>) -> Self { + pub fn with_size(&mut self, size: Option<u16>) -> &Self { self.size = size; self } - pub fn with_minlength(mut self, minlength: Option<u16>) -> Self { + pub fn with_minlength(&mut self, minlength: Option<u16>) -> &Self { self.minlength = minlength; self } - pub fn with_maxlength(mut self, maxlength: Option<u16>) -> Self { + pub fn with_maxlength(&mut self, maxlength: Option<u16>) -> &Self { self.maxlength = maxlength; self } - pub fn with_placeholder(mut self, placeholder: &str) -> Self { + pub fn with_placeholder(&mut self, placeholder: &str) -> &Self { self.placeholder.with_value(placeholder); self } - pub fn with_autofocus(mut self, toggle: bool) -> Self { + pub fn with_autofocus(&mut self, toggle: bool) -> &Self { self.autofocus.with_value(match toggle { true => "autofocus", false => "", @@ -202,7 +202,7 @@ impl Input { self } - pub fn with_autocomplete(mut self, toggle: bool) -> Self { + pub fn with_autocomplete(&mut self, toggle: bool) -> &Self { self.autocomplete.with_value(match toggle { true => "", false => "off", @@ -210,7 +210,7 @@ impl Input { self } - pub fn with_disabled(mut self, toggle: bool) -> Self { + pub fn with_disabled(&mut self, toggle: bool) -> &Self { self.disabled.with_value(match toggle { true => "disabled", false => "", @@ -218,7 +218,7 @@ impl Input { self } - pub fn with_readonly(mut self, toggle: bool) -> Self { + pub fn with_readonly(&mut self, toggle: bool) -> &Self { self.readonly.with_value(match toggle { true => "readonly", false => "", @@ -226,7 +226,7 @@ impl Input { self } - pub fn with_required(mut self, toggle: bool) -> Self { + pub fn with_required(&mut self, toggle: bool) -> &Self { self.required.with_value(match toggle { true => "required", false => "", @@ -234,22 +234,22 @@ impl Input { self } - pub fn with_help_text(mut self, help_text: &str) -> Self { + pub fn with_help_text(&mut self, help_text: &str) -> &Self { self.help_text.with_value(help_text); self } - pub fn set_classes(mut self, classes: &str) -> Self { + pub fn set_classes(&mut self, classes: &str) -> &Self { self.classes.set_classes(classes); self } - pub fn add_classes(mut self, classes: &str) -> Self { + pub fn add_classes(&mut self, classes: &str) -> &Self { self.classes.add_classes(classes); self } - pub fn using_template(mut self, template: &str) -> Self { + pub fn using_template(&mut self, template: &str) -> &Self { self.template = template.to_owned(); self } diff --git a/pagetop/src/base/component/grid/column.rs b/pagetop/src/base/component/grid/column.rs index a007c83b..e4e5525a 100644 --- a/pagetop/src/base/component/grid/column.rs +++ b/pagetop/src/base/component/grid/column.rs @@ -46,12 +46,12 @@ impl Column { // Column BUILDER. - pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { self.renderable = renderable; self } - pub fn with_weight(mut self, weight: i8) -> Self { + pub fn with_weight(&mut self, weight: i8) -> &Self { self.weight = weight; self } @@ -61,22 +61,22 @@ impl Column { self } - pub fn with_id(mut self, id: &str) -> Self { + pub fn with_id(&mut self, id: &str) -> &Self { self.id.with_value(id); self } - pub fn set_classes(mut self, classes: &str) -> Self { + pub fn set_classes(&mut self, classes: &str) -> &Self { self.classes.set_classes(classes); self } - pub fn add_classes(mut self, classes: &str) -> Self { + pub fn add_classes(&mut self, classes: &str) -> &Self { self.classes.add_classes(classes); self } - pub fn using_template(mut self, template: &str) -> Self { + pub fn using_template(&mut self, template: &str) -> &Self { self.template = template.to_owned(); self } diff --git a/pagetop/src/base/component/grid/row.rs b/pagetop/src/base/component/grid/row.rs index 2a185894..30a5f351 100644 --- a/pagetop/src/base/component/grid/row.rs +++ b/pagetop/src/base/component/grid/row.rs @@ -46,12 +46,12 @@ impl Row { // Row BUILDER. - pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { self.renderable = renderable; self } - pub fn with_weight(mut self, weight: i8) -> Self { + pub fn with_weight(&mut self, weight: i8) -> &Self { self.weight = weight; self } @@ -61,22 +61,22 @@ impl Row { self } - pub fn with_id(mut self, id: &str) -> Self { + pub fn with_id(&mut self, id: &str) -> &Self { self.id.with_value(id); self } - pub fn set_classes(mut self, classes: &str) -> Self { + pub fn set_classes(&mut self, classes: &str) -> &Self { self.classes.set_classes(classes); self } - pub fn add_classes(mut self, classes: &str) -> Self { + pub fn add_classes(&mut self, classes: &str) -> &Self { self.classes.add_classes(classes); self } - pub fn using_template(mut self, template: &str) -> Self { + pub fn using_template(&mut self, template: &str) -> &Self { self.template = template.to_owned(); self } diff --git a/pagetop/src/base/component/image.rs b/pagetop/src/base/component/image.rs index 1384f4df..30cca8f3 100644 --- a/pagetop/src/base/component/image.rs +++ b/pagetop/src/base/component/image.rs @@ -41,42 +41,44 @@ impl PageComponent for Image { impl Image { pub fn image(source: &str) -> Self { - Image::new().with_source(source) + let mut image = Image::new(); + image.with_source(source); + image } // Image BUILDER. - pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { self.renderable = renderable; self } - pub fn with_weight(mut self, weight: i8) -> Self { + pub fn with_weight(&mut self, weight: i8) -> &Self { self.weight = weight; self } - pub fn with_source(mut self, source: &str) -> Self { + pub fn with_source(&mut self, source: &str) -> &Self { self.source.with_value(source); self } - pub fn with_id(mut self, id: &str) -> Self { + pub fn with_id(&mut self, id: &str) -> &Self { self.id.with_value(id); self } - pub fn set_classes(mut self, classes: &str) -> Self { + pub fn set_classes(&mut self, classes: &str) -> &Self { self.classes.set_classes(classes); self } - pub fn add_classes(mut self, classes: &str) -> Self { + pub fn add_classes(&mut self, classes: &str) -> &Self { self.classes.add_classes(classes); self } - pub fn using_template(mut self, template: &str) -> Self { + pub fn using_template(&mut self, template: &str) -> &Self { self.template = template.to_owned(); self } From 93d6d455c8ecc8c37c4ac1c38cd9e859abcbdd0e Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Apr 2022 21:17:56 +0200 Subject: [PATCH 048/244] =?UTF-8?q?Actualiza=20y=20recupera=20definici?= =?UTF-8?q?=C3=B3n=20original=20de=20comp.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prácticamente se revierten los últimos cambios realizados en la estructura de componentes. --- pagetop-admin/src/summary.rs | 7 +-- pagetop-user/src/lib.rs | 14 ++--- pagetop/src/base/component/block.rs | 45 ++++++-------- pagetop/src/base/component/chunck.rs | 25 +++----- pagetop/src/base/component/container.rs | 46 +++++++------- pagetop/src/base/component/form/button.rs | 28 ++++----- pagetop/src/base/component/form/date.rs | 30 ++++----- pagetop/src/base/component/form/form.rs | 76 ++++++++++++----------- pagetop/src/base/component/form/hidden.rs | 13 ++-- pagetop/src/base/component/form/input.rs | 36 +++++------ pagetop/src/base/component/grid/column.rs | 42 +++++++------ pagetop/src/base/component/grid/row.rs | 32 +++++----- pagetop/src/base/component/image.rs | 18 +++--- pagetop/src/base/component/menu.rs | 20 +++--- pagetop/src/base/module/demopage/mod.rs | 28 ++++----- pagetop/src/base/theme/bootsier/mod.rs | 2 +- pagetop/src/response/page/component.rs | 9 --- pagetop/src/response/page/container.rs | 14 +++-- pagetop/src/response/page/mod.rs | 2 +- pagetop/src/response/page/page.rs | 4 +- pagetop/src/theme/definition.rs | 2 +- 21 files changed, 234 insertions(+), 259 deletions(-) diff --git a/pagetop-admin/src/summary.rs b/pagetop-admin/src/summary.rs index 6e6f2158..b91b97fa 100644 --- a/pagetop-admin/src/summary.rs +++ b/pagetop-admin/src/summary.rs @@ -38,18 +38,17 @@ pub async fn summary() -> app::Result<Markup> { .with_title("Admin") - .add_to("top-menu", top_menu.arc()) + .add_to("top-menu", top_menu) .add_to("content", grid::Row::new() .add_column(grid::Column::new() - .add(side_menu.arc()) + .add(side_menu) ) .add_column(grid::Column::new() .add(Chunck::with(html! { p { "Columna 2"} - }).arc()) + })) ) - .arc() ) diff --git a/pagetop-user/src/lib.rs b/pagetop-user/src/lib.rs index 06b0dd1a..c40057f0 100644 --- a/pagetop-user/src/lib.rs +++ b/pagetop-user/src/lib.rs @@ -31,8 +31,8 @@ impl ModuleTrait for UserModule { } } -fn form_login() -> ArcComponent { - Form::new()/* +fn form_login() -> Form { + Form::new() .with_id("user-login") .add(form::Input::textfield() .with_name("name") @@ -41,27 +41,23 @@ fn form_login() -> ArcComponent { "app" => SETTINGS.app.name.to_owned() ]).as_str()) .with_autofocus(true) - .arc() ) .add(form::Input::password() .with_name("pass") .with_label(l("password").as_str()) .with_help_text(l("password_help").as_str()) - .arc() ) - .add(form::Button::submit(l("login").as_str()).arc())*/ - .arc() + .add(form::Button::submit(l("login").as_str())) } async fn login() -> app::Result<Markup> { Page::new() .with_title( "Identificación del usuario" - )/* + ) .add_to("content", Container::new() .with_id("welcome") .add(form_login()) - .arc() - )*/ + ) .render() } diff --git a/pagetop/src/base/component/block.rs b/pagetop/src/base/component/block.rs index 64dd8d7c..99950286 100644 --- a/pagetop/src/base/component/block.rs +++ b/pagetop/src/base/component/block.rs @@ -3,8 +3,8 @@ use crate::prelude::*; pub struct Block { renderable: fn() -> bool, weight : i8, + components: PageContainer, title : OptAttr, - html : Vec<Markup>, id : OptIden, classes : Classes, template : String, @@ -15,8 +15,8 @@ impl PageComponent for Block { Block { renderable: always, weight : 0, + components: PageContainer::new(), title : OptAttr::none(), - html : Vec::new(), id : OptIden::none(), classes : Classes::none(), template : "default".to_owned(), @@ -40,9 +40,7 @@ impl PageComponent for Block { None => {} } div class="block-body" { - @for html in self.html().iter() { - (*html) - } + (self.components().render(assets)) } } } @@ -50,50 +48,51 @@ impl PageComponent for Block { } impl Block { - pub fn with(html: Markup) -> Self { - let mut block = Block::new(); - block.add(html); - block + + // Block CONTAINER. + + pub fn add(mut self, component: impl PageComponent) -> Self { + self.components.add(component); + self + } + + pub fn components(&self) -> &PageContainer { + &self.components } // Block BUILDER. - pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { self.renderable = renderable; self } - pub fn with_weight(&mut self, weight: i8) -> &Self { + pub fn with_weight(mut self, weight: i8) -> Self { self.weight = weight; self } - pub fn with_title(&mut self, title: &str) -> &Self { + pub fn with_title(mut self, title: &str) -> Self { self.title.with_value(title); self } - pub fn add(&mut self, html: Markup) -> &Self { - self.html.push(html); - self - } - - pub fn with_id(&mut self, id: &str) -> &Self { + pub fn with_id(mut self, id: &str) -> Self { self.id.with_value(id); self } - pub fn set_classes(&mut self, classes: &str) -> &Self { + pub fn set_classes(mut self, classes: &str) -> Self { self.classes.set_classes(classes); self } - pub fn add_classes(&mut self, classes: &str) -> &Self { + pub fn add_classes(mut self, classes: &str) -> Self { self.classes.add_classes(classes); self } - pub fn using_template(&mut self, template: &str) -> &Self { + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self } @@ -104,10 +103,6 @@ impl Block { self.title.option() } - pub fn html(&self) -> &Vec<Markup> { - &self.html - } - pub fn id(&self) -> &Option<String> { self.id.option() } diff --git a/pagetop/src/base/component/chunck.rs b/pagetop/src/base/component/chunck.rs index 7589ea4a..0e46c779 100644 --- a/pagetop/src/base/component/chunck.rs +++ b/pagetop/src/base/component/chunck.rs @@ -3,7 +3,7 @@ use crate::prelude::*; pub struct Chunck { renderable: fn() -> bool, weight : i8, - html : Vec<Markup>, + html : Markup, template : String, } @@ -12,7 +12,7 @@ impl PageComponent for Chunck { Chunck { renderable: always, weight : 0, - html : Vec::new(), + html : html! {}, template : "default".to_owned(), } } @@ -26,46 +26,37 @@ impl PageComponent for Chunck { } fn default_render(&self, _: &mut PageAssets) -> Markup { - html! { - @for html in self.html().iter() { - (*html) - } - } + html! { (*self.html()) } } } impl Chunck { pub fn with(html: Markup) -> Self { let mut chunck = Chunck::new(); - chunck.add(html); + chunck.html = html; chunck } // Chunck BUILDER. - pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { self.renderable = renderable; self } - pub fn with_weight(&mut self, weight: i8) -> &Self { + pub fn with_weight(mut self, weight: i8) -> Self { self.weight = weight; self } - pub fn add(&mut self, html: Markup) -> &Self { - self.html.push(html); - self - } - - pub fn using_template(&mut self, template: &str) -> &Self { + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self } // Chunck GETTERS. - pub fn html(&self) -> &Vec<Markup> { + pub fn html(&self) -> &Markup { &self.html } diff --git a/pagetop/src/base/component/container.rs b/pagetop/src/base/component/container.rs index 79f9b7a5..70162bb9 100644 --- a/pagetop/src/base/component/container.rs +++ b/pagetop/src/base/component/container.rs @@ -5,8 +5,8 @@ pub enum ContainerType { Header, Footer, Main, Section, Wrapper } pub struct Container { renderable: fn() -> bool, weight : i8, - container : ContainerType, components: PageContainer, + container : ContainerType, id : OptIden, classes : Classes, template : String, @@ -17,8 +17,8 @@ impl PageComponent for Container { Container { renderable: always, weight : 0, - container : ContainerType::Wrapper, components: PageContainer::new(), + container : ContainerType::Wrapper, id : OptIden::none(), classes : Classes::none(), template : "default".to_owned(), @@ -97,39 +97,45 @@ impl Container { c } - // Container BUILDER. + // Container CONTAINER. - pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { - self.renderable = renderable; - self - } - - pub fn with_weight(&mut self, weight: i8) -> &Self { - self.weight = weight; - self - } - - pub fn add(mut self, component: ArcComponent) -> Self { + pub fn add(mut self, component: impl PageComponent) -> Self { self.components.add(component); self } - pub fn with_id(&mut self, id: &str) -> &Self { + pub fn components(&self) -> &PageContainer { + &self.components + } + + // Container BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_id(mut self, id: &str) -> Self { self.id.with_value(id); self } - pub fn set_classes(&mut self, classes: &str) -> &Self { + pub fn set_classes(mut self, classes: &str) -> Self { self.classes.set_classes(classes); self } - pub fn add_classes(&mut self, classes: &str) -> &Self { + pub fn add_classes(mut self, classes: &str) -> Self { self.classes.add_classes(classes); self } - pub fn using_template(&mut self, template: &str) -> &Self { + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self } @@ -140,10 +146,6 @@ impl Container { &self.container } - pub fn components(&self) -> &PageContainer { - &self.components - } - pub fn id(&self) -> &Option<String> { self.id.option() } diff --git a/pagetop/src/base/component/form/button.rs b/pagetop/src/base/component/form/button.rs index f6fd474d..f99f06d3 100644 --- a/pagetop/src/base/component/form/button.rs +++ b/pagetop/src/base/component/form/button.rs @@ -68,48 +68,44 @@ impl PageComponent for Button { impl Button { pub fn button(value: &str) -> Self { - let mut button = Button::new(); - button.with_value(value); - button + Button::new().with_value(value) } pub fn reset(value: &str) -> Self { - let mut button = Button::new(); - button.with_value(value); + let mut button = Button::new().with_value(value); button.button_type = ButtonType::Reset; button } pub fn submit(value: &str) -> Self { - let mut button = Button::new(); - button.with_value(value); + let mut button = Button::new().with_value(value); button.button_type = ButtonType::Submit; button } // Button BUILDER. - pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { self.renderable = renderable; self } - pub fn with_weight(&mut self, weight: i8) -> &Self { + pub fn with_weight(mut self, weight: i8) -> Self { self.weight = weight; self } - pub fn with_name(&mut self, name: &str) -> &Self { + pub fn with_name(mut self, name: &str) -> Self { self.name.with_value(name); self } - pub fn with_value(&mut self, value: &str) -> &Self { + pub fn with_value(mut self, value: &str) -> Self { self.value.with_value(value); self } - pub fn with_autofocus(&mut self, toggle: bool) -> &Self { + pub fn with_autofocus(mut self, toggle: bool) -> Self { self.autofocus.with_value(match toggle { true => "autofocus", false => "", @@ -117,7 +113,7 @@ impl Button { self } - pub fn with_disabled(&mut self, toggle: bool) -> &Self { + pub fn with_disabled(mut self, toggle: bool) -> Self { self.disabled.with_value(match toggle { true => "disabled", false => "", @@ -125,17 +121,17 @@ impl Button { self } - pub fn set_classes(&mut self, classes: &str) -> &Self { + pub fn set_classes(mut self, classes: &str) -> Self { self.classes.set_classes(classes); self } - pub fn add_classes(&mut self, classes: &str) -> &Self { + pub fn add_classes(mut self, classes: &str) -> Self { self.classes.add_classes(classes); self } - pub fn using_template(&mut self, template: &str) -> &Self { + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self } diff --git a/pagetop/src/base/component/form/date.rs b/pagetop/src/base/component/form/date.rs index bc355a2a..40c2f784 100644 --- a/pagetop/src/base/component/form/date.rs +++ b/pagetop/src/base/component/form/date.rs @@ -95,37 +95,37 @@ impl Date { // Date BUILDER. - pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { self.renderable = renderable; self } - pub fn with_weight(&mut self, weight: i8) -> &Self { + pub fn with_weight(mut self, weight: i8) -> Self { self.weight = weight; self } - pub fn with_name(&mut self, name: &str) -> &Self { + pub fn with_name(mut self, name: &str) -> Self { self.name.with_value(name); self } - pub fn with_value(&mut self, value: &str) -> &Self { + pub fn with_value(mut self, value: &str) -> Self { self.value.with_value(value); self } - pub fn with_label(&mut self, label: &str) -> &Self { + pub fn with_label(mut self, label: &str) -> Self { self.label.with_value(label); self } - pub fn with_placeholder(&mut self, placeholder: &str) -> &Self { + pub fn with_placeholder(mut self, placeholder: &str) -> Self { self.placeholder.with_value(placeholder); self } - pub fn with_autofocus(&mut self, toggle: bool) -> &Self { + pub fn with_autofocus(mut self, toggle: bool) -> Self { self.autofocus.with_value(match toggle { true => "autofocus", false => "", @@ -133,7 +133,7 @@ impl Date { self } - pub fn with_autocomplete(&mut self, toggle: bool) -> &Self { + pub fn with_autocomplete(mut self, toggle: bool) -> Self { self.autocomplete.with_value(match toggle { true => "", false => "off", @@ -141,7 +141,7 @@ impl Date { self } - pub fn with_disabled(&mut self, toggle: bool) -> &Self { + pub fn with_disabled(mut self, toggle: bool) -> Self { self.disabled.with_value(match toggle { true => "disabled", false => "", @@ -149,7 +149,7 @@ impl Date { self } - pub fn with_readonly(&mut self, toggle: bool) -> &Self { + pub fn with_readonly(mut self, toggle: bool) -> Self { self.readonly.with_value(match toggle { true => "readonly", false => "", @@ -157,7 +157,7 @@ impl Date { self } - pub fn with_required(&mut self, toggle: bool) -> &Self { + pub fn with_required(mut self, toggle: bool) -> Self { self.required.with_value(match toggle { true => "required", false => "", @@ -165,22 +165,22 @@ impl Date { self } - pub fn with_help_text(&mut self, help_text: &str) -> &Self { + pub fn with_help_text(mut self, help_text: &str) -> Self { self.help_text.with_value(help_text); self } - pub fn set_classes(&mut self, classes: &str) -> &Self { + pub fn set_classes(mut self, classes: &str) -> Self { self.classes.set_classes(classes); self } - pub fn add_classes(&mut self, classes: &str) -> &Self { + pub fn add_classes(mut self, classes: &str) -> Self { self.classes.add_classes(classes); self } - pub fn using_template(&mut self, template: &str) -> &Self { + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self } diff --git a/pagetop/src/base/component/form/form.rs b/pagetop/src/base/component/form/form.rs index 3685d9a1..07cb6e17 100644 --- a/pagetop/src/base/component/form/form.rs +++ b/pagetop/src/base/component/form/form.rs @@ -5,10 +5,10 @@ pub enum FormMethod {Get, Post} pub struct Form { renderable: fn() -> bool, weight : i8, + elements : PageContainer, action : OptAttr, charset : OptAttr, method : FormMethod, - elements : PageContainer, id : OptIden, classes : Classes, template : String, @@ -19,10 +19,10 @@ impl PageComponent for Form { Form { renderable: always, weight : 0, + elements : PageContainer::new(), action : OptAttr::none(), charset : OptAttr::some("UTF-8"), method : FormMethod::Post, - elements : PageContainer::new(), id : OptIden::none(), classes : Classes::none(), template : "default".to_owned(), @@ -58,54 +58,60 @@ impl PageComponent for Form { impl Form { - // Form BUILDER. + // Form CONTAINER. - pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { - self.renderable = renderable; - self - } - - pub fn with_weight(&mut self, weight: i8) -> &Self { - self.weight = weight; - self - } - - pub fn with_action(&mut self, action: &str) -> &Self { - self.action.with_value(action); - self - } - - pub fn with_charset(&mut self, charset: &str) -> &Self { - self.charset.with_value(charset); - self - } - - pub fn with_method(&mut self, method: FormMethod) -> &Self { - self.method = method; - self - } - - pub fn add(mut self, element: ArcComponent) -> Self { + pub fn add(mut self, element: impl PageComponent) -> Self { self.elements.add(element); self } - pub fn with_id(&mut self, id: &str) -> &Self { + pub fn elements(&self) -> &PageContainer { + &self.elements + } + + // Form BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_action(mut self, action: &str) -> Self { + self.action.with_value(action); + self + } + + pub fn with_charset(mut self, charset: &str) -> Self { + self.charset.with_value(charset); + self + } + + pub fn with_method(mut self, method: FormMethod) -> Self { + self.method = method; + self + } + + pub fn with_id(mut self, id: &str) -> Self { self.id.with_value(id); self } - pub fn set_classes(&mut self, classes: &str) -> &Self { + pub fn set_classes(mut self, classes: &str) -> Self { self.classes.set_classes(classes); self } - pub fn add_classes(&mut self, classes: &str) -> &Self { + pub fn add_classes(mut self, classes: &str) -> Self { self.classes.add_classes(classes); self } - pub fn using_template(&mut self, template: &str) -> &Self { + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self } @@ -124,10 +130,6 @@ impl Form { &self.method } - pub fn elements(&self) -> &PageContainer { - &self.elements - } - pub fn id(&self) -> &Option<String> { self.id.option() } diff --git a/pagetop/src/base/component/form/hidden.rs b/pagetop/src/base/component/form/hidden.rs index 0e6e56c3..8f2cc4b3 100644 --- a/pagetop/src/base/component/form/hidden.rs +++ b/pagetop/src/base/component/form/hidden.rs @@ -32,25 +32,24 @@ impl PageComponent for Hidden { impl Hidden { pub fn set(name: &str, value: &str) -> Self { - let mut hidden = Hidden::new(); - hidden.with_name(name); - hidden.with_value(value); - hidden + Hidden::new() + .with_name(name) + .with_value(value) } // Hidden BUILDER. - pub fn with_weight(&mut self, weight: i8) -> &Self { + pub fn with_weight(mut self, weight: i8) -> Self { self.weight = weight; self } - pub fn with_name(&mut self, name: &str) -> &Self { + pub fn with_name(mut self, name: &str) -> Self { self.name.with_value(name); self } - pub fn with_value(&mut self, value: &str) -> &Self { + pub fn with_value(mut self, value: &str) -> Self { self.value.with_value(value); self } diff --git a/pagetop/src/base/component/form/input.rs b/pagetop/src/base/component/form/input.rs index c468cdfe..9d6e1afd 100644 --- a/pagetop/src/base/component/form/input.rs +++ b/pagetop/src/base/component/form/input.rs @@ -149,52 +149,52 @@ impl Input { // Input BUILDER. - pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { self.renderable = renderable; self } - pub fn with_weight(&mut self, weight: i8) -> &Self { + pub fn with_weight(mut self, weight: i8) -> Self { self.weight = weight; self } - pub fn with_name(&mut self, name: &str) -> &Self { + pub fn with_name(mut self, name: &str) -> Self { self.name.with_value(name); self } - pub fn with_value(&mut self, value: &str) -> &Self { + pub fn with_value(mut self, value: &str) -> Self { self.value.with_value(value); self } - pub fn with_label(&mut self, label: &str) -> &Self { + pub fn with_label(mut self, label: &str) -> Self { self.label.with_value(label); self } - pub fn with_size(&mut self, size: Option<u16>) -> &Self { + pub fn with_size(mut self, size: Option<u16>) -> Self { self.size = size; self } - pub fn with_minlength(&mut self, minlength: Option<u16>) -> &Self { + pub fn with_minlength(mut self, minlength: Option<u16>) -> Self { self.minlength = minlength; self } - pub fn with_maxlength(&mut self, maxlength: Option<u16>) -> &Self { + pub fn with_maxlength(mut self, maxlength: Option<u16>) -> Self { self.maxlength = maxlength; self } - pub fn with_placeholder(&mut self, placeholder: &str) -> &Self { + pub fn with_placeholder(mut self, placeholder: &str) -> Self { self.placeholder.with_value(placeholder); self } - pub fn with_autofocus(&mut self, toggle: bool) -> &Self { + pub fn with_autofocus(mut self, toggle: bool) -> Self { self.autofocus.with_value(match toggle { true => "autofocus", false => "", @@ -202,7 +202,7 @@ impl Input { self } - pub fn with_autocomplete(&mut self, toggle: bool) -> &Self { + pub fn with_autocomplete(mut self, toggle: bool) -> Self { self.autocomplete.with_value(match toggle { true => "", false => "off", @@ -210,7 +210,7 @@ impl Input { self } - pub fn with_disabled(&mut self, toggle: bool) -> &Self { + pub fn with_disabled(mut self, toggle: bool) -> Self { self.disabled.with_value(match toggle { true => "disabled", false => "", @@ -218,7 +218,7 @@ impl Input { self } - pub fn with_readonly(&mut self, toggle: bool) -> &Self { + pub fn with_readonly(mut self, toggle: bool) -> Self { self.readonly.with_value(match toggle { true => "readonly", false => "", @@ -226,7 +226,7 @@ impl Input { self } - pub fn with_required(&mut self, toggle: bool) -> &Self { + pub fn with_required(mut self, toggle: bool) -> Self { self.required.with_value(match toggle { true => "required", false => "", @@ -234,22 +234,22 @@ impl Input { self } - pub fn with_help_text(&mut self, help_text: &str) -> &Self { + pub fn with_help_text(mut self, help_text: &str) -> Self { self.help_text.with_value(help_text); self } - pub fn set_classes(&mut self, classes: &str) -> &Self { + pub fn set_classes(mut self, classes: &str) -> Self { self.classes.set_classes(classes); self } - pub fn add_classes(&mut self, classes: &str) -> &Self { + pub fn add_classes(mut self, classes: &str) -> Self { self.classes.add_classes(classes); self } - pub fn using_template(&mut self, template: &str) -> &Self { + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self } diff --git a/pagetop/src/base/component/grid/column.rs b/pagetop/src/base/component/grid/column.rs index e4e5525a..f29544ca 100644 --- a/pagetop/src/base/component/grid/column.rs +++ b/pagetop/src/base/component/grid/column.rs @@ -44,49 +44,51 @@ impl PageComponent for Column { impl Column { - // Column BUILDER. + // Column CONTAINER. - pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { - self.renderable = renderable; - self - } - - pub fn with_weight(&mut self, weight: i8) -> &Self { - self.weight = weight; - self - } - - pub fn add(mut self, component: ArcComponent) -> Self { + pub fn add(mut self, component: impl PageComponent) -> Self { self.components.add(component); self } - pub fn with_id(&mut self, id: &str) -> &Self { + pub fn components(&self) -> &PageContainer { + &self.components + } + + // Column BUILDER. + + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { + self.renderable = renderable; + self + } + + pub fn with_weight(mut self, weight: i8) -> Self { + self.weight = weight; + self + } + + pub fn with_id(mut self, id: &str) -> Self { self.id.with_value(id); self } - pub fn set_classes(&mut self, classes: &str) -> &Self { + pub fn set_classes(mut self, classes: &str) -> Self { self.classes.set_classes(classes); self } - pub fn add_classes(&mut self, classes: &str) -> &Self { + pub fn add_classes(mut self, classes: &str) -> Self { self.classes.add_classes(classes); self } - pub fn using_template(&mut self, template: &str) -> &Self { + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self } // Column GETTERS. - pub fn components(&self) -> &PageContainer { - &self.components - } - pub fn id(&self) -> &Option<String> { self.id.option() } diff --git a/pagetop/src/base/component/grid/row.rs b/pagetop/src/base/component/grid/row.rs index 30a5f351..59645b79 100644 --- a/pagetop/src/base/component/grid/row.rs +++ b/pagetop/src/base/component/grid/row.rs @@ -44,49 +44,51 @@ impl PageComponent for Row { impl Row { + // Row CONTAINER. + + pub fn add_column(mut self, column: grid::Column) -> Self { + self.columns.add(column); + self + } + + pub fn columns(&self) -> &PageContainer { + &self.columns + } + // Row BUILDER. - pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { self.renderable = renderable; self } - pub fn with_weight(&mut self, weight: i8) -> &Self { + pub fn with_weight(mut self, weight: i8) -> Self { self.weight = weight; self } - pub fn add_column(mut self, column: grid::Column) -> Self { - self.columns.add(column.arc()); - self - } - - pub fn with_id(&mut self, id: &str) -> &Self { + pub fn with_id(mut self, id: &str) -> Self { self.id.with_value(id); self } - pub fn set_classes(&mut self, classes: &str) -> &Self { + pub fn set_classes(mut self, classes: &str) -> Self { self.classes.set_classes(classes); self } - pub fn add_classes(&mut self, classes: &str) -> &Self { + pub fn add_classes(mut self, classes: &str) -> Self { self.classes.add_classes(classes); self } - pub fn using_template(&mut self, template: &str) -> &Self { + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self } // Row GETTERS. - pub fn columns(&self) -> &PageContainer { - &self.columns - } - pub fn id(&self) -> &Option<String> { self.id.option() } diff --git a/pagetop/src/base/component/image.rs b/pagetop/src/base/component/image.rs index 30cca8f3..1384f4df 100644 --- a/pagetop/src/base/component/image.rs +++ b/pagetop/src/base/component/image.rs @@ -41,44 +41,42 @@ impl PageComponent for Image { impl Image { pub fn image(source: &str) -> Self { - let mut image = Image::new(); - image.with_source(source); - image + Image::new().with_source(source) } // Image BUILDER. - pub fn with_renderable(&mut self, renderable: fn() -> bool) -> &Self { + pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { self.renderable = renderable; self } - pub fn with_weight(&mut self, weight: i8) -> &Self { + pub fn with_weight(mut self, weight: i8) -> Self { self.weight = weight; self } - pub fn with_source(&mut self, source: &str) -> &Self { + pub fn with_source(mut self, source: &str) -> Self { self.source.with_value(source); self } - pub fn with_id(&mut self, id: &str) -> &Self { + pub fn with_id(mut self, id: &str) -> Self { self.id.with_value(id); self } - pub fn set_classes(&mut self, classes: &str) -> &Self { + pub fn set_classes(mut self, classes: &str) -> Self { self.classes.set_classes(classes); self } - pub fn add_classes(&mut self, classes: &str) -> &Self { + pub fn add_classes(mut self, classes: &str) -> Self { self.classes.add_classes(classes); self } - pub fn using_template(&mut self, template: &str) -> &Self { + pub fn using_template(mut self, template: &str) -> Self { self.template = template.to_owned(); self } diff --git a/pagetop/src/base/component/menu.rs b/pagetop/src/base/component/menu.rs index 3f2b4ff4..01a60129 100644 --- a/pagetop/src/base/component/menu.rs +++ b/pagetop/src/base/component/menu.rs @@ -209,6 +209,17 @@ impl PageComponent for Menu { impl Menu { + // Menu CONTAINER. + + pub fn add(mut self, item: MenuItem) -> Self { + self.items.add(item); + self + } + + pub fn items(&self) -> &PageContainer { + &self.items + } + // Menu BUILDER. pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { @@ -221,11 +232,6 @@ impl Menu { self } - pub fn add(mut self, item: MenuItem) -> Self { - self.items.add(item.arc()); - self - } - pub fn with_id(mut self, id: &str) -> Self { self.id.with_value(id); self @@ -248,10 +254,6 @@ impl Menu { // Menu GETTERS. - pub fn items(&self) -> &PageContainer { - &self.items - } - pub fn id(&self) -> &Option<String> { self.id.option() } diff --git a/pagetop/src/base/module/demopage/mod.rs b/pagetop/src/base/module/demopage/mod.rs index d71c7176..489b6d3b 100644 --- a/pagetop/src/base/module/demopage/mod.rs +++ b/pagetop/src/base/module/demopage/mod.rs @@ -35,7 +35,7 @@ async fn demo() -> app::Result<Markup> { .render() } -fn hello_world() -> ArcComponent { +fn hello_world() -> Container { Container::header() .add(grid::Row::new() .add_column(grid::Column::new() @@ -68,17 +68,15 @@ fn hello_world() -> ArcComponent { i class="fas fa-paper-plane" {} "Get quote" } - }).arc()) + })) ) .add_column(grid::Column::new() - .add(Image::image("/bootsier/images/demo-header.svg").arc()) + .add(Image::image("/bootsier/images/demo-header.svg")) ) - .arc() ) - .arc() } -fn hello_world_original() -> ArcComponent { +fn hello_world_original() -> Chunck { Chunck::with(html! { header id="header" class="header" { div class="container" { @@ -123,10 +121,10 @@ fn hello_world_original() -> ArcComponent { } } } - }).arc() + }) } -fn just_visiting() -> ArcComponent { +fn just_visiting() -> Chunck { Chunck::with(html! { div id="details" class="basic-1" { div class="container" { @@ -153,10 +151,10 @@ fn just_visiting() -> ArcComponent { } } } - }).arc() + }) } -fn about_pagetop() -> ArcComponent { +fn about_pagetop() -> Chunck { Chunck::with(html! { div id="pagetop" class="basic-2" { div class="container" { @@ -177,10 +175,10 @@ fn about_pagetop() -> ArcComponent { } } } - }).arc() + }) } -fn promo_pagetop() -> ArcComponent { +fn promo_pagetop() -> Chunck { Chunck::with(html! { div id="promo" class="basic-3" { div class="container" { @@ -202,10 +200,10 @@ fn promo_pagetop() -> ArcComponent { } } } - }).arc() + }) } -fn reporting_problems() -> ArcComponent { +fn reporting_problems() -> Chunck { Chunck::with(html! { div id="reporting" class="basic-4" { div class="container" { @@ -225,5 +223,5 @@ fn reporting_problems() -> ArcComponent { } } } - }).arc() + }) } diff --git a/pagetop/src/base/theme/bootsier/mod.rs b/pagetop/src/base/theme/bootsier/mod.rs index b169351d..90111723 100644 --- a/pagetop/src/base/theme/bootsier/mod.rs +++ b/pagetop/src/base/theme/bootsier/mod.rs @@ -77,7 +77,7 @@ impl ThemeTrait for BootsierTheme { } } } - }).arc()) + })) .render() } } diff --git a/pagetop/src/response/page/component.rs b/pagetop/src/response/page/component.rs index b9a920d3..630b8a9b 100644 --- a/pagetop/src/response/page/component.rs +++ b/pagetop/src/response/page/component.rs @@ -3,11 +3,8 @@ use crate::response::page::PageAssets; use downcast_rs::{Downcast, impl_downcast}; -use std::sync::Arc; use std::any::type_name; -pub type ArcComponent = Arc<dyn PageComponent>; - pub trait PageComponent: Downcast + Send + Sync { fn new() -> Self where Self: Sized; @@ -36,12 +33,6 @@ pub trait PageComponent: Downcast + Send + Sync { 0 } - #[allow(unused_mut)] - fn arc(mut self) -> ArcComponent where Self: Sized { - let component = self; - Arc::new(component) - } - #[allow(unused_variables)] fn default_render(&self, assets: &mut PageAssets) -> Markup { html! {} diff --git a/pagetop/src/response/page/container.rs b/pagetop/src/response/page/container.rs index 7e5d4953..011e5f50 100644 --- a/pagetop/src/response/page/container.rs +++ b/pagetop/src/response/page/container.rs @@ -1,22 +1,24 @@ use crate::html::{Markup, html}; -use crate::response::page::{ArcComponent, PageAssets, render_component}; +use crate::response::page::{PageAssets, PageComponent, render_component}; + +use std::sync::Arc; #[derive(Clone)] -pub struct PageContainer(Vec<ArcComponent>); +pub struct PageContainer(Vec<Arc<dyn PageComponent>>); impl PageContainer { pub fn new() -> Self { PageContainer(Vec::new()) } - pub fn new_with(component: ArcComponent) -> Self { + pub fn new_with(component: impl PageComponent) -> Self { let mut container = PageContainer::new(); container.add(component); container } - pub fn add(&mut self, component: ArcComponent) { - self.0.push(component); + pub fn add(&mut self, component: impl PageComponent) { + self.0.push(Arc::new(component)); } pub fn render(&self, assets: &mut PageAssets) -> Markup { @@ -28,4 +30,4 @@ impl PageContainer { } } } -} \ No newline at end of file +} diff --git a/pagetop/src/response/page/mod.rs b/pagetop/src/response/page/mod.rs index 63c19a47..f34070e2 100644 --- a/pagetop/src/response/page/mod.rs +++ b/pagetop/src/response/page/mod.rs @@ -7,7 +7,7 @@ pub use assets::{ }; mod component; -pub use component::{ArcComponent, PageComponent}; +pub use component::PageComponent; mod container; pub use container::PageContainer; diff --git a/pagetop/src/response/page/page.rs b/pagetop/src/response/page/page.rs index 5cbe80cb..5501678a 100644 --- a/pagetop/src/response/page/page.rs +++ b/pagetop/src/response/page/page.rs @@ -100,7 +100,7 @@ impl<'a> Page<'a> { pub fn add_to( &mut self, region: &'a str, - component: ArcComponent + component: impl PageComponent ) -> &mut Self { if let Some(regions) = self.regions.get_mut(region) { regions.add(component); @@ -205,7 +205,7 @@ pub fn render_component( } } -pub fn add_component_to(region: &'static str, component: ArcComponent) { +pub fn add_component_to(region: &'static str, component: impl PageComponent) { let mut hmap = COMPONENTS.write().unwrap(); if let Some(regions) = hmap.get_mut(region) { regions.add(component); diff --git a/pagetop/src/theme/definition.rs b/pagetop/src/theme/definition.rs index db4c0e37..acc30f47 100644 --- a/pagetop/src/theme/definition.rs +++ b/pagetop/src/theme/definition.rs @@ -104,7 +104,7 @@ pub trait ThemeTrait: Send + Sync { div { h1 { (s) } } - }).arc()) + })) .render() } } From e11b36f7edb97c1fcc355b111884ebc2e819362e Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Apr 2022 23:54:38 +0200 Subject: [PATCH 049/244] Mejora el uso de referencias en los componentes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sin embargo requiere duplicar todos los métodos para recibir una referencia mutable a self en uno y directamente self en otro. --- pagetop/src/base/component/grid/row.rs | 5 +++++ pagetop/src/base/theme/bulmix/mod.rs | 8 ++++++-- pagetop/src/response/page/container.rs | 10 +++++----- pagetop/src/response/page/page.rs | 2 +- pagetop/src/theme/definition.rs | 2 +- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/pagetop/src/base/component/grid/row.rs b/pagetop/src/base/component/grid/row.rs index 59645b79..96d74afc 100644 --- a/pagetop/src/base/component/grid/row.rs +++ b/pagetop/src/base/component/grid/row.rs @@ -77,6 +77,11 @@ impl Row { self } + pub fn set_classes_ref(&mut self, classes: &str) -> &Self { + self.classes.set_classes(classes); + self + } + pub fn add_classes(mut self, classes: &str) -> Self { self.classes.add_classes(classes); self diff --git a/pagetop/src/base/theme/bulmix/mod.rs b/pagetop/src/base/theme/bulmix/mod.rs index 284353c1..cf83a8f6 100644 --- a/pagetop/src/base/theme/bulmix/mod.rs +++ b/pagetop/src/base/theme/bulmix/mod.rs @@ -34,17 +34,21 @@ impl ThemeTrait for BulmixTheme { fn render_component( &self, - component: &dyn PageComponent, + component: &mut dyn PageComponent, assets: &mut PageAssets ) -> Option<Markup> { match component.name() { "GridRow" => { - let row = component.downcast_ref::<grid::Row>().unwrap(); + let row = component.downcast_mut::<grid::Row>().unwrap(); + row.set_classes_ref("Prueba"); + None + /* Some(html! { div id=[row.id()] class=[row.classes("columns")] { (row.columns().render(assets)) } }) + */ }, "GridColumn" => { let col = component.downcast_ref::<grid::Column>().unwrap(); diff --git a/pagetop/src/response/page/container.rs b/pagetop/src/response/page/container.rs index 011e5f50..2e052ee9 100644 --- a/pagetop/src/response/page/container.rs +++ b/pagetop/src/response/page/container.rs @@ -1,10 +1,10 @@ use crate::html::{Markup, html}; use crate::response::page::{PageAssets, PageComponent, render_component}; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; #[derive(Clone)] -pub struct PageContainer(Vec<Arc<dyn PageComponent>>); +pub struct PageContainer(Vec<Arc<RwLock<dyn PageComponent>>>); impl PageContainer { pub fn new() -> Self { @@ -18,15 +18,15 @@ impl PageContainer { } pub fn add(&mut self, component: impl PageComponent) { - self.0.push(Arc::new(component)); + self.0.push(Arc::new(RwLock::new(component))); } pub fn render(&self, assets: &mut PageAssets) -> Markup { let mut components = self.0.clone(); - components.sort_by_key(|c| c.weight()); + components.sort_by_key(|c| c.read().unwrap().weight()); html! { @for c in components.iter() { - (render_component(&**c, assets)) + (render_component(&mut *c.write().unwrap(), assets)) } } } diff --git a/pagetop/src/response/page/page.rs b/pagetop/src/response/page/page.rs index 5501678a..56db5ecc 100644 --- a/pagetop/src/response/page/page.rs +++ b/pagetop/src/response/page/page.rs @@ -193,7 +193,7 @@ impl<'a> Page<'a> { } pub fn render_component( - component: &dyn PageComponent, + component: &mut dyn PageComponent, assets: &mut PageAssets ) -> Markup { match component.is_renderable() { diff --git a/pagetop/src/theme/definition.rs b/pagetop/src/theme/definition.rs index acc30f47..457860c7 100644 --- a/pagetop/src/theme/definition.rs +++ b/pagetop/src/theme/definition.rs @@ -77,7 +77,7 @@ pub trait ThemeTrait: Send + Sync { #[allow(unused_variables)] fn render_component( &self, - component: &dyn PageComponent, + component: &mut dyn PageComponent, assets: &mut PageAssets ) -> Option<Markup> { None From ba4cc982befeb57d844fe28e954687b50826beba Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 9 Apr 2022 18:40:44 +0200 Subject: [PATCH 050/244] =?UTF-8?q?A=C3=B1ade=20alteraci=C3=B3n=20de=20com?= =?UTF-8?q?ponentes=20antes=20del=20render?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Los componentes implementan a la vez el paradigma "builder" y la modificación por "setters" para poder ser modificados durante la creación de la página o alterados antes de ser renderizados. --- pagetop/src/base/component/block.rs | 67 ++++--- pagetop/src/base/component/chunck.rs | 41 +++-- pagetop/src/base/component/container.rs | 114 +++++++----- pagetop/src/base/component/form/button.rs | 102 +++++++---- pagetop/src/base/component/form/date.rs | 152 +++++++++++----- pagetop/src/base/component/form/form.rs | 83 ++++++--- pagetop/src/base/component/form/hidden.rs | 29 ++- pagetop/src/base/component/form/input.rs | 209 +++++++++++++++------- pagetop/src/base/component/grid/column.rs | 58 +++--- pagetop/src/base/component/grid/row.rs | 63 ++++--- pagetop/src/base/component/image.rs | 67 ++++--- pagetop/src/base/component/menu.rs | 86 ++++++--- pagetop/src/base/theme/bulmix/mod.rs | 26 +-- pagetop/src/html/classes.rs | 83 +++++++-- pagetop/src/html/mod.rs | 2 +- pagetop/src/html/optattr.rs | 10 +- pagetop/src/html/optiden.rs | 12 +- pagetop/src/response/page/assets.rs | 2 +- pagetop/src/response/page/component.rs | 4 + pagetop/src/response/page/mod.rs | 3 + pagetop/src/response/page/page.rs | 44 +++-- pagetop/src/theme/definition.rs | 27 ++- 22 files changed, 872 insertions(+), 412 deletions(-) diff --git a/pagetop/src/base/component/block.rs b/pagetop/src/base/component/block.rs index 99950286..86370ff4 100644 --- a/pagetop/src/base/component/block.rs +++ b/pagetop/src/base/component/block.rs @@ -13,12 +13,12 @@ pub struct Block { impl PageComponent for Block { fn new() -> Self { Block { - renderable: always, + renderable: render_always, weight : 0, components: PageContainer::new(), - title : OptAttr::none(), - id : OptIden::none(), - classes : Classes::none(), + title : OptAttr::new(), + id : OptIden::new(), + classes : Classes::new_with_default("block"), template : "default".to_owned(), } } @@ -34,7 +34,7 @@ impl PageComponent for Block { fn default_render(&self, assets: &mut PageAssets) -> Markup { let id = assets.serial_id(self.name(), self.id()); html! { - div id=(id) class=[self.classes("block")] { + div id=(id) class=[self.classes()] { @match self.title() { Some(title) => h2 class="block-title" { (title) }, None => {} @@ -63,36 +63,63 @@ impl Block { // Block BUILDER. pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { - self.renderable = renderable; + self.alter_renderable(renderable); self } pub fn with_weight(mut self, weight: i8) -> Self { - self.weight = weight; + self.alter_weight(weight); self } pub fn with_title(mut self, title: &str) -> Self { - self.title.with_value(title); + self.alter_title(title); self } pub fn with_id(mut self, id: &str) -> Self { - self.id.with_value(id); + self.alter_id(id); self } - pub fn set_classes(mut self, classes: &str) -> Self { - self.classes.set_classes(classes); - self - } - - pub fn add_classes(mut self, classes: &str) -> Self { - self.classes.add_classes(classes); + pub fn with_classes(mut self, classes: &str, op: ClassesOp) -> Self { + self.alter_classes(classes, op); self } pub fn using_template(mut self, template: &str) -> Self { + self.alter_template(template); + self + } + + // Block ALTER. + + pub fn alter_renderable(&mut self, renderable: fn() -> bool) -> &mut Self { + self.renderable = renderable; + self + } + + pub fn alter_weight(&mut self, weight: i8) -> &mut Self { + self.weight = weight; + self + } + + pub fn alter_title(&mut self, title: &str) -> &mut Self { + self.title.with_value(title); + self + } + + pub fn alter_id(&mut self, id: &str) -> &mut Self { + self.id.with_value(id); + self + } + + pub fn alter_classes(&mut self, classes: &str, op: ClassesOp) -> &mut Self { + self.classes.alter(classes, op); + self + } + + pub fn alter_template(&mut self, template: &str) -> &mut Self { self.template = template.to_owned(); self } @@ -107,15 +134,11 @@ impl Block { self.id.option() } - pub fn classes(&self, default: &str) -> Option<String> { - self.classes.option(default) + pub fn classes(&self) -> &Option<String> { + self.classes.option() } pub fn template(&self) -> &str { self.template.as_str() } } - -fn always() -> bool { - true -} diff --git a/pagetop/src/base/component/chunck.rs b/pagetop/src/base/component/chunck.rs index 0e46c779..6dbc0ff1 100644 --- a/pagetop/src/base/component/chunck.rs +++ b/pagetop/src/base/component/chunck.rs @@ -10,7 +10,7 @@ pub struct Chunck { impl PageComponent for Chunck { fn new() -> Self { Chunck { - renderable: always, + renderable: render_always, weight : 0, html : html! {}, template : "default".to_owned(), @@ -32,24 +32,49 @@ impl PageComponent for Chunck { impl Chunck { pub fn with(html: Markup) -> Self { - let mut chunck = Chunck::new(); - chunck.html = html; - chunck + Chunck::new().with_html(html) } // Chunck BUILDER. pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { - self.renderable = renderable; + self.alter_renderable(renderable); self } pub fn with_weight(mut self, weight: i8) -> Self { - self.weight = weight; + self.alter_weight(weight); + self + } + + pub fn with_html(mut self, html: Markup) -> Self { + self.alter_html(html); self } pub fn using_template(mut self, template: &str) -> Self { + self.alter_template(template); + self + } + + // Chunck ALTER. + + pub fn alter_renderable(&mut self, renderable: fn() -> bool) -> &mut Self { + self.renderable = renderable; + self + } + + pub fn alter_weight(&mut self, weight: i8) -> &mut Self { + self.weight = weight; + self + } + + pub fn alter_html(&mut self, html: Markup) -> &mut Self { + self.html = html; + self + } + + pub fn alter_template(&mut self, template: &str) -> &mut Self { self.template = template.to_owned(); self } @@ -64,7 +89,3 @@ impl Chunck { self.template.as_str() } } - -fn always() -> bool { - true -} diff --git a/pagetop/src/base/component/container.rs b/pagetop/src/base/component/container.rs index 70162bb9..fab8225a 100644 --- a/pagetop/src/base/component/container.rs +++ b/pagetop/src/base/component/container.rs @@ -3,25 +3,27 @@ use crate::prelude::*; pub enum ContainerType { Header, Footer, Main, Section, Wrapper } pub struct Container { - renderable: fn() -> bool, - weight : i8, - components: PageContainer, - container : ContainerType, - id : OptIden, - classes : Classes, - template : String, + renderable : fn() -> bool, + weight : i8, + components : PageContainer, + container : ContainerType, + id : OptIden, + classes : Classes, + inner_classes: Classes, + template : String, } impl PageComponent for Container { fn new() -> Self { Container { - renderable: always, - weight : 0, - components: PageContainer::new(), - container : ContainerType::Wrapper, - id : OptIden::none(), - classes : Classes::none(), - template : "default".to_owned(), + renderable : render_always, + weight : 0, + components : PageContainer::new(), + container : ContainerType::Wrapper, + id : OptIden::new(), + classes : Classes::new_with_default("container"), + inner_classes: Classes::new_with_default("container"), + template : "default".to_owned(), } } @@ -36,35 +38,35 @@ impl PageComponent for Container { fn default_render(&self, assets: &mut PageAssets) -> Markup { match self.container_type() { ContainerType::Header => html! { - header id=[self.id()] class=[self.classes("header")] { - div class="container" { + header id=[self.id()] class=[self.classes()] { + div class=[self.inner_classes()] { (self.components().render(assets)) } } }, ContainerType::Footer => html! { - footer id=[self.id()] class=[self.classes("footer")] { - div class="container" { + footer id=[self.id()] class=[self.classes()] { + div class=[self.inner_classes()] { (self.components().render(assets)) } } }, ContainerType::Main => html! { - main id=[self.id()] class=[self.classes("main")] { - div class="container" { + main id=[self.id()] class=[self.classes()] { + div class=[self.inner_classes()] { (self.components().render(assets)) } } }, ContainerType::Section => html! { - section id=[self.id()] class=[self.classes("section")] { - div class="container" { + section id=[self.id()] class=[self.classes()] { + div class=[self.inner_classes()] { (self.components().render(assets)) } } }, _ => html! { - div id=[self.id()] class=[self.classes("container")] { + div id=[self.id()] class=[self.classes()] { (self.components().render(assets)) } } @@ -74,25 +76,25 @@ impl PageComponent for Container { impl Container { pub fn header() -> Self { - let mut c = Container::new(); + let mut c = Container::new().with_classes("header", ClassesOp::SetDefault); c.container = ContainerType::Header; c } pub fn footer() -> Self { - let mut c = Container::new(); + let mut c = Container::new().with_classes("footer", ClassesOp::SetDefault); c.container = ContainerType::Footer; c } pub fn main() -> Self { - let mut c = Container::new(); + let mut c = Container::new().with_classes("main", ClassesOp::SetDefault); c.container = ContainerType::Main; c } pub fn section() -> Self { - let mut c = Container::new(); + let mut c = Container::new().with_classes("section", ClassesOp::SetDefault); c.container = ContainerType::Section; c } @@ -111,31 +113,63 @@ impl Container { // Container BUILDER. pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { - self.renderable = renderable; + self.alter_renderable(renderable); self } pub fn with_weight(mut self, weight: i8) -> Self { - self.weight = weight; + self.alter_weight(weight); self } pub fn with_id(mut self, id: &str) -> Self { - self.id.with_value(id); + self.alter_id(id); self } - pub fn set_classes(mut self, classes: &str) -> Self { - self.classes.set_classes(classes); + pub fn with_classes(mut self, classes: &str, op: ClassesOp) -> Self { + self.alter_classes(classes, op); self } - pub fn add_classes(mut self, classes: &str) -> Self { - self.classes.add_classes(classes); + pub fn with_inner_classes(mut self, classes: &str, op: ClassesOp) -> Self { + self.alter_inner_classes(classes, op); self } pub fn using_template(mut self, template: &str) -> Self { + self.alter_template(template); + self + } + + // Container ALTER. + + pub fn alter_renderable(&mut self, renderable: fn() -> bool) -> &mut Self { + self.renderable = renderable; + self + } + + pub fn alter_weight(&mut self, weight: i8) -> &mut Self { + self.weight = weight; + self + } + + pub fn alter_id(&mut self, id: &str) -> &mut Self { + self.id.with_value(id); + self + } + + pub fn alter_classes(&mut self, classes: &str, op: ClassesOp) -> &mut Self { + self.classes.alter(classes, op); + self + } + + pub fn alter_inner_classes(&mut self, classes: &str, op: ClassesOp) -> &mut Self { + self.inner_classes.alter(classes, op); + self + } + + pub fn alter_template(&mut self, template: &str) -> &mut Self { self.template = template.to_owned(); self } @@ -150,15 +184,15 @@ impl Container { self.id.option() } - pub fn classes(&self, default: &str) -> Option<String> { - self.classes.option(default) + pub fn classes(&self) -> &Option<String> { + self.classes.option() + } + + pub fn inner_classes(&self) -> &Option<String> { + self.inner_classes.option() } pub fn template(&self) -> &str { self.template.as_str() } } - -fn always() -> bool { - true -} diff --git a/pagetop/src/base/component/form/button.rs b/pagetop/src/base/component/form/button.rs index f99f06d3..4c75dc62 100644 --- a/pagetop/src/base/component/form/button.rs +++ b/pagetop/src/base/component/form/button.rs @@ -17,16 +17,17 @@ pub struct Button { impl PageComponent for Button { fn new() -> Self { Button { - renderable : always, + renderable : render_always, weight : 0, button_type: ButtonType::Button, - name : OptAttr::none(), - value : OptAttr::none(), - autofocus : OptAttr::none(), - disabled : OptAttr::none(), - classes : Classes::none(), + name : OptAttr::new(), + value : OptAttr::new(), + autofocus : OptAttr::new(), + disabled : OptAttr::new(), + classes : Classes::new_with_default("btn btn-primary"), template : "default".to_owned(), } + .with_classes("form-button", ClassesOp::AddFirst) } fn is_renderable(&self) -> bool { @@ -38,10 +39,10 @@ impl PageComponent for Button { } fn default_render(&self, _: &mut PageAssets) -> Markup { - let (button_type, button_class) = match self.button_type() { - ButtonType::Button => ("button", "btn btn-primary form-button"), - ButtonType::Reset => ("reset", "btn btn-primary form-reset" ), - ButtonType::Submit => ("submit", "btn btn-primary form-submit"), + let button_type = match self.button_type() { + ButtonType::Button => "button", + ButtonType::Reset => "reset", + ButtonType::Submit => "submit", }; let id = match self.name() { Some(name) => Some(concat_string!("edit-", name)), @@ -51,7 +52,7 @@ impl PageComponent for Button { button type=(button_type) id=[id] - class=[self.classes(button_class)] + class=[self.classes()] name=[self.name()] value=[self.value()] autofocus=[self.autofocus()] @@ -72,13 +73,17 @@ impl Button { } pub fn reset(value: &str) -> Self { - let mut button = Button::new().with_value(value); + let mut button = Button::new() + .with_classes("form-reset", ClassesOp::Replace("form-button")) + .with_value(value); button.button_type = ButtonType::Reset; button } pub fn submit(value: &str) -> Self { - let mut button = Button::new().with_value(value); + let mut button = Button::new() + .with_classes("form-submit", ClassesOp::Replace("form-button")) + .with_value(value); button.button_type = ButtonType::Submit; button } @@ -86,26 +91,68 @@ impl Button { // Button BUILDER. pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { - self.renderable = renderable; + self.alter_renderable(renderable); self } pub fn with_weight(mut self, weight: i8) -> Self { - self.weight = weight; + self.alter_weight(weight); self } pub fn with_name(mut self, name: &str) -> Self { - self.name.with_value(name); + self.alter_name(name); self } pub fn with_value(mut self, value: &str) -> Self { - self.value.with_value(value); + self.alter_value(value); self } pub fn with_autofocus(mut self, toggle: bool) -> Self { + self.alter_autofocus(toggle); + self + } + + pub fn with_disabled(mut self, toggle: bool) -> Self { + self.alter_disabled(toggle); + self + } + + pub fn with_classes(mut self, classes: &str, op: ClassesOp) -> Self { + self.alter_classes(classes, op); + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.alter_template(template); + self + } + + // Button ALTER. + + pub fn alter_renderable(&mut self, renderable: fn() -> bool) -> &mut Self { + self.renderable = renderable; + self + } + + pub fn alter_weight(&mut self, weight: i8) -> &mut Self { + self.weight = weight; + self + } + + pub fn alter_name(&mut self, name: &str) -> &mut Self { + self.name.with_value(name); + self + } + + pub fn alter_value(&mut self, value: &str) -> &mut Self { + self.value.with_value(value); + self + } + + pub fn alter_autofocus(&mut self, toggle: bool) -> &mut Self { self.autofocus.with_value(match toggle { true => "autofocus", false => "", @@ -113,7 +160,7 @@ impl Button { self } - pub fn with_disabled(mut self, toggle: bool) -> Self { + pub fn alter_disabled(&mut self, toggle: bool) -> &mut Self { self.disabled.with_value(match toggle { true => "disabled", false => "", @@ -121,17 +168,12 @@ impl Button { self } - pub fn set_classes(mut self, classes: &str) -> Self { - self.classes.set_classes(classes); + pub fn alter_classes(&mut self, classes: &str, op: ClassesOp) -> &mut Self { + self.classes.alter(classes, op); self } - pub fn add_classes(mut self, classes: &str) -> Self { - self.classes.add_classes(classes); - self - } - - pub fn using_template(mut self, template: &str) -> Self { + pub fn alter_template(&mut self, template: &str) -> &mut Self { self.template = template.to_owned(); self } @@ -158,15 +200,11 @@ impl Button { self.disabled.option() } - pub fn classes(&self, default: &str) -> Option<String> { - self.classes.option(default) + pub fn classes(&self) -> &Option<String> { + self.classes.option() } pub fn template(&self) -> &str { self.template.as_str() } } - -fn always() -> bool { - true -} diff --git a/pagetop/src/base/component/form/date.rs b/pagetop/src/base/component/form/date.rs index 40c2f784..10e795cb 100644 --- a/pagetop/src/base/component/form/date.rs +++ b/pagetop/src/base/component/form/date.rs @@ -20,21 +20,22 @@ pub struct Date { impl PageComponent for Date { fn new() -> Self { Date { - renderable : always, + renderable : render_always, weight : 0, - name : OptAttr::none(), - value : OptAttr::none(), - label : OptAttr::none(), - placeholder : OptAttr::none(), - autofocus : OptAttr::none(), - autocomplete: OptAttr::none(), - disabled : OptAttr::none(), - readonly : OptAttr::none(), - required : OptAttr::none(), - help_text : OptAttr::none(), - classes : Classes::none(), + name : OptAttr::new(), + value : OptAttr::new(), + label : OptAttr::new(), + placeholder : OptAttr::new(), + autofocus : OptAttr::new(), + autocomplete: OptAttr::new(), + disabled : OptAttr::new(), + readonly : OptAttr::new(), + required : OptAttr::new(), + help_text : OptAttr::new(), + classes : Classes::new_with_default("form-item"), template : "default".to_owned(), } + .with_classes("form-type-date", ClassesOp::AddFirst) } fn is_renderable(&self) -> bool { @@ -46,18 +47,12 @@ impl PageComponent for Date { } fn default_render(&self, _: &mut PageAssets) -> Markup { - let (classes, id) = match self.name() { - Some(name) => ( - concat_string!("form-item form-item-", name, " form-type-date"), - Some(concat_string!("edit-", name)) - ), - None => ( - "form-item form-type-date".to_owned(), - None - ) + let id = match self.name() { + Some(name) => Some(concat_string!("edit-", name)), + None => None, }; html! { - div class=[self.classes(classes.as_str())] { + div class=[self.classes()] { @match self.label() { Some(label) => label class="form-label" for=[&id] { (label) " " @@ -96,36 +91,108 @@ impl Date { // Date BUILDER. pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { - self.renderable = renderable; + self.alter_renderable(renderable); self } pub fn with_weight(mut self, weight: i8) -> Self { - self.weight = weight; + self.alter_weight(weight); self } pub fn with_name(mut self, name: &str) -> Self { - self.name.with_value(name); + self.alter_name(name); self } pub fn with_value(mut self, value: &str) -> Self { - self.value.with_value(value); + self.alter_value(value); self } pub fn with_label(mut self, label: &str) -> Self { - self.label.with_value(label); + self.alter_label(label); self } pub fn with_placeholder(mut self, placeholder: &str) -> Self { - self.placeholder.with_value(placeholder); + self.alter_placeholder(placeholder); self } pub fn with_autofocus(mut self, toggle: bool) -> Self { + self.alter_autofocus(toggle); + self + } + + pub fn with_autocomplete(mut self, toggle: bool) -> Self { + self.alter_autocomplete(toggle); + self + } + + pub fn with_disabled(mut self, toggle: bool) -> Self { + self.alter_disabled(toggle); + self + } + + pub fn with_readonly(mut self, toggle: bool) -> Self { + self.alter_readonly(toggle); + self + } + + pub fn with_required(mut self, toggle: bool) -> Self { + self.alter_required(toggle); + self + } + + pub fn with_help_text(mut self, help_text: &str) -> Self { + self.alter_help_text(help_text); + self + } + + pub fn with_classes(mut self, classes: &str, op: ClassesOp) -> Self { + self.alter_classes(classes, op); + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.alter_template(template); + self + } + + // Date ALTER. + + pub fn alter_renderable(&mut self, renderable: fn() -> bool) -> &mut Self { + self.renderable = renderable; + self + } + + pub fn alter_weight(&mut self, weight: i8) -> &mut Self { + self.weight = weight; + self + } + + pub fn alter_name(&mut self, name: &str) -> &mut Self { + self.name.with_value(name); + self + } + + pub fn alter_value(&mut self, value: &str) -> &mut Self { + self.value.with_value(value); + self + } + + pub fn alter_label(&mut self, label: &str) -> &mut Self { + self.label.with_value(label); + self + } + + pub fn alter_placeholder(&mut self, placeholder: &str) -> &mut Self { + self.placeholder.with_value(placeholder); + self + } + + pub fn alter_autofocus(&mut self, toggle: bool) -> &mut Self { self.autofocus.with_value(match toggle { true => "autofocus", false => "", @@ -133,7 +200,7 @@ impl Date { self } - pub fn with_autocomplete(mut self, toggle: bool) -> Self { + pub fn alter_autocomplete(&mut self, toggle: bool) -> &mut Self { self.autocomplete.with_value(match toggle { true => "", false => "off", @@ -141,7 +208,7 @@ impl Date { self } - pub fn with_disabled(mut self, toggle: bool) -> Self { + pub fn alter_disabled(&mut self, toggle: bool) -> &mut Self { self.disabled.with_value(match toggle { true => "disabled", false => "", @@ -149,7 +216,7 @@ impl Date { self } - pub fn with_readonly(mut self, toggle: bool) -> Self { + pub fn alter_readonly(&mut self, toggle: bool) -> &mut Self { self.readonly.with_value(match toggle { true => "readonly", false => "", @@ -157,7 +224,7 @@ impl Date { self } - pub fn with_required(mut self, toggle: bool) -> Self { + pub fn alter_required(&mut self, toggle: bool) -> &mut Self { self.required.with_value(match toggle { true => "required", false => "", @@ -165,22 +232,17 @@ impl Date { self } - pub fn with_help_text(mut self, help_text: &str) -> Self { + pub fn alter_help_text(&mut self, help_text: &str) -> &mut Self { self.help_text.with_value(help_text); self } - pub fn set_classes(mut self, classes: &str) -> Self { - self.classes.set_classes(classes); + pub fn alter_classes(&mut self, classes: &str, op: ClassesOp) -> &mut Self { + self.classes.alter(classes, op); self } - pub fn add_classes(mut self, classes: &str) -> Self { - self.classes.add_classes(classes); - self - } - - pub fn using_template(mut self, template: &str) -> Self { + pub fn alter_template(&mut self, template: &str) -> &mut Self { self.template = template.to_owned(); self } @@ -227,15 +289,11 @@ impl Date { self.help_text.option() } - pub fn classes(&self, default: &str) -> Option<String> { - self.classes.option(default) + pub fn classes(&self) -> &Option<String> { + self.classes.option() } pub fn template(&self) -> &str { self.template.as_str() } } - -fn always() -> bool { - true -} diff --git a/pagetop/src/base/component/form/form.rs b/pagetop/src/base/component/form/form.rs index 07cb6e17..73581ca2 100644 --- a/pagetop/src/base/component/form/form.rs +++ b/pagetop/src/base/component/form/form.rs @@ -17,14 +17,14 @@ pub struct Form { impl PageComponent for Form { fn new() -> Self { Form { - renderable: always, + renderable: render_always, weight : 0, elements : PageContainer::new(), - action : OptAttr::none(), - charset : OptAttr::some("UTF-8"), + action : OptAttr::new(), + charset : OptAttr::new_with_value("UTF-8"), method : FormMethod::Post, - id : OptIden::none(), - classes : Classes::none(), + id : OptIden::new(), + classes : Classes::new_with_default("form"), template : "default".to_owned(), } } @@ -45,7 +45,7 @@ impl PageComponent for Form { html! { form id=[self.id()] - class=[self.classes("form")] + class=[self.classes()] action=[self.action()] method=[method] accept-charset=[self.charset()] @@ -72,46 +72,83 @@ impl Form { // Form BUILDER. pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { - self.renderable = renderable; + self.alter_renderable(renderable); self } pub fn with_weight(mut self, weight: i8) -> Self { - self.weight = weight; + self.alter_weight(weight); self } pub fn with_action(mut self, action: &str) -> Self { - self.action.with_value(action); + self.alter_action(action); self } pub fn with_charset(mut self, charset: &str) -> Self { - self.charset.with_value(charset); + self.alter_charset(charset); self } pub fn with_method(mut self, method: FormMethod) -> Self { - self.method = method; + self.alter_method(method); self } pub fn with_id(mut self, id: &str) -> Self { - self.id.with_value(id); + self.alter_id(id); self } - pub fn set_classes(mut self, classes: &str) -> Self { - self.classes.set_classes(classes); - self - } - - pub fn add_classes(mut self, classes: &str) -> Self { - self.classes.add_classes(classes); + pub fn with_classes(mut self, classes: &str, op: ClassesOp) -> Self { + self.alter_classes(classes, op); self } pub fn using_template(mut self, template: &str) -> Self { + self.alter_template(template); + self + } + + // Form ALTER. + + pub fn alter_renderable(&mut self, renderable: fn() -> bool) -> &mut Self { + self.renderable = renderable; + self + } + + pub fn alter_weight(&mut self, weight: i8) -> &mut Self { + self.weight = weight; + self + } + + pub fn alter_action(&mut self, action: &str) -> &mut Self { + self.action.with_value(action); + self + } + + pub fn alter_charset(&mut self, charset: &str) -> &mut Self { + self.charset.with_value(charset); + self + } + + pub fn alter_method(&mut self, method: FormMethod) -> &mut Self { + self.method = method; + self + } + + pub fn alter_id(&mut self, id: &str) -> &mut Self { + self.id.with_value(id); + self + } + + pub fn alter_classes(&mut self, classes: &str, op: ClassesOp) -> &mut Self { + self.classes.alter(classes, op); + self + } + + pub fn alter_template(&mut self, template: &str) -> &mut Self { self.template = template.to_owned(); self } @@ -134,15 +171,11 @@ impl Form { self.id.option() } - pub fn classes(&self, default: &str) -> Option<String> { - self.classes.option(default) + pub fn classes(&self) -> &Option<String> { + self.classes.option() } pub fn template(&self) -> &str { self.template.as_str() } } - -fn always() -> bool { - true -} diff --git a/pagetop/src/base/component/form/hidden.rs b/pagetop/src/base/component/form/hidden.rs index 8f2cc4b3..736aa4ce 100644 --- a/pagetop/src/base/component/form/hidden.rs +++ b/pagetop/src/base/component/form/hidden.rs @@ -10,8 +10,8 @@ impl PageComponent for Hidden { fn new() -> Self { Hidden { weight: 0, - name : OptIden::none(), - value : OptAttr::none(), + name : OptIden::new(), + value : OptAttr::new(), } } @@ -32,24 +32,39 @@ impl PageComponent for Hidden { impl Hidden { pub fn set(name: &str, value: &str) -> Self { - Hidden::new() - .with_name(name) - .with_value(value) + Hidden::new().with_name(name).with_value(value) } // Hidden BUILDER. pub fn with_weight(mut self, weight: i8) -> Self { - self.weight = weight; + self.alter_weight(weight); self } pub fn with_name(mut self, name: &str) -> Self { - self.name.with_value(name); + self.alter_name(name); self } pub fn with_value(mut self, value: &str) -> Self { + self.alter_value(value); + self + } + + // Hidden ALTER. + + pub fn alter_weight(&mut self, weight: i8) -> &mut Self { + self.weight = weight; + self + } + + pub fn alter_name(&mut self, name: &str) -> &mut Self { + self.name.with_value(name); + self + } + + pub fn alter_value(&mut self, value: &str) -> &mut Self { self.value.with_value(value); self } diff --git a/pagetop/src/base/component/form/input.rs b/pagetop/src/base/component/form/input.rs index 9d6e1afd..71d801b7 100644 --- a/pagetop/src/base/component/form/input.rs +++ b/pagetop/src/base/component/form/input.rs @@ -26,25 +26,26 @@ pub struct Input { impl PageComponent for Input { fn new() -> Self { Input { - renderable : always, + renderable : render_always, weight : 0, input_type : InputType::Textfield, - name : OptIden::none(), - value : OptAttr::none(), - label : OptAttr::none(), + name : OptIden::new(), + value : OptAttr::new(), + label : OptAttr::new(), size : Some(60), minlength : None, maxlength : Some(128), - placeholder : OptAttr::none(), - autofocus : OptAttr::none(), - autocomplete: OptAttr::none(), - disabled : OptAttr::none(), - readonly : OptAttr::none(), - required : OptAttr::none(), - help_text : OptAttr::none(), - classes : Classes::none(), + placeholder : OptAttr::new(), + autofocus : OptAttr::new(), + autocomplete: OptAttr::new(), + disabled : OptAttr::new(), + readonly : OptAttr::new(), + required : OptAttr::new(), + help_text : OptAttr::new(), + classes : Classes::new_with_default("form-item"), template : "default".to_owned(), } + .with_classes("form-type-textfield", ClassesOp::AddFirst) } fn is_renderable(&self) -> bool { @@ -55,27 +56,28 @@ impl PageComponent for Input { self.weight } + fn before_render(&mut self, _: &mut PageAssets) { + if let Some(name) = self.name() { + let class = concat_string!("form-item-", name); + self.alter_classes(class.as_str(), ClassesOp::AddFirst); + } + } + fn default_render(&self, _: &mut PageAssets) -> Markup { - let (type_input, type_class) = match self.input_type() { - InputType::Email => ("email", "form-type-email"), - InputType::Password => ("password", "form-type-password"), - InputType::Search => ("search", "form-type-search"), - InputType::Telephone => ("tel", "form-type-telephone"), - InputType::Textfield => ("text", "form-type-textfield"), - InputType::Url => ("url", "form-type-url") + let type_input = match self.input_type() { + InputType::Email => "email", + InputType::Password => "password", + InputType::Search => "search", + InputType::Telephone => "tel", + InputType::Textfield => "text", + InputType::Url => "url", }; - let (class, id) = match self.name() { - Some(name) => ( - concat_string!("form-item form-item-", name, " ", type_class), - Some(concat_string!("edit-", name)) - ), - None => ( - concat_string!("form-item ", type_class), - None - ) + let id = match self.name() { + Some(name) => Some(concat_string!("edit-", name)), + None => None, }; html! { - div class=(class) { + div class=[self.classes()] { @match self.label() { Some(label) => label class="form-label" for=[&id] { (label) " " @@ -118,31 +120,36 @@ impl Input { } pub fn password() -> Self { - let mut input = Input::new(); + let mut input = Input::new() + .with_classes("form-type-password", ClassesOp::Replace("form-type-textfield")); input.input_type = InputType::Password; input } pub fn search() -> Self { - let mut input = Input::new(); + let mut input = Input::new() + .with_classes("form-type-search", ClassesOp::Replace("form-type-textfield")); input.input_type = InputType::Search; input } pub fn email() -> Self { - let mut input = Input::new(); + let mut input = Input::new() + .with_classes("form-type-email", ClassesOp::Replace("form-type-textfield")); input.input_type = InputType::Email; input } pub fn telephone() -> Self { - let mut input = Input::new(); + let mut input = Input::new() + .with_classes("form-type-telephone", ClassesOp::Replace("form-type-textfield")); input.input_type = InputType::Telephone; input } pub fn url() -> Self { - let mut input = Input::new(); + let mut input = Input::new() + .with_classes("form-type-url", ClassesOp::Replace("form-type-textfield")); input.input_type = InputType::Url; input } @@ -150,51 +157,138 @@ impl Input { // Input BUILDER. pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { - self.renderable = renderable; + self.alter_renderable(renderable); self } pub fn with_weight(mut self, weight: i8) -> Self { - self.weight = weight; + self.alter_weight(weight); self } pub fn with_name(mut self, name: &str) -> Self { - self.name.with_value(name); + self.alter_name(name); self } pub fn with_value(mut self, value: &str) -> Self { - self.value.with_value(value); + self.alter_value(value); self } pub fn with_label(mut self, label: &str) -> Self { - self.label.with_value(label); + self.alter_label(label); self } pub fn with_size(mut self, size: Option<u16>) -> Self { - self.size = size; + self.alter_size(size); self } pub fn with_minlength(mut self, minlength: Option<u16>) -> Self { - self.minlength = minlength; + self.alter_minlength(minlength); self } pub fn with_maxlength(mut self, maxlength: Option<u16>) -> Self { - self.maxlength = maxlength; + self.alter_maxlength(maxlength); self } pub fn with_placeholder(mut self, placeholder: &str) -> Self { - self.placeholder.with_value(placeholder); + self.alter_placeholder(placeholder); self } pub fn with_autofocus(mut self, toggle: bool) -> Self { + self.alter_autofocus(toggle); + self + } + + pub fn with_autocomplete(mut self, toggle: bool) -> Self { + self.alter_autocomplete(toggle); + self + } + + pub fn with_disabled(mut self, toggle: bool) -> Self { + self.alter_disabled(toggle); + self + } + + pub fn with_readonly(mut self, toggle: bool) -> Self { + self.alter_readonly(toggle); + self + } + + pub fn with_required(mut self, toggle: bool) -> Self { + self.alter_required(toggle); + self + } + + pub fn with_help_text(mut self, help_text: &str) -> Self { + self.alter_help_text(help_text); + self + } + + pub fn with_classes(mut self, classes: &str, op: ClassesOp) -> Self { + self.alter_classes(classes, op); + self + } + + pub fn using_template(mut self, template: &str) -> Self { + self.alter_template(template); + self + } + + // Input ALTER. + + pub fn alter_renderable(&mut self, renderable: fn() -> bool) -> &mut Self { + self.renderable = renderable; + self + } + + pub fn alter_weight(&mut self, weight: i8) -> &mut Self { + self.weight = weight; + self + } + + pub fn alter_name(&mut self, name: &str) -> &mut Self { + self.name.with_value(name); + self + } + + pub fn alter_value(&mut self, value: &str) -> &mut Self { + self.value.with_value(value); + self + } + + pub fn alter_label(&mut self, label: &str) -> &mut Self { + self.label.with_value(label); + self + } + + pub fn alter_size(&mut self, size: Option<u16>) -> &mut Self { + self.size = size; + self + } + + pub fn alter_minlength(&mut self, minlength: Option<u16>) -> &mut Self { + self.minlength = minlength; + self + } + + pub fn alter_maxlength(&mut self, maxlength: Option<u16>) -> &mut Self { + self.maxlength = maxlength; + self + } + + pub fn alter_placeholder(&mut self, placeholder: &str) -> &mut Self { + self.placeholder.with_value(placeholder); + self + } + + pub fn alter_autofocus(&mut self, toggle: bool) -> &mut Self { self.autofocus.with_value(match toggle { true => "autofocus", false => "", @@ -202,7 +296,7 @@ impl Input { self } - pub fn with_autocomplete(mut self, toggle: bool) -> Self { + pub fn alter_autocomplete(&mut self, toggle: bool) -> &mut Self { self.autocomplete.with_value(match toggle { true => "", false => "off", @@ -210,7 +304,7 @@ impl Input { self } - pub fn with_disabled(mut self, toggle: bool) -> Self { + pub fn alter_disabled(&mut self, toggle: bool) -> &mut Self { self.disabled.with_value(match toggle { true => "disabled", false => "", @@ -218,7 +312,7 @@ impl Input { self } - pub fn with_readonly(mut self, toggle: bool) -> Self { + pub fn alter_readonly(&mut self, toggle: bool) -> &mut Self { self.readonly.with_value(match toggle { true => "readonly", false => "", @@ -226,7 +320,7 @@ impl Input { self } - pub fn with_required(mut self, toggle: bool) -> Self { + pub fn alter_required(&mut self, toggle: bool) -> &mut Self { self.required.with_value(match toggle { true => "required", false => "", @@ -234,22 +328,17 @@ impl Input { self } - pub fn with_help_text(mut self, help_text: &str) -> Self { + pub fn alter_help_text(&mut self, help_text: &str) -> &mut Self { self.help_text.with_value(help_text); self } - pub fn set_classes(mut self, classes: &str) -> Self { - self.classes.set_classes(classes); + pub fn alter_classes(&mut self, classes: &str, op: ClassesOp) -> &mut Self { + self.classes.alter(classes, op); self } - pub fn add_classes(mut self, classes: &str) -> Self { - self.classes.add_classes(classes); - self - } - - pub fn using_template(mut self, template: &str) -> Self { + pub fn alter_template(&mut self, template: &str) -> &mut Self { self.template = template.to_owned(); self } @@ -312,15 +401,11 @@ impl Input { self.help_text.option() } - pub fn classes(&self, default: &str) -> Option<String> { - self.classes.option(default) + pub fn classes(&self) -> &Option<String> { + self.classes.option() } pub fn template(&self) -> &str { self.template.as_str() } } - -fn always() -> bool { - true -} diff --git a/pagetop/src/base/component/grid/column.rs b/pagetop/src/base/component/grid/column.rs index f29544ca..77512ea2 100644 --- a/pagetop/src/base/component/grid/column.rs +++ b/pagetop/src/base/component/grid/column.rs @@ -12,11 +12,11 @@ pub struct Column { impl PageComponent for Column { fn new() -> Self { Column { - renderable: always, + renderable: render_always, weight : 0, components: PageContainer::new(), - id : OptIden::none(), - classes : Classes::none(), + id : OptIden::new(), + classes : Classes::new_with_default("col"), template : "default".to_owned(), } } @@ -35,7 +35,7 @@ impl PageComponent for Column { fn default_render(&self, assets: &mut PageAssets) -> Markup { html! { - div id=[self.id()] class=[self.classes("col")] { + div id=[self.id()] class=[self.classes()] { (self.components().render(assets)) } } @@ -58,31 +58,53 @@ impl Column { // Column BUILDER. pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { - self.renderable = renderable; + self.alter_renderable(renderable); self } pub fn with_weight(mut self, weight: i8) -> Self { - self.weight = weight; + self.alter_weight(weight); self } pub fn with_id(mut self, id: &str) -> Self { - self.id.with_value(id); + self.alter_id(id); self } - pub fn set_classes(mut self, classes: &str) -> Self { - self.classes.set_classes(classes); - self - } - - pub fn add_classes(mut self, classes: &str) -> Self { - self.classes.add_classes(classes); + pub fn with_classes(mut self, classes: &str, op: ClassesOp) -> Self { + self.alter_classes(classes, op); self } pub fn using_template(mut self, template: &str) -> Self { + self.alter_template(template); + self + } + + // Column ALTER. + + pub fn alter_renderable(&mut self, renderable: fn() -> bool) -> &mut Self { + self.renderable = renderable; + self + } + + pub fn alter_weight(&mut self, weight: i8) -> &mut Self { + self.weight = weight; + self + } + + pub fn alter_id(&mut self, id: &str) -> &mut Self { + self.id.with_value(id); + self + } + + pub fn alter_classes(&mut self, classes: &str, op: ClassesOp) -> &mut Self { + self.classes.alter(classes, op); + self + } + + pub fn alter_template(&mut self, template: &str) -> &mut Self { self.template = template.to_owned(); self } @@ -93,15 +115,11 @@ impl Column { self.id.option() } - pub fn classes(&self, default: &str) -> Option<String> { - self.classes.option(default) + pub fn classes(&self) -> &Option<String> { + self.classes.option() } pub fn template(&self) -> &str { self.template.as_str() } } - -fn always() -> bool { - true -} diff --git a/pagetop/src/base/component/grid/row.rs b/pagetop/src/base/component/grid/row.rs index 96d74afc..4574b090 100644 --- a/pagetop/src/base/component/grid/row.rs +++ b/pagetop/src/base/component/grid/row.rs @@ -12,11 +12,11 @@ pub struct Row { impl PageComponent for Row { fn new() -> Self { Row { - renderable: always, + renderable: render_always, weight : 0, columns : PageContainer::new(), - id : OptIden::none(), - classes : Classes::none(), + id : OptIden::new(), + classes : Classes::new_with_default("row"), template : "default".to_owned(), } } @@ -35,7 +35,7 @@ impl PageComponent for Row { fn default_render(&self, assets: &mut PageAssets) -> Markup { html! { - div id=[self.id()] class=[self.classes("row")] { + div id=[self.id()] class=[self.classes()] { (self.columns().render(assets)) } } @@ -58,36 +58,53 @@ impl Row { // Row BUILDER. pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { - self.renderable = renderable; + self.alter_renderable(renderable); self } pub fn with_weight(mut self, weight: i8) -> Self { - self.weight = weight; + self.alter_weight(weight); self } pub fn with_id(mut self, id: &str) -> Self { - self.id.with_value(id); + self.alter_id(id); self } - pub fn set_classes(mut self, classes: &str) -> Self { - self.classes.set_classes(classes); - self - } - - pub fn set_classes_ref(&mut self, classes: &str) -> &Self { - self.classes.set_classes(classes); - self - } - - pub fn add_classes(mut self, classes: &str) -> Self { - self.classes.add_classes(classes); + pub fn with_classes(mut self, classes: &str, op: ClassesOp) -> Self { + self.alter_classes(classes, op); self } pub fn using_template(mut self, template: &str) -> Self { + self.alter_template(template); + self + } + + // Row ALTER. + + pub fn alter_renderable(&mut self, renderable: fn() -> bool) -> &mut Self { + self.renderable = renderable; + self + } + + pub fn alter_weight(&mut self, weight: i8) -> &mut Self { + self.weight = weight; + self + } + + pub fn alter_id(&mut self, id: &str) -> &mut Self { + self.id.with_value(id); + self + } + + pub fn alter_classes(&mut self, classes: &str, op: ClassesOp) -> &mut Self { + self.classes.alter(classes, op); + self + } + + pub fn alter_template(&mut self, template: &str) -> &mut Self { self.template = template.to_owned(); self } @@ -98,15 +115,11 @@ impl Row { self.id.option() } - pub fn classes(&self, default: &str) -> Option<String> { - self.classes.option(default) + pub fn classes(&self) -> &Option<String> { + self.classes.option() } pub fn template(&self) -> &str { self.template.as_str() } } - -fn always() -> bool { - true -} diff --git a/pagetop/src/base/component/image.rs b/pagetop/src/base/component/image.rs index 1384f4df..62690679 100644 --- a/pagetop/src/base/component/image.rs +++ b/pagetop/src/base/component/image.rs @@ -12,11 +12,11 @@ pub struct Image { impl PageComponent for Image { fn new() -> Self { Image { - renderable: always, + renderable: render_always, weight : 0, - source : OptAttr::none(), - id : OptIden::none(), - classes : Classes::none(), + source : OptAttr::new(), + id : OptIden::new(), + classes : Classes::new_with_default("img-fluid"), template : "default".to_owned(), } } @@ -34,7 +34,7 @@ impl PageComponent for Image { img src=[self.source()] id=[self.id()] - class=[self.classes("img-fluid")]; + class=[self.classes()]; } } } @@ -47,36 +47,63 @@ impl Image { // Image BUILDER. pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { - self.renderable = renderable; + self.alter_renderable(renderable); self } pub fn with_weight(mut self, weight: i8) -> Self { - self.weight = weight; + self.alter_weight(weight); self } pub fn with_source(mut self, source: &str) -> Self { - self.source.with_value(source); + self.alter_source(source); self } pub fn with_id(mut self, id: &str) -> Self { - self.id.with_value(id); + self.alter_id(id); self } - pub fn set_classes(mut self, classes: &str) -> Self { - self.classes.set_classes(classes); - self - } - - pub fn add_classes(mut self, classes: &str) -> Self { - self.classes.add_classes(classes); + pub fn with_classes(mut self, classes: &str, op: ClassesOp) -> Self { + self.alter_classes(classes, op); self } pub fn using_template(mut self, template: &str) -> Self { + self.alter_template(template); + self + } + + // Image ALTER. + + pub fn alter_renderable(&mut self, renderable: fn() -> bool) -> &mut Self { + self.renderable = renderable; + self + } + + pub fn alter_weight(&mut self, weight: i8) -> &mut Self { + self.weight = weight; + self + } + + pub fn alter_source(&mut self, source: &str) -> &mut Self { + self.source.with_value(source); + self + } + + pub fn alter_id(&mut self, id: &str) -> &mut Self { + self.id.with_value(id); + self + } + + pub fn alter_classes(&mut self, classes: &str, op: ClassesOp) -> &mut Self { + self.classes.alter(classes, op); + self + } + + pub fn alter_template(&mut self, template: &str) -> &mut Self { self.template = template.to_owned(); self } @@ -91,15 +118,11 @@ impl Image { self.id.option() } - pub fn classes(&self, default: &str) -> Option<String> { - self.classes.option(default) + pub fn classes(&self) -> &Option<String> { + self.classes.option() } pub fn template(&self) -> &str { self.template.as_str() } } - -fn always() -> bool { - true -} diff --git a/pagetop/src/base/component/menu.rs b/pagetop/src/base/component/menu.rs index 01a60129..68c5c97e 100644 --- a/pagetop/src/base/component/menu.rs +++ b/pagetop/src/base/component/menu.rs @@ -23,7 +23,7 @@ pub struct MenuItem { impl PageComponent for MenuItem { fn new() -> Self { MenuItem { - renderable: always, + renderable: render_always, weight : 0, item_type : MenuItemType::Void, } @@ -72,7 +72,7 @@ impl PageComponent for MenuItem { impl MenuItem { pub fn label(label: &str) -> Self { MenuItem { - renderable: always, + renderable: render_always, weight : 0, item_type : MenuItemType::Label(label.to_owned()), } @@ -80,7 +80,7 @@ impl MenuItem { pub fn link(label: &str, path: &str) -> Self { MenuItem { - renderable: always, + renderable: render_always, weight : 0, item_type : MenuItemType::Link( label.to_owned(), @@ -91,7 +91,7 @@ impl MenuItem { pub fn link_blank(label: &str, path: &str) -> Self { MenuItem { - renderable: always, + renderable: render_always, weight : 0, item_type : MenuItemType::LinkBlank( label.to_owned(), @@ -102,7 +102,7 @@ impl MenuItem { pub fn html(html: Markup) -> Self { MenuItem { - renderable: always, + renderable: render_always, weight : 0, item_type : MenuItemType::Html(html), } @@ -110,7 +110,7 @@ impl MenuItem { pub fn separator() -> Self { MenuItem { - renderable: always, + renderable: render_always, weight : 0, item_type : MenuItemType::Separator, } @@ -118,7 +118,7 @@ impl MenuItem { pub fn submenu(label: &str, menu: Menu) -> Self { MenuItem { - renderable: always, + renderable: render_always, weight : 0, item_type : MenuItemType::Submenu( label.to_owned(), @@ -130,11 +130,23 @@ impl MenuItem { // MenuItem BUILDER. pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { - self.renderable = renderable; + self.alter_renderable(renderable); self } pub fn with_weight(mut self, weight: i8) -> Self { + self.alter_weight(weight); + self + } + + // MenuItem ALTER. + + pub fn alter_renderable(&mut self, renderable: fn() -> bool) -> &mut Self { + self.renderable = renderable; + self + } + + pub fn alter_weight(&mut self, weight: i8) -> &mut Self { self.weight = weight; self } @@ -162,11 +174,11 @@ pub struct Menu { impl PageComponent for Menu { fn new() -> Self { Menu { - renderable: always, + renderable: render_always, weight : 0, items : PageContainer::new(), - id : OptIden::none(), - classes : Classes::none(), + id : OptIden::new(), + classes : Classes::new_with_default("sm sm-clean"), template : "default".to_owned(), } } @@ -194,7 +206,7 @@ impl PageComponent for Menu { let id = assets.serial_id(self.name(), self.id()); html! { - ul id=(id) class=[self.classes("sm sm-clean")] { + ul id=(id) class=[self.classes()] { (self.items().render(assets)) } script type="text/javascript" defer { @@ -223,31 +235,53 @@ impl Menu { // Menu BUILDER. pub fn with_renderable(mut self, renderable: fn() -> bool) -> Self { - self.renderable = renderable; + self.alter_renderable(renderable); self } pub fn with_weight(mut self, weight: i8) -> Self { - self.weight = weight; + self.alter_weight(weight); self } pub fn with_id(mut self, id: &str) -> Self { - self.id.with_value(id); + self.alter_id(id); self } - pub fn set_classes(mut self, classes: &str) -> Self { - self.classes.set_classes(classes); - self - } - - pub fn add_classes(mut self, classes: &str) -> Self { - self.classes.add_classes(classes); + pub fn with_classes(mut self, classes: &str, op: ClassesOp) -> Self { + self.alter_classes(classes, op); self } pub fn using_template(mut self, template: &str) -> Self { + self.alter_template(template); + self + } + + // Menu ALTER. + + pub fn alter_renderable(&mut self, renderable: fn() -> bool) -> &mut Self { + self.renderable = renderable; + self + } + + pub fn alter_weight(&mut self, weight: i8) -> &mut Self { + self.weight = weight; + self + } + + pub fn alter_id(&mut self, id: &str) -> &mut Self { + self.id.with_value(id); + self + } + + pub fn alter_classes(&mut self, classes: &str, op: ClassesOp) -> &mut Self { + self.classes.alter(classes, op); + self + } + + pub fn alter_template(&mut self, template: &str) -> &mut Self { self.template = template.to_owned(); self } @@ -258,15 +292,11 @@ impl Menu { self.id.option() } - pub fn classes(&self, default: &str) -> Option<String> { - self.classes.option(default) + pub fn classes(&self) -> &Option<String> { + self.classes.option() } pub fn template(&self) -> &str { self.template.as_str() } } - -fn always() -> bool { - true -} diff --git a/pagetop/src/base/theme/bulmix/mod.rs b/pagetop/src/base/theme/bulmix/mod.rs index cf83a8f6..c7aa3cb2 100644 --- a/pagetop/src/base/theme/bulmix/mod.rs +++ b/pagetop/src/base/theme/bulmix/mod.rs @@ -32,33 +32,21 @@ impl ThemeTrait for BulmixTheme { .add_jquery(); } - fn render_component( + fn before_render_component( &self, component: &mut dyn PageComponent, - assets: &mut PageAssets - ) -> Option<Markup> { + _assets: &mut PageAssets + ) { match component.name() { "GridRow" => { let row = component.downcast_mut::<grid::Row>().unwrap(); - row.set_classes_ref("Prueba"); - None - /* - Some(html! { - div id=[row.id()] class=[row.classes("columns")] { - (row.columns().render(assets)) - } - }) - */ + row.alter_classes("columns", ClassesOp::SetDefault); }, "GridColumn" => { - let col = component.downcast_ref::<grid::Column>().unwrap(); - Some(html! { - div id=[col.id()] class=[col.classes("column")] { - (col.components().render(assets)) - } - }) + let col = component.downcast_mut::<grid::Column>().unwrap(); + col.alter_classes("column", ClassesOp::SetDefault); }, - _ => None + _ => {}, } } } diff --git a/pagetop/src/html/classes.rs b/pagetop/src/html/classes.rs index 6c41aafb..225d6537 100644 --- a/pagetop/src/html/classes.rs +++ b/pagetop/src/html/classes.rs @@ -1,23 +1,82 @@ use crate::concat_string; -pub struct Classes(String); +pub enum ClassesOp { + Add, + AddAfter(&'static str), + AddBefore(&'static str), + AddFirst, + Replace(&'static str), + Reset, + SetDefault, +} + +pub struct Classes { + default: String, + added : String, + option : Option<String>, +} impl Classes { - pub fn none() -> Self { - Classes("".to_owned()) + pub fn new() -> Self { + Classes { + default: "".to_owned(), + added : "".to_owned(), + option : None, + } } - pub fn set_classes(&mut self, classes: &str) -> &mut Self { - self.0 = classes.to_owned(); + pub fn new_with_default(default: &str) -> Self { + let mut classes = Self::new(); + classes.alter(default, ClassesOp::SetDefault); + classes + } + + pub fn alter(&mut self, classes: &str, op: ClassesOp) -> &Self { + let classes = classes.trim(); + match op { + ClassesOp::Add => self.added.push_str(concat_string!(" ", classes).as_str()), + + ClassesOp::AddAfter(class) => { + let mut v_added: Vec<&str> = self.added.split_ascii_whitespace().collect(); + match v_added.iter().position(|c| c.eq(&class)) { + Some(pos) => v_added.insert(pos + 1, classes), + _ => v_added.push(classes), + } + self.added = v_added.join(" "); + }, + + ClassesOp::AddBefore(class) => { + let mut v_added: Vec<&str> = self.added.split_ascii_whitespace().collect(); + match v_added.iter().position(|c| c.eq(&class)) { + Some(pos) => v_added.insert(pos, classes), + _ => v_added.insert(0, classes), + } + self.added = v_added.join(" "); + }, + + ClassesOp::AddFirst => self.added = concat_string!(classes, " ", self.added), + + ClassesOp::Replace(class) => { + let mut v_added: Vec<&str> = self.added.split_ascii_whitespace().collect(); + match v_added.iter().position(|c| c.eq(&class)) { + Some(pos) => { + v_added.remove(pos); + v_added.insert(pos, classes); + }, + _ => v_added.push(classes), + } + self.added = v_added.join(" "); + }, + + ClassesOp::Reset => self.added = classes.to_owned(), + + ClassesOp::SetDefault => self.default = classes.to_owned(), + } + self.option = Some(concat_string!(self.default, " ", self.added).trim().to_owned()); self } - pub fn add_classes(&mut self, classes: &str) -> &mut Self { - self.0 = concat_string!(self.0, " ", classes).trim().to_owned(); - self - } - - pub fn option(&self, default: &str) -> Option<String> { - Some(concat_string!(default.to_owned(), " ", self.0).trim().to_owned()) + pub fn option(&self) -> &Option<String> { + &self.option } } diff --git a/pagetop/src/html/mod.rs b/pagetop/src/html/mod.rs index 52f735fe..56e5c6d2 100644 --- a/pagetop/src/html/mod.rs +++ b/pagetop/src/html/mod.rs @@ -5,4 +5,4 @@ pub use optiden::OptIden; mod optattr; pub use optattr::OptAttr; mod classes; -pub use classes::Classes; +pub use classes::{Classes, ClassesOp}; diff --git a/pagetop/src/html/optattr.rs b/pagetop/src/html/optattr.rs index d009e32e..86c21e8c 100644 --- a/pagetop/src/html/optattr.rs +++ b/pagetop/src/html/optattr.rs @@ -1,14 +1,14 @@ pub struct OptAttr(Option<String>); impl OptAttr { - pub fn none() -> Self { + pub fn new() -> Self { OptAttr(None) } - pub fn some(value: &str) -> Self { - let mut o = OptAttr(None); - o.with_value(value); - o + pub fn new_with_value(value: &str) -> Self { + let mut option = Self::new(); + option.with_value(value); + option } pub fn with_value(&mut self, value: &str) -> &mut Self { diff --git a/pagetop/src/html/optiden.rs b/pagetop/src/html/optiden.rs index 52a65c10..450867d9 100644 --- a/pagetop/src/html/optiden.rs +++ b/pagetop/src/html/optiden.rs @@ -1,17 +1,17 @@ pub struct OptIden(Option<String>); impl OptIden { - pub fn none() -> Self { + pub fn new() -> Self { OptIden(None) } - pub fn some(id: &str) -> Self { - let mut o = OptIden(None); - o.with_value(id); - o + pub fn new_with_value(id: &str) -> Self { + let mut option = Self::new(); + option.with_value(id); + option } - pub fn with_value(&mut self, id: &str) -> &mut Self { + pub fn with_value(&mut self, id: &str) -> &Self { let id = id.trim(); self.0 = match id.is_empty() { true => None, diff --git a/pagetop/src/response/page/assets.rs b/pagetop/src/response/page/assets.rs index 3d42a06f..8ab4d2eb 100644 --- a/pagetop/src/response/page/assets.rs +++ b/pagetop/src/response/page/assets.rs @@ -257,7 +257,7 @@ impl PageAssets { /// Assets GETTERS. - pub fn theme(&mut self) -> &'static dyn ThemeTrait { + pub(crate) fn theme(&mut self) -> &'static dyn ThemeTrait { self.theme } diff --git a/pagetop/src/response/page/component.rs b/pagetop/src/response/page/component.rs index 630b8a9b..05528fc8 100644 --- a/pagetop/src/response/page/component.rs +++ b/pagetop/src/response/page/component.rs @@ -33,6 +33,10 @@ pub trait PageComponent: Downcast + Send + Sync { 0 } + #[allow(unused_variables)] + fn before_render(&mut self, assets: &mut PageAssets) { + } + #[allow(unused_variables)] fn default_render(&self, assets: &mut PageAssets) -> Markup { html! {} diff --git a/pagetop/src/response/page/mod.rs b/pagetop/src/response/page/mod.rs index f34070e2..527f74f9 100644 --- a/pagetop/src/response/page/mod.rs +++ b/pagetop/src/response/page/mod.rs @@ -17,3 +17,6 @@ pub use page::Page; pub use page::render_component; pub use page::add_component_to; +pub fn render_always() -> bool { true } + +pub fn render_never() -> bool { false } \ No newline at end of file diff --git a/pagetop/src/response/page/page.rs b/pagetop/src/response/page/page.rs index 56db5ecc..f7bee609 100644 --- a/pagetop/src/response/page/page.rs +++ b/pagetop/src/response/page/page.rs @@ -1,6 +1,6 @@ use crate::{Lazy, app, trace}; use crate::config::SETTINGS; -use crate::html::{Classes, DOCTYPE, Markup, OptAttr, html}; +use crate::html::*; use crate::response::page::*; use std::sync::RwLock; @@ -55,18 +55,18 @@ impl<'a> Page<'a> { pub fn new() -> Self { Page { language : match &*DEFAULT_LANGUAGE { - Some(language) => OptAttr::some(language), - _ => OptAttr::none(), + Some(language) => OptAttr::new_with_value(language), + _ => OptAttr::new(), }, direction : match &*DEFAULT_DIRECTION { - Some(direction) => OptAttr::some(direction), - _ => OptAttr::none(), + Some(direction) => OptAttr::new_with_value(direction), + _ => OptAttr::new(), }, - title : OptAttr::none(), - description : OptAttr::none(), + title : OptAttr::new(), + description : OptAttr::new(), assets : PageAssets::new(), regions : COMPONENTS.read().unwrap().clone(), - body_classes: Classes::none(), + body_classes: Classes::new_with_default("body"), template : "default".to_owned(), } } @@ -110,13 +110,8 @@ impl<'a> Page<'a> { self } - pub fn set_body_classes(&mut self, classes: &str) -> &mut Self { - self.body_classes.set_classes(classes); - self - } - - pub fn add_body_classes(&mut self, classes: &str) -> &mut Self { - self.body_classes.add_classes(classes); + pub fn alter_body_classes(&mut self, classes: &str, op: ClassesOp) -> &mut Self { + self.body_classes.alter(classes, op); self } @@ -147,8 +142,8 @@ impl<'a> Page<'a> { &mut self.assets } - pub fn body_classes(&self, default: &str) -> Option<String> { - self.body_classes.option(default) + pub fn body_classes(&self) -> &Option<String> { + self.body_classes.option() } pub fn template(&self) -> &str { @@ -192,14 +187,15 @@ impl<'a> Page<'a> { } } -pub fn render_component( - component: &mut dyn PageComponent, - assets: &mut PageAssets -) -> Markup { +pub fn render_component(component: &mut dyn PageComponent, assets: &mut PageAssets) -> Markup { + component.before_render(assets); + assets.theme().before_render_component(component, assets); match component.is_renderable() { - true => match assets.theme().render_component(component, assets) { - Some(html) => html, - None => component.default_render(assets) + true => { + match assets.theme().render_component(component, assets) { + Some(html) => html, + None => component.default_render(assets) + } }, false => html! {} } diff --git a/pagetop/src/theme/definition.rs b/pagetop/src/theme/definition.rs index 457860c7..983bf0a6 100644 --- a/pagetop/src/theme/definition.rs +++ b/pagetop/src/theme/definition.rs @@ -55,7 +55,7 @@ pub trait ThemeTrait: Send + Sync { fn render_page_body(&self, page: &mut Page) -> Markup { html! { - body class=[page.body_classes("body")] { + body class=[page.body_classes()] { @match page.template() { "admin" => { @for region in &["top-menu", "side-menu", "content"] { @@ -75,10 +75,29 @@ pub trait ThemeTrait: Send + Sync { } #[allow(unused_variables)] - fn render_component( + fn before_render_component( &self, component: &mut dyn PageComponent, assets: &mut PageAssets + ) { + /* + Cómo usarlo: + + match component.name() { + "Block" => { + let block = component.downcast_mut::<Block>().unwrap(); + block.alter_title("New title"); + }, + _ => {}, + } + */ + } + + #[allow(unused_variables)] + fn render_component( + &self, + component: &dyn PageComponent, + assets: &mut PageAssets ) -> Option<Markup> { None /* @@ -89,10 +108,10 @@ pub trait ThemeTrait: Send + Sync { let block = component.downcast_ref::<Block>().unwrap(); match block.template() { "default" => Some(block_default(block)), - _ => None + _ => None, } }, - _ => None + _ => None, } */ } From 5b9c5ffdae8e5e9d9ea48cf9a578aa6a575e8c01 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 24 Jun 2025 15:57:55 +0200 Subject: [PATCH 051/244] =?UTF-8?q?=F0=9F=8E=89=20Inicia=20el=20proyecto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..8d626330 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +<div align="center"> + +<h1>PageTop</h1> + +<p>Un entorno para el desarrollo de soluciones web modulares, extensibles y configurables.</p> + +</div> + +`PageTop` reivindica la esencia de la web clásica usando [Rust](https://www.rust-lang.org/es) para +la creación de soluciones web SSR (*renderizadas en el servidor*) basadas en HTML, CSS y JavaScript. From 45e2882653f45c2f323f87c4634d4aaffa48c8c2 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 24 Jun 2025 20:23:28 +0200 Subject: [PATCH 052/244] =?UTF-8?q?=F0=9F=93=84=20A=C3=B1ade=20las=20licen?= =?UTF-8?q?cias=20del=20proyecto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE-APACHE | 201 +++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE-MIT | 21 ++++++ README.md | 23 ++++++ 3 files changed, 245 insertions(+) create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 00000000..263ddac1 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 Manuel Cillero + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 00000000..cd8af3d6 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Manuel Cillero + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 8d626330..7800fa53 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,30 @@ <p>Un entorno para el desarrollo de soluciones web modulares, extensibles y configurables.</p> +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) + </div> `PageTop` reivindica la esencia de la web clásica usando [Rust](https://www.rust-lang.org/es) para la creación de soluciones web SSR (*renderizadas en el servidor*) basadas en HTML, CSS y JavaScript. + + +# 📜 Licencia + +El código está disponible bajo una doble licencia: + + * **Licencia MIT** + ([LICENSE-MIT](LICENSE-MIT) o también https://opensource.org/licenses/MIT) + + * **Licencia Apache, Versión 2.0** + ([LICENSE-APACHE](LICENSE-APACHE) o también https://www.apache.org/licenses/LICENSE-2.0) + +Puedes elegir la licencia que prefieras. Este enfoque de doble licencia es el estándar de facto en +el ecosistema Rust. + + +# ✨ Contribuciones + +Cualquier contribución para añadir al proyecto se considerará automáticamente bajo la doble licencia +indicada arriba (MIT o Apache v2.0), sin términos o condiciones adicionales, tal y como permite la +licencia *Apache v2.0*. From cbee4c2cb88e9b03601fdaa26e6c2a09d56ed7bb Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 3 Jul 2025 20:33:52 +0200 Subject: [PATCH 053/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20servidor=20web?= =?UTF-8?q?=20y=20primeras=20macros=20de=20PageTop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Crea el crate raíz `pagetop` y configura el workspace con `helpers/pagetop-macros`. - Añade las macros #[pagetop::main] y #[pagetop::test] que envuelven Actix-web para crear aplicaciones y pruebas asíncronas sin depender explícitamente del framework. - Reexporta, mediante el módulo `service`, los tipos esenciales de Actix-web para gestionar servidores y servicios web. - Implementa `Application::{new, run, test}` para simplificar el arranque y la ejecución de tests. - Expone `pagetop::prelude` con las macros, `service` y `Application` para una API pública coherente. - Incorpora ejemplo `examples/app-basic.rs` que levanta un servidor web vacío con el código mínimo para hacerlo. --- .gitignore | 2 + Cargo.lock | 1509 +++++++++++++++++++++++++++++ Cargo.toml | 38 + README.md | 16 +- examples/app-basic.rs | 6 + helpers/pagetop-macros/Cargo.toml | 21 + helpers/pagetop-macros/README.md | 36 + helpers/pagetop-macros/src/lib.rs | 60 ++ src/app.rs | 50 + src/lib.rs | 46 + src/prelude.rs | 11 + src/service.rs | 9 + tests/service.rs | 15 + 13 files changed, 1818 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 examples/app-basic.rs create mode 100644 helpers/pagetop-macros/Cargo.toml create mode 100644 helpers/pagetop-macros/README.md create mode 100644 helpers/pagetop-macros/src/lib.rs create mode 100644 src/app.rs create mode 100644 src/lib.rs create mode 100644 src/prelude.rs create mode 100644 src/service.rs create mode 100644 tests/service.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..855694f3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Ignora directorios de compilación +**/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..0528b57c --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1509 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "actix-codec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-http" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44dfe5c9e0004c623edc65391dfd51daa201e7e30ebd9c9bedf873048ec32bc2" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "base64", + "bitflags", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "foldhash", + "futures-core", + "h2", + "http", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand", + "sha1", + "smallvec", + "tokio", + "tokio-util", + "tracing", + "zstd", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "actix-router" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" +dependencies = [ + "bytestring", + "cfg-if", + "http", + "regex", + "regex-lite", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e46f36bf0e5af44bdc4bdb36fbbd421aa98c79a9bce724e1edeb3894e10dc7f" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a597b77b5c6d6a1e1097fddde329a83665e25c5437c696a3a9a4aa514a614dea" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", + "bytes", + "bytestring", + "cfg-if", + "cookie", + "derive_more", + "encoding_rs", + "foldhash", + "futures-core", + "futures-util", + "impl-more", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "regex-lite", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2", + "time", + "tracing", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "brotli" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "bytestring" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" +dependencies = [ + "bytes", +] + +[[package]] +name = "cc" +version = "1.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-more" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" + +[[package]] +name = "indexmap" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom", + "libc", +] + +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "local-channel" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" +dependencies = [ + "futures-core", + "futures-sink", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "log", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "pagetop" +version = "0.0.1" +dependencies = [ + "actix-web", + "pagetop-macros", +] + +[[package]] +name = "pagetop-macros" +version = "0.0.1" +dependencies = [ + "quote", +] + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc-demangle" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.15+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..33bb5bf8 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "pagetop" +version = "0.0.1" +edition = "2021" + +description = """\ + Un entorno de desarrollo para crear soluciones web modulares, extensibles y configurables.\ +""" +categories = ["web-programming", "gui", "development-tools", "asynchronous"] +keywords = ["pagetop", "web", "framework", "frontend", "ssr"] + +repository.workspace = true +homepage.workspace = true +license.workspace = true +authors.workspace = true + +[dependencies] +actix-web = "4.11.0" + +pagetop-macros.workspace = true + + + +[workspace] +resolver = "2" +members = [ + "helpers/pagetop-macros", +] + +[workspace.package] +repository = "https://git.cillero.es/manuelcillero/pagetop" +homepage = "https://pagetop.cillero.es" +license = "MIT OR Apache-2.0" +authors = ["Manuel Cillero <manuel@cillero.es>"] + +[workspace.dependencies] +# Helpers +pagetop-macros = { version = "0.0", path = "helpers/pagetop-macros" } diff --git a/README.md b/README.md index 7800fa53..7293f88d 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,20 @@ la creación de soluciones web SSR (*renderizadas en el servidor*) basadas en HTML, CSS y JavaScript. +# ⚡️ Guía rápida + +La aplicación más sencilla de `PageTop` se ve así: + +```rust#ignore +use pagetop::prelude::*; + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::new().run()?.await +} +``` + + # 📜 Licencia El código está disponible bajo una doble licencia: @@ -26,7 +40,7 @@ Puedes elegir la licencia que prefieras. Este enfoque de doble licencia es el es el ecosistema Rust. -# ✨ Contribuciones +# ✨ Contribuir Cualquier contribución para añadir al proyecto se considerará automáticamente bajo la doble licencia indicada arriba (MIT o Apache v2.0), sin términos o condiciones adicionales, tal y como permite la diff --git a/examples/app-basic.rs b/examples/app-basic.rs new file mode 100644 index 00000000..53743870 --- /dev/null +++ b/examples/app-basic.rs @@ -0,0 +1,6 @@ +use pagetop::prelude::*; + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::new().run()?.await +} diff --git a/helpers/pagetop-macros/Cargo.toml b/helpers/pagetop-macros/Cargo.toml new file mode 100644 index 00000000..7a4d30e1 --- /dev/null +++ b/helpers/pagetop-macros/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "pagetop-macros" +version = "0.0.1" +edition = "2021" + +description = """\ + Una colección de macros que mejoran la experiencia de desarrollo con PageTop.\ +""" +categories = ["development-tools::procedural-macro-helpers", "web-programming"] +keywords = ["pagetop", "macros", "proc-macros", "codegen"] + +repository.workspace = true +homepage.workspace = true +license.workspace = true +authors.workspace = true + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0.40" diff --git a/helpers/pagetop-macros/README.md b/helpers/pagetop-macros/README.md new file mode 100644 index 00000000..8bdc94c2 --- /dev/null +++ b/helpers/pagetop-macros/README.md @@ -0,0 +1,36 @@ +<div align="center"> + +<h1>PageTop Macros</h1> + +<p>Una colección de macros que mejoran la experiencia de desarrollo con <strong>PageTop</strong>.</p> + +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) + +</div> + +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + + +# 🚧 Advertencia + +`PageTop` es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su +ecosistema. Su API está sujeta a cambios frecuentes. No se recomienda su uso en producción, al menos +hasta que se libere la versión **1.0.0**. + + +# 📜 Licencia + +El código está disponible bajo una doble licencia: + + * **Licencia MIT** + ([LICENSE-MIT](LICENSE-MIT) o también https://opensource.org/licenses/MIT) + + * **Licencia Apache, Versión 2.0** + ([LICENSE-APACHE](LICENSE-APACHE) o también https://www.apache.org/licenses/LICENSE-2.0) + +Puedes elegir la licencia que prefieras. Este enfoque de doble licencia es el estándar de facto en +el ecosistema Rust. diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs new file mode 100644 index 00000000..1ed29c5b --- /dev/null +++ b/helpers/pagetop-macros/src/lib.rs @@ -0,0 +1,60 @@ +//! <div align="center"> +//! +//! <h1>PageTop Macros</h1> +//! +//! <p>Una colección de macros que mejoran la experiencia de desarrollo con <strong>PageTop</strong>.</p> +//! +//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +//! +//! </div> +//! +//! ## Sobre PageTop +//! +//! [PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la +//! web clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles +//! y configurables, basadas en HTML, CSS y JavaScript. + +use proc_macro::TokenStream; +use quote::quote; + +/// Define una función `main` asíncrona como punto de entrada de `PageTop`. +/// +/// # Ejemplos +/// +/// ```rust#ignore +/// #[pagetop::main] +/// async fn main() { +/// async { println!("Hello world!"); }.await +/// } +/// ``` +#[proc_macro_attribute] +pub fn main(_: TokenStream, item: TokenStream) -> TokenStream { + let mut output: TokenStream = (quote! { + #[::pagetop::service::rt::main(system = "::pagetop::service::rt::System")] + }) + .into(); + + output.extend(item); + output +} + +/// Define funciones de prueba asíncronas para usar con `PageTop`. +/// +/// # Ejemplos +/// +/// ```rust#ignore +/// #[pagetop::test] +/// async fn test() { +/// assert_eq!(async { "Hello world" }.await, "Hello world"); +/// } +/// ``` +#[proc_macro_attribute] +pub fn test(_: TokenStream, item: TokenStream) -> TokenStream { + let mut output: TokenStream = (quote! { + #[::pagetop::service::rt::test(system = "::pagetop::service::rt::System")] + }) + .into(); + + output.extend(item); + output +} diff --git a/src/app.rs b/src/app.rs new file mode 100644 index 00000000..711c7631 --- /dev/null +++ b/src/app.rs @@ -0,0 +1,50 @@ +//! Prepara y ejecuta una aplicación creada con `Pagetop`. + +use crate::service; + +use std::io::Error; + +pub struct Application; + +impl Application { + /// Crea una instancia de la aplicación. + pub fn new() -> Self { + Self + } + + /// Ejecuta el servidor web de la aplicación. + pub fn run(self) -> Result<service::Server, Error> { + // Prepara el servidor web. + Ok(service::HttpServer::new(move || Self::service_app()) + .bind("localhost:8080")? + .run()) + } + + /// Prepara el servidor web de la aplicación para pruebas. + pub fn test( + self, + ) -> service::App< + impl service::Factory< + service::Request, + Config = (), + Response = service::Response<service::BoxBody>, + Error = service::Error, + InitError = (), + >, + > { + Self::service_app() + } + + // Configura el servicio web de la aplicación. + fn service_app() -> service::App< + impl service::Factory< + service::Request, + Config = (), + Response = service::Response<service::BoxBody>, + Error = service::Error, + InitError = (), + >, + > { + service::App::new() + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..c18003f8 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,46 @@ +//! <div align="center"> +//! +//! <img src="https://raw.githubusercontent.com/manuelcillero/pagetop/main/static/banner.png" /> +//! +//! <h1>PageTop</h1> +//! +//! <p>Un entorno de desarrollo para crear soluciones web modulares, extensibles y configurables.</p> +//! +//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +//! +//! <br> +//! </div> +//! +//! `PageTop` reivindica la esencia de la web clásica usando [Rust](https://www.rust-lang.org/es) +//! para la creación de soluciones web SSR (*renderizadas en el servidor*) basadas en HTML, CSS y +//! JavaScript. +//! +//! # ⚡️ Guía rápida +//! +//! La aplicación más sencilla de `PageTop` se ve así: +//! +//! ```rust#ignore +//! use pagetop::prelude::*; +//! +//! #[pagetop::main] +//! async fn main() -> std::io::Result<()> { +//! Application::new().run()?.await +//! } +//! ``` + +#![cfg_attr(docsrs, feature(doc_cfg))] + +// RE-EXPORTED ************************************************************************************* + +pub use pagetop_macros::{main, test}; + +// API ********************************************************************************************* + +// Gestión del servidor y servicios web. +pub mod service; +// Prepara y ejecuta la aplicación. +pub mod app; + +// PRELUDE ***************************************************************************************** + +pub mod prelude; diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 00000000..d35e9b11 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,11 @@ +//! *Prelude* de `PageTop`. + +// RE-EXPORTED. + +pub use crate::{main, test}; + +// API. + +pub use crate::service; + +pub use crate::app::Application; diff --git a/src/service.rs b/src/service.rs new file mode 100644 index 00000000..9fe2450e --- /dev/null +++ b/src/service.rs @@ -0,0 +1,9 @@ +//! Gestión del servidor y servicios web ([actix-web](https://docs.rs/actix-web)). + +pub use actix_web::body::BoxBody; +pub use actix_web::dev::Server; +pub use actix_web::dev::ServiceFactory as Factory; +pub use actix_web::dev::ServiceRequest as Request; +pub use actix_web::dev::ServiceResponse as Response; +pub use actix_web::{http, rt, test}; +pub use actix_web::{App, Error, HttpServer}; diff --git a/tests/service.rs b/tests/service.rs new file mode 100644 index 00000000..51e74c74 --- /dev/null +++ b/tests/service.rs @@ -0,0 +1,15 @@ +use pagetop::prelude::*; + +#[pagetop::test] +async fn homepage_returns_404() { + let app = service::test::init_service(Application::new().test()).await; + + let req = service::test::TestRequest::get().uri("/").to_request(); + 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); +} From f7dbd90af274dfc4366acf95a654a1ec0af6c527 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 5 Jul 2025 22:23:05 +0200 Subject: [PATCH 054/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20lectura=20de?= =?UTF-8?q?=20configuraci=C3=B3n=20global=20y=20modular?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Soporta jerarquía de ficheros TOML que mapean ajustes a estructuras fuertemente tipadas con valores predefinidos. - Permite definir configuraciones distintas para cada entorno. - Añade la macro `include_config!` para facilitar la asignación modular de ajustes de configuración. - Añade documentación detallada y tests de verificación. --- .gitignore | 5 + Cargo.lock | 141 ++++- Cargo.toml | 11 +- src/app.rs | 55 +- src/app/figfont.rs | 30 + src/app/slant.flf | 1295 +++++++++++++++++++++++++++++++++++++++++ src/app/small.flf | 1097 +++++++++++++++++++++++++++++++++++ src/app/speed.flf | 1301 ++++++++++++++++++++++++++++++++++++++++++ src/app/starwars.flf | 719 +++++++++++++++++++++++ src/config.rs | 179 ++++++ src/global.rs | 57 ++ src/lib.rs | 4 + src/prelude.rs | 7 + tests/config.rs | 41 ++ 14 files changed, 4938 insertions(+), 4 deletions(-) create mode 100644 src/app/figfont.rs create mode 100644 src/app/slant.flf create mode 100644 src/app/small.flf create mode 100644 src/app/speed.flf create mode 100644 src/app/starwars.flf create mode 100644 src/config.rs create mode 100644 src/global.rs create mode 100644 tests/config.rs diff --git a/.gitignore b/.gitignore index 855694f3..56ee30e4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ # Ignora directorios de compilación **/target + +# Archivos de configuración locales +**/local.*.toml +**/local.toml +.env diff --git a/Cargo.lock b/Cargo.lock index 0528b57c..045a72fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,6 +319,27 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +[[package]] +name = "colored" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "config" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595aae20e65c3be792d05818e8c63025294ac3cb7e200f11459063a352a6ef80" +dependencies = [ + "pathdiff", + "serde", + "toml", + "winnow", +] + [[package]] name = "cookie" version = "0.16.2" @@ -424,6 +445,22 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "errno" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "figlet-rs" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4742a071cd9694fc86f9fa1a08fa3e53d40cc899d7ee532295da2d085639fbc5" + [[package]] name = "flate2" version = "1.1.2" @@ -712,6 +749,12 @@ version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + [[package]] name = "litemap" version = "0.8.0" @@ -807,10 +850,16 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "pagetop" -version = "0.0.1" +version = "0.0.2" dependencies = [ "actix-web", + "colored", + "config", + "figlet-rs", "pagetop-macros", + "serde", + "substring", + "terminal_size", ] [[package]] @@ -843,6 +892,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -994,6 +1049,19 @@ version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + [[package]] name = "ryu" version = "1.0.20" @@ -1038,6 +1106,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1104,6 +1181,15 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "substring" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ee6433ecef213b2e72f587ef64a2f5943e7cd16fbd82dbe8bc07486c534c86" +dependencies = [ + "autocfg", +] + [[package]] name = "syn" version = "2.0.104" @@ -1126,6 +1212,16 @@ dependencies = [ "syn", ] +[[package]] +name = "terminal_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" +dependencies = [ + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "time" version = "0.3.41" @@ -1197,6 +1293,40 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tracing" version = "0.1.41" @@ -1367,6 +1497,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen-rt" version = "0.39.0" diff --git a/Cargo.toml b/Cargo.toml index 33bb5bf8..a844f527 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.1" +version = "0.0.2" edition = "2021" description = """\ @@ -15,6 +15,13 @@ license.workspace = true authors.workspace = true [dependencies] +colored = "3.0.0" +config = { version = "0.15.11", default-features = false, features = ["toml"] } +figlet-rs = "0.1.5" +serde.workspace = true +substring = "1.4.5" +terminal_size = "0.4.2" + actix-web = "4.11.0" pagetop-macros.workspace = true @@ -34,5 +41,7 @@ license = "MIT OR Apache-2.0" authors = ["Manuel Cillero <manuel@cillero.es>"] [workspace.dependencies] +serde = { version = "1.0", features = ["derive"] } + # Helpers pagetop-macros = { version = "0.0", path = "helpers/pagetop-macros" } diff --git a/src/app.rs b/src/app.rs index 711c7631..bac74821 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,6 +1,10 @@ //! Prepara y ejecuta una aplicación creada con `Pagetop`. -use crate::service; +mod figfont; + +use crate::{global, service}; + +use substring::Substring; use std::io::Error; @@ -9,14 +13,61 @@ pub struct Application; impl Application { /// Crea una instancia de la aplicación. pub fn new() -> Self { + // Al arrancar muestra una cabecera para la aplicación. + Self::show_banner(); Self } + // Muestra una cabecera para la aplicación basada en la configuración. + fn show_banner() { + use colored::Colorize; + use terminal_size::{terminal_size, Width}; + + if global::SETTINGS.app.startup_banner.to_lowercase() != "off" { + // Nombre de la aplicación, ajustado al ancho del terminal si es necesario. + let mut app_ff = String::new(); + let app_name = &global::SETTINGS.app.name; + if let Some((Width(term_width), _)) = terminal_size() { + if term_width >= 80 { + let maxlen: usize = ((term_width / 10) - 2).into(); + let mut app = app_name.substring(0, maxlen).to_owned(); + if app_name.len() > maxlen { + app = format!("{app}..."); + } + if let Some(ff) = figfont::FIGFONT.convert(&app) { + app_ff = ff.to_string(); + } + } + } + if app_ff.is_empty() { + println!("\n{app_name}"); + } else { + print!("\n{app_ff}"); + } + + // Descripción de la aplicación. + if !global::SETTINGS.app.description.is_empty() { + println!("{}", global::SETTINGS.app.description.cyan()); + }; + + // Versión de PageTop. + println!( + "{} {}\n", + "Powered by PageTop".yellow(), + env!("CARGO_PKG_VERSION").yellow() + ); + } + } + /// Ejecuta el servidor web de la aplicación. pub fn run(self) -> Result<service::Server, Error> { // Prepara el servidor web. Ok(service::HttpServer::new(move || Self::service_app()) - .bind("localhost:8080")? + .bind(format!( + "{}:{}", + &global::SETTINGS.server.bind_address, + &global::SETTINGS.server.bind_port + ))? .run()) } diff --git a/src/app/figfont.rs b/src/app/figfont.rs new file mode 100644 index 00000000..6592d813 --- /dev/null +++ b/src/app/figfont.rs @@ -0,0 +1,30 @@ +use crate::global; + +use std::sync::LazyLock; + +use figlet_rs::FIGfont; + +pub static FIGFONT: LazyLock<FIGfont> = LazyLock::new(|| { + let slant = include_str!("slant.flf"); + let small = include_str!("small.flf"); + let speed = include_str!("speed.flf"); + let starwars = include_str!("starwars.flf"); + + FIGfont::from_content( + match global::SETTINGS.app.startup_banner.to_lowercase().as_str() { + "off" => slant, + "slant" => slant, + "small" => small, + "speed" => speed, + "starwars" => starwars, + _ => { + println!( + "\n FIGfont \"{}\" not found for banner. Using \"Slant\". Check settings.", + global::SETTINGS.app.startup_banner, + ); + slant + } + }, + ) + .unwrap() +}); diff --git a/src/app/slant.flf b/src/app/slant.flf new file mode 100644 index 00000000..ea27b6ed --- /dev/null +++ b/src/app/slant.flf @@ -0,0 +1,1295 @@ +flf2a$ 6 5 16 15 10 0 18319 +Slant by Glenn Chappell 3/93 -- based on Standard +Includes ISO Latin-1 +figlet release 2.1 -- 12 Aug 1994 +Permission is hereby given to modify this font, as long as the +modifier's name is placed on a comment line. + +Modified by Paul Burton <solution@earthlink.net> 12/96 to include new parameter +supported by FIGlet and FIGWin. May also be slightly modified for better use +of new full-width/kern/smush alternatives, but default output is NOT changed. + + $$@ + $$ @ + $$ @ + $$ @ + $$ @ +$$ @@ + __@ + / /@ + / / @ + /_/ @ +(_) @ + @@ + _ _ @ +( | )@ +|/|/ @ + $ @ +$ @ + @@ + __ __ @ + __/ // /_@ + /_ _ __/@ +/_ _ __/ @ + /_//_/ @ + @@ + __@ + _/ /@ + / __/@ + (_ ) @ +/ _/ @ +/_/ @@ + _ __@ + (_)_/_/@ + _/_/ @ + _/_/_ @ +/_/ (_) @ + @@ + ___ @ + ( _ ) @ + / __ \/|@ +/ /_/ < @ +\____/\/ @ + @@ + _ @ + ( )@ + |/ @ + $ @ +$ @ + @@ + __@ + _/_/@ + / / @ + / / @ +/ / @ +|_| @@ + _ @ + | |@ + / /@ + / / @ + _/_/ @ +/_/ @@ + @ + __/|_@ + | /@ +/_ __| @ + |/ @ + @@ + @ + __ @ + __/ /_@ +/_ __/@ + /_/ @ + @@ + @ + @ + @ + _ @ +( )@ +|/ @@ + @ + @ + ______@ +/_____/@ + $ @ + @@ + @ + @ + @ + _ @ +(_)@ + @@ + __@ + _/_/@ + _/_/ @ + _/_/ @ +/_/ @ + @@ + ____ @ + / __ \@ + / / / /@ +/ /_/ / @ +\____/ @ + @@ + ___@ + < /@ + / / @ + / / @ +/_/ @ + @@ + ___ @ + |__ \@ + __/ /@ + / __/ @ +/____/ @ + @@ + _____@ + |__ /@ + /_ < @ + ___/ / @ +/____/ @ + @@ + __ __@ + / // /@ + / // /_@ +/__ __/@ + /_/ @ + @@ + ______@ + / ____/@ + /___ \ @ + ____/ / @ +/_____/ @ + @@ + _____@ + / ___/@ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ + _____@ +/__ /@ + / / @ + / / @ +/_/ @ + @@ + ____ @ + ( __ )@ + / __ |@ +/ /_/ / @ +\____/ @ + @@ + ____ @ + / __ \@ + / /_/ /@ + \__, / @ +/____/ @ + @@ + @ + _ @ + (_)@ + _ @ +(_) @ + @@ + @ + _ @ + (_)@ + _ @ +( ) @ +|/ @@ + __@ + / /@ +/ / @ +\ \ @ + \_\@ + @@ + @ + _____@ + /____/@ +/____/ @ + $ @ + @@ +__ @ +\ \ @ + \ \@ + / /@ +/_/ @ + @@ + ___ @ + /__ \@ + / _/@ + /_/ @ +(_) @ + @@ + ______ @ + / ____ \@ + / / __ `/@ +/ / /_/ / @ +\ \__,_/ @ + \____/ @@ + ___ @ + / |@ + / /| |@ + / ___ |@ +/_/ |_|@ + @@ + ____ @ + / __ )@ + / __ |@ + / /_/ / @ +/_____/ @ + @@ + ______@ + / ____/@ + / / @ +/ /___ @ +\____/ @ + @@ + ____ @ + / __ \@ + / / / /@ + / /_/ / @ +/_____/ @ + @@ + ______@ + / ____/@ + / __/ @ + / /___ @ +/_____/ @ + @@ + ______@ + / ____/@ + / /_ @ + / __/ @ +/_/ @ + @@ + ______@ + / ____/@ + / / __ @ +/ /_/ / @ +\____/ @ + @@ + __ __@ + / / / /@ + / /_/ / @ + / __ / @ +/_/ /_/ @ + @@ + ____@ + / _/@ + / / @ + _/ / @ +/___/ @ + @@ + __@ + / /@ + __ / / @ +/ /_/ / @ +\____/ @ + @@ + __ __@ + / //_/@ + / ,< @ + / /| | @ +/_/ |_| @ + @@ + __ @ + / / @ + / / @ + / /___@ +/_____/@ + @@ + __ ___@ + / |/ /@ + / /|_/ / @ + / / / / @ +/_/ /_/ @ + @@ + _ __@ + / | / /@ + / |/ / @ + / /| / @ +/_/ |_/ @ + @@ + ____ @ + / __ \@ + / / / /@ +/ /_/ / @ +\____/ @ + @@ + ____ @ + / __ \@ + / /_/ /@ + / ____/ @ +/_/ @ + @@ + ____ @ + / __ \@ + / / / /@ +/ /_/ / @ +\___\_\ @ + @@ + ____ @ + / __ \@ + / /_/ /@ + / _, _/ @ +/_/ |_| @ + @@ + _____@ + / ___/@ + \__ \ @ + ___/ / @ +/____/ @ + @@ + ______@ + /_ __/@ + / / @ + / / @ +/_/ @ + @@ + __ __@ + / / / /@ + / / / / @ +/ /_/ / @ +\____/ @ + @@ + _ __@ +| | / /@ +| | / / @ +| |/ / @ +|___/ @ + @@ + _ __@ +| | / /@ +| | /| / / @ +| |/ |/ / @ +|__/|__/ @ + @@ + _ __@ + | |/ /@ + | / @ + / | @ +/_/|_| @ + @@ +__ __@ +\ \/ /@ + \ / @ + / / @ +/_/ @ + @@ + _____@ +/__ /@ + / / @ + / /__@ +/____/@ + @@ + ___@ + / _/@ + / / @ + / / @ + / / @ +/__/ @@ +__ @ +\ \ @ + \ \ @ + \ \ @ + \_\@ + @@ + ___@ + / /@ + / / @ + / / @ + _/ / @ +/__/ @@ + //|@ + |/||@ + $ @ + $ @ +$ @ + @@ + @ + @ + @ + @ + ______@ +/_____/@@ + _ @ + ( )@ + V @ + $ @ +$ @ + @@ + @ + ____ _@ + / __ `/@ +/ /_/ / @ +\__,_/ @ + @@ + __ @ + / /_ @ + / __ \@ + / /_/ /@ +/_.___/ @ + @@ + @ + _____@ + / ___/@ +/ /__ @ +\___/ @ + @@ + __@ + ____/ /@ + / __ / @ +/ /_/ / @ +\__,_/ @ + @@ + @ + ___ @ + / _ \@ +/ __/@ +\___/ @ + @@ + ____@ + / __/@ + / /_ @ + / __/ @ +/_/ @ + @@ + @ + ____ _@ + / __ `/@ + / /_/ / @ + \__, / @ +/____/ @@ + __ @ + / /_ @ + / __ \@ + / / / /@ +/_/ /_/ @ + @@ + _ @ + (_)@ + / / @ + / / @ +/_/ @ + @@ + _ @ + (_)@ + / / @ + / / @ + __/ / @ +/___/ @@ + __ @ + / /__@ + / //_/@ + / ,< @ +/_/|_| @ + @@ + __@ + / /@ + / / @ + / / @ +/_/ @ + @@ + @ + ____ ___ @ + / __ `__ \@ + / / / / / /@ +/_/ /_/ /_/ @ + @@ + @ + ____ @ + / __ \@ + / / / /@ +/_/ /_/ @ + @@ + @ + ____ @ + / __ \@ +/ /_/ /@ +\____/ @ + @@ + @ + ____ @ + / __ \@ + / /_/ /@ + / .___/ @ +/_/ @@ + @ + ____ _@ + / __ `/@ +/ /_/ / @ +\__, / @ + /_/ @@ + @ + _____@ + / ___/@ + / / @ +/_/ @ + @@ + @ + _____@ + / ___/@ + (__ ) @ +/____/ @ + @@ + __ @ + / /_@ + / __/@ +/ /_ @ +\__/ @ + @@ + @ + __ __@ + / / / /@ +/ /_/ / @ +\__,_/ @ + @@ + @ + _ __@ +| | / /@ +| |/ / @ +|___/ @ + @@ + @ + _ __@ +| | /| / /@ +| |/ |/ / @ +|__/|__/ @ + @@ + @ + _ __@ + | |/_/@ + _> < @ +/_/|_| @ + @@ + @ + __ __@ + / / / /@ + / /_/ / @ + \__, / @ +/____/ @@ + @ + ____@ +/_ /@ + / /_@ +/___/@ + @@ + __@ + _/_/@ + _/_/ @ +< < @ +/ / @ +\_\ @@ + __@ + / /@ + / / @ + / / @ + / / @ +/_/ @@ + _ @ + | |@ + / /@ + _>_>@ + _/_/ @ +/_/ @@ + /\//@ + //\/ @ + $ @ + $ @ +$ @ + @@ + _ _ @ + (_)(_)@ + / _ | @ + / __ | @ +/_/ |_| @ + @@ + _ _ @ + (_)_(_)@ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ + _ _ @ + (_) (_)@ + / / / / @ +/ /_/ / @ +\____/ @ + @@ + _ _ @ + (_)_(_)@ + / __ `/ @ +/ /_/ / @ +\__,_/ @ + @@ + _ _ @ + (_)_(_)@ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ + _ _ @ + (_) (_)@ + / / / / @ +/ /_/ / @ +\__,_/ @ + @@ + ____ @ + / __ \@ + / / / /@ + / /_| | @ + / //__/ @ +/_/ @@ +160 NO-BREAK SPACE + $$@ + $$ @ + $$ @ + $$ @ + $$ @ +$$ @@ +161 INVERTED EXCLAMATION MARK + _ @ + (_)@ + / / @ + / / @ +/_/ @ + @@ +162 CENT SIGN + __@ + __/ /@ + / ___/@ +/ /__ @ +\ _/ @ +/_/ @@ +163 POUND SIGN + ____ @ + / ,__\@ + __/ /_ @ + _/ /___ @ +(_,____/ @ + @@ +164 CURRENCY SIGN + /|___/|@ + | __ / @ + / /_/ / @ + /___ | @ +|/ |/ @ + @@ +165 YEN SIGN + ____@ + _| / /@ + /_ __/@ +/_ __/ @ + /_/ @ + @@ +166 BROKEN BAR + __@ + / /@ + /_/ @ + __ @ + / / @ +/_/ @@ +167 SECTION SIGN + __ @ + _/ _)@ + / | | @ + | || | @ + | |_/ @ +(__/ @@ +168 DIAERESIS + _ _ @ + (_) (_)@ + $ $ @ + $ $ @ +$ $ @ + @@ +169 COPYRIGHT SIGN + ______ @ + / _____\ @ + / / ___/ |@ + / / /__ / @ +| \___/ / @ + \______/ @@ +170 FEMININE ORDINAL INDICATOR + ___ _@ + / _ `/@ + _\_,_/ @ +/____/ @ + $ @ + @@ +171 LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + ____@ + / / /@ +/ / / @ +\ \ \ @ + \_\_\@ + @@ +172 NOT SIGN + @ + ______@ +/___ /@ + /_/ @ + $ @ + @@ +173 SOFT HYPHEN + @ + @ + _____@ +/____/@ + $ @ + @@ +174 REGISTERED SIGN + ______ @ + / ___ \ @ + / / _ \ |@ + / / , _/ / @ +| /_/|_| / @ + \______/ @@ +175 MACRON + ______@ +/_____/@ + $ @ + $ @ +$ @ + @@ +176 DEGREE SIGN + ___ @ + / _ \@ +/ // /@ +\___/ @ + $ @ + @@ +177 PLUS-MINUS SIGN + __ @ + __/ /_@ + /_ __/@ + __/_/_ @ +/_____/ @ + @@ +178 SUPERSCRIPT TWO + ___ @ + |_ |@ + / __/ @ +/____/ @ + $ @ + @@ +179 SUPERSCRIPT THREE + ____@ + |_ /@ + _/_ < @ +/____/ @ + $ @ + @@ +180 ACUTE ACCENT + __@ + /_/@ + $ @ + $ @ +$ @ + @@ +181 MICRO SIGN + @ + __ __@ + / / / /@ + / /_/ / @ + / ._,_/ @ +/_/ @@ +182 PILCROW SIGN + _______@ + / _ /@ +/ (/ / / @ +\_ / / @ + /_/_/ @ + @@ +183 MIDDLE DOT + @ + _ @ +(_)@ + $ @ +$ @ + @@ +184 CEDILLA + @ + @ + @ + @ + _ @ +/_)@@ +185 SUPERSCRIPT ONE + ___@ + < /@ + / / @ +/_/ @ +$ @ + @@ +186 MASCULINE ORDINAL INDICATOR + ___ @ + / _ \@ + _\___/@ +/____/ @ + $ @ + @@ +187 RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +____ @ +\ \ \ @ + \ \ \@ + / / /@ +/_/_/ @ + @@ +188 VULGAR FRACTION ONE QUARTER + ___ __ @ + < / _/_/ @ + / /_/_/___@ +/_//_// / /@ + /_/ /_ _/@ + /_/ @@ +189 VULGAR FRACTION ONE HALF + ___ __ @ + < / _/_/__ @ + / /_/_/|_ |@ +/_//_/ / __/ @ + /_/ /____/ @ + @@ +190 VULGAR FRACTION THREE QUARTERS + ____ __ @ + |_ / _/_/ @ + _/_ < _/_/___@ +/____//_// / /@ + /_/ /_ _/@ + /_/ @@ +191 INVERTED QUESTION MARK + _ @ + (_)@ + _/ / @ +/ _/_ @ +\___/ @ + @@ +192 LATIN CAPITAL LETTER A WITH GRAVE + __ @ + _\_\@ + / _ |@ + / __ |@ +/_/ |_|@ + @@ +193 LATIN CAPITAL LETTER A WITH ACUTE + __@ + _/_/@ + / _ |@ + / __ |@ +/_/ |_|@ + @@ +194 LATIN CAPITAL LETTER A WITH CIRCUMFLEX + //|@ + _|/||@ + / _ | @ + / __ | @ +/_/ |_| @ + @@ +195 LATIN CAPITAL LETTER A WITH TILDE + /\//@ + _//\/ @ + / _ | @ + / __ | @ +/_/ |_| @ + @@ +196 LATIN CAPITAL LETTER A WITH DIAERESIS + _ _ @ + (_)(_)@ + / _ | @ + / __ | @ +/_/ |_| @ + @@ +197 LATIN CAPITAL LETTER A WITH RING ABOVE + (())@ + / |@ + / /| |@ + / ___ |@ +/_/ |_|@ + @@ +198 LATIN CAPITAL LETTER AE + __________@ + / ____/@ + / /| __/ @ + / __ /___ @ +/_/ /_____/ @ + @@ +199 LATIN CAPITAL LETTER C WITH CEDILLA + ______@ + / ____/@ + / / @ +/ /___ @ +\____/ @ + /_) @@ +200 LATIN CAPITAL LETTER E WITH GRAVE + __ @ + _\_\@ + / __/@ + / _/ @ +/___/ @ + @@ +201 LATIN CAPITAL LETTER E WITH ACUTE + __@ + _/_/@ + / __/@ + / _/ @ +/___/ @ + @@ +202 LATIN CAPITAL LETTER E WITH CIRCUMFLEX + //|@ + _|/||@ + / __/ @ + / _/ @ +/___/ @ + @@ +203 LATIN CAPITAL LETTER E WITH DIAERESIS + _ _ @ + (_)(_)@ + / __/ @ + / _/ @ +/___/ @ + @@ +204 LATIN CAPITAL LETTER I WITH GRAVE + __ @ + _\_\@ + / _/@ + _/ / @ +/___/ @ + @@ +205 LATIN CAPITAL LETTER I WITH ACUTE + __@ + _/_/@ + / _/@ + _/ / @ +/___/ @ + @@ +206 LATIN CAPITAL LETTER I WITH CIRCUMFLEX + //|@ + _|/||@ + / _/ @ + _/ / @ +/___/ @ + @@ +207 LATIN CAPITAL LETTER I WITH DIAERESIS + _ _ @ + (_)(_)@ + / _/ @ + _/ / @ +/___/ @ + @@ +208 LATIN CAPITAL LETTER ETH + ____ @ + / __ \@ + __/ /_/ /@ +/_ __/ / @ + /_____/ @ + @@ +209 LATIN CAPITAL LETTER N WITH TILDE + /\//@ + _//\/ @ + / |/ / @ + / / @ +/_/|_/ @ + @@ +210 LATIN CAPITAL LETTER O WITH GRAVE + __ @ + __\_\@ + / __ \@ +/ /_/ /@ +\____/ @ + @@ +211 LATIN CAPITAL LETTER O WITH ACUTE + __@ + __/_/@ + / __ \@ +/ /_/ /@ +\____/ @ + @@ +212 LATIN CAPITAL LETTER O WITH CIRCUMFLEX + //|@ + _|/||@ + / __ \@ +/ /_/ /@ +\____/ @ + @@ +213 LATIN CAPITAL LETTER O WITH TILDE + /\//@ + _//\/ @ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ +214 LATIN CAPITAL LETTER O WITH DIAERESIS + _ _ @ + (_)_(_)@ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ +215 MULTIPLICATION SIGN + @ + @ + /|/|@ + > < @ +|/|/ @ + @@ +216 LATIN CAPITAL LETTER O WITH STROKE + _____ @ + / _// \@ + / //// /@ +/ //// / @ +\_//__/ @ + @@ +217 LATIN CAPITAL LETTER U WITH GRAVE + __ @ + __\_\_@ + / / / /@ +/ /_/ / @ +\____/ @ + @@ +218 LATIN CAPITAL LETTER U WITH ACUTE + __ @ + __/_/_@ + / / / /@ +/ /_/ / @ +\____/ @ + @@ +219 LATIN CAPITAL LETTER U WITH CIRCUMFLEX + //| @ + _|/||_@ + / / / /@ +/ /_/ / @ +\____/ @ + @@ +220 LATIN CAPITAL LETTER U WITH DIAERESIS + _ _ @ + (_) (_)@ + / / / / @ +/ /_/ / @ +\____/ @ + @@ +221 LATIN CAPITAL LETTER Y WITH ACUTE + __ @ +__/_/_@ +\ \/ /@ + \ / @ + /_/ @ + @@ +222 LATIN CAPITAL LETTER THORN + __ @ + / /_ @ + / __ \@ + / ____/@ +/_/ @ + @@ +223 LATIN SMALL LETTER SHARP S + ____ @ + / __ \@ + / / / /@ + / /_| | @ + / //__/ @ +/_/ @@ +224 LATIN SMALL LETTER A WITH GRAVE + __ @ + __\_\_@ + / __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +225 LATIN SMALL LETTER A WITH ACUTE + __ @ + __/_/_@ + / __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +226 LATIN SMALL LETTER A WITH CIRCUMFLEX + //| @ + _|/||_@ + / __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +227 LATIN SMALL LETTER A WITH TILDE + /\//@ + _//\/_@ + / __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +228 LATIN SMALL LETTER A WITH DIAERESIS + _ _ @ + (_)_(_)@ + / __ `/ @ +/ /_/ / @ +\__,_/ @ + @@ +229 LATIN SMALL LETTER A WITH RING ABOVE + __ @ + __(())@ + / __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +230 LATIN SMALL LETTER AE + @ + ____ ___ @ + / __ ` _ \@ +/ /_/ __/@ +\__,_____/ @ + @@ +231 LATIN SMALL LETTER C WITH CEDILLA + @ + _____@ + / ___/@ +/ /__ @ +\___/ @ +/_) @@ +232 LATIN SMALL LETTER E WITH GRAVE + __ @ + _\_\@ + / _ \@ +/ __/@ +\___/ @ + @@ +233 LATIN SMALL LETTER E WITH ACUTE + __@ + _/_/@ + / _ \@ +/ __/@ +\___/ @ + @@ +234 LATIN SMALL LETTER E WITH CIRCUMFLEX + //|@ + _|/||@ + / _ \ @ +/ __/ @ +\___/ @ + @@ +235 LATIN SMALL LETTER E WITH DIAERESIS + _ _ @ + (_)(_)@ + / _ \ @ +/ __/ @ +\___/ @ + @@ +236 LATIN SMALL LETTER I WITH GRAVE + __ @ + \_\@ + / / @ + / / @ +/_/ @ + @@ +237 LATIN SMALL LETTER I WITH ACUTE + __@ + /_/@ + / / @ + / / @ +/_/ @ + @@ +238 LATIN SMALL LETTER I WITH CIRCUMFLEX + //|@ + |/||@ + / / @ + / / @ +/_/ @ + @@ +239 LATIN SMALL LETTER I WITH DIAERESIS + _ _ @ + (_)_(_)@ + / / @ + / / @ +/_/ @ + @@ +240 LATIN SMALL LETTER ETH + || @ + =||=@ + ___ || @ +/ __` | @ +\____/ @ + @@ +241 LATIN SMALL LETTER N WITH TILDE + /\//@ + _//\/ @ + / __ \ @ + / / / / @ +/_/ /_/ @ + @@ +242 LATIN SMALL LETTER O WITH GRAVE + __ @ + __\_\@ + / __ \@ +/ /_/ /@ +\____/ @ + @@ +243 LATIN SMALL LETTER O WITH ACUTE + __@ + __/_/@ + / __ \@ +/ /_/ /@ +\____/ @ + @@ +244 LATIN SMALL LETTER O WITH CIRCUMFLEX + //|@ + _|/||@ + / __ \@ +/ /_/ /@ +\____/ @ + @@ +245 LATIN SMALL LETTER O WITH TILDE + /\//@ + _//\/ @ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ +246 LATIN SMALL LETTER O WITH DIAERESIS + _ _ @ + (_)_(_)@ + / __ \ @ +/ /_/ / @ +\____/ @ + @@ +247 DIVISION SIGN + @ + _ @ + __(_)_@ +/_____/@ + (_) @ + @@ +248 LATIN SMALL LETTER O WITH STROKE + @ + _____ @ + / _// \@ +/ //// /@ +\_//__/ @ + @@ +249 LATIN SMALL LETTER U WITH GRAVE + __ @ + __\_\_@ + / / / /@ +/ /_/ / @ +\__,_/ @ + @@ +250 LATIN SMALL LETTER U WITH ACUTE + __ @ + __/_/_@ + / / / /@ +/ /_/ / @ +\__,_/ @ + @@ +251 LATIN SMALL LETTER U WITH CIRCUMFLEX + //| @ + _|/||_@ + / / / /@ +/ /_/ / @ +\__,_/ @ + @@ +252 LATIN SMALL LETTER U WITH DIAERESIS + _ _ @ + (_) (_)@ + / / / / @ +/ /_/ / @ +\__,_/ @ + @@ +253 LATIN SMALL LETTER Y WITH ACUTE + __ @ + __/_/_@ + / / / /@ + / /_/ / @ + \__, / @ +/____/ @@ +254 LATIN SMALL LETTER THORN + __ @ + / /_ @ + / __ \@ + / /_/ /@ + / .___/ @ +/_/ @@ +255 LATIN SMALL LETTER Y WITH DIAERESIS + _ _ @ + (_) (_)@ + / / / / @ + / /_/ / @ + \__, / @ +/____/ @@ diff --git a/src/app/small.flf b/src/app/small.flf new file mode 100644 index 00000000..d2a2c49c --- /dev/null +++ b/src/app/small.flf @@ -0,0 +1,1097 @@ +flf2a$ 5 4 13 15 10 0 22415 +Small by Glenn Chappell 4/93 -- based on Standard +Includes ISO Latin-1 +figlet release 2.1 -- 12 Aug 1994 +Permission is hereby given to modify this font, as long as the +modifier's name is placed on a comment line. + +Modified by Paul Burton <solution@earthlink.net> 12/96 to include new parameter +supported by FIGlet and FIGWin. May also be slightly modified for better use +of new full-width/kern/smush alternatives, but default output is NOT changed. + + $@ + $@ + $@ + $@ + $@@ + _ @ + | |@ + |_|@ + (_)@ + @@ + _ _ @ + ( | )@ + V V @ + $ @ + @@ + _ _ @ + _| | |_ @ + |_ . _|@ + |_ _|@ + |_|_| @@ + @ + ||_@ + (_-<@ + / _/@ + || @@ + _ __ @ + (_)/ / @ + / /_ @ + /_/(_)@ + @@ + __ @ + / _|___ @ + > _|_ _|@ + \_____| @ + @@ + _ @ + ( )@ + |/ @ + $ @ + @@ + __@ + / /@ + | | @ + | | @ + \_\@@ + __ @ + \ \ @ + | |@ + | |@ + /_/ @@ + @ + _/\_@ + > <@ + \/ @ + @@ + _ @ + _| |_ @ + |_ _|@ + |_| @ + @@ + @ + @ + _ @ + ( )@ + |/ @@ + @ + ___ @ + |___|@ + $ @ + @@ + @ + @ + _ @ + (_)@ + @@ + __@ + / /@ + / / @ + /_/ @ + @@ + __ @ + / \ @ + | () |@ + \__/ @ + @@ + _ @ + / |@ + | |@ + |_|@ + @@ + ___ @ + |_ )@ + / / @ + /___|@ + @@ + ____@ + |__ /@ + |_ \@ + |___/@ + @@ + _ _ @ + | | | @ + |_ _|@ + |_| @ + @@ + ___ @ + | __|@ + |__ \@ + |___/@ + @@ + __ @ + / / @ + / _ \@ + \___/@ + @@ + ____ @ + |__ |@ + / / @ + /_/ @ + @@ + ___ @ + ( _ )@ + / _ \@ + \___/@ + @@ + ___ @ + / _ \@ + \_, /@ + /_/ @ + @@ + _ @ + (_)@ + _ @ + (_)@ + @@ + _ @ + (_)@ + _ @ + ( )@ + |/ @@ + __@ + / /@ + < < @ + \_\@ + @@ + @ + ___ @ + |___|@ + |___|@ + @@ + __ @ + \ \ @ + > >@ + /_/ @ + @@ + ___ @ + |__ \@ + /_/@ + (_) @ + @@ + ____ @ + / __ \ @ + / / _` |@ + \ \__,_|@ + \____/ @@ + _ @ + /_\ @ + / _ \ @ + /_/ \_\@ + @@ + ___ @ + | _ )@ + | _ \@ + |___/@ + @@ + ___ @ + / __|@ + | (__ @ + \___|@ + @@ + ___ @ + | \ @ + | |) |@ + |___/ @ + @@ + ___ @ + | __|@ + | _| @ + |___|@ + @@ + ___ @ + | __|@ + | _| @ + |_| @ + @@ + ___ @ + / __|@ + | (_ |@ + \___|@ + @@ + _ _ @ + | || |@ + | __ |@ + |_||_|@ + @@ + ___ @ + |_ _|@ + | | @ + |___|@ + @@ + _ @ + _ | |@ + | || |@ + \__/ @ + @@ + _ __@ + | |/ /@ + | ' < @ + |_|\_\@ + @@ + _ @ + | | @ + | |__ @ + |____|@ + @@ + __ __ @ + | \/ |@ + | |\/| |@ + |_| |_|@ + @@ + _ _ @ + | \| |@ + | .` |@ + |_|\_|@ + @@ + ___ @ + / _ \ @ + | (_) |@ + \___/ @ + @@ + ___ @ + | _ \@ + | _/@ + |_| @ + @@ + ___ @ + / _ \ @ + | (_) |@ + \__\_\@ + @@ + ___ @ + | _ \@ + | /@ + |_|_\@ + @@ + ___ @ + / __|@ + \__ \@ + |___/@ + @@ + _____ @ + |_ _|@ + | | @ + |_| @ + @@ + _ _ @ + | | | |@ + | |_| |@ + \___/ @ + @@ + __ __@ + \ \ / /@ + \ V / @ + \_/ @ + @@ + __ __@ + \ \ / /@ + \ \/\/ / @ + \_/\_/ @ + @@ + __ __@ + \ \/ /@ + > < @ + /_/\_\@ + @@ + __ __@ + \ \ / /@ + \ V / @ + |_| @ + @@ + ____@ + |_ /@ + / / @ + /___|@ + @@ + __ @ + | _|@ + | | @ + | | @ + |__|@@ + __ @ + \ \ @ + \ \ @ + \_\@ + @@ + __ @ + |_ |@ + | |@ + | |@ + |__|@@ + /\ @ + |/\|@ + $ @ + $ @ + @@ + @ + @ + @ + ___ @ + |___|@@ + _ @ + ( )@ + \|@ + $ @ + @@ + @ + __ _ @ + / _` |@ + \__,_|@ + @@ + _ @ + | |__ @ + | '_ \@ + |_.__/@ + @@ + @ + __ @ + / _|@ + \__|@ + @@ + _ @ + __| |@ + / _` |@ + \__,_|@ + @@ + @ + ___ @ + / -_)@ + \___|@ + @@ + __ @ + / _|@ + | _|@ + |_| @ + @@ + @ + __ _ @ + / _` |@ + \__, |@ + |___/ @@ + _ @ + | |_ @ + | ' \ @ + |_||_|@ + @@ + _ @ + (_)@ + | |@ + |_|@ + @@ + _ @ + (_)@ + | |@ + _/ |@ + |__/ @@ + _ @ + | |__@ + | / /@ + |_\_\@ + @@ + _ @ + | |@ + | |@ + |_|@ + @@ + @ + _ __ @ + | ' \ @ + |_|_|_|@ + @@ + @ + _ _ @ + | ' \ @ + |_||_|@ + @@ + @ + ___ @ + / _ \@ + \___/@ + @@ + @ + _ __ @ + | '_ \@ + | .__/@ + |_| @@ + @ + __ _ @ + / _` |@ + \__, |@ + |_|@@ + @ + _ _ @ + | '_|@ + |_| @ + @@ + @ + ___@ + (_-<@ + /__/@ + @@ + _ @ + | |_ @ + | _|@ + \__|@ + @@ + @ + _ _ @ + | || |@ + \_,_|@ + @@ + @ + __ __@ + \ V /@ + \_/ @ + @@ + @ + __ __ __@ + \ V V /@ + \_/\_/ @ + @@ + @ + __ __@ + \ \ /@ + /_\_\@ + @@ + @ + _ _ @ + | || |@ + \_, |@ + |__/ @@ + @ + ___@ + |_ /@ + /__|@ + @@ + __@ + / /@ + _| | @ + | | @ + \_\@@ + _ @ + | |@ + | |@ + | |@ + |_|@@ + __ @ + \ \ @ + | |_@ + | | @ + /_/ @@ + /\/|@ + |/\/ @ + $ @ + $ @ + @@ + _ _ @ + (_)(_)@ + /--\ @ + /_/\_\@ + @@ + _ _ @ + (_)(_)@ + / __ \@ + \____/@ + @@ + _ _ @ + (_) (_)@ + | |_| |@ + \___/ @ + @@ + _ _ @ + (_)(_)@ + / _` |@ + \__,_|@ + @@ + _ _ @ + (_)_(_)@ + / _ \ @ + \___/ @ + @@ + _ _ @ + (_)(_)@ + | || |@ + \_,_|@ + @@ + ___ @ + / _ \@ + | |< <@ + | ||_/@ + |_| @@ +160 NO-BREAK SPACE + $@ + $@ + $@ + $@ + $@@ +161 INVERTED EXCLAMATION MARK + _ @ + (_)@ + | |@ + |_|@ + @@ +162 CENT SIGN + @ + || @ + / _)@ + \ _)@ + || @@ +163 POUND SIGN + __ @ + _/ _\ @ + |_ _|_ @ + (_,___|@ + @@ +164 CURRENCY SIGN + /\_/\@ + \ . /@ + / _ \@ + \/ \/@ + @@ +165 YEN SIGN + __ __ @ + \ V / @ + |__ __|@ + |__ __|@ + |_| @@ +166 BROKEN BAR + _ @ + | |@ + |_|@ + | |@ + |_|@@ +167 SECTION SIGN + __ @ + / _)@ + /\ \ @ + \ \/ @ + (__/ @@ +168 DIAERESIS + _ _ @ + (_)(_)@ + $ $ @ + $ $ @ + @@ +169 COPYRIGHT SIGN + ____ @ + / __ \ @ + / / _| \@ + \ \__| /@ + \____/ @@ +170 FEMININE ORDINAL INDICATOR + __ _ @ + / _` |@ + \__,_|@ + |____|@ + @@ +171 LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + ____@ + / / /@ + < < < @ + \_\_\@ + @@ +172 NOT SIGN + ____ @ + |__ |@ + |_|@ + $ @ + @@ +173 SOFT HYPHEN + @ + __ @ + |__|@ + $ @ + @@ +174 REGISTERED SIGN + ____ @ + / __ \ @ + / | -) \@ + \ ||\\ /@ + \____/ @@ +175 MACRON + ___ @ + |___|@ + $ @ + $ @ + @@ +176 DEGREE SIGN + _ @ + /.\@ + \_/@ + $ @ + @@ +177 PLUS-MINUS SIGN + _ @ + _| |_ @ + |_ _|@ + _|_|_ @ + |_____|@@ +178 SUPERSCRIPT TWO + __ @ + |_ )@ + /__|@ + $ @ + @@ +179 SUPERSCRIPT THREE + ___@ + |_ /@ + |__)@ + $ @ + @@ +180 ACUTE ACCENT + __@ + /_/@ + $ @ + $ @ + @@ +181 MICRO SIGN + @ + _ _ @ + | || |@ + | .,_|@ + |_| @@ +182 PILCROW SIGN + ____ @ + / |@ + \_ | |@ + |_|_|@ + @@ +183 MIDDLE DOT + @ + _ @ + (_)@ + $ @ + @@ +184 CEDILLA + @ + @ + @ + _ @ + )_)@@ +185 SUPERSCRIPT ONE + _ @ + / |@ + |_|@ + $ @ + @@ +186 MASCULINE ORDINAL INDICATOR + ___ @ + / _ \@ + \___/@ + |___|@ + @@ +187 RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + ____ @ + \ \ \ @ + > > >@ + /_/_/ @ + @@ +188 VULGAR FRACTION ONE QUARTER + _ __ @ + / |/ /__ @ + |_/ /_' |@ + /_/ |_|@ + @@ +189 VULGAR FRACTION ONE HALF + _ __ @ + / |/ /_ @ + |_/ /_ )@ + /_//__|@ + @@ +190 VULGAR FRACTION THREE QUARTERS + ___ __ @ + |_ // /__ @ + |__) /_' |@ + /_/ |_|@ + @@ +191 INVERTED QUESTION MARK + _ @ + (_) @ + / /_ @ + \___|@ + @@ +192 LATIN CAPITAL LETTER A WITH GRAVE + __ @ + \_\ @ + /--\ @ + /_/\_\@ + @@ +193 LATIN CAPITAL LETTER A WITH ACUTE + __ @ + /_/ @ + /--\ @ + /_/\_\@ + @@ +194 LATIN CAPITAL LETTER A WITH CIRCUMFLEX + /\ @ + |/\| @ + /--\ @ + /_/\_\@ + @@ +195 LATIN CAPITAL LETTER A WITH TILDE + /\/|@ + |/\/ @ + /--\ @ + /_/\_\@ + @@ +196 LATIN CAPITAL LETTER A WITH DIAERESIS + _ _ @ + (_)(_)@ + /--\ @ + /_/\_\@ + @@ +197 LATIN CAPITAL LETTER A WITH RING ABOVE + __ @ + (()) @ + /--\ @ + /_/\_\@ + @@ +198 LATIN CAPITAL LETTER AE + ____ @ + /, __|@ + / _ _| @ + /_/|___|@ + @@ +199 LATIN CAPITAL LETTER C WITH CEDILLA + ___ @ + / __|@ + | (__ @ + \___|@ + )_) @@ +200 LATIN CAPITAL LETTER E WITH GRAVE + __ @ + \_\@ + | -<@ + |__<@ + @@ +201 LATIN CAPITAL LETTER E WITH ACUTE + __@ + /_/@ + | -<@ + |__<@ + @@ +202 LATIN CAPITAL LETTER E WITH CIRCUMFLEX + /\ @ + |/\|@ + | -<@ + |__<@ + @@ +203 LATIN CAPITAL LETTER E WITH DIAERESIS + _ _ @ + (_)(_)@ + | -< @ + |__< @ + @@ +204 LATIN CAPITAL LETTER I WITH GRAVE + __ @ + \_\ @ + |_ _|@ + |___|@ + @@ +205 LATIN CAPITAL LETTER I WITH ACUTE + __ @ + /_/ @ + |_ _|@ + |___|@ + @@ +206 LATIN CAPITAL LETTER I WITH CIRCUMFLEX + //\ @ + |/_\|@ + |_ _|@ + |___|@ + @@ +207 LATIN CAPITAL LETTER I WITH DIAERESIS + _ _ @ + (_)_(_)@ + |_ _| @ + |___| @ + @@ +208 LATIN CAPITAL LETTER ETH + ____ @ + | __ \ @ + |_ _|) |@ + |____/ @ + @@ +209 LATIN CAPITAL LETTER N WITH TILDE + /\/|@ + |/\/ @ + | \| |@ + |_|\_|@ + @@ +210 LATIN CAPITAL LETTER O WITH GRAVE + __ @ + \_\_ @ + / __ \@ + \____/@ + @@ +211 LATIN CAPITAL LETTER O WITH ACUTE + __ @ + _/_/ @ + / __ \@ + \____/@ + @@ +212 LATIN CAPITAL LETTER O WITH CIRCUMFLEX + /\ @ + |/\| @ + / __ \@ + \____/@ + @@ +213 LATIN CAPITAL LETTER O WITH TILDE + /\/|@ + |/\/ @ + / __ \@ + \____/@ + @@ +214 LATIN CAPITAL LETTER O WITH DIAERESIS + _ _ @ + (_)(_)@ + / __ \@ + \____/@ + @@ +215 MULTIPLICATION SIGN + @ + /\/\@ + > <@ + \/\/@ + @@ +216 LATIN CAPITAL LETTER O WITH STROKE + ____ @ + / _//\ @ + | (//) |@ + \//__/ @ + @@ +217 LATIN CAPITAL LETTER U WITH GRAVE + __ @ + _\_\_ @ + | |_| |@ + \___/ @ + @@ +218 LATIN CAPITAL LETTER U WITH ACUTE + __ @ + _/_/_ @ + | |_| |@ + \___/ @ + @@ +219 LATIN CAPITAL LETTER U WITH CIRCUMFLEX + //\ @ + |/ \| @ + | |_| |@ + \___/ @ + @@ +220 LATIN CAPITAL LETTER U WITH DIAERESIS + _ _ @ + (_) (_)@ + | |_| |@ + \___/ @ + @@ +221 LATIN CAPITAL LETTER Y WITH ACUTE + __ @ + _/_/_@ + \ V /@ + |_| @ + @@ +222 LATIN CAPITAL LETTER THORN + _ @ + | |_ @ + | -_)@ + |_| @ + @@ +223 LATIN SMALL LETTER SHARP S + ___ @ + / _ \@ + | |< <@ + | ||_/@ + |_| @@ +224 LATIN SMALL LETTER A WITH GRAVE + __ @ + \_\_ @ + / _` |@ + \__,_|@ + @@ +225 LATIN SMALL LETTER A WITH ACUTE + __ @ + _/_/ @ + / _` |@ + \__,_|@ + @@ +226 LATIN SMALL LETTER A WITH CIRCUMFLEX + /\ @ + |/\| @ + / _` |@ + \__,_|@ + @@ +227 LATIN SMALL LETTER A WITH TILDE + /\/|@ + |/\/ @ + / _` |@ + \__,_|@ + @@ +228 LATIN SMALL LETTER A WITH DIAERESIS + _ _ @ + (_)(_)@ + / _` |@ + \__,_|@ + @@ +229 LATIN SMALL LETTER A WITH RING ABOVE + __ @ + (()) @ + / _` |@ + \__,_|@ + @@ +230 LATIN SMALL LETTER AE + @ + __ ___ @ + / _` -_)@ + \__,___|@ + @@ +231 LATIN SMALL LETTER C WITH CEDILLA + @ + __ @ + / _|@ + \__|@ + )_)@@ +232 LATIN SMALL LETTER E WITH GRAVE + __ @ + \_\ @ + / -_)@ + \___|@ + @@ +233 LATIN SMALL LETTER E WITH ACUTE + __ @ + /_/ @ + / -_)@ + \___|@ + @@ +234 LATIN SMALL LETTER E WITH CIRCUMFLEX + //\ @ + |/_\|@ + / -_)@ + \___|@ + @@ +235 LATIN SMALL LETTER E WITH DIAERESIS + _ _ @ + (_)_(_)@ + / -_) @ + \___| @ + @@ +236 LATIN SMALL LETTER I WITH GRAVE + __ @ + \_\@ + | |@ + |_|@ + @@ +237 LATIN SMALL LETTER I WITH ACUTE + __@ + /_/@ + | |@ + |_|@ + @@ +238 LATIN SMALL LETTER I WITH CIRCUMFLEX + //\ @ + |/_\|@ + | | @ + |_| @ + @@ +239 LATIN SMALL LETTER I WITH DIAERESIS + _ _ @ + (_)_(_)@ + | | @ + |_| @ + @@ +240 LATIN SMALL LETTER ETH + \\/\ @ + \/\\ @ + / _` |@ + \___/ @ + @@ +241 LATIN SMALL LETTER N WITH TILDE + /\/| @ + |/\/ @ + | ' \ @ + |_||_|@ + @@ +242 LATIN SMALL LETTER O WITH GRAVE + __ @ + \_\ @ + / _ \@ + \___/@ + @@ +243 LATIN SMALL LETTER O WITH ACUTE + __ @ + /_/ @ + / _ \@ + \___/@ + @@ +244 LATIN SMALL LETTER O WITH CIRCUMFLEX + //\ @ + |/_\|@ + / _ \@ + \___/@ + @@ +245 LATIN SMALL LETTER O WITH TILDE + /\/|@ + |/\/ @ + / _ \@ + \___/@ + @@ +246 LATIN SMALL LETTER O WITH DIAERESIS + _ _ @ + (_)_(_)@ + / _ \ @ + \___/ @ + @@ +247 DIVISION SIGN + _ @ + (_) @ + |___|@ + (_) @ + @@ +248 LATIN SMALL LETTER O WITH STROKE + @ + ___ @ + / //\@ + \//_/@ + @@ +249 LATIN SMALL LETTER U WITH GRAVE + __ @ + \_\_ @ + | || |@ + \_,_|@ + @@ +250 LATIN SMALL LETTER U WITH ACUTE + __ @ + _/_/ @ + | || |@ + \_,_|@ + @@ +251 LATIN SMALL LETTER U WITH CIRCUMFLEX + /\ @ + |/\| @ + | || |@ + \_,_|@ + @@ +252 LATIN SMALL LETTER U WITH DIAERESIS + _ _ @ + (_)(_)@ + | || |@ + \_,_|@ + @@ +253 LATIN SMALL LETTER Y WITH ACUTE + __ @ + _/_/ @ + | || |@ + \_, |@ + |__/ @@ +254 LATIN SMALL LETTER THORN + _ @ + | |__ @ + | '_ \@ + | .__/@ + |_| @@ +255 LATIN SMALL LETTER Y WITH DIAERESIS + _ _ @ + (_)(_)@ + | || |@ + \_, |@ + |__/ @@ diff --git a/src/app/speed.flf b/src/app/speed.flf new file mode 100644 index 00000000..d294c52f --- /dev/null +++ b/src/app/speed.flf @@ -0,0 +1,1301 @@ +flf2a$ 6 5 16 15 16 +Speed by Claude Martins 2/95 -- based on Slant +Includes ISO Latin-1 +figlet release 2.1 -- 12 Aug 1994 +Permission is hereby given to modify this font, as long as the +modifier's name is placed on a comment line. + +Explanation of first line: +flf2 - "magic number" for file identification +a - should always be `a', for now +$ - the "hardblank" -- prints as a blank, but can't be smushed +6 - height of a character +5 - height of a character, not including descenders +14 - max line length (excluding comment lines) + a fudge factor +15 - default smushmode for this font +16 - number of comment lines + + $$@ + $$ @ + $$ @ + $$ @ + $$ @ +$$ @@ +______@ +___ /@ +__ / @ + /_/ @ +(_) @ + @@ +___ _ @ +_( | )@ +_|/|/ @ + $ @ + $ @ + @@ +_______ __ @ +____/ // /_@ +_ _ _ __/@ +/_ _ __/ @ + /_//_/ @ + @@ +_______@ +____/ /@ +__ __/@ +_(_ ) @ +/ _/ @ +/_/ @@ +____ __@ +__(_)_/_/@ +____/_/ @ +__/_/_ @ +/_/ (_) @ + @@ +______ @ +__( _ ) @ +_ __ \/|@ +/ /_/ < @ +\____/\/ @ + @@ +___ @ +_( )@ +_|/ @ + $ @ +$ @ + @@ +_______@ +____/_/@ +__ / @ +_ / @ +/ / @ +|_| @@ +______ @ +____| |@ +____ /@ +___ / @ +__/_/ @ +/_/ @@ +_____ @ +____/|_@ +_| /@ +/_ __| @ + |/ @ + @@ + @ +______ @ +___/ /_@ +/_ __/@ + /_/ @ + @@ + @ + @ + @ +___ @ +_( )@ +_|/ @@ + @ + @ +________@ +_/_____/@ + $ @ + @@ + @ + @ + @ +___ @ +_(_)@ + @@ +_________@ +______/_/@ +____/_/ @ +__/_/ @ +/_/ @ + @@ +_______ @ +__ __ \@ +_ / / /@ +/ /_/ / @ +\____/ @ + @@ +______@ +__< /@ +__ / @ +_ / @ +/_/ @ + @@ +______ @ +__|__ \@ +____/ /@ +_ __/ @ +/____/ @ + @@ +________@ +__|__ /@ +___/_ < @ +____/ / @ +/____/ @ + @@ +_____ __@ +__ // /@ +_ // /_@ +/__ __/@ + /_/ @ + @@ +__________@ +___ ____/@ +______ \ @ + ____/ / @ +/_____/ @ + @@ +________@ +__ ___/@ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +______@ +/__ /@ +__ / @ +_ / @ +/_/ @ + @@ +_______ @ +__( __ )@ +_ __ |@ +/ /_/ / @ +\____/ @ + @@ +_______ @ +__ __ \@ +_ /_/ /@ +_\__, / @ +/____/ @ + @@ + @ +_____ @ +___(_)@ +___ @ +_(_) @ + @@ + @ +_____ @ +___(_)@ +___ @ +_( ) @ +_|/ @@ +____@ +_ /@ +/ / @ +\ \ @ + \_\@ + @@ + @ +_______@ +_ ____/@ +/____/ @ + $ @ + @@ +___ @ +__ \ @ +___ \@ +__ /@ +_/_/ @ + @@ +_____ @ +_ __ \@ +__/ _/@ +_/_/ @ +(_) @ + @@ +_________ @ +__ ____ \@ +_ / __ `/@ +/ / /_/ / @ +\ \__,_/ @ + \____/ @@ +_______ @ +___ |@ +__ /| |@ +_ ___ |@ +/_/ |_|@ + @@ +________ @ +___ __ )@ +__ __ |@ +_ /_/ / @ +/_____/ @ + @@ +_________@ +__ ____/@ +_ / @ +/ /___ @ +\____/ @ + @@ +________ @ +___ __ \@ +__ / / /@ +_ /_/ / @ +/_____/ @ + @@ +__________@ +___ ____/@ +__ __/ @ +_ /___ @ +/_____/ @ + @@ +__________@ +___ ____/@ +__ /_ @ +_ __/ @ +/_/ @ + @@ +_________@ +__ ____/@ +_ / __ @ +/ /_/ / @ +\____/ @ + @@ +______ __@ +___ / / /@ +__ /_/ / @ +_ __ / @ +/_/ /_/ @ + @@ +________@ +____ _/@ + __ / @ +__/ / @ +/___/ @ + @@ +_________@ +______ /@ +___ _ / @ +/ /_/ / @ +\____/ @ + @@ +______ __@ +___ //_/@ +__ ,< @ +_ /| | @ +/_/ |_| @ + @@ +______ @ +___ / @ +__ / @ +_ /___@ +/_____/@ + @@ +______ ___@ +___ |/ /@ +__ /|_/ / @ +_ / / / @ +/_/ /_/ @ + @@ +_____ __@ +___ | / /@ +__ |/ / @ +_ /| / @ +/_/ |_/ @ + @@ +_______ @ +__ __ \@ +_ / / /@ +/ /_/ / @ +\____/ @ + @@ +________ @ +___ __ \@ +__ /_/ /@ +_ ____/ @ +/_/ @ + @@ +_______ @ +__ __ \@ +_ / / /@ +/ /_/ / @ +\___\_\ @ + @@ +________ @ +___ __ \@ +__ /_/ /@ +_ _, _/ @ +/_/ |_| @ + @@ +________@ +__ ___/@ +_____ \ @ +____/ / @ +/____/ @ + @@ +________@ +___ __/@ +__ / @ +_ / @ +/_/ @ + @@ +_____ __@ +__ / / /@ +_ / / / @ +/ /_/ / @ +\____/ @ + @@ +___ __@ +__ | / /@ +__ | / / @ +__ |/ / @ +_____/ @ + @@ +___ __@ +__ | / /@ +__ | /| / / @ +__ |/ |/ / @ +____/|__/ @ + @@ +____ __@ +__ |/ /@ +__ / @ +_ | @ +/_/|_| @ + @@ +__ __@ +_ \/ /@ +__ / @ +_ / @ +/_/ @ + @@ +______@ +___ /@ +__ / @ +_ /__@ +/____/@ + @@ +________@ +____ _/@ +___ / @ +__ / @ +_ / @ +/__/ @@ +___ @ +__ \ @ +___ \ @ +____ \ @ +______\@ + @@ +________@ +____/ /@ +____ / @ +___ / @ +__/ / @ +/__/ @@ +_ //|@ +_|/||@ + $ @ + $ @ +$ @ + @@ + @ + @ + @ + @ +________@ +_/_____/@@ +___ @ +_( )@ +__V @ + $ @ +$ @ + @@ + @ +______ _@ +_ __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +______ @ +___ /_ @ +__ __ \@ +_ /_/ /@ +/_.___/ @ + @@ + @ +_______@ +_ ___/@ +/ /__ @ +\___/ @ + @@ +_________@ +______ /@ +_ __ / @ +/ /_/ / @ +\__,_/ @ + @@ + @ +_____ @ +_ _ \@ +/ __/@ +\___/ @ + @@ +________@ +___ __/@ +__ /_ @ +_ __/ @ +/_/ @ + @@ + @ +_______ _@ +__ __ `/@ +_ /_/ / @ +_\__, / @ +/____/ @@ +______ @ +___ /_ @ +__ __ \@ +_ / / /@ +/_/ /_/ @ + @@ +_____ @ +___(_)@ +__ / @ +_ / @ +/_/ @ + @@ +________ @ +______(_)@ +_____ / @ +____ / @ +___ / @ +/___/ @@ +______ @ +___ /__@ +__ //_/@ +_ ,< @ +/_/|_| @ + @@ +______@ +___ /@ +__ / @ +_ / @ +/_/ @ + @@ + @ +_______ ___ @ +__ __ `__ \@ +_ / / / / /@ +/_/ /_/ /_/ @ + @@ + @ +_______ @ +__ __ \@ +_ / / /@ +/_/ /_/ @ + @@ + @ +______ @ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ + @ +________ @ +___ __ \@ +__ /_/ /@ +_ .___/ @ +/_/ @@ + @ +______ _@ +_ __ `/@ +/ /_/ / @ +\__, / @ + /_/ @@ + @ +________@ +__ ___/@ +_ / @ +/_/ @ + @@ + @ +________@ +__ ___/@ +_(__ ) @ +/____/ @ + @@ +_____ @ +__ /_@ +_ __/@ +/ /_ @ +\__/ @ + @@ + @ +____ __@ +_ / / /@ +/ /_/ / @ +\__,_/ @ + @@ + @ +___ __@ +__ | / /@ +__ |/ / @ +_____/ @ + @@ + @ +___ __@ +__ | /| / /@ +__ |/ |/ / @ +____/|__/ @ + @@ + @ +____ __@ +__ |/_/@ +__> < @ +/_/|_| @ + @@ + @ +_____ __@ +__ / / /@ +_ /_/ / @ +_\__, / @ +/____/ @@ + @ +______@ +___ /@ +__ /_@ +_____/@ + @@ +_______@ +____/_/@ +__/_/ @ +< < @ +/ / @ +\_\ @@ +_______@ +____ /@ +___ / @ +__ / @ +_ / @ +/_/ @@ +____ _ @ +____| |@ +____/ /@ +____>_>@ +__/_/ @ +/_/ @@ +__/\//@ +_//\/ @ + $ @ + $ @ +$ @ + @@ +_____ _ @ +___(_)(_)@ +__ _ | @ +_ __ | @ +/_/ |_| @ + @@ +____ _ @ +__(_)_(_)@ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +____ _ @ +__(_) (_)@ +_ / / / @ +/ /_/ / @ +\____/ @ + @@ +____ _ @ +__(_)_(_)@ +_ __ `/ @ +/ /_/ / @ +\__,_/ @ + @@ +____ _ @ +__(_)_(_)@ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +____ _ @ +__(_) (_)@ +_ / / / @ +/ /_/ / @ +\__,_/ @ + @@ +_________ @ +____ __ \@ +___ / / /@ +__ /_| | @ +_ //__/ @ +/_/ @@ +160 + $$@ + $$ @ + $$ @ + $$ @ + $$ @ +$$ @@ +161 +_____ @ +___(_)@ +__ / @ +_ / @ +/_/ @ + @@ +162 +_______@ +____/ /@ +_ ___/@ +/ /__ @ +\ _/ @ +/_/ @@ +163 +_________ @ +____ ,__\@ +___/ /_ @ +__/ /___ @ +(_,____/ @ + @@ +164 +___ /|___/|@ +___| __ / @ +__ /_/ / @ +_ ___ | @ +|/ |/ @ + @@ +165 +___ ____@ +___| / /@ +_ _ __/@ +/_ __/ @ + /_/ @ + @@ +166 +_______@ +____ /@ +_____/ @ +____ @ +_ / @ +/_/ @@ +167 +_______ @ +____/ _)@ +__ | | @ +_| || | @ +_| |_/ @ +(__/ @@ +168 +___ _ @ +_(_) (_)@ + $ $ @ + $ $ @ +$ $ @ + @@ +169 +__________ @ +___ _____\ @ +__ / ___/ |@ +_ / /__ / @ +| \___/ / @ + \______/ @@ +170 +______ _@ +__ _ `/@ +__\_,_/ @ +/____/ @ + $ @ + @@ +171 +______@ +_ / /@ +/ / / @ +\ \ \ @ + \_\_\@ + @@ +172 + @ +________@ +_/___ /@ + /_/ @ + $ @ + @@ +173 + @ + @ +_______@ +_/____/@ + $ @ + @@ +174 +__________ @ +___ ___ \ @ +__ / _ \ |@ +_ / , _/ / @ +| /_/|_| / @ + \______/ @@ +175 +________@ +_/_____/@ + $ @ + $ @ + $ @ + @@ +176 +_____ @ +_ _ \@ +/ // /@ +\___/ @ + $ @ + @@ +177 +________ @ +_____/ /_@ +____ __/@ +___/_/_ @ +/_____/ @ + @@ +178 +__ ___ @ +__|_ |@ +_ __/ @ +/____/ @ + $ @ + @@ +179 +__ ____@ +__|_ /@ +__/_ < @ +/____/ @ + $ @ + @@ +180 +____@ +_/_/@ + $ @ + $ @ +$ @ + @@ +181 + @ +______ __@ +___ / / /@ +__ /_/ / @ +_ ._,_/ @ +/_/ @@ +182 +_________@ +_ _ /@ +/ (/ / / @ +\_ / / @ + /_/_/ @ + @@ +183 + @ +___ @ +_(_)@ + $ @ + $ @ + @@ +184 + @ + @ + @ + @ +___ @ +_/_)@@ +185 +_____@ +_< /@ +_ / @ +/_/ @ +$ @ + @@ +186 +______ @ +__ _ \@ +__\___/@ +/____/ @ + $ @ + @@ +187 +_____ @ +__ \ \ @ +___ \ \@ +__ / /@ +___/_/ @ + @@ +188 +_____ __ @ +_< / _/_/ @ +_/ /_/_/___@ +/_//_// / /@ + /_/ /_ _/@ + /_/ @@ +189 +_____ __ @ +_< / _/_/__ @ +_/ /_/_/|_ |@ +/_//_/ / __/ @ + /_/ /____/ @ + @@ +190 +__ ____ __ @ +__|_ / _/_/ @ +__/_ < _/_/___@ +/____//_// / /@ + /_/ /_ _/@ + /_/ @@ +191 +___ _ @ +___(_)@ +__ / @ +/ _/_ @ +\___/ @ + @@ +192 +______ @ +____\_\@ +__ _ |@ +_ __ |@ +/_/ |_|@ + @@ +193 +_______@ +____/_/@ +__ _ |@ +_ __ |@ +/_/ |_|@ + @@ +194 +____ //|@ +____|/||@ +__ _ | @ +_ __ | @ +/_/ |_| @ + @@ +195 +_____/\//@ +____//\/ @ +__ _ | @ +_ __ | @ +/_/ |_| @ + @@ +196 +_____ _ @ +___(_)(_)@ +__ _ | @ +_ __ | @ +/_/ |_| @ + @@ +197 +____(())@ +___ |@ +__ /| |@ +_ ___ |@ +/_/ |_|@ + @@ +198 +______________@ +___ ____/@ +__ /| __/ @ +_ __ /___ @ +/_/ /_____/ @ + @@ +199 +_________@ +__ ____/@ +_ / @ +/ /___ @ +\____/ @ + /_) @@ +200 +______ @ +____\_\@ +__ __/@ +_ _/ @ +/___/ @ + @@ +201 +_______@ +____/_/@ +__ __/@ +_ _/ @ +/___/ @ + @@ +202 +____ //|@ +____|/||@ +__ __/ @ +_ _/ @ +/___/ @ + @@ +203 +_____ _ @ +___(_)(_)@ +__ __/ @ +_ _/ @ +/___/ @ + @@ +204 +______ @ +____\_\@ +__ _/@ +__/ / @ +/___/ @ + @@ +205 +_______@ +____/_/@ +__ _/@ +__/ / @ +/___/ @ + @@ +206 +____ //|@ +____|/||@ +__ _/ @ +__/ / @ +/___/ @ + @@ +207 +_____ _ @ +___(_)(_)@ +__ _/ @ +__/ / @ +/___/ @ + @@ +208 +_________ @ +____ __ \@ +___ /_/ /@ +/_ __/ / @ + /_____/ @ + @@ +209 +_____/\//@ +____//\/ @ +__ |/ / @ +_ / @ +/_/|_/ @ + @@ +210 +______ @ +____\_\@ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ +211 +_______@ +____/_/@ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ +212 +___ //|@ +___|/||@ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ +213 +____/\//@ +___//\/ @ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +214 +____ _ @ +__(_)_(_)@ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +215 + @ +__ @ +_/|/|@ + > < @ +|/|/ @ + @@ +216 +________ @ +__ _// \@ +_ //// /@ +/ //// / @ +\_//__/ @ + @@ +217 +______ @ +____\_\_@ +_ / / /@ +/ /_/ / @ +\____/ @ + @@ +218 +_______ @ +____/_/_@ +_ / / /@ +/ /_/ / @ +\____/ @ + @@ +219 +___ //| @ +___|/||_@ +_ / / /@ +/ /_/ / @ +\____/ @ + @@ +220 +____ _ @ +__(_) (_)@ +_ / / / @ +/ /_/ / @ +\____/ @ + @@ +221 +______ @ +___/_/_@ +__ \/ /@ +___ / @ +__/_/ @ + @@ +222 +______ @ +___ /_ @ +__ __ \@ +_ ____/@ +/_/ @ + @@ +223 +_________ @ +____ __ \@ +___ / / /@ +__ /_| | @ +_ //__/ @ +/_/ @@ +224 +______ @ +____\_\_@ +_ __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +225 +_______ @ +____/_/_@ +_ __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +226 +___ //| @ +___|/||_@ +_ __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +227 +____/\//@ +___//\/_@ +_ __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +228 +____ _ @ +__(_)_(_)@ +_ __ `/ @ +/ /_/ / @ +\__,_/ @ + @@ +229 +_______ @ +____(())@ +_ __ `/@ +/ /_/ / @ +\__,_/ @ + @@ +230 + @ +______ ___ @ +_ __ ` _ \@ +/ /_/ __/@ +\__,_____/ @ + @@ +231 + @ +_______@ +_ ___/@ +/ /__ @ +\___/ @ +/_) @@ +232 +_____ @ +___\_\@ +_ _ \@ +/ __/@ +\___/ @ + @@ +233 +______@ +___/_/@ +_ _ \@ +/ __/@ +\___/ @ + @@ +234 +___ //|@ +___|/||@ +_ _ \ @ +/ __/ @ +\___/ @ + @@ +235 +____ _ @ +__(_)(_)@ +_ _ \ @ +/ __/ @ +\___/ @ + @@ +236 +_____ @ +___\_\@ +__ / @ +_ / @ +/_/ @ + @@ +237 +______@ +___/_/@ +__ / @ +_ / @ +/_/ @ + @@ +238 +___ //|@ +___|/||@ +__ / @ +_ / @ +/_/ @ + @@ +239 +_ _ _ @ +_(_)_(_)@ +__/ / @ +_ / @ +/_/ @ + @@ +240 +____ || @ +____=||=@ +____ || @ +/ __` | @ +\____/ @ + @@ +241 +_____/\//@ +____//\/ @ +__ __ \ @ +_ / / / @ +/_/ /_/ @ + @@ +242 +______ @ +____\_\@ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ +243 +_______@ +____/_/@ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ +244 +___ //|@ +___|/||@ +_ __ \@ +/ /_/ /@ +\____/ @ + @@ +245 +____/\//@ +___//\/ @ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +246 +____ _ @ +__(_)_(_)@ +_ __ \ @ +/ /_/ / @ +\____/ @ + @@ +247 + @ +_____ @ +___(_)_@ +/_____/@ + (_) @ + @@ +248 + @ +_______ @ +_ _// \@ +/ //// /@ +\_//__/ @ + @@ +249 +______ @ +____\_\_@ +_ / / /@ +/ /_/ / @ +\__,_/ @ + @@ +250 +_______ @ +____/_/_@ +_ / / /@ +/ /_/ / @ +\__,_/ @ + @@ +251 +___ //| @ +___|/||_@ +_ / / /@ +/ /_/ / @ +\__,_/ @ + @@ +252 +____ _ @ +__(_) (_)@ +_ / / / @ +/ /_/ / @ +\__,_/ @ + @@ +253 +________ @ +_____/_/_@ +__ / / /@ +_ /_/ / @ +_\__, / @ +/____/ @@ +254 +_______ @ +____ /_ @ +___ __ \@ +__ /_/ /@ +_ .___/ @ +/_/ @@ +255 +_____ _ @ +___(_) (_)@ +__ / / / @ +_ /_/ / @ +_\__, / @ +/____/ @@ diff --git a/src/app/starwars.flf b/src/app/starwars.flf new file mode 100644 index 00000000..6ea55f02 --- /dev/null +++ b/src/app/starwars.flf @@ -0,0 +1,719 @@ +flf2a$ 7 6 22 15 4 +starwars.flf by Ryan Youck (youck@cs.uregina.ca) Dec 25/1994 +I am not responsible for use of this font +Based on Big.flf by Glenn Chappell + +$ $@ +$ $@ +$ $@ +$ $@ +$ $@ +$ $@ +$ $@@ + __ $@ +| |$@ +| |$@ +| |$@ +|__|$@ +(__)$@ + $@@ + _ _ @ +( | )@ + V V @ + $ @ + $ @ + $ @ + @@ + _ _ @ + _| || |_$@ +|_ __ _|@ + _| || |_ @ +|_ __ _|@ + |_||_| $@ + @@ + __,--,_.@ + / |@ + | (----`@ + \ \ $@ +.----) | $@ +|_ __/ $@ + '--' $@@ + _ ___$ @ + / \ / /$ @ +( o ) / / $ @ + \_/ / / _$ @ + / / / \ @ + / / ( o )@ + /__/ \_/ @@ + @ + ___ @ + ( _ ) $@ + / _ \/\@ +| (_> <@ + \___/\/@ + $@@ + __ @ +(_ )@ + |/ @ + $ @ + $ @ + $ @ + @@ + ___@ + / /@ +| |$@ +| |$@ +| |$@ +| |$@ + \__\@@ +___ @ +\ \ @ + | |@ + | |@ + | |@ + | |@ +/__/ @@ + _ @ + /\| |/\ @ + \ ` ' /$@ +|_ _|@ + / , . \$@ + \/|_|\/ @ + @@ + @ + _ @ + _| |_$@ +|_ _|@ + |_| $@ + $ @ + @@ + @ + @ + $ @ + $ @ + __ @ +(_ )@ + |/ @@ + @ + @ + ______ @ +|______|@ + $ @ + $ @ + @@ + @ + @ + @ + $ @ + __ @ +(__)@ + @@ + ___@ + / /@ + / / @ + / /$ @ + / /$ @ +/__/$ @ + @@ + ___ $@ + / _ \ $@ +| | | |$@ +| | | |$@ +| |_| |$@ + \___/ $@ + $@@ + __ $@ +/_ |$@ + | |$@ + | |$@ + | |$@ + |_|$@ + $@@ + ___ $@ +|__ \ $@ + $) |$@ + / / $@ + / /_ $@ +|____|$@ + $@@ + ____ $@ +|___ \ $@ + __) |$@ + |__ < $@ + ___) |$@ +|____/ $@ + $@@ + _ _ $@ +| || | $@ +| || |_ $@ +|__ _|$@ + | | $@ + |_| $@ + $@@ + _____ $@ +| ____|$@ +| |__ $@ +|___ \ $@ + ___) |$@ +|____/ $@ + $@@ + __ $@ + / / $@ + / /_ $@ +| '_ \ $@ +| (_) |$@ + \___/ $@ + $@@ + ______ $@ +|____ |$@ + $/ / $@ + / / $@ + / / $@ + /_/ $@ + $@@ + ___ $@ + / _ \ $@ +| (_) |$@ + > _ < $@ +| (_) |$@ + \___/ $@ + $@@ + ___ $@ + / _ \ $@ +| (_) |$@ + \__, |$@ + / / $@ + /_/ $@ + $@@ + @ + _ @ +(_)@ + $ @ + _ @ +(_)@ + @@ + @ + _ @ +(_)@ + $ @ + _ @ +( )@ +|/ @@ + ___@ + / /@ + / /$@ +< <$ @ + \ \$@ + \__\@ + @@ + @ + ______ @ +|______|@ + ______ @ +|______|@ + @ + @@ +___ @ +\ \$ @ + \ \ @ + > >@ + / / @ +/__/$ @ + @@ + ______ $@ +| \ $@ +`----) |$@ + / / $@ + |__| $@ + __ $@ + (__) $@@ + ____ @ + / __ \ @ + / / _` |@ +| | (_| |@ + \ \__,_|@ + \____/ @ + @@ + ___ $ @ + / \ $ @ + / ^ \$ @ + / /_\ \$ @ + / _____ \$ @ +/__/ \__\$@ + $@@ +.______ $@ +| _ \ $@ +| |_) |$@ +| _ < $@ +| |_) |$@ +|______/ $@ + $@@ + ______$@ + / |@ +| ,----'@ +| | $@ +| `----.@ + \______|@ + $@@ + _______ $@ +| \$@ +| .--. |@ +| | | |@ +| '--' |@ +|_______/$@ + $@@ + _______ @ +| ____|@ +| |__ $@ +| __| $@ +| |____ @ +|_______|@ + @@ + _______ @ +| ____|@ +| |__ $@ +| __| $@ +| | $ @ +|__| @ + @@ + _______ @ + / _____|@ +| | __ $@ +| | |_ |$@ +| |__| |$@ + \______|$@ + $@@ + __ __ $@ +| | | |$@ +| |__| |$@ +| __ |$@ +| | | |$@ +|__| |__|$@ + $@@ + __ $@ +| |$@ +| |$@ +| |$@ +| |$@ +|__|$@ + $@@ + __ $@ + | |$@ + | |$@ +.--. | |$@ +| `--' |$@ + \______/ $@ + $@@ + __ ___$@ +| |/ /$@ +| ' / $@ +| < $@ +| . \ $@ +|__|\__\$@ + $@@ + __ $@ +| | $@ +| | $@ +| | $@ +| `----.@ +|_______|@ + $@@ +.___ ___.$@ +| \/ |$@ +| \ / |$@ +| |\/| |$@ +| | | |$@ +|__| |__|$@ + $@@ +.__ __.$@ +| \ | |$@ +| \| |$@ +| . ` |$@ +| |\ |$@ +|__| \__|$@ + $@@ + ______ $@ + / __ \ $@ +| | | |$@ +| | | |$@ +| `--' |$@ + \______/ $@ + $@@ +.______ $@ +| _ \ $@ +| |_) |$@ +| ___/ $@ +| | $ @ +| _| $ @ + $ @@ + ______ $ @ + / __ \ $ @ +| | | | $ @ +| | | | $ @ +| `--' '--. @ + \_____\_____\@ + $ @@ +.______ $ @ +| _ \ $ @ +| |_) | $ @ +| / $ @ +| |\ \----.@ +| _| `._____|@ + $@@ + _______.@ + / |@ + | (----`@ + \ \ $@ +.----) | $@ +|_______/ $@ + $@@ +.___________.@ +| |@ +`---| |----`@ + | | $ @ + | | $ @ + |__| $ @ + $ @@ + __ __ $@ +| | | |$@ +| | | |$@ +| | | |$@ +| `--' |$@ + \______/ $@ + $@@ +____ ____$@ +\ \ / /$@ + \ \/ /$ @ + \ /$ @ + \ /$ @ + \__/$ @ + $ @@ +____ __ ____$@ +\ \ / \ / /$@ + \ \/ \/ /$ @ + \ /$ @ + \ /\ /$ @ + \__/ \__/$ @ + $ @@ +___ ___$@ +\ \ / /$@ + \ V / $@ + > < $@ + / . \ $@ +/__/ \__\$@ + $@@ +____ ____$@ +\ \ / /$@ + \ \/ /$ @ + \_ _/$ @ + | |$ @ + |__|$ @ + $ @@ + ________ $@ +| / $@ +`---/ / $@ + / / $@ + / /----.@ + /________|@ + $@@ + ____ @ +| |@ +| |-`@ +| | $@ +| | $@ +| |-.@ +|____|@@ +___ @ +\ \ $ @ + \ \$ @ + \ \$ @ + \ \$@ + \__\@ + @@ + ____ @ +| |@ +`-| |@ + | |@ + | |@ +.-| |@ +|____|@@ + ___ @ + / \ @ +/--^--\@ + $@ + $@ + $@ + $@@ + @ + @ + @ + $ @ + $ @ + ______ @ +|______|@@ + __ @ +( _)@ + \| @ + $ @ + $ @ + $ @ + @@ + ___ $ @ + / \ $ @ + / ^ \$ @ + / /_\ \$ @ + / _____ \$ @ +/__/ \__\$@ + $@@ +.______ $@ +| _ \ $@ +| |_) |$@ +| _ < $@ +| |_) |$@ +|______/ $@ + $@@ + ______$@ + / |@ +| ,----'@ +| | $@ +| `----.@ + \______|@ + $@@ + _______ $@ +| \$@ +| .--. |@ +| | | |@ +| '--' |@ +|_______/$@ + $@@ + _______ @ +| ____|@ +| |__ $@ +| __| $@ +| |____ @ +|_______|@ + @@ + _______ @ +| ____|@ +| |__ $@ +| __| $@ +| | $ @ +|__| @ + @@ + _______ @ + / _____|@ +| | __ $@ +| | |_ |$@ +| |__| |$@ + \______|$@ + $@@ + __ __ $@ +| | | |$@ +| |__| |$@ +| __ |$@ +| | | |$@ +|__| |__|$@ + $@@ + __ $@ +| |$@ +| |$@ +| |$@ +| |$@ +|__|$@ + $@@ + __ $@ + | |$@ + | |$@ +.--. | |$@ +| `--' |$@ + \______/ $@ + $@@ + __ ___$@ +| |/ /$@ +| ' / $@ +| < $@ +| . \ $@ +|__|\__\$@ + $@@ + __ $@ +| | $@ +| | $@ +| | $@ +| `----.@ +|_______|@ + $@@ +.___ ___.$@ +| \/ |$@ +| \ / |$@ +| |\/| |$@ +| | | |$@ +|__| |__|$@ + $@@ +.__ __.$@ +| \ | |$@ +| \| |$@ +| . ` |$@ +| |\ |$@ +|__| \__|$@ + $@@ + ______ $@ + / __ \ $@ +| | | |$@ +| | | |$@ +| `--' |$@ + \______/ $@ + $@@ +.______ $@ +| _ \ $@ +| |_) |$@ +| ___/ $@ +| | $ @ +| _| $ @ + $ @@ + ______ $ @ + / __ \ $ @ +| | | | $ @ +| | | | $ @ +| `--' '--. @ + \_____\_____\@ + $ @@ +.______ $ @ +| _ \ $ @ +| |_) | $ @ +| / $ @ +| |\ \----.@ +| _| `._____|@ + $@@ + _______.@ + / |@ + | (----`@ + \ \ $@ +.----) | $@ +|_______/ $@ + $@@ +.___________.@ +| |@ +`---| |----`@ + | | $ @ + | | $ @ + |__| $ @ + $ @@ + __ __ $@ +| | | |$@ +| | | |$@ +| | | |$@ +| `--' |$@ + \______/ $@ + $@@ +____ ____$@ +\ \ / /$@ + \ \/ /$ @ + \ /$ @ + \ /$ @ + \__/$ @ + $ @@ +____ __ ____$@ +\ \ / \ / /$@ + \ \/ \/ /$ @ + \ /$ @ + \ /\ /$ @ + \__/ \__/$ @ + $ @@ +___ ___$@ +\ \ / /$@ + \ V / $@ + > < $@ + / . \ $@ +/__/ \__\$@ + $@@ +____ ____$@ +\ \ / /$@ + \ \/ /$ @ + \_ _/$ @ + | |$ @ + |__|$ @ + $ @@ + ________ $@ +| / $@ +`---/ / $@ + / / $@ + / /----.@ + /________|@ + $@@ + ___@ + / /@ + | |$@ +/ /$ @ +\ \$ @ + | |$@ + \__\@@ + __ $@ +| |$@ +| |$@ +| |$@ +| |$@ +| |$@ +|__|$@@ +___ @ +\ \$ @ + | | @ + \ \@ + / /@ + | | @ +/__/$ @@ + __ _ @ + / \/ |@ +|_/\__/ @ + $ @ + $ @ + $ @ + @@ + _ _ @ + (_)_(_) @ + / \ @ + / _ \ @ + / ___ \ @ +/_/ \_\@ + @@ + _ _ @ +(_)_(_)@ + / _ \ @ +| | | |@ +| |_| |@ + \___/ @ + @@ + _ _ @ +(_) (_)@ +| | | |@ +| | | |@ +| |_| |@ + \___/ @ + @@ + _ _ @ +(_) (_)@ + __ _ @ + / _` |@ +| (_| |@ + \__,_|@ + @@ + _ _ @ +(_) (_)@ + ___ @ + / _ \ @ +| (_) |@ + \___/ @ + @@ + _ _ @ +(_) (_)@ + _ _ @ +| | | |@ +| |_| |@ + \__,_|@ + @@ + ___ @ + / _ \ @ +| | ) |@ +| |< < @ +| | ) |@ +| ||_/ @ +|_| @@ diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 00000000..aa5790ca --- /dev/null +++ b/src/config.rs @@ -0,0 +1,179 @@ +//! Carga las opciones de configuración. +//! +//! Estos ajustes se obtienen de archivos [TOML](https://toml.io) como pares `clave = valor` que se +//! mapean a estructuras **fuertemente tipadas** y valores predefinidos. +//! +//! Siguiendo la metodología [Twelve-Factor App](https://12factor.net/config), `PageTop` separa el +//! **código** de la **configuración**, lo que permite tener configuraciones diferentes para cada +//! despliegue, como *dev*, *staging* o *production*, sin modificar el código fuente. +//! +//! +//! # Orden de carga +//! +//! Si tu aplicación necesita archivos de configuración, crea un directorio `config` en la raíz del +//! proyecto, al mismo nivel que el archivo *Cargo.toml* o que el binario de la aplicación. +//! +//! `PageTop` carga en este orden, y siempre de forma opcional, los siguientes archivos TOML: +//! +//! 1. **config/common.toml**, para ajustes comunes a todos los entornos. Este enfoque simplifica el +//! mantenimiento al centralizar los valores de configuración comunes. +//! +//! 2. **config/{rm}.toml**, donde `{rm}` es el valor de la variable de entorno `PAGETOP_RUN_MODE`: +//! +//! * Si `PAGETOP_RUN_MODE` no está definida, se asume el valor `default`, y `PageTop` intentará +//! cargar *config/default.toml* si el archivo existe. +//! +//! * Útil para definir configuraciones específicas por entorno, garantizando que cada uno (p.e. +//! *dev*, *staging* o *production*) disponga de sus propias opciones, como claves de API, +//! URLs o ajustes de rendimiento, sin afectar a los demás. +//! +//! 3. **config/local.{rm}.toml**, útil para configuraciones locales específicas de la máquina o de +//! la ejecución: +//! +//! * Permite añadir o sobrescribir ajustes propios del entorno. Por ejemplo, `local.dev.toml` +//! para desarrollo o `local.production.toml` para retoques en producción. +//! +//! * Facilita que cada desarrollador adapte la configuración a su equipo en un entorno dado. Por +//! lo general no se comparte ni se sube al sistema de control de versiones. +//! +//! 4. **config/local.toml**, para ajustes locales válidos en cualquier entorno, ideal para cambios +//! rápidos o valores temporales que no dependan de un entorno concreto. +//! +//! Los archivos se combinan en el orden anterior, cada archivo sobrescribe a los anteriores en caso +//! de conflicto. +//! +//! +//! # Cómo añadir opciones de configuración a tu código +//! +//! Añade [*serde*](https://docs.rs/serde) en tu archivo *Cargo.toml* con la *feature* `derive`: +//! +//! ```toml +//! [dependencies] +//! serde = { version = "1.0", features = ["derive"] } +//! ``` +//! +//! Y usa la macro [`include_config!`](crate::include_config) para inicializar tus ajustes en una +//! estructura con tipos seguros. Por ejemplo: +//! +//! ```rust#ignore +//! use pagetop::prelude::*; +//! use serde::Deserialize; +//! +//! include_config!(SETTINGS: Settings => [ +//! // [myapp] +//! "myapp.name" => "Value Name", +//! "myapp.width" => 900, +//! "myapp.height" => 320, +//! ]); +//! +//! #[derive(Debug, Deserialize)] +//! pub struct Settings { +//! pub myapp: MyApp, +//! } +//! +//! #[derive(Debug, Deserialize)] +//! pub struct MyApp { +//! pub name: String, +//! pub description: Option<String>, +//! pub width: u16, +//! pub height: u16, +//! } +//! ``` +//! +//! De esta forma estás añadiendo una nueva sección `[myapp]` a la configuración, igual que existen +//! `[app]` o `[server]` en las opciones globales de [`Settings`](crate::global::Settings). +//! +//! Se recomienda proporcionar siempre valores por defecto o usar `Option<T>` para los ajustes +//! opcionales. +//! +//! Si la configuración no se inicializa correctamente, la aplicación lanzará *panic* y detendrá la +//! ejecución. +//! +//! Las estructuras de configuración son de **sólo lectura** durante la ejecución. +//! +//! +//! # Usando tus opciones de configuración +//! +//! ```rust#ignore +//! use pagetop::prelude::*; +//! use crate::config; +//! +//! fn global_settings() { +//! println!("Nombre de la app: {}", &global::SETTINGS.app.name); +//! println!("Descripción: {}", &global::SETTINGS.app.description); +//! println!("Run mode: {}", &global::SETTINGS.app.run_mode); +//! } +//! +//! fn extension_settings() { +//! println!("{} - {:?}", &config::SETTINGS.myapp.name, &config::SETTINGS.myapp.description); +//! println!("{}", &config::SETTINGS.myapp.width); +//! } +//! ``` + +use config::builder::DefaultState; +use config::{Config, ConfigBuilder, File}; + +use std::env; +use std::path::{Path, PathBuf}; +use std::sync::LazyLock; + +// Nombre del directorio de configuración por defecto. +const DEFAULT_CONFIG_DIR: &str = "config"; + +// Modo de ejecución por defecto. +const DEFAULT_RUN_MODE: &str = "default"; + +/// Valores originales cargados desde los archivos de configuración como pares `clave = valor`. +pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new(|| { + // Determina el directorio de configuración: + // - Usa CONFIG_DIR si está definido en el entorno (p.e.: CONFIG_DIR=/etc/myapp ./myapp). + // - Si no, intenta DEFAULT_CONFIG_DIR dentro del proyecto (en CARGO_MANIFEST_DIR). + // - Si nada de esto aplica, entonces usa DEFAULT_CONFIG_DIR relativo al ejecutable. + let config_dir: PathBuf = if let Ok(env_dir) = env::var("CONFIG_DIR") { + env_dir.into() + } else if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") { + let manifest_config = Path::new(&manifest_dir).join(DEFAULT_CONFIG_DIR); + if manifest_config.exists() { + manifest_config + } else { + DEFAULT_CONFIG_DIR.into() + } + } else { + DEFAULT_CONFIG_DIR.into() + }; + + // Determina el modo de ejecución según la variable de entorno PAGETOP_RUN_MODE. Por defecto usa + // DEFAULT_RUN_MODE si no está definida (p.e.: PAGETOP_RUN_MODE=production ./myapp). + let rm = env::var("PAGETOP_RUN_MODE").unwrap_or_else(|_| DEFAULT_RUN_MODE.into()); + + Config::builder() + // 1. Configuración común para todos los entornos (common.toml). + .add_source(File::from(config_dir.join("common.toml")).required(false)) + // 2. Configuración específica del entorno (p.e.: default.toml, production.toml). + .add_source(File::from(config_dir.join(format!("{rm}.toml"))).required(false)) + // 3. Configuración local reservada para cada entorno (p.e.: local.default.toml). + .add_source(File::from(config_dir.join(format!("local.{rm}.toml"))).required(false)) + // 4. Configuración local común (local.toml). + .add_source(File::from(config_dir.join("local.toml")).required(false)) + // Guarda el modo de ejecución explícitamente. + .set_override("app.run_mode", rm) + .expect("Failed to set application run mode") +}); + +#[macro_export] +macro_rules! include_config { + ( $SETTINGS:ident : $Settings:ty => [ $( $key:expr => $value:expr ),* $(,)? ] ) => { + /// Valores asignados o predefinidos para la configuración de [`$Settings`]. + pub static $SETTINGS: std::sync::LazyLock<$Settings> = std::sync::LazyLock::new(|| { + let mut settings = $crate::config::CONFIG_VALUES.clone(); + $( + settings = settings.set_default($key, $value).unwrap(); + )* + settings + .build() + .expect(concat!("Failed to build config for ", stringify!($Settings))) + .try_deserialize::<$Settings>() + .expect(concat!("Error parsing settings for ", stringify!($Settings))) + }); + }; +} diff --git a/src/global.rs b/src/global.rs new file mode 100644 index 00000000..5e3d52f2 --- /dev/null +++ b/src/global.rs @@ -0,0 +1,57 @@ +//! Opciones de configuración globales. + +use crate::include_config; + +use serde::Deserialize; + +include_config!(SETTINGS: Settings => [ + // [app] + "app.name" => "Sample", + "app.description" => "Developed with the amazing PageTop framework.", + "app.startup_banner" => "Slant", + + // [server] + "server.bind_address" => "localhost", + "server.bind_port" => 8080, +]); + +#[derive(Debug, Deserialize)] +/// Ajustes de configuración para las secciones globales [`[app]`](App) y [`[server]`](Server). +/// Consulta [`SETTINGS`] para los valores por defecto. +pub struct Settings { + pub app: App, + pub server: Server, +} + +#[derive(Debug, Deserialize)] +/// Sección `[app]` de la configuración. +/// +/// Forma parte de [`Settings`]. +pub struct App { + /// Nombre de la aplicación. + /// Valor por defecto: *"Sample"*. + pub name: String, + /// Breve descripción de la aplicación. + /// Valor por defecto: *"Developed with the amazing PageTop framework."*. + pub description: String, + /// ASCII banner printed at startup: *"Off"*, *"Slant"*, *"Small"*, *"Speed"*, or *"Starwars"*. + /// Default: *"Slant"*. + pub startup_banner: String, + /// Modo de ejecución. + /// Valor por defecto: el definido por la variable de entorno + /// `PAGETOP_RUN_MODE`, o *"default"* si no está establecida. + pub run_mode: String, +} + +#[derive(Debug, Deserialize)] +/// Sección `[server]` de la configuración. +/// +/// Forma parte de [`Settings`]. +pub struct Server { + /// Dirección de enlace para el servidor web. + /// Valor por defecto: *"localhost"*. + pub bind_address: String, + /// Puerto de escucha del servidor web. + /// Valor por defecto: *8088*. + pub bind_port: u16, +} diff --git a/src/lib.rs b/src/lib.rs index c18003f8..82f9ebaa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,6 +36,10 @@ pub use pagetop_macros::{main, test}; // API ********************************************************************************************* +// Carga las opciones de configuración. +pub mod config; +// Opciones de configuración globales. +pub mod global; // Gestión del servidor y servicios web. pub mod service; // Prepara y ejecuta la aplicación. diff --git a/src/prelude.rs b/src/prelude.rs index d35e9b11..bee222e8 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -4,8 +4,15 @@ pub use crate::{main, test}; +// MACROS. + +// crate::config +pub use crate::include_config; + // API. +pub use crate::global; + pub use crate::service; pub use crate::app::Application; diff --git a/tests/config.rs b/tests/config.rs new file mode 100644 index 00000000..ff7135c0 --- /dev/null +++ b/tests/config.rs @@ -0,0 +1,41 @@ +use pagetop::prelude::*; + +use serde::Deserialize; + +use std::env; + +include_config!(SETTINGS: Settings => [ + "test.string_value" => "Test String", + "test.int_value" => -321, + "test.float_value" => 2.3456, +]); + +#[derive(Debug, Deserialize)] +pub struct Settings { + pub test: Test, +} + +#[derive(Debug, Deserialize)] +pub struct Test { + pub string_value: String, + pub int_value: i32, + pub float_value: f32, +} + +#[pagetop::test] +async fn check_global_config() { + env::set_var("PAGETOP_RUN_MODE", "test"); + + assert_eq!(global::SETTINGS.app.run_mode, "test"); + assert_eq!(global::SETTINGS.app.name, "Testing"); + assert_eq!(global::SETTINGS.server.bind_port, 9000); +} + +#[pagetop::test] +async fn check_local_config() { + env::set_var("PAGETOP_RUN_MODE", "test"); + + assert_eq!(SETTINGS.test.string_value, "Modified value"); + assert_eq!(SETTINGS.test.int_value, -321); + assert_eq!(SETTINGS.test.float_value, 8.7654); +} From 60d550a4f97591a315ed86c835a6526c9ed4999d Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 6 Jul 2025 20:08:17 +0200 Subject: [PATCH 055/244] =?UTF-8?q?=F0=9F=93=9D=20(config):=20Ampl=C3=ADa?= =?UTF-8?q?=20y=20corrige=20documentaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- helpers/pagetop-macros/src/lib.rs | 4 +- src/config.rs | 119 ++++++++++++++++++++++++++---- src/lib.rs | 2 +- 4 files changed, 108 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 7293f88d..159aabe0 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ la creación de soluciones web SSR (*renderizadas en el servidor*) basadas en HT La aplicación más sencilla de `PageTop` se ve así: -```rust#ignore +```rust use pagetop::prelude::*; #[pagetop::main] diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 1ed29c5b..31d8dcdd 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -21,7 +21,7 @@ use quote::quote; /// /// # Ejemplos /// -/// ```rust#ignore +/// ```rust,ignore /// #[pagetop::main] /// async fn main() { /// async { println!("Hello world!"); }.await @@ -42,7 +42,7 @@ pub fn main(_: TokenStream, item: TokenStream) -> TokenStream { /// /// # Ejemplos /// -/// ```rust#ignore +/// ```rust,ignore /// #[pagetop::test] /// async fn test() { /// assert_eq!(async { "Hello world" }.await, "Hello world"); diff --git a/src/config.rs b/src/config.rs index aa5790ca..eae182fc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -55,7 +55,7 @@ //! Y usa la macro [`include_config!`](crate::include_config) para inicializar tus ajustes en una //! estructura con tipos seguros. Por ejemplo: //! -//! ```rust#ignore +//! ```rust,no_run //! use pagetop::prelude::*; //! use serde::Deserialize; //! @@ -94,7 +94,7 @@ //! //! # Usando tus opciones de configuración //! -//! ```rust#ignore +//! ```rust,ignore //! use pagetop::prelude::*; //! use crate::config; //! @@ -160,20 +160,109 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( .expect("Failed to set application run mode") }); +/// Incluye los ajustes necesarios de la configuración anticipando valores por defecto. +/// +/// ### Sintaxis +/// +/// Hay que añadir en nuestra librería el siguiente código: +/// +/// ```rust,ignore +/// include_config!(SETTINGS: Settings => [ +/// "ruta.clave" => valor, +/// // … +/// ]); +/// ``` +/// +/// donde: +/// +/// * **`SETTINGS_NAME`** es el nombre de la variable global que se usará para referenciar los +/// ajustes. Se recomienda usar `SETTINGS`, aunque no es obligatorio. +/// * **`Settings_Type`** es la referencia a la estructura que define los tipos para deserializar la +/// configuración. Debe implementar `Deserialize` (derivable con `#[derive(Deserialize)]`). +/// * **Lista de pares** con las claves TOML que requieran valores por defecto. Siguen la notación +/// `"seccion.subclave"` para coincidir con el árbol TOML. +/// +/// ### Ejemplo básico +/// +/// ```rust,no_run +/// use pagetop::prelude::*; +/// use serde::Deserialize; +/// +/// include_config!(SETTINGS: BlogSettings => [ +/// // [blog] +/// "blog.title" => "Mi Blog", +/// "blog.port" => 8080, +/// ]); +/// +/// #[derive(Debug, Deserialize)] +/// pub struct BlogSettings { +/// pub blog: Blog, +/// } +/// +/// #[derive(Debug, Deserialize)] +/// pub struct Blog { +/// pub title: String, +/// pub description: Option<String>, +/// pub port: u16, +/// } +/// +/// fn print_title() { +/// // Lectura en tiempo de ejecución. +/// println!("Título: {}", SETTINGS.blog.title); +/// } +/// ``` +/// +/// ### Buenas prácticas +/// +/// * **Valores por defecto**. Declara un valor por defecto para cada clave obligatoria. Las claves +/// opcionales pueden ser `Option<T>`. +/// +/// * **Secciones únicas**. Agrupa tus claves dentro de una sección exclusiva (p.e. `[blog]`) para +/// evitar colisiones con otras librerías. +/// +/// * **Solo lectura**. La variable generada es inmutable durante toda la vida del programa. Para +/// configurar distintos entornos (*dev*, *staging*, *prod*) usa los archivos TOML descritos en la +/// documentación de [`config`](crate::config). +/// +/// * **Errores explícitos**. Si la deserialización falla, la macro lanzará un `panic!` con un +/// mensaje que indica la estructura problemática, facilitando la depuración. +/// +/// ### Requisitos +/// +/// * Dependencia `serde` con la *feature* `derive`. +/// * Las claves deben coincidir con los campos (*snake case*) de tu estructura `Settings_Type`. +/// +/// ```toml +/// [dependencies] +/// serde = { version = "1.0", features = ["derive"] } +/// ``` + #[macro_export] macro_rules! include_config { - ( $SETTINGS:ident : $Settings:ty => [ $( $key:expr => $value:expr ),* $(,)? ] ) => { - /// Valores asignados o predefinidos para la configuración de [`$Settings`]. - pub static $SETTINGS: std::sync::LazyLock<$Settings> = std::sync::LazyLock::new(|| { - let mut settings = $crate::config::CONFIG_VALUES.clone(); - $( - settings = settings.set_default($key, $value).unwrap(); - )* - settings - .build() - .expect(concat!("Failed to build config for ", stringify!($Settings))) - .try_deserialize::<$Settings>() - .expect(concat!("Error parsing settings for ", stringify!($Settings))) - }); + ( $SETTINGS_NAME:ident : $Settings_Type:ty => [ $( $k:literal => $v:expr ),* $(,)? ] ) => { + #[doc = concat!( + "Referencia a los ajustes de configuración deserializados de [`", + stringify!($Settings_Type), + "`]." + )] + #[doc = ""] + #[doc = "Valores por defecto:"] + #[doc = "```text"] + $( + #[doc = concat!($k, " = ", stringify!($v))] + )* + #[doc = "```"] + pub static $SETTINGS_NAME: std::sync::LazyLock<$Settings_Type> = + std::sync::LazyLock::new(|| { + let mut settings = $crate::config::CONFIG_VALUES.clone(); + $( + settings = settings.set_default($k, $v).unwrap(); + )* + settings + .build() + .expect(concat!("Failed to build config for ", stringify!($Settings_Type))) + .try_deserialize::<$Settings_Type>() + .expect(concat!("Error parsing settings for ", stringify!($Settings_Type))) + }); }; } diff --git a/src/lib.rs b/src/lib.rs index 82f9ebaa..81e7bc6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,7 @@ //! //! La aplicación más sencilla de `PageTop` se ve así: //! -//! ```rust#ignore +//! ```rust,no_run //! use pagetop::prelude::*; //! //! #[pagetop::main] From 84e48a3357705070fab06504d73bc919c77c91cc Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 6 Jul 2025 23:03:21 +0200 Subject: [PATCH 056/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20gesti=C3=B3n?= =?UTF-8?q?=20de=20trazas=20y=20registro=20de=20eventos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Reexporta macros esenciales de `tracing` para el registro de eventos. - Inicializa el gestor de trazas en el servidor web. --- .gitignore | 3 + Cargo.lock | 324 ++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 7 +- src/app.rs | 23 ++-- src/global.rs | 51 +++++--- src/lib.rs | 2 + src/prelude.rs | 2 + src/trace.rs | 85 +++++++++++++ 8 files changed, 467 insertions(+), 30 deletions(-) create mode 100644 src/trace.rs diff --git a/.gitignore b/.gitignore index 56ee30e4..65db440e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # Ignora directorios de compilación **/target +# Archivos de log +**/log/*.log* + # Archivos de configuración locales **/local.*.toml **/local.toml diff --git a/Cargo.lock b/Cargo.lock index 045a72fd..43eb2107 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -287,6 +287,12 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + [[package]] name = "bytes" version = "1.10.1" @@ -369,6 +375,21 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + [[package]] name = "crypto-common" version = "0.1.6" @@ -737,12 +758,28 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "language-tags" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.174" @@ -794,6 +831,15 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.7.5" @@ -827,6 +873,22 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "mutually_exclusive_features" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94e1e6445d314f972ff7395df2de295fe51b71821694f0b0e1e79c4f12c8577" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -848,9 +910,15 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "pagetop" -version = "0.0.2" +version = "0.0.3" dependencies = [ "actix-web", "colored", @@ -860,6 +928,10 @@ dependencies = [ "serde", "substring", "terminal_size", + "tracing", + "tracing-actix-web", + "tracing-appender", + "tracing-subscriber", ] [[package]] @@ -904,6 +976,26 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1016,8 +1108,17 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -1028,7 +1129,7 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.5", ] [[package]] @@ -1037,6 +1138,12 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.5" @@ -1062,6 +1169,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + [[package]] name = "ryu" version = "1.0.20" @@ -1138,6 +1251,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1222,6 +1344,35 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "time" version = "0.3.41" @@ -1339,6 +1490,31 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-actix-web" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2340b7722695166c7fc9b3e3cd1166e7c74fedb9075b8f0c74d3822d2e41caf5" +dependencies = [ + "actix-web", + "mutually_exclusive_features", + "pin-project", + "tracing", + "uuid", +] + +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.30" @@ -1357,6 +1533,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", ] [[package]] @@ -1394,6 +1613,23 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "uuid" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +dependencies = [ + "getrandom", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "version_check" version = "0.9.5" @@ -1415,6 +1651,86 @@ dependencies = [ "wit-bindgen-rt", ] +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index a844f527..f5948d56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.2" +version = "0.0.3" edition = "2021" description = """\ @@ -22,6 +22,11 @@ serde.workspace = true substring = "1.4.5" terminal_size = "0.4.2" +tracing = "0.1.41" +tracing-appender = "0.2.3" +tracing-subscriber = { version = "0.3.19", features = ["json", "env-filter"] } +tracing-actix-web = "0.7.18" + actix-web = "4.11.0" pagetop-macros.workspace = true diff --git a/src/app.rs b/src/app.rs index bac74821..d21c08a0 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,11 +2,12 @@ mod figfont; -use crate::{global, service}; +use crate::{global, service, trace}; use substring::Substring; use std::io::Error; +use std::sync::LazyLock; pub struct Application; @@ -15,6 +16,10 @@ impl Application { pub fn new() -> Self { // Al arrancar muestra una cabecera para la aplicación. Self::show_banner(); + + // Inicia gestión de trazas y registro de eventos (logging). + LazyLock::force(&trace::TRACING); + Self } @@ -62,13 +67,15 @@ impl Application { /// Ejecuta el servidor web de la aplicación. pub fn run(self) -> Result<service::Server, Error> { // Prepara el servidor web. - Ok(service::HttpServer::new(move || Self::service_app()) - .bind(format!( - "{}:{}", - &global::SETTINGS.server.bind_address, - &global::SETTINGS.server.bind_port - ))? - .run()) + Ok(service::HttpServer::new(move || { + Self::service_app().wrap(tracing_actix_web::TracingLogger::default()) + }) + .bind(format!( + "{}:{}", + &global::SETTINGS.server.bind_address, + &global::SETTINGS.server.bind_port + ))? + .run()) } /// Prepara el servidor web de la aplicación para pruebas. diff --git a/src/global.rs b/src/global.rs index 5e3d52f2..8432032a 100644 --- a/src/global.rs +++ b/src/global.rs @@ -10,48 +10,65 @@ include_config!(SETTINGS: Settings => [ "app.description" => "Developed with the amazing PageTop framework.", "app.startup_banner" => "Slant", + // [log] + "log.tracing" => "Info", + "log.rolling" => "Stdout", + "log.path" => "log", + "log.prefix" => "tracing.log", + "log.format" => "Full", + // [server] "server.bind_address" => "localhost", "server.bind_port" => 8080, ]); #[derive(Debug, Deserialize)] -/// Ajustes de configuración para las secciones globales [`[app]`](App) y [`[server]`](Server). -/// Consulta [`SETTINGS`] para los valores por defecto. +/// Ajustes para las secciones globales [`[app]`](App), [`[log]`](Log) y [`[server]`](Server) de +/// [`SETTINGS`]. pub struct Settings { pub app: App, + pub log: Log, pub server: Server, } #[derive(Debug, Deserialize)] -/// Sección `[app]` de la configuración. -/// -/// Forma parte de [`Settings`]. +/// Sección `[app]` de la configuración. Forma parte de [`Settings`]. pub struct App { /// Nombre de la aplicación. - /// Valor por defecto: *"Sample"*. pub name: String, /// Breve descripción de la aplicación. - /// Valor por defecto: *"Developed with the amazing PageTop framework."*. pub description: String, - /// ASCII banner printed at startup: *"Off"*, *"Slant"*, *"Small"*, *"Speed"*, or *"Starwars"*. - /// Default: *"Slant"*. + /// Banner ASCII mostrado al inicio: *"Off"* (desactivado), *"Slant"*, *"Small"*, *"Speed"* o + /// *"Starwars"*. pub startup_banner: String, - /// Modo de ejecución. - /// Valor por defecto: el definido por la variable de entorno - /// `PAGETOP_RUN_MODE`, o *"default"* si no está establecida. + /// Modo de ejecución, dado por la variable de entorno `PAGETOP_RUN_MODE`, o *"default"* si no + /// está definido. pub run_mode: String, } #[derive(Debug, Deserialize)] -/// Sección `[server]` de la configuración. -/// -/// Forma parte de [`Settings`]. +/// Sección `[log]` de la configuración. Forma parte de [`Settings`]. +pub struct Log { + /// Opciones, o combinación de opciones separadas por comas, para filtrar las trazas: *"Error"*, + /// *"Warn"*, *"Info"*, *"Debug"* o *"Trace"*. + /// Ejemplo: "Error,actix_server::builder=Info,tracing_actix_web=Debug". + pub tracing: String, + /// Muestra los mensajes de traza en el terminal (*"Stdout"*) o las registra en archivos con + /// rotación: *"Daily"*, *"Hourly"*, *"Minutely"* o *"Endless"*. + pub rolling: String, + /// Directorio para los archivos de traza (si `rolling` ≠ *"Stdout"*). + pub path: String, + /// Prefijo para los archivos de traza (si `rolling` ≠ *"Stdout"*). + pub prefix: String, + /// Formato de salida de las trazas. Opciones: *"Full"*, *"Compact"*, *"Pretty"* o *"Json"*. + pub format: String, +} + +#[derive(Debug, Deserialize)] +/// Sección `[server]` de la configuración. Forma parte de [`Settings`]. pub struct Server { /// Dirección de enlace para el servidor web. - /// Valor por defecto: *"localhost"*. pub bind_address: String, /// Puerto de escucha del servidor web. - /// Valor por defecto: *8088*. pub bind_port: u16, } diff --git a/src/lib.rs b/src/lib.rs index 81e7bc6b..308c1633 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,8 @@ pub use pagetop_macros::{main, test}; pub mod config; // Opciones de configuración globales. pub mod global; +// Gestión de trazas y registro de eventos de la aplicación. +pub mod trace; // Gestión del servidor y servicios web. pub mod service; // Prepara y ejecuta la aplicación. diff --git a/src/prelude.rs b/src/prelude.rs index bee222e8..5d5851fc 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -13,6 +13,8 @@ pub use crate::include_config; pub use crate::global; +pub use crate::trace; + pub use crate::service; pub use crate::app::Application; diff --git a/src/trace.rs b/src/trace.rs new file mode 100644 index 00000000..93a8ff2d --- /dev/null +++ b/src/trace.rs @@ -0,0 +1,85 @@ +//! Gestión de trazas y registro de eventos de la aplicación. +//! +//! `PageTop` recopila información de diagnóstico de la aplicación de forma estructurada y basada en +//! eventos. +//! +//! En los sistemas asíncronos, interpretar los mensajes de log tradicionales suele volverse +//! complicado. Las tareas individuales se multiplexan en el mismo hilo y los eventos y registros +//! asociados se entremezclan, lo que dificulta seguir la secuencia lógica. +//! +//! `PageTop` usa [`tracing`](https://docs.rs/tracing) para registrar eventos estructurados y con +//! información adicional sobre la *temporalidad* y la *causalidad*. A diferencia de un mensaje de +//! log, un *span* (intervalo) tiene un momento de inicio y de fin, puede entrar y salir del flujo +//! de ejecución y puede existir dentro de un árbol anidado de *spans* similares. Además, estos +//! *spans* son estructurados, con la capacidad de registrar tipos de datos y mensajes de texto. + +use crate::global; + +pub use tracing::{debug, error, info, trace, warn}; +pub use tracing::{debug_span, error_span, info_span, trace_span, warn_span}; + +use tracing_appender::non_blocking::WorkerGuard; +use tracing_subscriber::EnvFilter; + +use std::sync::LazyLock; + +/// Trazado y registro de eventos de la aplicación. +/// +/// Para aumentar el rendimiento, un hilo dedicado utiliza un sistema de escritura no bloqueante que +/// actúa de forma periódica en lugar de enviar cada traza o evento al instante. Si el programa +/// termina abruptamente (por ejemplo, debido a un `panic!` o a una llamada a `std::process::exit`), +/// es posible que algunas trazas o eventos no se envíen. +/// +/// Dado que las trazas o eventos registrados poco antes de un fallo suelen ser cruciales para +/// diagnosticar la causa, `Lazy<WorkerGuard>` garantiza que todos los registros almacenados se +/// envíen antes de finalizar la ejecución. + +#[rustfmt::skip] +pub(crate) static TRACING: LazyLock<WorkerGuard> = LazyLock::new(|| { + let env_filter = EnvFilter::try_new(&global::SETTINGS.log.tracing) + .unwrap_or_else(|_| EnvFilter::new("Info")); + + let rolling = global::SETTINGS.log.rolling.to_lowercase(); + + let (non_blocking, guard) = match rolling.as_str() { + "stdout" => tracing_appender::non_blocking(std::io::stdout()), + _ => tracing_appender::non_blocking({ + let path = &global::SETTINGS.log.path; + let prefix = &global::SETTINGS.log.prefix; + match rolling.as_str() { + "daily" => tracing_appender::rolling::daily(path, prefix), + "hourly" => tracing_appender::rolling::hourly(path, prefix), + "minutely" => tracing_appender::rolling::minutely(path, prefix), + "endless" => tracing_appender::rolling::never(path, prefix), + _ => { + println!( + "Rolling value \"{}\" not valid. Using \"daily\". Check the settings file.", + global::SETTINGS.log.rolling, + ); + tracing_appender::rolling::daily(path, prefix) + } + } + }), + }; + + let subscriber = tracing_subscriber::fmt() + .with_env_filter(env_filter) + .with_writer(non_blocking) + .with_ansi(rolling.as_str() == "stdout"); + + match global::SETTINGS.log.format.to_lowercase().as_str() { + "json" => subscriber.json().init(), + "full" => subscriber.init(), + "compact" => subscriber.compact().init(), + "pretty" => subscriber.pretty().init(), + _ => { + println!( + "Tracing format \"{}\" not valid. Using \"Full\". Check the settings file.", + global::SETTINGS.log.format, + ); + subscriber.init(); + } + } + + guard +}); From 1fb8e937d161cfb1a894d0482d1cb9ea6bf29d2d Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 7 Jul 2025 18:21:00 +0200 Subject: [PATCH 057/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20macro=20para?= =?UTF-8?q?=20componer=20HTML=20en=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Incorpora el código de la versión 0.25.0 de `maud_macros` creado por Chris Wong. - Y reexporta los elementos esenciales desde la librería principal. --- Cargo.lock | 80 ++- Cargo.toml | 3 +- helpers/pagetop-macros/Cargo.toml | 4 + helpers/pagetop-macros/README.md | 7 + helpers/pagetop-macros/src/lib.rs | 9 + helpers/pagetop-macros/src/maud.rs | 39 + helpers/pagetop-macros/src/maud/ast.rs | 221 ++++++ helpers/pagetop-macros/src/maud/escape.rs | 34 + helpers/pagetop-macros/src/maud/generate.rs | 308 ++++++++ helpers/pagetop-macros/src/maud/parse.rs | 752 ++++++++++++++++++++ src/html.rs | 4 + src/html/maud.rs | 350 +++++++++ src/html/maud/escape.rs | 34 + src/lib.rs | 4 +- src/prelude.rs | 4 +- 15 files changed, 1834 insertions(+), 19 deletions(-) create mode 100644 helpers/pagetop-macros/src/maud.rs create mode 100644 helpers/pagetop-macros/src/maud/ast.rs create mode 100644 helpers/pagetop-macros/src/maud/escape.rs create mode 100644 helpers/pagetop-macros/src/maud/generate.rs create mode 100644 helpers/pagetop-macros/src/maud/parse.rs create mode 100644 src/html.rs create mode 100644 src/html/maud.rs create mode 100644 src/html/maud/escape.rs diff --git a/Cargo.lock b/Cargo.lock index 43eb2107..d53ffd7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -182,7 +182,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -426,7 +426,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", "unicode-xid", ] @@ -448,7 +448,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -918,12 +918,13 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.0.3" +version = "0.0.4" dependencies = [ "actix-web", "colored", "config", "figlet-rs", + "itoa", "pagetop-macros", "serde", "substring", @@ -938,7 +939,11 @@ dependencies = [ name = "pagetop-macros" version = "0.0.1" dependencies = [ + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", "quote", + "syn 2.0.104", ] [[package]] @@ -993,7 +998,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1038,6 +1043,39 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -1204,7 +1242,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1312,6 +1350,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.104" @@ -1331,7 +1379,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1361,7 +1409,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1523,7 +1571,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1673,7 +1721,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 2.0.104", "wasm-bindgen-shared", ] @@ -1695,7 +1743,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1857,7 +1905,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", "synstructure", ] @@ -1878,7 +1926,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] @@ -1898,7 +1946,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", "synstructure", ] @@ -1932,7 +1980,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.104", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f5948d56..b8b3f5fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.3" +version = "0.0.4" edition = "2021" description = """\ @@ -18,6 +18,7 @@ authors.workspace = true colored = "3.0.0" config = { version = "0.15.11", default-features = false, features = ["toml"] } figlet-rs = "0.1.5" +itoa = "1.0.15" serde.workspace = true substring = "1.4.5" terminal_size = "0.4.2" diff --git a/helpers/pagetop-macros/Cargo.toml b/helpers/pagetop-macros/Cargo.toml index 7a4d30e1..80413821 100644 --- a/helpers/pagetop-macros/Cargo.toml +++ b/helpers/pagetop-macros/Cargo.toml @@ -18,4 +18,8 @@ authors.workspace = true proc-macro = true [dependencies] +proc-macro2 = "1.0.95" +proc-macro-crate = "3.3.0" +proc-macro-error = "1.0.4" quote = "1.0.40" +syn = { version = "2.0.104", features = ["full"] } diff --git a/helpers/pagetop-macros/README.md b/helpers/pagetop-macros/README.md index 8bdc94c2..06799668 100644 --- a/helpers/pagetop-macros/README.md +++ b/helpers/pagetop-macros/README.md @@ -8,6 +8,13 @@ </div> +## Descripción general + +Entre sus macros se incluye una adaptación de [maud-macros](https://crates.io/crates/maud_macros) +([0.25.0](https://github.com/lambda-fairy/maud/tree/v0.25.0/maud_macros)) de +[Chris Wong](https://crates.io/users/lambda-fairy) para no tener que referenciar `maud` en las +dependencias del archivo `Cargo.toml` de cada proyecto `PageTop`. + ## Sobre PageTop [PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 31d8dcdd..65badb04 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -14,9 +14,18 @@ //! web clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles //! y configurables, basadas en HTML, CSS y JavaScript. +mod maud; + use proc_macro::TokenStream; +use proc_macro_error::proc_macro_error; use quote::quote; +#[proc_macro] +#[proc_macro_error] +pub fn html(input: TokenStream) -> TokenStream { + maud::expand(input.into()).into() +} + /// Define una función `main` asíncrona como punto de entrada de `PageTop`. /// /// # Ejemplos diff --git a/helpers/pagetop-macros/src/maud.rs b/helpers/pagetop-macros/src/maud.rs new file mode 100644 index 00000000..a4e7873f --- /dev/null +++ b/helpers/pagetop-macros/src/maud.rs @@ -0,0 +1,39 @@ +// #![doc(html_root_url = "https://docs.rs/maud_macros/0.25.0")] +// TokenStream values are reference counted, and the mental overhead of tracking +// lifetimes outweighs the marginal gains from explicit borrowing +// #![allow(clippy::needless_pass_by_value)] + +mod ast; +mod escape; +mod generate; +mod parse; + +use proc_macro2::{Ident, Span, TokenStream, TokenTree}; +use proc_macro_crate::{crate_name, FoundCrate}; +use quote::quote; + +pub fn expand(input: TokenStream) -> TokenStream { + let output_ident = TokenTree::Ident(Ident::new("__maud_output", Span::mixed_site())); + // Heuristic: the size of the resulting markup tends to correlate with the + // code size of the template itself + let size_hint = input.to_string().len(); + let markups = parse::parse(input); + let stmts = generate::generate(markups, output_ident.clone()); + + let found_crate = crate_name("pagetop").expect("pagetop is present in `Cargo.toml`"); + let pre_escaped = match found_crate { + FoundCrate::Itself => quote!( + crate::html::PreEscaped(#output_ident) + ), + _ => quote!( + pagetop::html::PreEscaped(#output_ident) + ), + }; + + quote!({ + extern crate alloc; + let mut #output_ident = alloc::string::String::with_capacity(#size_hint); + #stmts + #pre_escaped + }) +} diff --git a/helpers/pagetop-macros/src/maud/ast.rs b/helpers/pagetop-macros/src/maud/ast.rs new file mode 100644 index 00000000..cd8a2cef --- /dev/null +++ b/helpers/pagetop-macros/src/maud/ast.rs @@ -0,0 +1,221 @@ +use proc_macro2::{TokenStream, TokenTree}; +use proc_macro_error::SpanRange; + +#[derive(Debug)] +pub enum Markup { + /// Used as a placeholder value on parse error. + ParseError { + span: SpanRange, + }, + Block(Block), + Literal { + content: String, + span: SpanRange, + }, + Symbol { + symbol: TokenStream, + }, + Splice { + expr: TokenStream, + outer_span: SpanRange, + }, + Element { + name: TokenStream, + attrs: Vec<Attr>, + body: ElementBody, + }, + Let { + at_span: SpanRange, + tokens: TokenStream, + }, + Special { + segments: Vec<Special>, + }, + Match { + at_span: SpanRange, + head: TokenStream, + arms: Vec<MatchArm>, + arms_span: SpanRange, + }, +} + +impl Markup { + pub fn span(&self) -> SpanRange { + match *self { + Markup::ParseError { span } => span, + Markup::Block(ref block) => block.span(), + Markup::Literal { span, .. } => span, + Markup::Symbol { ref symbol } => span_tokens(symbol.clone()), + Markup::Splice { outer_span, .. } => outer_span, + Markup::Element { + ref name, ref body, .. + } => { + let name_span = span_tokens(name.clone()); + name_span.join_range(body.span()) + } + Markup::Let { + at_span, + ref tokens, + } => at_span.join_range(span_tokens(tokens.clone())), + Markup::Special { ref segments } => join_ranges(segments.iter().map(Special::span)), + Markup::Match { + at_span, arms_span, .. + } => at_span.join_range(arms_span), + } + } +} + +#[derive(Debug)] +pub enum Attr { + Class { + dot_span: SpanRange, + name: Markup, + toggler: Option<Toggler>, + }, + Id { + hash_span: SpanRange, + name: Markup, + }, + Named { + named_attr: NamedAttr, + }, +} + +impl Attr { + pub fn span(&self) -> SpanRange { + match *self { + Attr::Class { + dot_span, + ref name, + ref toggler, + } => { + let name_span = name.span(); + let dot_name_span = dot_span.join_range(name_span); + if let Some(toggler) = toggler { + dot_name_span.join_range(toggler.cond_span) + } else { + dot_name_span + } + } + Attr::Id { + hash_span, + ref name, + } => { + let name_span = name.span(); + hash_span.join_range(name_span) + } + Attr::Named { ref named_attr } => named_attr.span(), + } + } +} + +#[derive(Debug)] +pub enum ElementBody { + Void { semi_span: SpanRange }, + Block { block: Block }, +} + +impl ElementBody { + pub fn span(&self) -> SpanRange { + match *self { + ElementBody::Void { semi_span } => semi_span, + ElementBody::Block { ref block } => block.span(), + } + } +} + +#[derive(Debug)] +pub struct Block { + pub markups: Vec<Markup>, + pub outer_span: SpanRange, +} + +impl Block { + pub fn span(&self) -> SpanRange { + self.outer_span + } +} + +#[derive(Debug)] +pub struct Special { + pub at_span: SpanRange, + pub head: TokenStream, + pub body: Block, +} + +impl Special { + pub fn span(&self) -> SpanRange { + let body_span = self.body.span(); + self.at_span.join_range(body_span) + } +} + +#[derive(Debug)] +pub struct NamedAttr { + pub name: TokenStream, + pub attr_type: AttrType, +} + +impl NamedAttr { + fn span(&self) -> SpanRange { + let name_span = span_tokens(self.name.clone()); + if let Some(attr_type_span) = self.attr_type.span() { + name_span.join_range(attr_type_span) + } else { + name_span + } + } +} + +#[derive(Debug)] +pub enum AttrType { + Normal { value: Markup }, + Optional { toggler: Toggler }, + Empty { toggler: Option<Toggler> }, +} + +impl AttrType { + fn span(&self) -> Option<SpanRange> { + match *self { + AttrType::Normal { ref value } => Some(value.span()), + AttrType::Optional { ref toggler } => Some(toggler.span()), + AttrType::Empty { ref toggler } => toggler.as_ref().map(Toggler::span), + } + } +} + +#[derive(Debug)] +pub struct Toggler { + pub cond: TokenStream, + pub cond_span: SpanRange, +} + +impl Toggler { + fn span(&self) -> SpanRange { + self.cond_span + } +} + +#[derive(Debug)] +pub struct MatchArm { + pub head: TokenStream, + pub body: Block, +} + +pub fn span_tokens<I: IntoIterator<Item = TokenTree>>(tokens: I) -> SpanRange { + join_ranges(tokens.into_iter().map(|s| SpanRange::single_span(s.span()))) +} + +pub fn join_ranges<I: IntoIterator<Item = SpanRange>>(ranges: I) -> SpanRange { + let mut iter = ranges.into_iter(); + let first = match iter.next() { + Some(span) => span, + None => return SpanRange::call_site(), + }; + let last = iter.last().unwrap_or(first); + first.join_range(last) +} + +pub fn name_to_string(name: TokenStream) -> String { + name.into_iter().map(|token| token.to_string()).collect() +} diff --git a/helpers/pagetop-macros/src/maud/escape.rs b/helpers/pagetop-macros/src/maud/escape.rs new file mode 100644 index 00000000..49ece776 --- /dev/null +++ b/helpers/pagetop-macros/src/maud/escape.rs @@ -0,0 +1,34 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !!!!!!!! PLEASE KEEP THIS IN SYNC WITH `maud/src/escape.rs` !!!!!!!!! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +extern crate alloc; + +use alloc::string::String; + +pub fn escape_to_string(input: &str, output: &mut String) { + for b in input.bytes() { + match b { + b'&' => output.push_str("&amp;"), + b'<' => output.push_str("&lt;"), + b'>' => output.push_str("&gt;"), + b'"' => output.push_str("&quot;"), + _ => unsafe { output.as_mut_vec().push(b) }, + } + } +} + +#[cfg(test)] +mod test { + extern crate alloc; + + use super::escape_to_string; + use alloc::string::String; + + #[test] + fn it_works() { + let mut s = String::new(); + escape_to_string("<script>launchMissiles()</script>", &mut s); + assert_eq!(s, "&lt;script&gt;launchMissiles()&lt;/script&gt;"); + } +} diff --git a/helpers/pagetop-macros/src/maud/generate.rs b/helpers/pagetop-macros/src/maud/generate.rs new file mode 100644 index 00000000..be7946d0 --- /dev/null +++ b/helpers/pagetop-macros/src/maud/generate.rs @@ -0,0 +1,308 @@ +use proc_macro2::{Delimiter, Group, Ident, Literal, Span, TokenStream, TokenTree}; +use proc_macro_error::SpanRange; +use quote::quote; + +use crate::maud::{ast::*, escape}; + +use proc_macro_crate::{crate_name, FoundCrate}; + +pub fn generate(markups: Vec<Markup>, output_ident: TokenTree) -> TokenStream { + let mut build = Builder::new(output_ident.clone()); + Generator::new(output_ident).markups(markups, &mut build); + build.finish() +} + +struct Generator { + output_ident: TokenTree, +} + +impl Generator { + fn new(output_ident: TokenTree) -> Generator { + Generator { output_ident } + } + + fn builder(&self) -> Builder { + Builder::new(self.output_ident.clone()) + } + + fn markups(&self, markups: Vec<Markup>, build: &mut Builder) { + for markup in markups { + self.markup(markup, build); + } + } + + fn markup(&self, markup: Markup, build: &mut Builder) { + match markup { + Markup::ParseError { .. } => {} + Markup::Block(Block { + markups, + outer_span, + }) => { + if markups + .iter() + .any(|markup| matches!(*markup, Markup::Let { .. })) + { + self.block( + Block { + markups, + outer_span, + }, + build, + ); + } else { + self.markups(markups, build); + } + } + Markup::Literal { content, .. } => build.push_escaped(&content), + Markup::Symbol { symbol } => self.name(symbol, build), + Markup::Splice { expr, .. } => self.splice(expr, build), + Markup::Element { name, attrs, body } => self.element(name, attrs, body, build), + Markup::Let { tokens, .. } => build.push_tokens(tokens), + Markup::Special { segments } => { + for Special { head, body, .. } in segments { + build.push_tokens(head); + self.block(body, build); + } + } + Markup::Match { + head, + arms, + arms_span, + .. + } => { + let body = { + let mut build = self.builder(); + for MatchArm { head, body } in arms { + build.push_tokens(head); + self.block(body, &mut build); + } + build.finish() + }; + let mut body = TokenTree::Group(Group::new(Delimiter::Brace, body)); + body.set_span(arms_span.collapse()); + build.push_tokens(quote!(#head #body)); + } + } + } + + fn block( + &self, + Block { + markups, + outer_span, + }: Block, + build: &mut Builder, + ) { + let block = { + let mut build = self.builder(); + self.markups(markups, &mut build); + build.finish() + }; + let mut block = TokenTree::Group(Group::new(Delimiter::Brace, block)); + block.set_span(outer_span.collapse()); + build.push_tokens(TokenStream::from(block)); + } + + fn splice(&self, expr: TokenStream, build: &mut Builder) { + let output_ident = self.output_ident.clone(); + + let found_crate = crate_name("pagetop").expect("pagetop is present in `Cargo.toml`"); + build.push_tokens(match found_crate { + FoundCrate::Itself => quote!( + crate::html::html_private::render_to!(&#expr, &mut #output_ident); + ), + _ => quote!( + pagetop::html::html_private::render_to!(&#expr, &mut #output_ident); + ), + }); + } + + fn element(&self, name: TokenStream, attrs: Vec<Attr>, body: ElementBody, build: &mut Builder) { + build.push_str("<"); + self.name(name.clone(), build); + self.attrs(attrs, build); + build.push_str(">"); + if let ElementBody::Block { block } = body { + self.markups(block.markups, build); + build.push_str("</"); + self.name(name, build); + build.push_str(">"); + } + } + + fn name(&self, name: TokenStream, build: &mut Builder) { + build.push_escaped(&name_to_string(name)); + } + + fn attrs(&self, attrs: Vec<Attr>, build: &mut Builder) { + for NamedAttr { name, attr_type } in desugar_attrs(attrs) { + match attr_type { + AttrType::Normal { value } => { + build.push_str(" "); + self.name(name, build); + build.push_str("=\""); + self.markup(value, build); + build.push_str("\""); + } + AttrType::Optional { + toggler: Toggler { cond, .. }, + } => { + let inner_value = quote!(inner_value); + let body = { + let mut build = self.builder(); + build.push_str(" "); + self.name(name, &mut build); + build.push_str("=\""); + self.splice(inner_value.clone(), &mut build); + build.push_str("\""); + build.finish() + }; + build.push_tokens(quote!(if let Some(#inner_value) = (#cond) { #body })); + } + AttrType::Empty { toggler: None } => { + build.push_str(" "); + self.name(name, build); + } + AttrType::Empty { + toggler: Some(Toggler { cond, .. }), + } => { + let body = { + let mut build = self.builder(); + build.push_str(" "); + self.name(name, &mut build); + build.finish() + }; + build.push_tokens(quote!(if (#cond) { #body })); + } + } + } + } +} + +//////////////////////////////////////////////////////// + +fn desugar_attrs(attrs: Vec<Attr>) -> Vec<NamedAttr> { + let mut classes_static = vec![]; + let mut classes_toggled = vec![]; + let mut ids = vec![]; + let mut named_attrs = vec![]; + for attr in attrs { + match attr { + Attr::Class { + name, + toggler: Some(toggler), + .. + } => classes_toggled.push((name, toggler)), + Attr::Class { + name, + toggler: None, + .. + } => classes_static.push(name), + Attr::Id { name, .. } => ids.push(name), + Attr::Named { named_attr } => named_attrs.push(named_attr), + } + } + let classes = desugar_classes_or_ids("class", classes_static, classes_toggled); + let ids = desugar_classes_or_ids("id", ids, vec![]); + classes.into_iter().chain(ids).chain(named_attrs).collect() +} + +fn desugar_classes_or_ids( + attr_name: &'static str, + values_static: Vec<Markup>, + values_toggled: Vec<(Markup, Toggler)>, +) -> Option<NamedAttr> { + if values_static.is_empty() && values_toggled.is_empty() { + return None; + } + let mut markups = Vec::new(); + let mut leading_space = false; + for name in values_static { + markups.extend(prepend_leading_space(name, &mut leading_space)); + } + for (name, Toggler { cond, cond_span }) in values_toggled { + let body = Block { + markups: prepend_leading_space(name, &mut leading_space), + // TODO: is this correct? + outer_span: cond_span, + }; + markups.push(Markup::Special { + segments: vec![Special { + at_span: SpanRange::call_site(), + head: quote!(if (#cond)), + body, + }], + }); + } + Some(NamedAttr { + name: TokenStream::from(TokenTree::Ident(Ident::new(attr_name, Span::call_site()))), + attr_type: AttrType::Normal { + value: Markup::Block(Block { + markups, + outer_span: SpanRange::call_site(), + }), + }, + }) +} + +fn prepend_leading_space(name: Markup, leading_space: &mut bool) -> Vec<Markup> { + let mut markups = Vec::new(); + if *leading_space { + markups.push(Markup::Literal { + content: " ".to_owned(), + span: name.span(), + }); + } + *leading_space = true; + markups.push(name); + markups +} + +//////////////////////////////////////////////////////// + +struct Builder { + output_ident: TokenTree, + tokens: Vec<TokenTree>, + tail: String, +} + +impl Builder { + fn new(output_ident: TokenTree) -> Builder { + Builder { + output_ident, + tokens: Vec::new(), + tail: String::new(), + } + } + + fn push_str(&mut self, string: &str) { + self.tail.push_str(string); + } + + fn push_escaped(&mut self, string: &str) { + escape::escape_to_string(string, &mut self.tail); + } + + fn push_tokens(&mut self, tokens: TokenStream) { + self.cut(); + self.tokens.extend(tokens); + } + + fn cut(&mut self) { + if self.tail.is_empty() { + return; + } + let push_str_expr = { + let output_ident = self.output_ident.clone(); + let string = TokenTree::Literal(Literal::string(&self.tail)); + quote!(#output_ident.push_str(#string);) + }; + self.tail.clear(); + self.tokens.extend(push_str_expr); + } + + fn finish(mut self) -> TokenStream { + self.cut(); + self.tokens.into_iter().collect() + } +} diff --git a/helpers/pagetop-macros/src/maud/parse.rs b/helpers/pagetop-macros/src/maud/parse.rs new file mode 100644 index 00000000..d24cea6e --- /dev/null +++ b/helpers/pagetop-macros/src/maud/parse.rs @@ -0,0 +1,752 @@ +use proc_macro2::{Delimiter, Ident, Literal, Spacing, Span, TokenStream, TokenTree}; +use proc_macro_error::{abort, abort_call_site, emit_error, SpanRange}; +use std::collections::HashMap; + +use syn::Lit; + +use crate::maud::ast; + +pub fn parse(input: TokenStream) -> Vec<ast::Markup> { + Parser::new(input).markups() +} + +#[derive(Clone)] +struct Parser { + /// If we're inside an attribute, then this contains the attribute name. + current_attr: Option<String>, + input: <TokenStream as IntoIterator>::IntoIter, +} + +impl Iterator for Parser { + type Item = TokenTree; + + fn next(&mut self) -> Option<TokenTree> { + self.input.next() + } +} + +impl Parser { + fn new(input: TokenStream) -> Parser { + Parser { + current_attr: None, + input: input.into_iter(), + } + } + + fn with_input(&self, input: TokenStream) -> Parser { + Parser { + current_attr: self.current_attr.clone(), + input: input.into_iter(), + } + } + + /// Returns the next token in the stream without consuming it. + fn peek(&mut self) -> Option<TokenTree> { + self.clone().next() + } + + /// Returns the next two tokens in the stream without consuming them. + fn peek2(&mut self) -> Option<(TokenTree, Option<TokenTree>)> { + let mut clone = self.clone(); + clone.next().map(|first| (first, clone.next())) + } + + /// Advances the cursor by one step. + fn advance(&mut self) { + self.next(); + } + + /// Advances the cursor by two steps. + fn advance2(&mut self) { + self.next(); + self.next(); + } + + /// Parses multiple blocks of markup. + fn markups(&mut self) -> Vec<ast::Markup> { + let mut result = Vec::new(); + loop { + match self.peek2() { + None => break, + Some((TokenTree::Punct(ref punct), _)) if punct.as_char() == ';' => self.advance(), + Some((TokenTree::Punct(ref punct), Some(TokenTree::Ident(ref ident)))) + if punct.as_char() == '@' && *ident == "let" => + { + self.advance2(); + let keyword = TokenTree::Ident(ident.clone()); + result.push(self.let_expr(punct.span(), keyword)); + } + _ => result.push(self.markup()), + } + } + result + } + + /// Parses a single block of markup. + fn markup(&mut self) -> ast::Markup { + let token = match self.peek() { + Some(token) => token, + None => { + abort_call_site!("unexpected end of input"); + } + }; + let markup = match token { + // Literal + TokenTree::Literal(literal) => { + self.advance(); + self.literal(literal) + } + // Special form + TokenTree::Punct(ref punct) if punct.as_char() == '@' => { + self.advance(); + let at_span = punct.span(); + match self.next() { + Some(TokenTree::Ident(ident)) => { + let keyword = TokenTree::Ident(ident.clone()); + match ident.to_string().as_str() { + "if" => { + let mut segments = Vec::new(); + self.if_expr(at_span, vec![keyword], &mut segments); + ast::Markup::Special { segments } + } + "while" => self.while_expr(at_span, keyword), + "for" => self.for_expr(at_span, keyword), + "match" => self.match_expr(at_span, keyword), + "let" => { + let span = SpanRange { + first: at_span, + last: ident.span(), + }; + abort!(span, "`@let` only works inside a block"); + } + other => { + let span = SpanRange { + first: at_span, + last: ident.span(), + }; + abort!(span, "unknown keyword `@{}`", other); + } + } + } + _ => { + abort!(at_span, "expected keyword after `@`"); + } + } + } + // Element + TokenTree::Ident(ident) => { + let ident_string = ident.to_string(); + match ident_string.as_str() { + "if" | "while" | "for" | "match" | "let" => { + abort!( + ident, + "found keyword `{}`", ident_string; + help = "should this be a `@{}`?", ident_string + ); + } + "true" | "false" => { + if let Some(attr_name) = &self.current_attr { + emit_error!( + ident, + r#"attribute value must be a string"#; + help = "to declare an empty attribute, omit the equals sign: `{}`", + attr_name; + help = "to toggle the attribute, use square brackets: `{}[some_boolean_flag]`", + attr_name; + ); + return ast::Markup::ParseError { + span: SpanRange::single_span(ident.span()), + }; + } + } + _ => {} + } + + // `.try_namespaced_name()` should never fail as we've + // already seen an `Ident` + let name = self.try_namespaced_name().expect("identifier"); + self.element(name) + } + // Div element shorthand + TokenTree::Punct(ref punct) if punct.as_char() == '.' || punct.as_char() == '#' => { + let name = TokenTree::Ident(Ident::new("div", punct.span())); + self.element(name.into()) + } + // Splice + TokenTree::Group(ref group) if group.delimiter() == Delimiter::Parenthesis => { + self.advance(); + ast::Markup::Splice { + expr: group.stream(), + outer_span: SpanRange::single_span(group.span()), + } + } + // Block + TokenTree::Group(ref group) if group.delimiter() == Delimiter::Brace => { + self.advance(); + ast::Markup::Block(self.block(group.stream(), SpanRange::single_span(group.span()))) + } + // ??? + token => { + abort!(token, "invalid syntax"); + } + }; + markup + } + + /// Parses a literal string. + fn literal(&mut self, literal: Literal) -> ast::Markup { + match Lit::new(literal.clone()) { + Lit::Str(lit_str) => { + return ast::Markup::Literal { + content: lit_str.value(), + span: SpanRange::single_span(literal.span()), + } + } + // Boolean literals are idents, so `Lit::Bool` is handled in + // `markup`, not here. + Lit::Int(..) | Lit::Float(..) => { + emit_error!(literal, r#"literal must be double-quoted: `"{}"`"#, literal); + } + Lit::Char(lit_char) => { + emit_error!( + literal, + r#"literal must be double-quoted: `"{}"`"#, + lit_char.value(), + ); + } + _ => { + emit_error!(literal, "expected string"); + } + } + ast::Markup::ParseError { + span: SpanRange::single_span(literal.span()), + } + } + + /// Parses an `@if` expression. + /// + /// The leading `@if` should already be consumed. + fn if_expr(&mut self, at_span: Span, prefix: Vec<TokenTree>, segments: &mut Vec<ast::Special>) { + let mut head = prefix; + let body = loop { + match self.next() { + Some(TokenTree::Group(ref block)) if block.delimiter() == Delimiter::Brace => { + break self.block(block.stream(), SpanRange::single_span(block.span())); + } + Some(token) => head.push(token), + None => { + let mut span = ast::span_tokens(head); + span.first = at_span; + abort!(span, "expected body for this `@if`"); + } + } + }; + segments.push(ast::Special { + at_span: SpanRange::single_span(at_span), + head: head.into_iter().collect(), + body, + }); + self.else_if_expr(segments) + } + + /// Parses an optional `@else if` or `@else`. + /// + /// The leading `@else if` or `@else` should *not* already be consumed. + fn else_if_expr(&mut self, segments: &mut Vec<ast::Special>) { + match self.peek2() { + Some((TokenTree::Punct(ref punct), Some(TokenTree::Ident(ref else_keyword)))) + if punct.as_char() == '@' && *else_keyword == "else" => + { + self.advance2(); + let at_span = punct.span(); + let else_keyword = TokenTree::Ident(else_keyword.clone()); + match self.peek() { + // `@else if` + Some(TokenTree::Ident(ref if_keyword)) if *if_keyword == "if" => { + self.advance(); + let if_keyword = TokenTree::Ident(if_keyword.clone()); + self.if_expr(at_span, vec![else_keyword, if_keyword], segments) + } + // Just an `@else` + _ => match self.next() { + Some(TokenTree::Group(ref group)) + if group.delimiter() == Delimiter::Brace => + { + let body = + self.block(group.stream(), SpanRange::single_span(group.span())); + segments.push(ast::Special { + at_span: SpanRange::single_span(at_span), + head: vec![else_keyword].into_iter().collect(), + body, + }); + } + _ => { + let span = SpanRange { + first: at_span, + last: else_keyword.span(), + }; + abort!(span, "expected body for this `@else`"); + } + }, + } + } + // We didn't find an `@else`; stop + _ => {} + } + } + + /// Parses an `@while` expression. + /// + /// The leading `@while` should already be consumed. + fn while_expr(&mut self, at_span: Span, keyword: TokenTree) -> ast::Markup { + let keyword_span = keyword.span(); + let mut head = vec![keyword]; + let body = loop { + match self.next() { + Some(TokenTree::Group(ref block)) if block.delimiter() == Delimiter::Brace => { + break self.block(block.stream(), SpanRange::single_span(block.span())); + } + Some(token) => head.push(token), + None => { + let span = SpanRange { + first: at_span, + last: keyword_span, + }; + abort!(span, "expected body for this `@while`"); + } + } + }; + ast::Markup::Special { + segments: vec![ast::Special { + at_span: SpanRange::single_span(at_span), + head: head.into_iter().collect(), + body, + }], + } + } + + /// Parses a `@for` expression. + /// + /// The leading `@for` should already be consumed. + fn for_expr(&mut self, at_span: Span, keyword: TokenTree) -> ast::Markup { + let keyword_span = keyword.span(); + let mut head = vec![keyword]; + loop { + match self.next() { + Some(TokenTree::Ident(ref in_keyword)) if *in_keyword == "in" => { + head.push(TokenTree::Ident(in_keyword.clone())); + break; + } + Some(token) => head.push(token), + None => { + let span = SpanRange { + first: at_span, + last: keyword_span, + }; + abort!(span, "missing `in` in `@for` loop"); + } + } + } + let body = loop { + match self.next() { + Some(TokenTree::Group(ref block)) if block.delimiter() == Delimiter::Brace => { + break self.block(block.stream(), SpanRange::single_span(block.span())); + } + Some(token) => head.push(token), + None => { + let span = SpanRange { + first: at_span, + last: keyword_span, + }; + abort!(span, "expected body for this `@for`"); + } + } + }; + ast::Markup::Special { + segments: vec![ast::Special { + at_span: SpanRange::single_span(at_span), + head: head.into_iter().collect(), + body, + }], + } + } + + /// Parses a `@match` expression. + /// + /// The leading `@match` should already be consumed. + fn match_expr(&mut self, at_span: Span, keyword: TokenTree) -> ast::Markup { + let keyword_span = keyword.span(); + let mut head = vec![keyword]; + let (arms, arms_span) = loop { + match self.next() { + Some(TokenTree::Group(ref body)) if body.delimiter() == Delimiter::Brace => { + let span = SpanRange::single_span(body.span()); + break (self.with_input(body.stream()).match_arms(), span); + } + Some(token) => head.push(token), + None => { + let span = SpanRange { + first: at_span, + last: keyword_span, + }; + abort!(span, "expected body for this `@match`"); + } + } + }; + ast::Markup::Match { + at_span: SpanRange::single_span(at_span), + head: head.into_iter().collect(), + arms, + arms_span, + } + } + + fn match_arms(&mut self) -> Vec<ast::MatchArm> { + let mut arms = Vec::new(); + while let Some(arm) = self.match_arm() { + arms.push(arm); + } + arms + } + + fn match_arm(&mut self) -> Option<ast::MatchArm> { + let mut head = Vec::new(); + loop { + match self.peek2() { + Some((TokenTree::Punct(ref eq), Some(TokenTree::Punct(ref gt)))) + if eq.as_char() == '=' + && gt.as_char() == '>' + && eq.spacing() == Spacing::Joint => + { + self.advance2(); + head.push(TokenTree::Punct(eq.clone())); + head.push(TokenTree::Punct(gt.clone())); + break; + } + Some((token, _)) => { + self.advance(); + head.push(token); + } + None => { + if head.is_empty() { + return None; + } else { + let head_span = ast::span_tokens(head); + abort!(head_span, "unexpected end of @match pattern"); + } + } + } + } + let body = match self.next() { + // $pat => { $stmts } + Some(TokenTree::Group(ref body)) if body.delimiter() == Delimiter::Brace => { + let body = self.block(body.stream(), SpanRange::single_span(body.span())); + // Trailing commas are optional if the match arm is a braced block + if let Some(TokenTree::Punct(ref punct)) = self.peek() { + if punct.as_char() == ',' { + self.advance(); + } + } + body + } + // $pat => $expr + Some(first_token) => { + let mut span = SpanRange::single_span(first_token.span()); + let mut body = vec![first_token]; + loop { + match self.next() { + Some(TokenTree::Punct(ref punct)) if punct.as_char() == ',' => break, + Some(token) => { + span.last = token.span(); + body.push(token); + } + None => break, + } + } + self.block(body.into_iter().collect(), span) + } + None => { + let span = ast::span_tokens(head); + abort!(span, "unexpected end of @match arm"); + } + }; + Some(ast::MatchArm { + head: head.into_iter().collect(), + body, + }) + } + + /// Parses a `@let` expression. + /// + /// The leading `@let` should already be consumed. + fn let_expr(&mut self, at_span: Span, keyword: TokenTree) -> ast::Markup { + let mut tokens = vec![keyword]; + loop { + match self.next() { + Some(token) => match token { + TokenTree::Punct(ref punct) if punct.as_char() == '=' => { + tokens.push(token.clone()); + break; + } + _ => tokens.push(token), + }, + None => { + let mut span = ast::span_tokens(tokens); + span.first = at_span; + abort!(span, "unexpected end of `@let` expression"); + } + } + } + loop { + match self.next() { + Some(token) => match token { + TokenTree::Punct(ref punct) if punct.as_char() == ';' => { + tokens.push(token.clone()); + break; + } + _ => tokens.push(token), + }, + None => { + let mut span = ast::span_tokens(tokens); + span.first = at_span; + abort!( + span, + "unexpected end of `@let` expression"; + help = "are you missing a semicolon?" + ); + } + } + } + ast::Markup::Let { + at_span: SpanRange::single_span(at_span), + tokens: tokens.into_iter().collect(), + } + } + + /// Parses an element node. + /// + /// The element name should already be consumed. + fn element(&mut self, name: TokenStream) -> ast::Markup { + if self.current_attr.is_some() { + let span = ast::span_tokens(name); + abort!(span, "unexpected element"); + } + let attrs = self.attrs(); + let body = match self.peek() { + Some(TokenTree::Punct(ref punct)) + if punct.as_char() == ';' || punct.as_char() == '/' => + { + // Void element + self.advance(); + if punct.as_char() == '/' { + emit_error!( + punct, + "void elements must use `;`, not `/`"; + help = "change this to `;`"; + help = "see https://github.com/lambda-fairy/maud/pull/315 for details"; + ); + } + ast::ElementBody::Void { + semi_span: SpanRange::single_span(punct.span()), + } + } + Some(_) => match self.markup() { + ast::Markup::Block(block) => ast::ElementBody::Block { block }, + markup => { + let markup_span = markup.span(); + abort!( + markup_span, + "element body must be wrapped in braces"; + help = "see https://github.com/lambda-fairy/maud/pull/137 for details" + ); + } + }, + None => abort_call_site!("expected `;`, found end of macro"), + }; + ast::Markup::Element { name, attrs, body } + } + + /// Parses the attributes of an element. + fn attrs(&mut self) -> Vec<ast::Attr> { + let mut attrs = Vec::new(); + loop { + if let Some(name) = self.try_namespaced_name() { + // Attribute + match self.peek() { + // Non-empty attribute + Some(TokenTree::Punct(ref punct)) if punct.as_char() == '=' => { + self.advance(); + // Parse a value under an attribute context + assert!(self.current_attr.is_none()); + self.current_attr = Some(ast::name_to_string(name.clone())); + let attr_type = match self.attr_toggler() { + Some(toggler) => ast::AttrType::Optional { toggler }, + None => { + let value = self.markup(); + ast::AttrType::Normal { value } + } + }; + self.current_attr = None; + attrs.push(ast::Attr::Named { + named_attr: ast::NamedAttr { name, attr_type }, + }); + } + // Empty attribute (legacy syntax) + Some(TokenTree::Punct(ref punct)) if punct.as_char() == '?' => { + self.advance(); + let toggler = self.attr_toggler(); + attrs.push(ast::Attr::Named { + named_attr: ast::NamedAttr { + name: name.clone(), + attr_type: ast::AttrType::Empty { toggler }, + }, + }); + } + // Empty attribute (new syntax) + _ => { + let toggler = self.attr_toggler(); + attrs.push(ast::Attr::Named { + named_attr: ast::NamedAttr { + name: name.clone(), + attr_type: ast::AttrType::Empty { toggler }, + }, + }); + } + } + } else { + match self.peek() { + // Class shorthand + Some(TokenTree::Punct(ref punct)) if punct.as_char() == '.' => { + self.advance(); + let name = self.class_or_id_name(); + let toggler = self.attr_toggler(); + attrs.push(ast::Attr::Class { + dot_span: SpanRange::single_span(punct.span()), + name, + toggler, + }); + } + // ID shorthand + Some(TokenTree::Punct(ref punct)) if punct.as_char() == '#' => { + self.advance(); + let name = self.class_or_id_name(); + attrs.push(ast::Attr::Id { + hash_span: SpanRange::single_span(punct.span()), + name, + }); + } + // If it's not a valid attribute, backtrack and bail out + _ => break, + } + } + } + + let mut attr_map: HashMap<String, Vec<SpanRange>> = HashMap::new(); + let mut has_class = false; + for attr in &attrs { + let name = match attr { + ast::Attr::Class { .. } => { + if has_class { + // Only check the first class to avoid spurious duplicates + continue; + } + has_class = true; + "class".to_string() + } + ast::Attr::Id { .. } => "id".to_string(), + ast::Attr::Named { named_attr } => named_attr + .name + .clone() + .into_iter() + .map(|token| token.to_string()) + .collect(), + }; + let entry = attr_map.entry(name).or_default(); + entry.push(attr.span()); + } + + for (name, spans) in attr_map { + if spans.len() > 1 { + let mut spans = spans.into_iter(); + let first_span = spans.next().expect("spans should be non-empty"); + abort!(first_span, "duplicate attribute `{}`", name); + } + } + + attrs + } + + /// Parses the name of a class or ID. + fn class_or_id_name(&mut self) -> ast::Markup { + if let Some(symbol) = self.try_name() { + ast::Markup::Symbol { symbol } + } else { + self.markup() + } + } + + /// Parses the `[cond]` syntax after an empty attribute or class shorthand. + fn attr_toggler(&mut self) -> Option<ast::Toggler> { + match self.peek() { + Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::Bracket => { + self.advance(); + Some(ast::Toggler { + cond: group.stream(), + cond_span: SpanRange::single_span(group.span()), + }) + } + _ => None, + } + } + + /// Parses an identifier, without dealing with namespaces. + fn try_name(&mut self) -> Option<TokenStream> { + let mut result = Vec::new(); + if let Some(token @ TokenTree::Ident(_)) = self.peek() { + self.advance(); + result.push(token); + } else { + return None; + } + let mut expect_ident = false; + loop { + expect_ident = match self.peek() { + Some(TokenTree::Punct(ref punct)) if punct.as_char() == '-' => { + self.advance(); + result.push(TokenTree::Punct(punct.clone())); + true + } + Some(TokenTree::Ident(ref ident)) if expect_ident => { + self.advance(); + result.push(TokenTree::Ident(ident.clone())); + false + } + _ => break, + }; + } + Some(result.into_iter().collect()) + } + + /// Parses a HTML element or attribute name, along with a namespace + /// if necessary. + fn try_namespaced_name(&mut self) -> Option<TokenStream> { + let mut result = vec![self.try_name()?]; + if let Some(TokenTree::Punct(ref punct)) = self.peek() { + if punct.as_char() == ':' { + self.advance(); + result.push(TokenStream::from(TokenTree::Punct(punct.clone()))); + result.push(self.try_name()?); + } + } + Some(result.into_iter().collect()) + } + + /// Parses the given token stream as a Maud expression. + fn block(&mut self, body: TokenStream, outer_span: SpanRange) -> ast::Block { + let markups = self.with_input(body).markups(); + ast::Block { + markups, + outer_span, + } + } +} diff --git a/src/html.rs b/src/html.rs new file mode 100644 index 00000000..1f24f630 --- /dev/null +++ b/src/html.rs @@ -0,0 +1,4 @@ +//! HTML en código. + +mod maud; +pub use maud::{html, html_private, Markup, PreEscaped, DOCTYPE}; diff --git a/src/html/maud.rs b/src/html/maud.rs new file mode 100644 index 00000000..db9308af --- /dev/null +++ b/src/html/maud.rs @@ -0,0 +1,350 @@ +//#![no_std] + +//! A macro for writing HTML templates. +//! +//! This documentation only describes the runtime API. For a general +//! guide, check out the [book] instead. +//! +//! [book]: https://maud.lambda.xyz/ + +//#![doc(html_root_url = "https://docs.rs/maud/0.25.0")] + +extern crate alloc; + +use alloc::{borrow::Cow, boxed::Box, string::String}; +use core::fmt::{self, Arguments, Display, Write}; + +pub use pagetop_macros::html; + +mod escape; + +/// An adapter that escapes HTML special characters. +/// +/// The following characters are escaped: +/// +/// * `&` is escaped as `&amp;` +/// * `<` is escaped as `&lt;` +/// * `>` is escaped as `&gt;` +/// * `"` is escaped as `&quot;` +/// +/// All other characters are passed through unchanged. +/// +/// **Note:** In versions prior to 0.13, the single quote (`'`) was +/// escaped as well. +/// +/// # Example +/// +/// ```rust#ignore +/// use maud::Escaper; +/// use std::fmt::Write; +/// let mut s = String::new(); +/// write!(Escaper::new(&mut s), "<script>launchMissiles()</script>").unwrap(); +/// assert_eq!(s, "&lt;script&gt;launchMissiles()&lt;/script&gt;"); +/// ``` +pub struct Escaper<'a>(&'a mut String); + +impl<'a> Escaper<'a> { + /// Creates an `Escaper` from a `String`. + pub fn new(buffer: &'a mut String) -> Escaper<'a> { + Escaper(buffer) + } +} + +impl<'a> fmt::Write for Escaper<'a> { + fn write_str(&mut self, s: &str) -> fmt::Result { + escape::escape_to_string(s, self.0); + Ok(()) + } +} + +/// Represents a type that can be rendered as HTML. +/// +/// To implement this for your own type, override either the `.render()` +/// or `.render_to()` methods; since each is defined in terms of the +/// other, you only need to implement one of them. See the example below. +/// +/// # Minimal implementation +/// +/// An implementation of this trait must override at least one of +/// `.render()` or `.render_to()`. Since the default definitions of +/// these methods call each other, not doing this will result in +/// infinite recursion. +/// +/// # Example +/// +/// ```rust#ignore +/// use maud::{html, Markup, Render}; +/// +/// /// Provides a shorthand for linking to a CSS stylesheet. +/// pub struct Stylesheet(&'static str); +/// +/// impl Render for Stylesheet { +/// fn render(&self) -> Markup { +/// html! { +/// link rel="stylesheet" type="text/css" href=(self.0); +/// } +/// } +/// } +/// ``` +pub trait Render { + /// Renders `self` as a block of `Markup`. + fn render(&self) -> Markup { + let mut buffer = String::new(); + self.render_to(&mut buffer); + PreEscaped(buffer) + } + + /// Appends a representation of `self` to the given buffer. + /// + /// Its default implementation just calls `.render()`, but you may + /// override it with something more efficient. + /// + /// Note that no further escaping is performed on data written to + /// the buffer. If you override this method, you must make sure that + /// any data written is properly escaped, whether by hand or using + /// the [`Escaper`](struct.Escaper.html) wrapper struct. + fn render_to(&self, buffer: &mut String) { + buffer.push_str(&self.render().into_string()); + } +} + +impl Render for str { + fn render_to(&self, w: &mut String) { + escape::escape_to_string(self, w); + } +} + +impl Render for String { + fn render_to(&self, w: &mut String) { + str::render_to(self, w); + } +} + +impl<'a> Render for Cow<'a, str> { + fn render_to(&self, w: &mut String) { + str::render_to(self, w); + } +} + +impl<'a> Render for Arguments<'a> { + fn render_to(&self, w: &mut String) { + let _ = Escaper::new(w).write_fmt(*self); + } +} + +impl<'a, T: Render + ?Sized> Render for &'a T { + fn render_to(&self, w: &mut String) { + T::render_to(self, w); + } +} + +impl<'a, T: Render + ?Sized> Render for &'a mut T { + fn render_to(&self, w: &mut String) { + T::render_to(self, w); + } +} + +impl<T: Render + ?Sized> Render for Box<T> { + fn render_to(&self, w: &mut String) { + T::render_to(self, w); + } +} + +macro_rules! impl_render_with_display { + ($($ty:ty)*) => { + $( + impl Render for $ty { + fn render_to(&self, w: &mut String) { + // TODO: remove the explicit arg when Rust 1.58 is released + format_args!("{self}", self = self).render_to(w); + } + } + )* + }; +} + +impl_render_with_display! { + char f32 f64 +} + +macro_rules! impl_render_with_itoa { + ($($ty:ty)*) => { + $( + impl Render for $ty { + fn render_to(&self, w: &mut String) { + w.push_str(itoa::Buffer::new().format(*self)); + } + } + )* + }; +} + +impl_render_with_itoa! { + i8 i16 i32 i64 i128 isize + u8 u16 u32 u64 u128 usize +} + +/// Renders a value using its [`Display`] impl. +/// +/// # Example +/// +/// ```rust#ignore +/// use maud::html; +/// use std::net::Ipv4Addr; +/// +/// let ip_address = Ipv4Addr::new(127, 0, 0, 1); +/// +/// let markup = html! { +/// "My IP address is: " +/// (maud::display(ip_address)) +/// }; +/// +/// assert_eq!(markup.into_string(), "My IP address is: 127.0.0.1"); +/// ``` +pub fn display(value: impl Display) -> impl Render { + struct DisplayWrapper<T>(T); + + impl<T: Display> Render for DisplayWrapper<T> { + fn render_to(&self, w: &mut String) { + format_args!("{0}", self.0).render_to(w); + } + } + + DisplayWrapper(value) +} + +/// A wrapper that renders the inner value without escaping. +#[derive(Debug, Clone, Copy)] +pub struct PreEscaped<T: AsRef<str>>(pub T); + +impl<T: AsRef<str>> Render for PreEscaped<T> { + fn render_to(&self, w: &mut String) { + w.push_str(self.0.as_ref()); + } +} + +/// A block of markup is a string that does not need to be escaped. +/// +/// The `html!` macro expands to an expression of this type. +pub type Markup = PreEscaped<String>; + +impl Markup { + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +impl<T: AsRef<str> + Into<String>> PreEscaped<T> { + /// Converts the inner value to a string. + pub fn into_string(self) -> String { + self.0.into() + } +} + +impl<T: AsRef<str> + Into<String>> From<PreEscaped<T>> for String { + fn from(value: PreEscaped<T>) -> String { + value.into_string() + } +} + +impl<T: AsRef<str> + Default> Default for PreEscaped<T> { + fn default() -> Self { + Self(Default::default()) + } +} + +/// The literal string `<!DOCTYPE html>`. +/// +/// # Example +/// +/// A minimal web page: +/// +/// ```rust#ignore +/// use maud::{DOCTYPE, html}; +/// +/// let markup = html! { +/// (DOCTYPE) +/// html { +/// head { +/// meta charset="utf-8"; +/// title { "Test page" } +/// } +/// body { +/// p { "Hello, world!" } +/// } +/// } +/// }; +/// ``` +pub const DOCTYPE: PreEscaped<&'static str> = PreEscaped("<!DOCTYPE html>"); + +mod actix_support { + extern crate alloc; + + use crate::html::PreEscaped; + use actix_web::{http::header, HttpRequest, HttpResponse, Responder}; + use alloc::string::String; + + impl Responder for PreEscaped<String> { + type Body = String; + + fn respond_to(self, _req: &HttpRequest) -> HttpResponse<Self::Body> { + HttpResponse::Ok() + .content_type(header::ContentType::html()) + .message_body(self.0) + .unwrap() + } + } +} + +#[doc(hidden)] +pub mod html_private { + extern crate alloc; + + use super::{display, Render}; + use alloc::string::String; + use core::fmt::Display; + + #[doc(hidden)] + #[macro_export] + macro_rules! render_to { + ($x:expr, $buffer:expr) => {{ + use $crate::html::html_private::*; + match ChooseRenderOrDisplay($x) { + x => (&&x).implements_render_or_display().render_to(x.0, $buffer), + } + }}; + } + + pub use render_to; + + pub struct ChooseRenderOrDisplay<T>(pub T); + + pub struct ViaRenderTag; + pub struct ViaDisplayTag; + + pub trait ViaRender { + fn implements_render_or_display(&self) -> ViaRenderTag { + ViaRenderTag + } + } + pub trait ViaDisplay { + fn implements_render_or_display(&self) -> ViaDisplayTag { + ViaDisplayTag + } + } + + impl<T: Render> ViaRender for &ChooseRenderOrDisplay<T> {} + impl<T: Display> ViaDisplay for ChooseRenderOrDisplay<T> {} + + impl ViaRenderTag { + pub fn render_to<T: Render + ?Sized>(self, value: &T, buffer: &mut String) { + value.render_to(buffer); + } + } + + impl ViaDisplayTag { + pub fn render_to<T: Display + ?Sized>(self, value: &T, buffer: &mut String) { + display(value).render_to(buffer); + } + } +} diff --git a/src/html/maud/escape.rs b/src/html/maud/escape.rs new file mode 100644 index 00000000..94cdeec1 --- /dev/null +++ b/src/html/maud/escape.rs @@ -0,0 +1,34 @@ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !!!!! PLEASE KEEP THIS IN SYNC WITH `maud_macros/src/escape.rs` !!!!! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +extern crate alloc; + +use alloc::string::String; + +pub fn escape_to_string(input: &str, output: &mut String) { + for b in input.bytes() { + match b { + b'&' => output.push_str("&amp;"), + b'<' => output.push_str("&lt;"), + b'>' => output.push_str("&gt;"), + b'"' => output.push_str("&quot;"), + _ => unsafe { output.as_mut_vec().push(b) }, + } + } +} + +#[cfg(test)] +mod test { + extern crate alloc; + + use super::escape_to_string; + use alloc::string::String; + + #[test] + fn it_works() { + let mut s = String::new(); + escape_to_string("<script>launchMissiles()</script>", &mut s); + assert_eq!(s, "&lt;script&gt;launchMissiles()&lt;/script&gt;"); + } +} diff --git a/src/lib.rs b/src/lib.rs index 308c1633..2f973518 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,7 @@ // RE-EXPORTED ************************************************************************************* -pub use pagetop_macros::{main, test}; +pub use pagetop_macros::{html, main, test}; // API ********************************************************************************************* @@ -42,6 +42,8 @@ pub mod config; pub mod global; // Gestión de trazas y registro de eventos de la aplicación. pub mod trace; +// HTML en código. +pub mod html; // Gestión del servidor y servicios web. pub mod service; // Prepara y ejecuta la aplicación. diff --git a/src/prelude.rs b/src/prelude.rs index 5d5851fc..eb59c4f2 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -2,7 +2,7 @@ // RE-EXPORTED. -pub use crate::{main, test}; +pub use crate::{html, main, test}; // MACROS. @@ -15,6 +15,8 @@ pub use crate::global; pub use crate::trace; +pub use crate::html::*; + pub use crate::service; pub use crate::app::Application; From 6944938910d3ae48208ba7b50163a234e422b9c1 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 7 Jul 2025 20:31:00 +0200 Subject: [PATCH 058/244] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Actualiza=20el=20c?= =?UTF-8?q?=C3=B3digo=20de=20maud=20a=20la=20versi=C3=B3n=200.27.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 82 +- helpers/pagetop-macros/Cargo.toml | 4 +- helpers/pagetop-macros/src/lib.rs | 3 +- helpers/pagetop-macros/src/maud.rs | 53 +- helpers/pagetop-macros/src/maud/ast.rs | 1222 ++++++++++++++++--- helpers/pagetop-macros/src/maud/escape.rs | 7 - helpers/pagetop-macros/src/maud/generate.rs | 478 +++++--- helpers/pagetop-macros/src/maud/parse.rs | 752 ------------ src/html.rs | 2 +- src/html/maud.rs | 75 +- src/service.rs | 2 +- 11 files changed, 1459 insertions(+), 1221 deletions(-) delete mode 100644 helpers/pagetop-macros/src/maud/parse.rs diff --git a/Cargo.lock b/Cargo.lock index d53ffd7c..cf974c87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -182,7 +182,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -426,7 +426,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", "unicode-xid", ] @@ -448,7 +448,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -937,13 +937,13 @@ dependencies = [ [[package]] name = "pagetop-macros" -version = "0.0.1" +version = "0.0.2" dependencies = [ "proc-macro-crate", - "proc-macro-error", "proc-macro2", + "proc-macro2-diagnostics", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -998,7 +998,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -1052,30 +1052,6 @@ dependencies = [ "toml_edit", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" version = "1.0.95" @@ -1085,6 +1061,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "version_check", +] + [[package]] name = "quote" version = "1.0.40" @@ -1242,7 +1230,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -1350,16 +1338,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.104" @@ -1379,7 +1357,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -1409,7 +1387,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -1571,7 +1549,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -1721,7 +1699,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.104", + "syn", "wasm-bindgen-shared", ] @@ -1743,7 +1721,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1905,7 +1883,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", "synstructure", ] @@ -1926,7 +1904,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] @@ -1946,7 +1924,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", "synstructure", ] @@ -1980,7 +1958,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn", ] [[package]] diff --git a/helpers/pagetop-macros/Cargo.toml b/helpers/pagetop-macros/Cargo.toml index 80413821..ea6404b9 100644 --- a/helpers/pagetop-macros/Cargo.toml +++ b/helpers/pagetop-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-macros" -version = "0.0.1" +version = "0.0.2" edition = "2021" description = """\ @@ -19,7 +19,7 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.95" +proc-macro2-diagnostics = { version = "0.10.1", default-features = false } proc-macro-crate = "3.3.0" -proc-macro-error = "1.0.4" quote = "1.0.40" syn = { version = "2.0.104", features = ["full"] } diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 65badb04..e0f3badd 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -17,11 +17,10 @@ mod maud; use proc_macro::TokenStream; -use proc_macro_error::proc_macro_error; use quote::quote; +/// Macro para escribir plantillas HTML ([Maud](https://docs.rs/maud)). #[proc_macro] -#[proc_macro_error] pub fn html(input: TokenStream) -> TokenStream { maud::expand(input.into()).into() } diff --git a/helpers/pagetop-macros/src/maud.rs b/helpers/pagetop-macros/src/maud.rs index a4e7873f..9077dbb9 100644 --- a/helpers/pagetop-macros/src/maud.rs +++ b/helpers/pagetop-macros/src/maud.rs @@ -1,4 +1,4 @@ -// #![doc(html_root_url = "https://docs.rs/maud_macros/0.25.0")] +// #![doc(html_root_url = "https://docs.rs/maud_macros/0.27.0")] // TokenStream values are reference counted, and the mental overhead of tracking // lifetimes outweighs the marginal gains from explicit borrowing // #![allow(clippy::needless_pass_by_value)] @@ -6,34 +6,55 @@ mod ast; mod escape; mod generate; -mod parse; -use proc_macro2::{Ident, Span, TokenStream, TokenTree}; +use ast::DiagnosticParse; +use proc_macro2::{Ident, Span, TokenStream}; +use proc_macro2_diagnostics::Diagnostic; use proc_macro_crate::{crate_name, FoundCrate}; use quote::quote; +use syn::parse::{ParseStream, Parser}; pub fn expand(input: TokenStream) -> TokenStream { - let output_ident = TokenTree::Ident(Ident::new("__maud_output", Span::mixed_site())); // Heuristic: the size of the resulting markup tends to correlate with the // code size of the template itself let size_hint = input.to_string().len(); - let markups = parse::parse(input); - let stmts = generate::generate(markups, output_ident.clone()); - let found_crate = crate_name("pagetop").expect("pagetop is present in `Cargo.toml`"); - let pre_escaped = match found_crate { - FoundCrate::Itself => quote!( - crate::html::PreEscaped(#output_ident) - ), - _ => quote!( - pagetop::html::PreEscaped(#output_ident) - ), + let mut diagnostics = Vec::new(); + let markups = match Parser::parse2( + |input: ParseStream| ast::Markups::diagnostic_parse(input, &mut diagnostics), + input, + ) { + Ok(data) => data, + Err(err) => { + let err = err.to_compile_error(); + let diag_tokens = diagnostics.into_iter().map(Diagnostic::emit_as_expr_tokens); + + return quote! {{ + #err + #(#diag_tokens)* + }}; + } }; - quote!({ + let diag_tokens = diagnostics.into_iter().map(Diagnostic::emit_as_expr_tokens); + + let output_ident = Ident::new("__maud_output", Span::mixed_site()); + let stmts = generate::generate(markups, output_ident.clone()); + + let found_crate = crate_name("pagetop").expect("pagetop must be in Cargo.toml"); + let crate_ident = match found_crate { + FoundCrate::Itself => Ident::new("pagetop", Span::call_site()), + FoundCrate::Name(ref name) => Ident::new(name, Span::call_site()), + }; + let pre_escaped = quote! { + #crate_ident::html::PreEscaped(#output_ident) + }; + + quote! {{ extern crate alloc; let mut #output_ident = alloc::string::String::with_capacity(#size_hint); #stmts + #(#diag_tokens)* #pre_escaped - }) + }} } diff --git a/helpers/pagetop-macros/src/maud/ast.rs b/helpers/pagetop-macros/src/maud/ast.rs index cd8a2cef..fd499ae2 100644 --- a/helpers/pagetop-macros/src/maud/ast.rs +++ b/helpers/pagetop-macros/src/maud/ast.rs @@ -1,221 +1,1105 @@ -use proc_macro2::{TokenStream, TokenTree}; -use proc_macro_error::SpanRange; +use std::fmt::{self, Display, Formatter}; -#[derive(Debug)] -pub enum Markup { - /// Used as a placeholder value on parse error. - ParseError { - span: SpanRange, - }, - Block(Block), - Literal { - content: String, - span: SpanRange, - }, - Symbol { - symbol: TokenStream, - }, - Splice { - expr: TokenStream, - outer_span: SpanRange, - }, - Element { - name: TokenStream, - attrs: Vec<Attr>, - body: ElementBody, - }, - Let { - at_span: SpanRange, - tokens: TokenStream, - }, - Special { - segments: Vec<Special>, - }, - Match { - at_span: SpanRange, - head: TokenStream, - arms: Vec<MatchArm>, - arms_span: SpanRange, +use proc_macro2::TokenStream; +use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt}; +use quote::ToTokens; +use syn::{ + braced, bracketed, + ext::IdentExt, + parenthesized, + parse::{Lookahead1, Parse, ParseStream}, + punctuated::{Pair, Punctuated}, + spanned::Spanned, + token::{ + At, Brace, Bracket, Colon, Comma, Dot, Else, Eq, FatArrow, For, If, In, Let, Match, Minus, + Paren, Pound, Question, Semi, Slash, While, }, + Error, Expr, Ident, Lit, LitBool, LitInt, LitStr, Local, Pat, Stmt, +}; + +#[derive(Debug, Clone)] +pub struct Markups<E> { + pub markups: Vec<Markup<E>>, } -impl Markup { - pub fn span(&self) -> SpanRange { - match *self { - Markup::ParseError { span } => span, - Markup::Block(ref block) => block.span(), - Markup::Literal { span, .. } => span, - Markup::Symbol { ref symbol } => span_tokens(symbol.clone()), - Markup::Splice { outer_span, .. } => outer_span, - Markup::Element { - ref name, ref body, .. - } => { - let name_span = span_tokens(name.clone()); - name_span.join_range(body.span()) - } - Markup::Let { - at_span, - ref tokens, - } => at_span.join_range(span_tokens(tokens.clone())), - Markup::Special { ref segments } => join_ranges(segments.iter().map(Special::span)), - Markup::Match { - at_span, arms_span, .. - } => at_span.join_range(arms_span), +impl<E: MaybeElement> DiagnosticParse for Markups<E> { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + let mut markups = Vec::new(); + while !input.is_empty() { + markups.push(Markup::diagnostic_parse_in_block(input, diagnostics)?) + } + Ok(Self { markups }) + } +} + +impl<E: ToTokens> ToTokens for Markups<E> { + fn to_tokens(&self, tokens: &mut TokenStream) { + for markup in &self.markups { + markup.to_tokens(tokens); } } } -#[derive(Debug)] -pub enum Attr { +#[derive(Debug, Clone)] +pub enum Markup<E> { + Block(Block<E>), + Lit(HtmlLit), + Splice { paren_token: Paren, expr: Expr }, + Element(E), + ControlFlow(ControlFlow<E>), + Semi(Semi), +} + +impl<E: MaybeElement> Markup<E> { + pub fn diagnostic_parse_in_block( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + if input.peek(Let) + || input.peek(If) + || input.peek(Else) + || input.peek(For) + || input.peek(While) + || input.peek(Match) + { + let kw = input.call(Ident::parse_any)?; + diagnostics.push( + kw.span() + .error(format!("found keyword `{kw}`")) + .help(format!("should this be `@{kw}`?")), + ); + } + + let lookahead = input.lookahead1(); + + if lookahead.peek(Brace) { + input.diagnostic_parse(diagnostics).map(Self::Block) + } else if lookahead.peek(Lit) { + input.diagnostic_parse(diagnostics).map(Self::Lit) + } else if lookahead.peek(Paren) { + let content; + Ok(Self::Splice { + paren_token: parenthesized!(content in input), + expr: content.parse()?, + }) + } else if let Some(parse_element) = E::should_parse(&lookahead) { + parse_element(input, diagnostics).map(Self::Element) + } else if lookahead.peek(At) { + input.diagnostic_parse(diagnostics).map(Self::ControlFlow) + } else if lookahead.peek(Semi) { + input.parse().map(Self::Semi) + } else { + Err(lookahead.error()) + } + } +} + +impl<E: MaybeElement> DiagnosticParse for Markup<E> { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + let markup = Self::diagnostic_parse_in_block(input, diagnostics)?; + + if let Self::ControlFlow(ControlFlow { + kind: ControlFlowKind::Let(_), + .. + }) = &markup + { + diagnostics.push( + markup + .span() + .error("`@let` bindings are only allowed inside blocks"), + ) + } + + Ok(markup) + } +} + +impl<E: ToTokens> ToTokens for Markup<E> { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Block(block) => block.to_tokens(tokens), + Self::Lit(lit) => lit.to_tokens(tokens), + Self::Splice { paren_token, expr } => { + paren_token.surround(tokens, |tokens| { + expr.to_tokens(tokens); + }); + } + Self::Element(element) => element.to_tokens(tokens), + Self::ControlFlow(control_flow) => control_flow.to_tokens(tokens), + Self::Semi(semi) => semi.to_tokens(tokens), + } + } +} + +/// Represents a context that may or may not allow elements. +/// +/// An attribute accepts almost the same syntax as an element body, except child elements aren't +/// allowed. To enable code reuse, introduce a trait that abstracts over whether an element is +/// allowed or not. +pub trait MaybeElement: Sized + ToTokens { + /// If an element can be parsed here, returns `Some` with a parser for the rest of the element. + fn should_parse(lookahead: &Lookahead1<'_>) -> Option<DiagnosticParseFn<Self>>; +} + +/// An implementation of `DiagnosticParse::diagnostic_parse`. +pub type DiagnosticParseFn<T> = fn(ParseStream, &mut Vec<Diagnostic>) -> syn::Result<T>; + +/// Represents an attribute context, where elements are disallowed. +#[derive(Debug, Clone)] +pub enum NoElement {} + +impl MaybeElement for NoElement { + fn should_parse( + _lookahead: &Lookahead1<'_>, + ) -> Option<fn(ParseStream, &mut Vec<Diagnostic>) -> syn::Result<Self>> { + None + } +} + +impl ToTokens for NoElement { + fn to_tokens(&self, _tokens: &mut TokenStream) { + match *self {} + } +} + +#[derive(Debug, Clone)] +pub struct Element { + pub name: Option<HtmlName>, + pub attrs: Vec<Attribute>, + pub body: ElementBody, +} + +impl From<NoElement> for Element { + fn from(value: NoElement) -> Self { + match value {} + } +} + +impl MaybeElement for Element { + fn should_parse( + lookahead: &Lookahead1<'_>, + ) -> Option<fn(ParseStream, &mut Vec<Diagnostic>) -> syn::Result<Self>> { + if lookahead.peek(Ident::peek_any) || lookahead.peek(Dot) || lookahead.peek(Pound) { + Some(Element::diagnostic_parse) + } else { + None + } + } +} + +impl DiagnosticParse for Element { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + Ok(Self { + name: if input.peek(Ident::peek_any) { + Some(input.diagnostic_parse(diagnostics)?) + } else { + None + }, + attrs: { + let mut id_pushed = false; + let mut attrs = Vec::new(); + + while input.peek(Ident::peek_any) + || input.peek(Lit) + || input.peek(Dot) + || input.peek(Pound) + { + let attr = input.diagnostic_parse(diagnostics)?; + + if let Attribute::Id { .. } = attr { + if id_pushed { + return Err(Error::new_spanned( + attr, + "duplicate id (`#`) attribute specified", + )); + } + id_pushed = true; + } + + attrs.push(attr); + } + + if !(input.peek(Brace) || input.peek(Semi) || input.peek(Slash)) { + let lookahead = input.lookahead1(); + + lookahead.peek(Ident::peek_any); + lookahead.peek(Lit); + lookahead.peek(Dot); + lookahead.peek(Pound); + + lookahead.peek(Brace); + lookahead.peek(Semi); + + return Err(lookahead.error()); + } + + attrs + }, + body: input.diagnostic_parse(diagnostics)?, + }) + } +} + +impl ToTokens for Element { + fn to_tokens(&self, tokens: &mut TokenStream) { + if let Some(name) = &self.name { + name.to_tokens(tokens); + } + for attr in &self.attrs { + attr.to_tokens(tokens); + } + self.body.to_tokens(tokens); + } +} + +#[derive(Debug, Clone)] +pub enum ElementBody { + Void(Semi), + Block(Block<Element>), +} + +impl DiagnosticParse for ElementBody { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + let lookahead = input.lookahead1(); + + if lookahead.peek(Semi) { + input.parse().map(Self::Void) + } else if lookahead.peek(Brace) { + input.diagnostic_parse(diagnostics).map(Self::Block) + } else if lookahead.peek(Slash) { + diagnostics.push( + input + .parse::<Slash>()? + .span() + .error("void elements must use `;`, not `/`") + .help("change this to `;`") + .help("see https://github.com/lambda-fairy/maud/pull/315 for details"), + ); + + Ok(Self::Void(<Semi>::default())) + } else { + Err(lookahead.error()) + } + } +} + +impl ToTokens for ElementBody { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Void(semi) => semi.to_tokens(tokens), + Self::Block(block) => block.to_tokens(tokens), + } + } +} + +#[derive(Debug, Clone)] +pub struct Block<E> { + pub brace_token: Brace, + pub markups: Markups<E>, +} + +impl<E: MaybeElement> DiagnosticParse for Block<E> { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + let content; + Ok(Self { + brace_token: braced!(content in input), + markups: content.diagnostic_parse(diagnostics)?, + }) + } +} + +impl<E: ToTokens> ToTokens for Block<E> { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.brace_token.surround(tokens, |tokens| { + self.markups.to_tokens(tokens); + }); + } +} + +#[derive(Debug, Clone)] +pub enum Attribute { Class { - dot_span: SpanRange, - name: Markup, + dot_token: Dot, + name: HtmlNameOrMarkup, toggler: Option<Toggler>, }, Id { - hash_span: SpanRange, - name: Markup, + pound_token: Pound, + name: HtmlNameOrMarkup, }, Named { - named_attr: NamedAttr, + name: HtmlName, + attr_type: AttributeType, }, } -impl Attr { - pub fn span(&self) -> SpanRange { - match *self { - Attr::Class { - dot_span, - ref name, - ref toggler, +impl DiagnosticParse for Attribute { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + let lookahead = input.lookahead1(); + + if lookahead.peek(Dot) { + Ok(Self::Class { + dot_token: input.parse()?, + name: input.diagnostic_parse(diagnostics)?, + toggler: { + let lookahead = input.lookahead1(); + + if lookahead.peek(Bracket) { + Some(input.diagnostic_parse(diagnostics)?) + } else { + None + } + }, + }) + } else if lookahead.peek(Pound) { + Ok(Self::Id { + pound_token: input.parse()?, + name: input.diagnostic_parse(diagnostics)?, + }) + } else { + let name = input.diagnostic_parse::<HtmlName>(diagnostics)?; + + if input.peek(Question) { + input.parse::<Question>()?; + } + + let fork = input.fork(); + + let attr = Self::Named { + name: name.clone(), + attr_type: input.diagnostic_parse(diagnostics)?, + }; + + if fork.peek(Eq) && fork.peek2(LitBool) { + diagnostics.push( + attr.span() + .error("attribute value must be a string") + .help(format!("to declare an empty attribute, omit the equals sign: `{name}`")) + .help(format!("to toggle the attribute, use square brackets: `{name}[some_boolean_flag]`")) + ); + } + + Ok(attr) + } + } +} + +impl ToTokens for Attribute { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Class { + dot_token, + name, + toggler, } => { - let name_span = name.span(); - let dot_name_span = dot_span.join_range(name_span); + dot_token.to_tokens(tokens); + name.to_tokens(tokens); if let Some(toggler) = toggler { - dot_name_span.join_range(toggler.cond_span) - } else { - dot_name_span + toggler.to_tokens(tokens); } } - Attr::Id { - hash_span, - ref name, - } => { - let name_span = name.span(); - hash_span.join_range(name_span) + Self::Id { pound_token, name } => { + pound_token.to_tokens(tokens); + name.to_tokens(tokens); + } + Self::Named { name, attr_type } => { + name.to_tokens(tokens); + attr_type.to_tokens(tokens); } - Attr::Named { ref named_attr } => named_attr.span(), } } } -#[derive(Debug)] -pub enum ElementBody { - Void { semi_span: SpanRange }, - Block { block: Block }, +#[derive(Debug, Clone)] +pub enum HtmlNameOrMarkup { + HtmlName(HtmlName), + Markup(Markup<NoElement>), } -impl ElementBody { - pub fn span(&self) -> SpanRange { - match *self { - ElementBody::Void { semi_span } => semi_span, - ElementBody::Block { ref block } => block.span(), - } - } -} - -#[derive(Debug)] -pub struct Block { - pub markups: Vec<Markup>, - pub outer_span: SpanRange, -} - -impl Block { - pub fn span(&self) -> SpanRange { - self.outer_span - } -} - -#[derive(Debug)] -pub struct Special { - pub at_span: SpanRange, - pub head: TokenStream, - pub body: Block, -} - -impl Special { - pub fn span(&self) -> SpanRange { - let body_span = self.body.span(); - self.at_span.join_range(body_span) - } -} - -#[derive(Debug)] -pub struct NamedAttr { - pub name: TokenStream, - pub attr_type: AttrType, -} - -impl NamedAttr { - fn span(&self) -> SpanRange { - let name_span = span_tokens(self.name.clone()); - if let Some(attr_type_span) = self.attr_type.span() { - name_span.join_range(attr_type_span) +impl DiagnosticParse for HtmlNameOrMarkup { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + if input.peek(Ident::peek_any) || input.peek(Lit) { + input.diagnostic_parse(diagnostics).map(Self::HtmlName) } else { - name_span + input.diagnostic_parse(diagnostics).map(Self::Markup) } } } -#[derive(Debug)] -pub enum AttrType { - Normal { value: Markup }, - Optional { toggler: Toggler }, - Empty { toggler: Option<Toggler> }, +impl Parse for HtmlNameOrMarkup { + fn parse(input: ParseStream) -> syn::Result<Self> { + Self::diagnostic_parse(input, &mut Vec::new()) + } } -impl AttrType { - fn span(&self) -> Option<SpanRange> { - match *self { - AttrType::Normal { ref value } => Some(value.span()), - AttrType::Optional { ref toggler } => Some(toggler.span()), - AttrType::Empty { ref toggler } => toggler.as_ref().map(Toggler::span), +impl ToTokens for HtmlNameOrMarkup { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::HtmlName(name) => name.to_tokens(tokens), + Self::Markup(markup) => markup.to_tokens(tokens), } } } -#[derive(Debug)] +impl Display for HtmlNameOrMarkup { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Self::HtmlName(name) => name.fmt(f), + Self::Markup(markup) => markup.to_token_stream().fmt(f), + } + } +} + +#[derive(Debug, Clone)] +pub enum AttributeType { + Normal { + eq_token: Eq, + value: Markup<NoElement>, + }, + Optional { + eq_token: Eq, + toggler: Toggler, + }, + Empty(Option<Toggler>), +} + +impl DiagnosticParse for AttributeType { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + let lookahead = input.lookahead1(); + + if lookahead.peek(Eq) { + let eq_token = input.parse()?; + + if input.peek(Bracket) { + Ok(Self::Optional { + eq_token, + toggler: input.diagnostic_parse(diagnostics)?, + }) + } else { + Ok(Self::Normal { + eq_token, + value: input.diagnostic_parse(diagnostics)?, + }) + } + } else if lookahead.peek(Bracket) { + Ok(Self::Empty(Some(input.diagnostic_parse(diagnostics)?))) + } else { + Ok(Self::Empty(None)) + } + } +} + +impl ToTokens for AttributeType { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Normal { eq_token, value } => { + eq_token.to_tokens(tokens); + value.to_tokens(tokens); + } + Self::Optional { eq_token, toggler } => { + eq_token.to_tokens(tokens); + toggler.to_tokens(tokens); + } + Self::Empty(toggler) => { + if let Some(toggler) = toggler { + toggler.to_tokens(tokens); + } + } + } + } +} + +#[derive(Debug, Clone)] +pub struct HtmlName { + pub name: Punctuated<HtmlNameFragment, HtmlNamePunct>, +} + +impl DiagnosticParse for HtmlName { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + Ok(Self { + name: { + let mut punctuated = Punctuated::new(); + + loop { + punctuated.push_value(input.diagnostic_parse(diagnostics)?); + + if !(input.peek(Minus) || input.peek(Colon)) { + break; + } + + let punct = input.diagnostic_parse(diagnostics)?; + punctuated.push_punct(punct); + } + + punctuated + }, + }) + } +} + +impl Parse for HtmlName { + fn parse(input: ParseStream) -> syn::Result<Self> { + Self::diagnostic_parse(input, &mut Vec::new()) + } +} + +impl ToTokens for HtmlName { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.name.to_tokens(tokens); + } +} + +impl Display for HtmlName { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + for pair in self.name.pairs() { + match pair { + Pair::Punctuated(fragment, punct) => { + fragment.fmt(f)?; + punct.fmt(f)?; + } + Pair::End(fragment) => { + fragment.fmt(f)?; + } + } + } + + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub enum HtmlNameFragment { + Ident(Ident), + LitInt(LitInt), + LitStr(LitStr), + Empty, +} + +impl DiagnosticParse for HtmlNameFragment { + fn diagnostic_parse( + input: ParseStream, + _diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + let lookahead = input.lookahead1(); + + if lookahead.peek(Ident::peek_any) { + input.call(Ident::parse_any).map(Self::Ident) + } else if lookahead.peek(LitInt) { + input.parse().map(Self::LitInt) + } else if lookahead.peek(LitStr) { + input.parse().map(Self::LitStr) + } else if lookahead.peek(Minus) || lookahead.peek(Colon) { + Ok(Self::Empty) + } else { + Err(lookahead.error()) + } + } +} + +impl ToTokens for HtmlNameFragment { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Ident(ident) => ident.to_tokens(tokens), + Self::LitInt(lit) => lit.to_tokens(tokens), + Self::LitStr(lit) => lit.to_tokens(tokens), + Self::Empty => {} + } + } +} + +impl Display for HtmlNameFragment { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Self::Ident(ident) => ident.fmt(f), + Self::LitInt(lit) => lit.fmt(f), + Self::LitStr(lit) => lit.value().fmt(f), + Self::Empty => Ok(()), + } + } +} + +#[derive(Debug, Clone)] +pub struct HtmlLit { + pub lit: LitStr, +} + +impl DiagnosticParse for HtmlLit { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + let lookahead = input.lookahead1(); + + if lookahead.peek(Lit) { + let lit = input.parse()?; + match lit { + Lit::Str(lit) => Ok(Self { lit }), + Lit::Int(lit) => { + diagnostics.push( + lit.span() + .error(format!(r#"literal must be double-quoted: `"{lit}"`"#)), + ); + Ok(Self { + lit: LitStr::new("", lit.span()), + }) + } + Lit::Float(lit) => { + diagnostics.push( + lit.span() + .error(format!(r#"literal must be double-quoted: `"{lit}"`"#)), + ); + Ok(Self { + lit: LitStr::new("", lit.span()), + }) + } + Lit::Char(lit) => { + diagnostics.push(lit.span().error(format!( + r#"literal must be double-quoted: `"{}"`"#, + lit.value() + ))); + Ok(Self { + lit: LitStr::new("", lit.span()), + }) + } + Lit::Bool(_) => { + // diagnostic handled earlier with more information + Ok(Self { + lit: LitStr::new("", lit.span()), + }) + } + _ => { + diagnostics.push(lit.span().error("expected string")); + Ok(Self { + lit: LitStr::new("", lit.span()), + }) + } + } + } else { + Err(lookahead.error()) + } + } +} + +impl ToTokens for HtmlLit { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.lit.to_tokens(tokens); + } +} + +impl Display for HtmlLit { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + self.lit.value().fmt(f) + } +} + +#[derive(Debug, Clone)] +pub enum HtmlNamePunct { + Colon(Colon), + Hyphen(Minus), +} + +impl DiagnosticParse for HtmlNamePunct { + fn diagnostic_parse(input: ParseStream, _: &mut Vec<Diagnostic>) -> syn::Result<Self> { + let lookahead = input.lookahead1(); + + if lookahead.peek(Colon) { + input.parse().map(Self::Colon) + } else if lookahead.peek(Minus) { + input.parse().map(Self::Hyphen) + } else { + Err(lookahead.error()) + } + } +} + +impl ToTokens for HtmlNamePunct { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::Colon(token) => token.to_tokens(tokens), + Self::Hyphen(token) => token.to_tokens(tokens), + } + } +} + +impl Display for HtmlNamePunct { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Self::Colon(_) => f.write_str(":"), + Self::Hyphen(_) => f.write_str("-"), + } + } +} + +#[derive(Debug, Clone)] pub struct Toggler { - pub cond: TokenStream, - pub cond_span: SpanRange, + pub bracket_token: Bracket, + pub cond: Expr, } -impl Toggler { - fn span(&self) -> SpanRange { - self.cond_span +impl DiagnosticParse for Toggler { + fn diagnostic_parse(input: ParseStream, _: &mut Vec<Diagnostic>) -> syn::Result<Self> { + let content; + Ok(Self { + bracket_token: bracketed!(content in input), + cond: content.parse()?, + }) } } -#[derive(Debug)] -pub struct MatchArm { - pub head: TokenStream, - pub body: Block, +impl ToTokens for Toggler { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.bracket_token.surround(tokens, |tokens| { + self.cond.to_tokens(tokens); + }); + } } -pub fn span_tokens<I: IntoIterator<Item = TokenTree>>(tokens: I) -> SpanRange { - join_ranges(tokens.into_iter().map(|s| SpanRange::single_span(s.span()))) +#[derive(Debug, Clone)] +pub struct ControlFlow<E> { + pub at_token: At, + pub kind: ControlFlowKind<E>, } -pub fn join_ranges<I: IntoIterator<Item = SpanRange>>(ranges: I) -> SpanRange { - let mut iter = ranges.into_iter(); - let first = match iter.next() { - Some(span) => span, - None => return SpanRange::call_site(), - }; - let last = iter.last().unwrap_or(first); - first.join_range(last) +impl<E: MaybeElement> DiagnosticParse for ControlFlow<E> { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + Ok(Self { + at_token: input.parse()?, + kind: { + let lookahead = input.lookahead1(); + + if lookahead.peek(If) { + ControlFlowKind::If(input.diagnostic_parse(diagnostics)?) + } else if lookahead.peek(For) { + ControlFlowKind::For(input.diagnostic_parse(diagnostics)?) + } else if lookahead.peek(While) { + ControlFlowKind::While(input.diagnostic_parse(diagnostics)?) + } else if lookahead.peek(Match) { + ControlFlowKind::Match(input.diagnostic_parse(diagnostics)?) + } else if lookahead.peek(Let) { + let Stmt::Local(local) = input.parse()? else { + unreachable!() + }; + + ControlFlowKind::Let(local) + } else { + return Err(lookahead.error()); + } + }, + }) + } } -pub fn name_to_string(name: TokenStream) -> String { - name.into_iter().map(|token| token.to_string()).collect() +impl<E: ToTokens> ToTokens for ControlFlow<E> { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.at_token.to_tokens(tokens); + match &self.kind { + ControlFlowKind::Let(local) => local.to_tokens(tokens), + ControlFlowKind::If(if_) => if_.to_tokens(tokens), + ControlFlowKind::For(for_) => for_.to_tokens(tokens), + ControlFlowKind::While(while_) => while_.to_tokens(tokens), + ControlFlowKind::Match(match_) => match_.to_tokens(tokens), + } + } +} + +#[derive(Debug, Clone)] +pub enum ControlFlowKind<E> { + Let(Local), + If(IfExpr<E>), + For(ForExpr<E>), + While(WhileExpr<E>), + Match(MatchExpr<E>), +} + +#[derive(Debug, Clone)] +pub struct IfExpr<E> { + pub if_token: If, + pub cond: Expr, + pub then_branch: Block<E>, + pub else_branch: Option<(At, Else, Box<IfOrBlock<E>>)>, +} + +impl<E: MaybeElement> DiagnosticParse for IfExpr<E> { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + Ok(Self { + if_token: input.parse()?, + cond: input.call(Expr::parse_without_eager_brace)?, + then_branch: input.diagnostic_parse(diagnostics)?, + else_branch: { + if input.peek(At) && input.peek2(Else) { + Some(( + input.parse()?, + input.parse()?, + input.diagnostic_parse(diagnostics)?, + )) + } else { + None + } + }, + }) + } +} + +impl<E: ToTokens> ToTokens for IfExpr<E> { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.if_token.to_tokens(tokens); + self.cond.to_tokens(tokens); + self.then_branch.to_tokens(tokens); + if let Some((at_token, else_token, else_branch)) = &self.else_branch { + at_token.to_tokens(tokens); + else_token.to_tokens(tokens); + else_branch.to_tokens(tokens); + } + } +} + +#[derive(Debug, Clone)] +pub enum IfOrBlock<E> { + If(IfExpr<E>), + Block(Block<E>), +} + +impl<E: MaybeElement> DiagnosticParse for IfOrBlock<E> { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + let lookahead = input.lookahead1(); + + if lookahead.peek(If) { + input.diagnostic_parse(diagnostics).map(Self::If) + } else if lookahead.peek(Brace) { + input.diagnostic_parse(diagnostics).map(Self::Block) + } else { + Err(lookahead.error()) + } + } +} + +impl<E: ToTokens> ToTokens for IfOrBlock<E> { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Self::If(if_) => if_.to_tokens(tokens), + Self::Block(block) => block.to_tokens(tokens), + } + } +} + +#[derive(Debug, Clone)] +pub struct ForExpr<E> { + pub for_token: For, + pub pat: Pat, + pub in_token: In, + pub expr: Expr, + pub body: Block<E>, +} + +impl<E: MaybeElement> DiagnosticParse for ForExpr<E> { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + Ok(Self { + for_token: input.parse()?, + pat: input.call(Pat::parse_multi_with_leading_vert)?, + in_token: input.parse()?, + expr: input.call(Expr::parse_without_eager_brace)?, + body: input.diagnostic_parse(diagnostics)?, + }) + } +} + +impl<E: ToTokens> ToTokens for ForExpr<E> { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.for_token.to_tokens(tokens); + self.pat.to_tokens(tokens); + self.in_token.to_tokens(tokens); + self.expr.to_tokens(tokens); + self.body.to_tokens(tokens); + } +} + +#[derive(Debug, Clone)] +pub struct WhileExpr<E> { + pub while_token: While, + pub cond: Expr, + pub body: Block<E>, +} + +impl<E: MaybeElement> DiagnosticParse for WhileExpr<E> { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + Ok(Self { + while_token: input.parse()?, + cond: input.call(Expr::parse_without_eager_brace)?, + body: input.diagnostic_parse(diagnostics)?, + }) + } +} + +impl<E: ToTokens> ToTokens for WhileExpr<E> { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.while_token.to_tokens(tokens); + self.cond.to_tokens(tokens); + self.body.to_tokens(tokens); + } +} + +#[derive(Debug, Clone)] +pub struct MatchExpr<E> { + pub match_token: Match, + pub expr: Expr, + pub brace_token: Brace, + pub arms: Vec<MatchArm<E>>, +} + +impl<E: MaybeElement> DiagnosticParse for MatchExpr<E> { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + let match_token = input.parse()?; + let expr = input.call(Expr::parse_without_eager_brace)?; + + let content; + let brace_token = braced!(content in input); + + let mut arms = Vec::new(); + while !content.is_empty() { + arms.push(content.diagnostic_parse(diagnostics)?); + } + + Ok(Self { + match_token, + expr, + brace_token, + arms, + }) + } +} + +impl<E: ToTokens> ToTokens for MatchExpr<E> { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.match_token.to_tokens(tokens); + self.expr.to_tokens(tokens); + self.brace_token.surround(tokens, |tokens| { + for arm in &self.arms { + arm.to_tokens(tokens); + } + }); + } +} + +#[derive(Debug, Clone)] +pub struct MatchArm<E> { + pub pat: Pat, + pub guard: Option<(If, Expr)>, + pub fat_arrow_token: FatArrow, + pub body: Markup<E>, + pub comma_token: Option<Comma>, +} + +impl<E: MaybeElement> DiagnosticParse for MatchArm<E> { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + Ok(Self { + pat: Pat::parse_multi_with_leading_vert(input)?, + guard: { + if input.peek(If) { + Some((input.parse()?, input.parse()?)) + } else { + None + } + }, + fat_arrow_token: input.parse()?, + body: Markup::diagnostic_parse_in_block(input, diagnostics)?, + comma_token: if input.peek(Comma) { + Some(input.parse()?) + } else { + None + }, + }) + } +} + +impl<E: ToTokens> ToTokens for MatchArm<E> { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.pat.to_tokens(tokens); + if let Some((if_token, guard)) = &self.guard { + if_token.to_tokens(tokens); + guard.to_tokens(tokens); + } + self.fat_arrow_token.to_tokens(tokens); + self.body.to_tokens(tokens); + if let Some(comma_token) = &self.comma_token { + comma_token.to_tokens(tokens); + } + } +} + +pub trait DiagnosticParse: Sized { + fn diagnostic_parse(input: ParseStream, diagnostics: &mut Vec<Diagnostic>) + -> syn::Result<Self>; +} + +impl<T: DiagnosticParse> DiagnosticParse for Box<T> { + fn diagnostic_parse( + input: ParseStream, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<Self> { + Ok(Box::new(input.diagnostic_parse(diagnostics)?)) + } +} + +trait DiagonsticParseExt: Sized { + fn diagnostic_parse<T: DiagnosticParse>( + self, + diagnostics: &mut Vec<Diagnostic>, + ) -> syn::Result<T>; +} + +impl DiagonsticParseExt for ParseStream<'_> { + fn diagnostic_parse<T>(self, diagnostics: &mut Vec<Diagnostic>) -> syn::Result<T> + where + T: DiagnosticParse, + { + T::diagnostic_parse(self, diagnostics) + } } diff --git a/helpers/pagetop-macros/src/maud/escape.rs b/helpers/pagetop-macros/src/maud/escape.rs index 49ece776..786d8c77 100644 --- a/helpers/pagetop-macros/src/maud/escape.rs +++ b/helpers/pagetop-macros/src/maud/escape.rs @@ -2,10 +2,6 @@ // !!!!!!!! PLEASE KEEP THIS IN SYNC WITH `maud/src/escape.rs` !!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -extern crate alloc; - -use alloc::string::String; - pub fn escape_to_string(input: &str, output: &mut String) { for b in input.bytes() { match b { @@ -20,10 +16,7 @@ pub fn escape_to_string(input: &str, output: &mut String) { #[cfg(test)] mod test { - extern crate alloc; - use super::escape_to_string; - use alloc::string::String; #[test] fn it_works() { diff --git a/helpers/pagetop-macros/src/maud/generate.rs b/helpers/pagetop-macros/src/maud/generate.rs index be7946d0..1f825783 100644 --- a/helpers/pagetop-macros/src/maud/generate.rs +++ b/helpers/pagetop-macros/src/maud/generate.rs @@ -1,23 +1,23 @@ -use proc_macro2::{Delimiter, Group, Ident, Literal, Span, TokenStream, TokenTree}; -use proc_macro_error::SpanRange; -use quote::quote; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::{quote, ToTokens}; +use syn::{parse_quote, token::Brace, Expr, Local}; use crate::maud::{ast::*, escape}; use proc_macro_crate::{crate_name, FoundCrate}; -pub fn generate(markups: Vec<Markup>, output_ident: TokenTree) -> TokenStream { +pub fn generate(markups: Markups<Element>, output_ident: Ident) -> TokenStream { let mut build = Builder::new(output_ident.clone()); Generator::new(output_ident).markups(markups, &mut build); build.finish() } struct Generator { - output_ident: TokenTree, + output_ident: Ident, } impl Generator { - fn new(output_ident: TokenTree) -> Generator { + fn new(output_ident: Ident) -> Generator { Generator { output_ident } } @@ -25,257 +25,341 @@ impl Generator { Builder::new(self.output_ident.clone()) } - fn markups(&self, markups: Vec<Markup>, build: &mut Builder) { - for markup in markups { + fn markups<E: Into<Element>>(&self, markups: Markups<E>, build: &mut Builder) { + for markup in markups.markups { self.markup(markup, build); } } - fn markup(&self, markup: Markup, build: &mut Builder) { + fn markup<E: Into<Element>>(&self, markup: Markup<E>, build: &mut Builder) { match markup { - Markup::ParseError { .. } => {} - Markup::Block(Block { - markups, - outer_span, - }) => { - if markups - .iter() - .any(|markup| matches!(*markup, Markup::Let { .. })) - { - self.block( - Block { - markups, - outer_span, - }, - build, - ); + Markup::Block(block) => { + if block.markups.markups.iter().any(|markup| { + matches!( + *markup, + Markup::ControlFlow(ControlFlow { + kind: ControlFlowKind::Let(_), + .. + }) + ) + }) { + self.block(block, build); } else { - self.markups(markups, build); + self.markups(block.markups, build); } } - Markup::Literal { content, .. } => build.push_escaped(&content), - Markup::Symbol { symbol } => self.name(symbol, build), + Markup::Lit(lit) => build.push_escaped(&lit.to_string()), Markup::Splice { expr, .. } => self.splice(expr, build), - Markup::Element { name, attrs, body } => self.element(name, attrs, body, build), - Markup::Let { tokens, .. } => build.push_tokens(tokens), - Markup::Special { segments } => { - for Special { head, body, .. } in segments { - build.push_tokens(head); - self.block(body, build); - } - } - Markup::Match { - head, - arms, - arms_span, - .. - } => { - let body = { - let mut build = self.builder(); - for MatchArm { head, body } in arms { - build.push_tokens(head); - self.block(body, &mut build); - } - build.finish() - }; - let mut body = TokenTree::Group(Group::new(Delimiter::Brace, body)); - body.set_span(arms_span.collapse()); - build.push_tokens(quote!(#head #body)); - } + Markup::Element(element) => self.element(element.into(), build), + Markup::ControlFlow(control_flow) => self.control_flow(control_flow, build), + Markup::Semi(_) => {} } } - fn block( - &self, - Block { - markups, - outer_span, - }: Block, - build: &mut Builder, - ) { - let block = { + fn block<E: Into<Element>>(&self, block: Block<E>, build: &mut Builder) { + let markups = { let mut build = self.builder(); - self.markups(markups, &mut build); + self.markups(block.markups, &mut build); build.finish() }; - let mut block = TokenTree::Group(Group::new(Delimiter::Brace, block)); - block.set_span(outer_span.collapse()); - build.push_tokens(TokenStream::from(block)); + + build.push_tokens(quote!({ #markups })); } - fn splice(&self, expr: TokenStream, build: &mut Builder) { - let output_ident = self.output_ident.clone(); + fn splice(&self, expr: Expr, build: &mut Builder) { + let output_ident = &self.output_ident; - let found_crate = crate_name("pagetop").expect("pagetop is present in `Cargo.toml`"); - build.push_tokens(match found_crate { - FoundCrate::Itself => quote!( - crate::html::html_private::render_to!(&#expr, &mut #output_ident); - ), - _ => quote!( - pagetop::html::html_private::render_to!(&#expr, &mut #output_ident); - ), + let found_crate = crate_name("pagetop").expect("pagetop debe existir en Cargo.toml"); + let crate_ident = match found_crate { + FoundCrate::Itself => Ident::new("pagetop", Span::call_site()), + FoundCrate::Name(name) => Ident::new(&name, Span::call_site()), + }; + build.push_tokens(quote! { + #crate_ident::html::html_private::render_to!(&(#expr), &mut #output_ident); }); } - fn element(&self, name: TokenStream, attrs: Vec<Attr>, body: ElementBody, build: &mut Builder) { + fn element(&self, element: Element, build: &mut Builder) { + let element_name = element.name.clone().unwrap_or_else(|| parse_quote!(div)); build.push_str("<"); - self.name(name.clone(), build); - self.attrs(attrs, build); + self.name(element_name.clone(), build); + self.attrs(element.attrs, build); build.push_str(">"); - if let ElementBody::Block { block } = body { + if let ElementBody::Block(block) = element.body { self.markups(block.markups, build); build.push_str("</"); - self.name(name, build); + self.name(element_name, build); build.push_str(">"); } } - fn name(&self, name: TokenStream, build: &mut Builder) { - build.push_escaped(&name_to_string(name)); + fn name(&self, name: HtmlName, build: &mut Builder) { + build.push_escaped(&name.to_string()); } - fn attrs(&self, attrs: Vec<Attr>, build: &mut Builder) { - for NamedAttr { name, attr_type } in desugar_attrs(attrs) { - match attr_type { - AttrType::Normal { value } => { + fn name_or_markup(&self, name: HtmlNameOrMarkup, build: &mut Builder) { + match name { + HtmlNameOrMarkup::HtmlName(name) => self.name(name, build), + HtmlNameOrMarkup::Markup(markup) => self.markup(markup, build), + } + } + + fn attr(&self, name: HtmlName, value: AttributeType, build: &mut Builder) { + match value { + AttributeType::Normal { value, .. } => { + build.push_str(" "); + self.name(name, build); + build.push_str("=\""); + self.markup(value, build); + build.push_str("\""); + } + AttributeType::Optional { + toggler: Toggler { cond, .. }, + .. + } => { + let inner_value: Expr = parse_quote!(inner_value); + + let body = { + let mut build = self.builder(); build.push_str(" "); - self.name(name, build); + self.name(name, &mut build); build.push_str("=\""); - self.markup(value, build); + self.splice(inner_value.clone(), &mut build); build.push_str("\""); - } - AttrType::Optional { - toggler: Toggler { cond, .. }, - } => { - let inner_value = quote!(inner_value); - let body = { - let mut build = self.builder(); - build.push_str(" "); - self.name(name, &mut build); - build.push_str("=\""); - self.splice(inner_value.clone(), &mut build); - build.push_str("\""); - build.finish() - }; - build.push_tokens(quote!(if let Some(#inner_value) = (#cond) { #body })); - } - AttrType::Empty { toggler: None } => { + build.finish() + }; + build.push_tokens(quote!(if let Some(#inner_value) = (#cond) { #body })); + } + AttributeType::Empty(None) => { + build.push_str(" "); + self.name(name, build); + } + AttributeType::Empty(Some(Toggler { cond, .. })) => { + let body = { + let mut build = self.builder(); build.push_str(" "); - self.name(name, build); - } - AttrType::Empty { - toggler: Some(Toggler { cond, .. }), - } => { - let body = { - let mut build = self.builder(); - build.push_str(" "); - self.name(name, &mut build); - build.finish() - }; - build.push_tokens(quote!(if (#cond) { #body })); - } + self.name(name, &mut build); + build.finish() + }; + build.push_tokens(quote!(if (#cond) { #body })); } } } + + fn attrs(&self, attrs: Vec<Attribute>, build: &mut Builder) { + let (classes, id, named_attrs) = split_attrs(attrs); + + if !classes.is_empty() { + let mut toggle_class_exprs = vec![]; + + build.push_str(" "); + self.name(parse_quote!(class), build); + build.push_str("=\""); + for (i, (name, toggler)) in classes.into_iter().enumerate() { + if let Some(toggler) = toggler { + toggle_class_exprs.push((i > 0, name, toggler)); + } else { + if i > 0 { + build.push_str(" "); + } + self.name_or_markup(name, build); + } + } + + for (not_first, name, toggler) in toggle_class_exprs { + let body = { + let mut build = self.builder(); + if not_first { + build.push_str(" "); + } + self.name_or_markup(name, &mut build); + build.finish() + }; + build.push_tokens(quote!(if (#toggler) { #body })); + } + + build.push_str("\""); + } + + if let Some(id) = id { + build.push_str(" "); + self.name(parse_quote!(id), build); + build.push_str("=\""); + self.name_or_markup(id, build); + build.push_str("\""); + } + + for (name, attr_type) in named_attrs { + self.attr(name, attr_type, build); + } + } + + fn control_flow<E: Into<Element>>(&self, control_flow: ControlFlow<E>, build: &mut Builder) { + match control_flow.kind { + ControlFlowKind::If(if_) => self.control_flow_if(if_, build), + ControlFlowKind::Let(let_) => self.control_flow_let(let_, build), + ControlFlowKind::For(for_) => self.control_flow_for(for_, build), + ControlFlowKind::While(while_) => self.control_flow_while(while_, build), + ControlFlowKind::Match(match_) => self.control_flow_match(match_, build), + } + } + + fn control_flow_if<E: Into<Element>>( + &self, + IfExpr { + if_token, + cond, + then_branch, + else_branch, + }: IfExpr<E>, + build: &mut Builder, + ) { + build.push_tokens(quote!(#if_token #cond)); + self.block(then_branch, build); + + if let Some((_, else_token, if_or_block)) = else_branch { + build.push_tokens(quote!(#else_token)); + self.control_flow_if_or_block(*if_or_block, build); + } + } + + fn control_flow_if_or_block<E: Into<Element>>( + &self, + if_or_block: IfOrBlock<E>, + build: &mut Builder, + ) { + match if_or_block { + IfOrBlock::If(if_) => self.control_flow_if(if_, build), + IfOrBlock::Block(block) => self.block(block, build), + } + } + + fn control_flow_let(&self, let_: Local, build: &mut Builder) { + build.push_tokens(let_.to_token_stream()); + } + + fn control_flow_for<E: Into<Element>>( + &self, + ForExpr { + for_token, + pat, + in_token, + expr, + body, + }: ForExpr<E>, + build: &mut Builder, + ) { + build.push_tokens(quote!(#for_token #pat #in_token (#expr))); + self.block(body, build); + } + + fn control_flow_while<E: Into<Element>>( + &self, + WhileExpr { + while_token, + cond, + body, + }: WhileExpr<E>, + build: &mut Builder, + ) { + build.push_tokens(quote!(#while_token #cond)); + self.block(body, build); + } + + fn control_flow_match<E: Into<Element>>( + &self, + MatchExpr { + match_token, + expr, + brace_token, + arms, + }: MatchExpr<E>, + build: &mut Builder, + ) { + let arms = { + let mut build = self.builder(); + for MatchArm { + pat, + guard, + fat_arrow_token, + body, + comma_token, + } in arms + { + build.push_tokens(quote!(#pat)); + if let Some((if_token, cond)) = guard { + build.push_tokens(quote!(#if_token #cond)); + } + build.push_tokens(quote!(#fat_arrow_token)); + self.block( + Block { + brace_token: Brace(Span::call_site()), + markups: Markups { + markups: vec![body], + }, + }, + &mut build, + ); + build.push_tokens(quote!(#comma_token)); + } + build.finish() + }; + + let mut arm_block = TokenStream::new(); + + brace_token.surround(&mut arm_block, |tokens| { + arms.to_tokens(tokens); + }); + + build.push_tokens(quote!(#match_token #expr #arm_block)); + } } //////////////////////////////////////////////////////// -fn desugar_attrs(attrs: Vec<Attr>) -> Vec<NamedAttr> { - let mut classes_static = vec![]; - let mut classes_toggled = vec![]; - let mut ids = vec![]; +#[allow(clippy::type_complexity)] +fn split_attrs( + attrs: Vec<Attribute>, +) -> ( + Vec<(HtmlNameOrMarkup, Option<Expr>)>, + Option<HtmlNameOrMarkup>, + Vec<(HtmlName, AttributeType)>, +) { + let mut classes = vec![]; + let mut id = None; let mut named_attrs = vec![]; + for attr in attrs { match attr { - Attr::Class { - name, - toggler: Some(toggler), - .. - } => classes_toggled.push((name, toggler)), - Attr::Class { - name, - toggler: None, - .. - } => classes_static.push(name), - Attr::Id { name, .. } => ids.push(name), - Attr::Named { named_attr } => named_attrs.push(named_attr), + Attribute::Class { name, toggler, .. } => { + classes.push((name, toggler.map(|toggler| toggler.cond))) + } + Attribute::Id { name, .. } => id = Some(name), + Attribute::Named { name, attr_type } => named_attrs.push((name, attr_type)), } } - let classes = desugar_classes_or_ids("class", classes_static, classes_toggled); - let ids = desugar_classes_or_ids("id", ids, vec![]); - classes.into_iter().chain(ids).chain(named_attrs).collect() -} -fn desugar_classes_or_ids( - attr_name: &'static str, - values_static: Vec<Markup>, - values_toggled: Vec<(Markup, Toggler)>, -) -> Option<NamedAttr> { - if values_static.is_empty() && values_toggled.is_empty() { - return None; - } - let mut markups = Vec::new(); - let mut leading_space = false; - for name in values_static { - markups.extend(prepend_leading_space(name, &mut leading_space)); - } - for (name, Toggler { cond, cond_span }) in values_toggled { - let body = Block { - markups: prepend_leading_space(name, &mut leading_space), - // TODO: is this correct? - outer_span: cond_span, - }; - markups.push(Markup::Special { - segments: vec![Special { - at_span: SpanRange::call_site(), - head: quote!(if (#cond)), - body, - }], - }); - } - Some(NamedAttr { - name: TokenStream::from(TokenTree::Ident(Ident::new(attr_name, Span::call_site()))), - attr_type: AttrType::Normal { - value: Markup::Block(Block { - markups, - outer_span: SpanRange::call_site(), - }), - }, - }) -} - -fn prepend_leading_space(name: Markup, leading_space: &mut bool) -> Vec<Markup> { - let mut markups = Vec::new(); - if *leading_space { - markups.push(Markup::Literal { - content: " ".to_owned(), - span: name.span(), - }); - } - *leading_space = true; - markups.push(name); - markups + (classes, id, named_attrs) } //////////////////////////////////////////////////////// struct Builder { - output_ident: TokenTree, - tokens: Vec<TokenTree>, + output_ident: Ident, + tokens: TokenStream, tail: String, } impl Builder { - fn new(output_ident: TokenTree) -> Builder { + fn new(output_ident: Ident) -> Builder { Builder { output_ident, - tokens: Vec::new(), + tokens: TokenStream::new(), tail: String::new(), } } - fn push_str(&mut self, string: &str) { + fn push_str(&mut self, string: &'static str) { self.tail.push_str(string); } @@ -294,8 +378,8 @@ impl Builder { } let push_str_expr = { let output_ident = self.output_ident.clone(); - let string = TokenTree::Literal(Literal::string(&self.tail)); - quote!(#output_ident.push_str(#string);) + let tail = &self.tail; + quote!(#output_ident.push_str(#tail);) }; self.tail.clear(); self.tokens.extend(push_str_expr); @@ -303,6 +387,6 @@ impl Builder { fn finish(mut self) -> TokenStream { self.cut(); - self.tokens.into_iter().collect() + self.tokens } } diff --git a/helpers/pagetop-macros/src/maud/parse.rs b/helpers/pagetop-macros/src/maud/parse.rs deleted file mode 100644 index d24cea6e..00000000 --- a/helpers/pagetop-macros/src/maud/parse.rs +++ /dev/null @@ -1,752 +0,0 @@ -use proc_macro2::{Delimiter, Ident, Literal, Spacing, Span, TokenStream, TokenTree}; -use proc_macro_error::{abort, abort_call_site, emit_error, SpanRange}; -use std::collections::HashMap; - -use syn::Lit; - -use crate::maud::ast; - -pub fn parse(input: TokenStream) -> Vec<ast::Markup> { - Parser::new(input).markups() -} - -#[derive(Clone)] -struct Parser { - /// If we're inside an attribute, then this contains the attribute name. - current_attr: Option<String>, - input: <TokenStream as IntoIterator>::IntoIter, -} - -impl Iterator for Parser { - type Item = TokenTree; - - fn next(&mut self) -> Option<TokenTree> { - self.input.next() - } -} - -impl Parser { - fn new(input: TokenStream) -> Parser { - Parser { - current_attr: None, - input: input.into_iter(), - } - } - - fn with_input(&self, input: TokenStream) -> Parser { - Parser { - current_attr: self.current_attr.clone(), - input: input.into_iter(), - } - } - - /// Returns the next token in the stream without consuming it. - fn peek(&mut self) -> Option<TokenTree> { - self.clone().next() - } - - /// Returns the next two tokens in the stream without consuming them. - fn peek2(&mut self) -> Option<(TokenTree, Option<TokenTree>)> { - let mut clone = self.clone(); - clone.next().map(|first| (first, clone.next())) - } - - /// Advances the cursor by one step. - fn advance(&mut self) { - self.next(); - } - - /// Advances the cursor by two steps. - fn advance2(&mut self) { - self.next(); - self.next(); - } - - /// Parses multiple blocks of markup. - fn markups(&mut self) -> Vec<ast::Markup> { - let mut result = Vec::new(); - loop { - match self.peek2() { - None => break, - Some((TokenTree::Punct(ref punct), _)) if punct.as_char() == ';' => self.advance(), - Some((TokenTree::Punct(ref punct), Some(TokenTree::Ident(ref ident)))) - if punct.as_char() == '@' && *ident == "let" => - { - self.advance2(); - let keyword = TokenTree::Ident(ident.clone()); - result.push(self.let_expr(punct.span(), keyword)); - } - _ => result.push(self.markup()), - } - } - result - } - - /// Parses a single block of markup. - fn markup(&mut self) -> ast::Markup { - let token = match self.peek() { - Some(token) => token, - None => { - abort_call_site!("unexpected end of input"); - } - }; - let markup = match token { - // Literal - TokenTree::Literal(literal) => { - self.advance(); - self.literal(literal) - } - // Special form - TokenTree::Punct(ref punct) if punct.as_char() == '@' => { - self.advance(); - let at_span = punct.span(); - match self.next() { - Some(TokenTree::Ident(ident)) => { - let keyword = TokenTree::Ident(ident.clone()); - match ident.to_string().as_str() { - "if" => { - let mut segments = Vec::new(); - self.if_expr(at_span, vec![keyword], &mut segments); - ast::Markup::Special { segments } - } - "while" => self.while_expr(at_span, keyword), - "for" => self.for_expr(at_span, keyword), - "match" => self.match_expr(at_span, keyword), - "let" => { - let span = SpanRange { - first: at_span, - last: ident.span(), - }; - abort!(span, "`@let` only works inside a block"); - } - other => { - let span = SpanRange { - first: at_span, - last: ident.span(), - }; - abort!(span, "unknown keyword `@{}`", other); - } - } - } - _ => { - abort!(at_span, "expected keyword after `@`"); - } - } - } - // Element - TokenTree::Ident(ident) => { - let ident_string = ident.to_string(); - match ident_string.as_str() { - "if" | "while" | "for" | "match" | "let" => { - abort!( - ident, - "found keyword `{}`", ident_string; - help = "should this be a `@{}`?", ident_string - ); - } - "true" | "false" => { - if let Some(attr_name) = &self.current_attr { - emit_error!( - ident, - r#"attribute value must be a string"#; - help = "to declare an empty attribute, omit the equals sign: `{}`", - attr_name; - help = "to toggle the attribute, use square brackets: `{}[some_boolean_flag]`", - attr_name; - ); - return ast::Markup::ParseError { - span: SpanRange::single_span(ident.span()), - }; - } - } - _ => {} - } - - // `.try_namespaced_name()` should never fail as we've - // already seen an `Ident` - let name = self.try_namespaced_name().expect("identifier"); - self.element(name) - } - // Div element shorthand - TokenTree::Punct(ref punct) if punct.as_char() == '.' || punct.as_char() == '#' => { - let name = TokenTree::Ident(Ident::new("div", punct.span())); - self.element(name.into()) - } - // Splice - TokenTree::Group(ref group) if group.delimiter() == Delimiter::Parenthesis => { - self.advance(); - ast::Markup::Splice { - expr: group.stream(), - outer_span: SpanRange::single_span(group.span()), - } - } - // Block - TokenTree::Group(ref group) if group.delimiter() == Delimiter::Brace => { - self.advance(); - ast::Markup::Block(self.block(group.stream(), SpanRange::single_span(group.span()))) - } - // ??? - token => { - abort!(token, "invalid syntax"); - } - }; - markup - } - - /// Parses a literal string. - fn literal(&mut self, literal: Literal) -> ast::Markup { - match Lit::new(literal.clone()) { - Lit::Str(lit_str) => { - return ast::Markup::Literal { - content: lit_str.value(), - span: SpanRange::single_span(literal.span()), - } - } - // Boolean literals are idents, so `Lit::Bool` is handled in - // `markup`, not here. - Lit::Int(..) | Lit::Float(..) => { - emit_error!(literal, r#"literal must be double-quoted: `"{}"`"#, literal); - } - Lit::Char(lit_char) => { - emit_error!( - literal, - r#"literal must be double-quoted: `"{}"`"#, - lit_char.value(), - ); - } - _ => { - emit_error!(literal, "expected string"); - } - } - ast::Markup::ParseError { - span: SpanRange::single_span(literal.span()), - } - } - - /// Parses an `@if` expression. - /// - /// The leading `@if` should already be consumed. - fn if_expr(&mut self, at_span: Span, prefix: Vec<TokenTree>, segments: &mut Vec<ast::Special>) { - let mut head = prefix; - let body = loop { - match self.next() { - Some(TokenTree::Group(ref block)) if block.delimiter() == Delimiter::Brace => { - break self.block(block.stream(), SpanRange::single_span(block.span())); - } - Some(token) => head.push(token), - None => { - let mut span = ast::span_tokens(head); - span.first = at_span; - abort!(span, "expected body for this `@if`"); - } - } - }; - segments.push(ast::Special { - at_span: SpanRange::single_span(at_span), - head: head.into_iter().collect(), - body, - }); - self.else_if_expr(segments) - } - - /// Parses an optional `@else if` or `@else`. - /// - /// The leading `@else if` or `@else` should *not* already be consumed. - fn else_if_expr(&mut self, segments: &mut Vec<ast::Special>) { - match self.peek2() { - Some((TokenTree::Punct(ref punct), Some(TokenTree::Ident(ref else_keyword)))) - if punct.as_char() == '@' && *else_keyword == "else" => - { - self.advance2(); - let at_span = punct.span(); - let else_keyword = TokenTree::Ident(else_keyword.clone()); - match self.peek() { - // `@else if` - Some(TokenTree::Ident(ref if_keyword)) if *if_keyword == "if" => { - self.advance(); - let if_keyword = TokenTree::Ident(if_keyword.clone()); - self.if_expr(at_span, vec![else_keyword, if_keyword], segments) - } - // Just an `@else` - _ => match self.next() { - Some(TokenTree::Group(ref group)) - if group.delimiter() == Delimiter::Brace => - { - let body = - self.block(group.stream(), SpanRange::single_span(group.span())); - segments.push(ast::Special { - at_span: SpanRange::single_span(at_span), - head: vec![else_keyword].into_iter().collect(), - body, - }); - } - _ => { - let span = SpanRange { - first: at_span, - last: else_keyword.span(), - }; - abort!(span, "expected body for this `@else`"); - } - }, - } - } - // We didn't find an `@else`; stop - _ => {} - } - } - - /// Parses an `@while` expression. - /// - /// The leading `@while` should already be consumed. - fn while_expr(&mut self, at_span: Span, keyword: TokenTree) -> ast::Markup { - let keyword_span = keyword.span(); - let mut head = vec![keyword]; - let body = loop { - match self.next() { - Some(TokenTree::Group(ref block)) if block.delimiter() == Delimiter::Brace => { - break self.block(block.stream(), SpanRange::single_span(block.span())); - } - Some(token) => head.push(token), - None => { - let span = SpanRange { - first: at_span, - last: keyword_span, - }; - abort!(span, "expected body for this `@while`"); - } - } - }; - ast::Markup::Special { - segments: vec![ast::Special { - at_span: SpanRange::single_span(at_span), - head: head.into_iter().collect(), - body, - }], - } - } - - /// Parses a `@for` expression. - /// - /// The leading `@for` should already be consumed. - fn for_expr(&mut self, at_span: Span, keyword: TokenTree) -> ast::Markup { - let keyword_span = keyword.span(); - let mut head = vec![keyword]; - loop { - match self.next() { - Some(TokenTree::Ident(ref in_keyword)) if *in_keyword == "in" => { - head.push(TokenTree::Ident(in_keyword.clone())); - break; - } - Some(token) => head.push(token), - None => { - let span = SpanRange { - first: at_span, - last: keyword_span, - }; - abort!(span, "missing `in` in `@for` loop"); - } - } - } - let body = loop { - match self.next() { - Some(TokenTree::Group(ref block)) if block.delimiter() == Delimiter::Brace => { - break self.block(block.stream(), SpanRange::single_span(block.span())); - } - Some(token) => head.push(token), - None => { - let span = SpanRange { - first: at_span, - last: keyword_span, - }; - abort!(span, "expected body for this `@for`"); - } - } - }; - ast::Markup::Special { - segments: vec![ast::Special { - at_span: SpanRange::single_span(at_span), - head: head.into_iter().collect(), - body, - }], - } - } - - /// Parses a `@match` expression. - /// - /// The leading `@match` should already be consumed. - fn match_expr(&mut self, at_span: Span, keyword: TokenTree) -> ast::Markup { - let keyword_span = keyword.span(); - let mut head = vec![keyword]; - let (arms, arms_span) = loop { - match self.next() { - Some(TokenTree::Group(ref body)) if body.delimiter() == Delimiter::Brace => { - let span = SpanRange::single_span(body.span()); - break (self.with_input(body.stream()).match_arms(), span); - } - Some(token) => head.push(token), - None => { - let span = SpanRange { - first: at_span, - last: keyword_span, - }; - abort!(span, "expected body for this `@match`"); - } - } - }; - ast::Markup::Match { - at_span: SpanRange::single_span(at_span), - head: head.into_iter().collect(), - arms, - arms_span, - } - } - - fn match_arms(&mut self) -> Vec<ast::MatchArm> { - let mut arms = Vec::new(); - while let Some(arm) = self.match_arm() { - arms.push(arm); - } - arms - } - - fn match_arm(&mut self) -> Option<ast::MatchArm> { - let mut head = Vec::new(); - loop { - match self.peek2() { - Some((TokenTree::Punct(ref eq), Some(TokenTree::Punct(ref gt)))) - if eq.as_char() == '=' - && gt.as_char() == '>' - && eq.spacing() == Spacing::Joint => - { - self.advance2(); - head.push(TokenTree::Punct(eq.clone())); - head.push(TokenTree::Punct(gt.clone())); - break; - } - Some((token, _)) => { - self.advance(); - head.push(token); - } - None => { - if head.is_empty() { - return None; - } else { - let head_span = ast::span_tokens(head); - abort!(head_span, "unexpected end of @match pattern"); - } - } - } - } - let body = match self.next() { - // $pat => { $stmts } - Some(TokenTree::Group(ref body)) if body.delimiter() == Delimiter::Brace => { - let body = self.block(body.stream(), SpanRange::single_span(body.span())); - // Trailing commas are optional if the match arm is a braced block - if let Some(TokenTree::Punct(ref punct)) = self.peek() { - if punct.as_char() == ',' { - self.advance(); - } - } - body - } - // $pat => $expr - Some(first_token) => { - let mut span = SpanRange::single_span(first_token.span()); - let mut body = vec![first_token]; - loop { - match self.next() { - Some(TokenTree::Punct(ref punct)) if punct.as_char() == ',' => break, - Some(token) => { - span.last = token.span(); - body.push(token); - } - None => break, - } - } - self.block(body.into_iter().collect(), span) - } - None => { - let span = ast::span_tokens(head); - abort!(span, "unexpected end of @match arm"); - } - }; - Some(ast::MatchArm { - head: head.into_iter().collect(), - body, - }) - } - - /// Parses a `@let` expression. - /// - /// The leading `@let` should already be consumed. - fn let_expr(&mut self, at_span: Span, keyword: TokenTree) -> ast::Markup { - let mut tokens = vec![keyword]; - loop { - match self.next() { - Some(token) => match token { - TokenTree::Punct(ref punct) if punct.as_char() == '=' => { - tokens.push(token.clone()); - break; - } - _ => tokens.push(token), - }, - None => { - let mut span = ast::span_tokens(tokens); - span.first = at_span; - abort!(span, "unexpected end of `@let` expression"); - } - } - } - loop { - match self.next() { - Some(token) => match token { - TokenTree::Punct(ref punct) if punct.as_char() == ';' => { - tokens.push(token.clone()); - break; - } - _ => tokens.push(token), - }, - None => { - let mut span = ast::span_tokens(tokens); - span.first = at_span; - abort!( - span, - "unexpected end of `@let` expression"; - help = "are you missing a semicolon?" - ); - } - } - } - ast::Markup::Let { - at_span: SpanRange::single_span(at_span), - tokens: tokens.into_iter().collect(), - } - } - - /// Parses an element node. - /// - /// The element name should already be consumed. - fn element(&mut self, name: TokenStream) -> ast::Markup { - if self.current_attr.is_some() { - let span = ast::span_tokens(name); - abort!(span, "unexpected element"); - } - let attrs = self.attrs(); - let body = match self.peek() { - Some(TokenTree::Punct(ref punct)) - if punct.as_char() == ';' || punct.as_char() == '/' => - { - // Void element - self.advance(); - if punct.as_char() == '/' { - emit_error!( - punct, - "void elements must use `;`, not `/`"; - help = "change this to `;`"; - help = "see https://github.com/lambda-fairy/maud/pull/315 for details"; - ); - } - ast::ElementBody::Void { - semi_span: SpanRange::single_span(punct.span()), - } - } - Some(_) => match self.markup() { - ast::Markup::Block(block) => ast::ElementBody::Block { block }, - markup => { - let markup_span = markup.span(); - abort!( - markup_span, - "element body must be wrapped in braces"; - help = "see https://github.com/lambda-fairy/maud/pull/137 for details" - ); - } - }, - None => abort_call_site!("expected `;`, found end of macro"), - }; - ast::Markup::Element { name, attrs, body } - } - - /// Parses the attributes of an element. - fn attrs(&mut self) -> Vec<ast::Attr> { - let mut attrs = Vec::new(); - loop { - if let Some(name) = self.try_namespaced_name() { - // Attribute - match self.peek() { - // Non-empty attribute - Some(TokenTree::Punct(ref punct)) if punct.as_char() == '=' => { - self.advance(); - // Parse a value under an attribute context - assert!(self.current_attr.is_none()); - self.current_attr = Some(ast::name_to_string(name.clone())); - let attr_type = match self.attr_toggler() { - Some(toggler) => ast::AttrType::Optional { toggler }, - None => { - let value = self.markup(); - ast::AttrType::Normal { value } - } - }; - self.current_attr = None; - attrs.push(ast::Attr::Named { - named_attr: ast::NamedAttr { name, attr_type }, - }); - } - // Empty attribute (legacy syntax) - Some(TokenTree::Punct(ref punct)) if punct.as_char() == '?' => { - self.advance(); - let toggler = self.attr_toggler(); - attrs.push(ast::Attr::Named { - named_attr: ast::NamedAttr { - name: name.clone(), - attr_type: ast::AttrType::Empty { toggler }, - }, - }); - } - // Empty attribute (new syntax) - _ => { - let toggler = self.attr_toggler(); - attrs.push(ast::Attr::Named { - named_attr: ast::NamedAttr { - name: name.clone(), - attr_type: ast::AttrType::Empty { toggler }, - }, - }); - } - } - } else { - match self.peek() { - // Class shorthand - Some(TokenTree::Punct(ref punct)) if punct.as_char() == '.' => { - self.advance(); - let name = self.class_or_id_name(); - let toggler = self.attr_toggler(); - attrs.push(ast::Attr::Class { - dot_span: SpanRange::single_span(punct.span()), - name, - toggler, - }); - } - // ID shorthand - Some(TokenTree::Punct(ref punct)) if punct.as_char() == '#' => { - self.advance(); - let name = self.class_or_id_name(); - attrs.push(ast::Attr::Id { - hash_span: SpanRange::single_span(punct.span()), - name, - }); - } - // If it's not a valid attribute, backtrack and bail out - _ => break, - } - } - } - - let mut attr_map: HashMap<String, Vec<SpanRange>> = HashMap::new(); - let mut has_class = false; - for attr in &attrs { - let name = match attr { - ast::Attr::Class { .. } => { - if has_class { - // Only check the first class to avoid spurious duplicates - continue; - } - has_class = true; - "class".to_string() - } - ast::Attr::Id { .. } => "id".to_string(), - ast::Attr::Named { named_attr } => named_attr - .name - .clone() - .into_iter() - .map(|token| token.to_string()) - .collect(), - }; - let entry = attr_map.entry(name).or_default(); - entry.push(attr.span()); - } - - for (name, spans) in attr_map { - if spans.len() > 1 { - let mut spans = spans.into_iter(); - let first_span = spans.next().expect("spans should be non-empty"); - abort!(first_span, "duplicate attribute `{}`", name); - } - } - - attrs - } - - /// Parses the name of a class or ID. - fn class_or_id_name(&mut self) -> ast::Markup { - if let Some(symbol) = self.try_name() { - ast::Markup::Symbol { symbol } - } else { - self.markup() - } - } - - /// Parses the `[cond]` syntax after an empty attribute or class shorthand. - fn attr_toggler(&mut self) -> Option<ast::Toggler> { - match self.peek() { - Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::Bracket => { - self.advance(); - Some(ast::Toggler { - cond: group.stream(), - cond_span: SpanRange::single_span(group.span()), - }) - } - _ => None, - } - } - - /// Parses an identifier, without dealing with namespaces. - fn try_name(&mut self) -> Option<TokenStream> { - let mut result = Vec::new(); - if let Some(token @ TokenTree::Ident(_)) = self.peek() { - self.advance(); - result.push(token); - } else { - return None; - } - let mut expect_ident = false; - loop { - expect_ident = match self.peek() { - Some(TokenTree::Punct(ref punct)) if punct.as_char() == '-' => { - self.advance(); - result.push(TokenTree::Punct(punct.clone())); - true - } - Some(TokenTree::Ident(ref ident)) if expect_ident => { - self.advance(); - result.push(TokenTree::Ident(ident.clone())); - false - } - _ => break, - }; - } - Some(result.into_iter().collect()) - } - - /// Parses a HTML element or attribute name, along with a namespace - /// if necessary. - fn try_namespaced_name(&mut self) -> Option<TokenStream> { - let mut result = vec![self.try_name()?]; - if let Some(TokenTree::Punct(ref punct)) = self.peek() { - if punct.as_char() == ':' { - self.advance(); - result.push(TokenStream::from(TokenTree::Punct(punct.clone()))); - result.push(self.try_name()?); - } - } - Some(result.into_iter().collect()) - } - - /// Parses the given token stream as a Maud expression. - fn block(&mut self, body: TokenStream, outer_span: SpanRange) -> ast::Block { - let markups = self.with_input(body).markups(); - ast::Block { - markups, - outer_span, - } - } -} diff --git a/src/html.rs b/src/html.rs index 1f24f630..14e72b94 100644 --- a/src/html.rs +++ b/src/html.rs @@ -1,4 +1,4 @@ //! HTML en código. mod maud; -pub use maud::{html, html_private, Markup, PreEscaped, DOCTYPE}; +pub use maud::{display, html, html_private, Escaper, Markup, PreEscaped, Render, DOCTYPE}; diff --git a/src/html/maud.rs b/src/html/maud.rs index db9308af..19429869 100644 --- a/src/html/maud.rs +++ b/src/html/maud.rs @@ -1,4 +1,4 @@ -//#![no_std] +// #![no_std] //! A macro for writing HTML templates. //! @@ -7,11 +7,11 @@ //! //! [book]: https://maud.lambda.xyz/ -//#![doc(html_root_url = "https://docs.rs/maud/0.25.0")] +// #![doc(html_root_url = "https://docs.rs/maud/0.27.0")] extern crate alloc; -use alloc::{borrow::Cow, boxed::Box, string::String}; +use alloc::{borrow::Cow, boxed::Box, string::String, sync::Arc}; use core::fmt::{self, Arguments, Display, Write}; pub use pagetop_macros::html; @@ -34,8 +34,8 @@ mod escape; /// /// # Example /// -/// ```rust#ignore -/// use maud::Escaper; +/// ```rust +/// use pagetop::html::Escaper; /// use std::fmt::Write; /// let mut s = String::new(); /// write!(Escaper::new(&mut s), "<script>launchMissiles()</script>").unwrap(); @@ -50,7 +50,7 @@ impl<'a> Escaper<'a> { } } -impl<'a> fmt::Write for Escaper<'a> { +impl fmt::Write for Escaper<'_> { fn write_str(&mut self, s: &str) -> fmt::Result { escape::escape_to_string(s, self.0); Ok(()) @@ -72,8 +72,8 @@ impl<'a> fmt::Write for Escaper<'a> { /// /// # Example /// -/// ```rust#ignore -/// use maud::{html, Markup, Render}; +/// ```rust +/// use pagetop::html::{html, Markup, Render}; /// /// /// Provides a shorthand for linking to a CSS stylesheet. /// pub struct Stylesheet(&'static str); @@ -120,25 +120,25 @@ impl Render for String { } } -impl<'a> Render for Cow<'a, str> { +impl Render for Cow<'_, str> { fn render_to(&self, w: &mut String) { str::render_to(self, w); } } -impl<'a> Render for Arguments<'a> { +impl Render for Arguments<'_> { fn render_to(&self, w: &mut String) { let _ = Escaper::new(w).write_fmt(*self); } } -impl<'a, T: Render + ?Sized> Render for &'a T { +impl<T: Render + ?Sized> Render for &T { fn render_to(&self, w: &mut String) { T::render_to(self, w); } } -impl<'a, T: Render + ?Sized> Render for &'a mut T { +impl<T: Render + ?Sized> Render for &mut T { fn render_to(&self, w: &mut String) { T::render_to(self, w); } @@ -150,6 +150,12 @@ impl<T: Render + ?Sized> Render for Box<T> { } } +impl<T: Render + ?Sized> Render for Arc<T> { + fn render_to(&self, w: &mut String) { + T::render_to(self, w); + } +} + macro_rules! impl_render_with_display { ($($ty:ty)*) => { $( @@ -188,15 +194,15 @@ impl_render_with_itoa! { /// /// # Example /// -/// ```rust#ignore -/// use maud::html; +/// ```rust +/// use pagetop::html::{display, html}; /// use std::net::Ipv4Addr; /// /// let ip_address = Ipv4Addr::new(127, 0, 0, 1); /// /// let markup = html! { /// "My IP address is: " -/// (maud::display(ip_address)) +/// (display(ip_address)) /// }; /// /// assert_eq!(markup.into_string(), "My IP address is: 127.0.0.1"); @@ -215,7 +221,7 @@ pub fn display(value: impl Display) -> impl Render { /// A wrapper that renders the inner value without escaping. #[derive(Debug, Clone, Copy)] -pub struct PreEscaped<T: AsRef<str>>(pub T); +pub struct PreEscaped<T>(pub T); impl<T: AsRef<str>> Render for PreEscaped<T> { fn render_to(&self, w: &mut String) { @@ -234,20 +240,20 @@ impl Markup { } } -impl<T: AsRef<str> + Into<String>> PreEscaped<T> { +impl<T: Into<String>> PreEscaped<T> { /// Converts the inner value to a string. pub fn into_string(self) -> String { self.0.into() } } -impl<T: AsRef<str> + Into<String>> From<PreEscaped<T>> for String { +impl<T: Into<String>> From<PreEscaped<T>> for String { fn from(value: PreEscaped<T>) -> String { value.into_string() } } -impl<T: AsRef<str> + Default> Default for PreEscaped<T> { +impl<T: Default> Default for PreEscaped<T> { fn default() -> Self { Self(Default::default()) } @@ -259,8 +265,8 @@ impl<T: AsRef<str> + Default> Default for PreEscaped<T> { /// /// A minimal web page: /// -/// ```rust#ignore -/// use maud::{DOCTYPE, html}; +/// ```rust +/// use pagetop::html::{DOCTYPE, html}; /// /// let markup = html! { /// (DOCTYPE) @@ -280,10 +286,35 @@ pub const DOCTYPE: PreEscaped<&'static str> = PreEscaped("<!DOCTYPE html>"); mod actix_support { extern crate alloc; + use core::{ + pin::Pin, + task::{Context, Poll}, + }; + use crate::html::PreEscaped; - use actix_web::{http::header, HttpRequest, HttpResponse, Responder}; + use actix_web::{ + body::{BodySize, MessageBody}, + http::header, + web::Bytes, + HttpRequest, HttpResponse, Responder, + }; use alloc::string::String; + impl MessageBody for PreEscaped<String> { + type Error = <String as MessageBody>::Error; + + fn size(&self) -> BodySize { + self.0.size() + } + + fn poll_next( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll<Option<Result<Bytes, Self::Error>>> { + Pin::new(&mut self.0).poll_next(cx) + } + } + impl Responder for PreEscaped<String> { type Body = String; diff --git a/src/service.rs b/src/service.rs index 9fe2450e..e6904b82 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,4 +1,4 @@ -//! Gestión del servidor y servicios web ([actix-web](https://docs.rs/actix-web)). +//! Gestión del servidor y servicios web ([Actix Web](https://docs.rs/actix-web)). pub use actix_web::body::BoxBody; pub use actix_web::dev::Server; From 7a0d02d57e4c8e7ad1a0445dfc14f781bc154d30 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 7 Jul 2025 21:23:06 +0200 Subject: [PATCH 059/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20AutoDefault=20?= =?UTF-8?q?para=20derivar=20Default=20avanzado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- helpers/pagetop-macros/Cargo.toml | 2 +- helpers/pagetop-macros/README.md | 9 +- helpers/pagetop-macros/src/lib.rs | 20 ++- helpers/pagetop-macros/src/smart_default.rs | 4 + .../src/smart_default/body_impl.rs | 158 ++++++++++++++++++ .../src/smart_default/default_attr.rs | 89 ++++++++++ .../pagetop-macros/src/smart_default/util.rs | 21 +++ src/lib.rs | 2 +- src/prelude.rs | 2 + src/service.rs | 2 +- 11 files changed, 303 insertions(+), 8 deletions(-) create mode 100644 helpers/pagetop-macros/src/smart_default.rs create mode 100644 helpers/pagetop-macros/src/smart_default/body_impl.rs create mode 100644 helpers/pagetop-macros/src/smart_default/default_attr.rs create mode 100644 helpers/pagetop-macros/src/smart_default/util.rs diff --git a/Cargo.lock b/Cargo.lock index cf974c87..3fe4d512 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -937,7 +937,7 @@ dependencies = [ [[package]] name = "pagetop-macros" -version = "0.0.2" +version = "0.0.3" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/helpers/pagetop-macros/Cargo.toml b/helpers/pagetop-macros/Cargo.toml index ea6404b9..9f914bfd 100644 --- a/helpers/pagetop-macros/Cargo.toml +++ b/helpers/pagetop-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-macros" -version = "0.0.2" +version = "0.0.3" edition = "2021" description = """\ diff --git a/helpers/pagetop-macros/README.md b/helpers/pagetop-macros/README.md index 06799668..e41dd0ec 100644 --- a/helpers/pagetop-macros/README.md +++ b/helpers/pagetop-macros/README.md @@ -11,9 +11,12 @@ ## Descripción general Entre sus macros se incluye una adaptación de [maud-macros](https://crates.io/crates/maud_macros) -([0.25.0](https://github.com/lambda-fairy/maud/tree/v0.25.0/maud_macros)) de -[Chris Wong](https://crates.io/users/lambda-fairy) para no tener que referenciar `maud` en las -dependencias del archivo `Cargo.toml` de cada proyecto `PageTop`. +([0.27.0](https://github.com/lambda-fairy/maud/tree/v0.27.0/maud_macros)) de +[Chris Wong](https://crates.io/users/lambda-fairy) y una versión renombrada de +[SmartDefault](https://crates.io/crates/smart_default) (0.7.1) de +[Jane Doe](https://crates.io/users/jane-doe), llamada `AutoDefault`. Estas macros eliminan la +necesidad de referenciar `maud` o `smart_default` en las dependencias del archivo `Cargo.toml` de +cada proyecto `PageTop`. ## Sobre PageTop diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index e0f3badd..eecebed3 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -15,16 +15,34 @@ //! y configurables, basadas en HTML, CSS y JavaScript. mod maud; +mod smart_default; use proc_macro::TokenStream; use quote::quote; +use syn::{parse_macro_input, DeriveInput}; -/// Macro para escribir plantillas HTML ([Maud](https://docs.rs/maud)). +/// Macro para escribir plantillas HTML (basada en [Maud](https://docs.rs/maud)). #[proc_macro] pub fn html(input: TokenStream) -> TokenStream { maud::expand(input.into()).into() } +/// Deriva [`Default`] con atributos personalizados (basada en +/// [SmartDefault](https://docs.rs/smart-default)). +/// +/// Al derivar una estructura con *AutoDefault* se genera automáticamente la implementación de +/// [`Default`]. Aunque, a diferencia de un simple `#[derive(Default)]`, el atributo +/// `#[derive(AutoDefault)]` permite usar anotaciones en los campos como `#[default = "..."]`, +/// funcionando incluso en estructuras con campos que no implementan [`Default`] o en *enums*. +#[proc_macro_derive(AutoDefault, attributes(default))] +pub fn derive_auto_default(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + match smart_default::body_impl::impl_my_derive(&input) { + Ok(output) => output.into(), + Err(error) => error.to_compile_error().into(), + } +} + /// Define una función `main` asíncrona como punto de entrada de `PageTop`. /// /// # Ejemplos diff --git a/helpers/pagetop-macros/src/smart_default.rs b/helpers/pagetop-macros/src/smart_default.rs new file mode 100644 index 00000000..87177dca --- /dev/null +++ b/helpers/pagetop-macros/src/smart_default.rs @@ -0,0 +1,4 @@ +pub mod body_impl; + +mod default_attr; +mod util; diff --git a/helpers/pagetop-macros/src/smart_default/body_impl.rs b/helpers/pagetop-macros/src/smart_default/body_impl.rs new file mode 100644 index 00000000..6a76f904 --- /dev/null +++ b/helpers/pagetop-macros/src/smart_default/body_impl.rs @@ -0,0 +1,158 @@ +use proc_macro2::TokenStream; + +use quote::quote; +use syn::parse::Error; +use syn::spanned::Spanned; +use syn::DeriveInput; + +use crate::smart_default::default_attr::{ConversionStrategy, DefaultAttr}; +use crate::smart_default::util::find_only; + +pub fn impl_my_derive(input: &DeriveInput) -> Result<TokenStream, Error> { + let name = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + + let (default_expr, doc) = match input.data { + syn::Data::Struct(ref body) => { + let (body_assignment, _doc) = default_body_tt(&body.fields)?; + ( + quote! { + #name #body_assignment + }, + format!("Returns a `{}` default.", name), + ) + } + syn::Data::Enum(ref body) => { + let default_variant = find_only(body.variants.iter(), |variant| { + if let Some(meta) = DefaultAttr::find_in_attributes(&variant.attrs)? { + if meta.code.is_none() { + Ok(true) + } else { + Err(Error::new( + meta.code.span(), + "Attribute #[default] on variants should have no value", + )) + } + } else { + Ok(false) + } + })? + .ok_or_else(|| Error::new(input.span(), "No default variant"))?; + let default_variant_name = &default_variant.ident; + let (body_assignment, _doc) = default_body_tt(&default_variant.fields)?; + ( + quote! { + #name :: #default_variant_name #body_assignment + }, + format!("Returns a `{}::{}` default.", name, default_variant_name), + ) + } + syn::Data::Union(_) => { + panic!() + } + }; + Ok(quote! { + #[automatically_derived] + impl #impl_generics Default for #name #ty_generics #where_clause { + #[doc = #doc] + fn default() -> Self { + #default_expr + } + } + }) +} + +/// Return a token-tree for the default "body" - the part after the name that contains the values. +/// That is, the `{ ... }` part for structs, the `(...)` part for tuples, and nothing for units. +fn default_body_tt(body: &syn::Fields) -> Result<(TokenStream, String), Error> { + let mut doc = String::new(); + use std::fmt::Write; + let body_tt = match body { + syn::Fields::Named(ref fields) => { + doc.push_str(" {"); + let result = { + let field_assignments = fields + .named + .iter() + .map(|field| { + let field_name = field.ident.as_ref(); + let (default_value, default_doc) = field_default_expr_and_doc(field)?; + write!( + &mut doc, + "\n {}: {},", + field_name.expect("field value in struct is empty"), + default_doc + ) + .unwrap(); + // let default_value = default_value.into_token_stream(); + Ok(quote! { #field_name : #default_value }) + }) + .collect::<Result<Vec<_>, Error>>()?; + quote! { + { + #( #field_assignments ),* + } + } + }; + if doc.ends_with(',') { + doc.pop(); + doc.push('\n'); + }; + doc.push('}'); + result + } + syn::Fields::Unnamed(ref fields) => { + doc.push('('); + let result = { + let field_assignments = fields + .unnamed + .iter() + .map(|field| { + let (default_value, default_doc) = field_default_expr_and_doc(field)?; + write!(&mut doc, "{}, ", default_doc).unwrap(); + Ok(default_value) + }) + .collect::<Result<Vec<TokenStream>, Error>>()?; + quote! { + ( + #( #field_assignments ),* + ) + } + }; + if doc.ends_with(", ") { + doc.pop(); + doc.pop(); + }; + doc.push(')'); + result + } + &syn::Fields::Unit => quote! {}, + }; + Ok((body_tt, doc)) +} + +/// Return a default expression for a field based on it's `#[default = "..."]` attribute. Panic +/// if there is more than one, of if there is a `#[default]` attribute without value. +fn field_default_expr_and_doc(field: &syn::Field) -> Result<(TokenStream, String), Error> { + if let Some(default_attr) = DefaultAttr::find_in_attributes(&field.attrs)? { + let conversion_strategy = default_attr.conversion_strategy(); + let field_value = default_attr.code.ok_or_else(|| { + Error::new(field.span(), "Expected #[default = ...] or #[default(...)]") + })?; + + let field_value = match conversion_strategy { + ConversionStrategy::NoConversion => field_value, + ConversionStrategy::Into => quote!((#field_value).into()), + }; + + let field_doc = format!("{}", field_value); + Ok((field_value, field_doc)) + } else { + Ok(( + quote! { + Default::default() + }, + "Default::default()".to_owned(), + )) + } +} diff --git a/helpers/pagetop-macros/src/smart_default/default_attr.rs b/helpers/pagetop-macros/src/smart_default/default_attr.rs new file mode 100644 index 00000000..8487fc06 --- /dev/null +++ b/helpers/pagetop-macros/src/smart_default/default_attr.rs @@ -0,0 +1,89 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{parse::Error, MetaNameValue}; + +use crate::smart_default::util::find_only; + +#[derive(Debug, Clone, Copy)] +pub enum ConversionStrategy { + NoConversion, + Into, +} + +pub struct DefaultAttr { + pub code: Option<TokenStream>, + conversion_strategy: Option<ConversionStrategy>, +} + +impl DefaultAttr { + pub fn find_in_attributes(attrs: &[syn::Attribute]) -> Result<Option<Self>, Error> { + if let Some(default_attr) = + find_only(attrs.iter(), |attr| Ok(attr.path().is_ident("default")))? + { + match &default_attr.meta { + syn::Meta::Path(_) => Ok(Some(Self { + code: None, + conversion_strategy: None, + })), + syn::Meta::List(meta) => { + // If the meta contains exactly (_code = "...") take the string literal as the + // expression + if let Ok(ParseCodeHack(code_hack)) = syn::parse(meta.tokens.clone().into()) { + Ok(Some(Self { + code: Some(code_hack), + conversion_strategy: Some(ConversionStrategy::NoConversion), + })) + } else { + Ok(Some(Self { + code: Some(meta.tokens.clone()), + conversion_strategy: None, + })) + } + } + syn::Meta::NameValue(MetaNameValue { value, .. }) => Ok(Some(Self { + code: Some(value.into_token_stream()), + conversion_strategy: None, + })), + } + } else { + Ok(None) + } + } + + pub fn conversion_strategy(&self) -> ConversionStrategy { + if let Some(conversion_strategy) = self.conversion_strategy { + // Conversion strategy already set + return conversion_strategy; + } + let code = if let Some(code) = &self.code { + code + } else { + // #[default] - so no conversion (`Default::default()` already has the correct type) + return ConversionStrategy::NoConversion; + }; + match syn::parse::<syn::Lit>(code.clone().into()) { + Ok(syn::Lit::Str(_)) | Ok(syn::Lit::ByteStr(_)) => { + // A string literal - so we need a conversion in case we need to make it a `String` + return ConversionStrategy::Into; + } + _ => {} + } + // Not handled by one of the rules, so we don't convert it to avoid causing trouble + ConversionStrategy::NoConversion + } +} + +struct ParseCodeHack(TokenStream); + +impl syn::parse::Parse for ParseCodeHack { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { + let ident: syn::Ident = input.parse()?; + if ident != "_code" { + return Err(Error::new(ident.span(), "Expected `_code`")); + } + input.parse::<syn::token::Eq>()?; + let code: syn::LitStr = input.parse()?; + let code: TokenStream = code.parse()?; + Ok(ParseCodeHack(code)) + } +} diff --git a/helpers/pagetop-macros/src/smart_default/util.rs b/helpers/pagetop-macros/src/smart_default/util.rs new file mode 100644 index 00000000..0d4b247b --- /dev/null +++ b/helpers/pagetop-macros/src/smart_default/util.rs @@ -0,0 +1,21 @@ +use syn::parse::Error; +use syn::spanned::Spanned; + +/// Return the value that fulfills the predicate if there is one in the slice. Panic if there is +/// more than one. +pub fn find_only<T, F>(iter: impl Iterator<Item = T>, pred: F) -> Result<Option<T>, Error> +where + T: Spanned, + F: Fn(&T) -> Result<bool, Error>, +{ + let mut result = None; + for item in iter { + if pred(&item)? { + if result.is_some() { + return Err(Error::new(item.span(), "Multiple defaults")); + } + result = Some(item); + } + } + Ok(result) +} diff --git a/src/lib.rs b/src/lib.rs index 2f973518..b9b2a4bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,7 @@ // RE-EXPORTED ************************************************************************************* -pub use pagetop_macros::{html, main, test}; +pub use pagetop_macros::{html, main, test, AutoDefault}; // API ********************************************************************************************* diff --git a/src/prelude.rs b/src/prelude.rs index eb59c4f2..872447aa 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -4,6 +4,8 @@ pub use crate::{html, main, test}; +pub use crate::AutoDefault; + // MACROS. // crate::config diff --git a/src/service.rs b/src/service.rs index e6904b82..90b13758 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,4 +1,4 @@ -//! Gestión del servidor y servicios web ([Actix Web](https://docs.rs/actix-web)). +//! Gestión del servidor y servicios web (con [Actix Web](https://docs.rs/actix-web)). pub use actix_web::body::BoxBody; pub use actix_web::dev::Server; From 7e03d926bba7a420b0e1433eed01ae91e49a299f Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 8 Jul 2025 20:57:39 +0200 Subject: [PATCH 060/244] =?UTF-8?q?=F0=9F=9A=A8=20Aplica=20retoques=20por?= =?UTF-8?q?=20ejecuci=C3=B3n=20de=20clippy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.rs | 6 ++++++ src/config.rs | 13 ++++++------- src/trace.rs | 1 - 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/app.rs b/src/app.rs index d21c08a0..082419ab 100644 --- a/src/app.rs +++ b/src/app.rs @@ -11,6 +11,12 @@ use std::sync::LazyLock; pub struct Application; +impl Default for Application { + fn default() -> Self { + Self::new() + } +} + impl Application { /// Crea una instancia de la aplicación. pub fn new() -> Self { diff --git a/src/config.rs b/src/config.rs index eae182fc..d532ba14 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,7 +23,7 @@ //! * Si `PAGETOP_RUN_MODE` no está definida, se asume el valor `default`, y `PageTop` intentará //! cargar *config/default.toml* si el archivo existe. //! -//! * Útil para definir configuraciones específicas por entorno, garantizando que cada uno (p.e. +//! * Útil para definir configuraciones específicas por entorno, garantizando que cada uno (p.ej. //! *dev*, *staging* o *production*) disponga de sus propias opciones, como claves de API, //! URLs o ajustes de rendimiento, sin afectar a los demás. //! @@ -126,7 +126,7 @@ const DEFAULT_RUN_MODE: &str = "default"; /// Valores originales cargados desde los archivos de configuración como pares `clave = valor`. pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new(|| { // Determina el directorio de configuración: - // - Usa CONFIG_DIR si está definido en el entorno (p.e.: CONFIG_DIR=/etc/myapp ./myapp). + // - Usa CONFIG_DIR si está definido en el entorno (p.ej.: CONFIG_DIR=/etc/myapp ./myapp). // - Si no, intenta DEFAULT_CONFIG_DIR dentro del proyecto (en CARGO_MANIFEST_DIR). // - Si nada de esto aplica, entonces usa DEFAULT_CONFIG_DIR relativo al ejecutable. let config_dir: PathBuf = if let Ok(env_dir) = env::var("CONFIG_DIR") { @@ -143,15 +143,15 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( }; // Determina el modo de ejecución según la variable de entorno PAGETOP_RUN_MODE. Por defecto usa - // DEFAULT_RUN_MODE si no está definida (p.e.: PAGETOP_RUN_MODE=production ./myapp). + // DEFAULT_RUN_MODE si no está definida (p.ej.: PAGETOP_RUN_MODE=production ./myapp). let rm = env::var("PAGETOP_RUN_MODE").unwrap_or_else(|_| DEFAULT_RUN_MODE.into()); Config::builder() // 1. Configuración común para todos los entornos (common.toml). .add_source(File::from(config_dir.join("common.toml")).required(false)) - // 2. Configuración específica del entorno (p.e.: default.toml, production.toml). + // 2. Configuración específica del entorno (p.ej.: default.toml, production.toml). .add_source(File::from(config_dir.join(format!("{rm}.toml"))).required(false)) - // 3. Configuración local reservada para cada entorno (p.e.: local.default.toml). + // 3. Configuración local reservada para cada entorno (p.ej.: local.default.toml). .add_source(File::from(config_dir.join(format!("local.{rm}.toml"))).required(false)) // 4. Configuración local común (local.toml). .add_source(File::from(config_dir.join("local.toml")).required(false)) @@ -217,7 +217,7 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( /// * **Valores por defecto**. Declara un valor por defecto para cada clave obligatoria. Las claves /// opcionales pueden ser `Option<T>`. /// -/// * **Secciones únicas**. Agrupa tus claves dentro de una sección exclusiva (p.e. `[blog]`) para +/// * **Secciones únicas**. Agrupa tus claves dentro de una sección exclusiva (p.ej. `[blog]`) para /// evitar colisiones con otras librerías. /// /// * **Solo lectura**. La variable generada es inmutable durante toda la vida del programa. Para @@ -236,7 +236,6 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( /// [dependencies] /// serde = { version = "1.0", features = ["derive"] } /// ``` - #[macro_export] macro_rules! include_config { ( $SETTINGS_NAME:ident : $Settings_Type:ty => [ $( $k:literal => $v:expr ),* $(,)? ] ) => { diff --git a/src/trace.rs b/src/trace.rs index 93a8ff2d..bd8ce56d 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -33,7 +33,6 @@ use std::sync::LazyLock; /// Dado que las trazas o eventos registrados poco antes de un fallo suelen ser cruciales para /// diagnosticar la causa, `Lazy<WorkerGuard>` garantiza que todos los registros almacenados se /// envíen antes de finalizar la ejecución. - #[rustfmt::skip] pub(crate) static TRACING: LazyLock<WorkerGuard> = LazyLock::new(|| { let env_filter = EnvFilter::try_new(&global::SETTINGS.log.tracing) From 896b066ca9f53adf82b622e86916ac55fe936e68 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 9 Jul 2025 20:39:39 +0200 Subject: [PATCH 061/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20soporte=20para?= =?UTF-8?q?=20localizaci=C3=B3n=20y=20traducci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Incluye recursos Fluent básicos y pruebas asociadas. - Nueva variable de configuración global para definir el idioma predeterminado. --- Cargo.lock | 278 ++++++++++++++++++++++++- Cargo.toml | 5 +- src/app.rs | 5 +- src/global.rs | 3 + src/lib.rs | 4 + src/locale.rs | 364 +++++++++++++++++++++++++++++++++ src/locale/en-US/languages.ftl | 5 + src/locale/en-US/test.ftl | 11 + src/locale/es-ES/languages.ftl | 5 + src/locale/es-ES/test.ftl | 11 + src/prelude.rs | 8 + src/util.rs | 26 +++ tests/locale.rs | 58 ++++++ 13 files changed, 780 insertions(+), 3 deletions(-) create mode 100644 src/locale.rs create mode 100644 src/locale/en-US/languages.ftl create mode 100644 src/locale/en-US/test.ftl create mode 100644 src/locale/es-ES/languages.ftl create mode 100644 src/locale/es-ES/test.ftl create mode 100644 src/util.rs create mode 100644 tests/locale.rs diff --git a/Cargo.lock b/Cargo.lock index 3fe4d512..64073ea1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -287,6 +287,16 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bstr" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "bumpalo" version = "3.19.0" @@ -384,6 +394,25 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -492,6 +521,81 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fluent-bundle" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493" +dependencies = [ + "fluent-langneg", + "fluent-syntax", + "intl-memoizer", + "intl_pluralrules", + "rustc-hash 1.1.0", + "self_cell 0.10.3", + "smallvec", + "unic-langid", +] + +[[package]] +name = "fluent-langneg" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "fluent-syntax" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" +dependencies = [ + "thiserror", +] + +[[package]] +name = "fluent-template-macros" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ed02449601d0dacdc05cb5e13db5dab8f2b98d773aff5c53b62fad43a1b19a1" +dependencies = [ + "flume", + "ignore", + "proc-macro2", + "quote", + "syn", + "unic-langid", +] + +[[package]] +name = "fluent-templates" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69855a5fe87629495efca79aec72adfa97954f1006f928e3a2ec750cb3e85386" +dependencies = [ + "fluent-bundle", + "fluent-langneg", + "fluent-syntax", + "fluent-template-macros", + "flume", + "ignore", + "intl-memoizer", + "log", + "thiserror", + "unic-langid", +] + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "spin", +] + [[package]] name = "fnv" version = "1.0.7" @@ -571,6 +675,19 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "globset" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + [[package]] name = "h2" version = "0.3.26" @@ -726,6 +843,22 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "ignore" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata 0.4.9", + "same-file", + "walkdir", + "winapi-util", +] + [[package]] name = "impl-more" version = "0.1.9" @@ -742,6 +875,25 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "intl-memoizer" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310da2e345f5eb861e7a07ee182262e94975051db9e4223e909ba90f392f163f" +dependencies = [ + "type-map", + "unic-langid", +] + +[[package]] +name = "intl_pluralrules" +version = "7.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972" +dependencies = [ + "unic-langid", +] + [[package]] name = "itoa" version = "1.0.15" @@ -918,12 +1070,13 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.0.4" +version = "0.0.5" dependencies = [ "actix-web", "colored", "config", "figlet-rs", + "fluent-templates", "itoa", "pagetop-macros", "serde", @@ -933,6 +1086,7 @@ dependencies = [ "tracing-actix-web", "tracing-appender", "tracing-subscriber", + "unic-langid", ] [[package]] @@ -1052,6 +1206,12 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + [[package]] name = "proc-macro2" version = "1.0.95" @@ -1182,6 +1342,18 @@ version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustix" version = "1.0.7" @@ -1207,12 +1379,36 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "self_cell" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" +dependencies = [ + "self_cell 1.2.0", +] + +[[package]] +name = "self_cell" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" + [[package]] name = "serde" version = "1.0.219" @@ -1323,6 +1519,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -1604,12 +1809,64 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "type-map" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90" +dependencies = [ + "rustc-hash 2.1.1", +] + [[package]] name = "typenum" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +[[package]] +name = "unic-langid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05" +dependencies = [ + "unic-langid-impl", + "unic-langid-macros", +] + +[[package]] +name = "unic-langid-impl" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658" +dependencies = [ + "tinystr", +] + +[[package]] +name = "unic-langid-macros" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5957eb82e346d7add14182a3315a7e298f04e1ba4baac36f7f0dbfedba5fc25" +dependencies = [ + "proc-macro-hack", + "tinystr", + "unic-langid-impl", + "unic-langid-macros-impl", +] + +[[package]] +name = "unic-langid-macros-impl" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1249a628de3ad34b821ecb1001355bca3940bcb2f88558f1a8bd82e977f75b5" +dependencies = [ + "proc-macro-hack", + "quote", + "syn", + "unic-langid-impl", +] + [[package]] name = "unicode-ident" version = "1.0.18" @@ -1662,6 +1919,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -1751,6 +2018,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index b8b3f5fa..bcf1fd50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.4" +version = "0.0.5" edition = "2021" description = """\ @@ -28,6 +28,9 @@ tracing-appender = "0.2.3" tracing-subscriber = { version = "0.3.19", features = ["json", "env-filter"] } tracing-actix-web = "0.7.18" +fluent-templates = "0.13.0" +unic-langid = { version = "0.9.6", features = ["macros"] } + actix-web = "4.11.0" pagetop-macros.workspace = true diff --git a/src/app.rs b/src/app.rs index 082419ab..b02b294a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,7 +2,7 @@ mod figfont; -use crate::{global, service, trace}; +use crate::{global, locale, service, trace}; use substring::Substring; @@ -26,6 +26,9 @@ impl Application { // Inicia gestión de trazas y registro de eventos (logging). LazyLock::force(&trace::TRACING); + // Valida el identificador de idioma por defecto. + LazyLock::force(&locale::DEFAULT_LANGID); + Self } diff --git a/src/global.rs b/src/global.rs index 8432032a..a90aa86c 100644 --- a/src/global.rs +++ b/src/global.rs @@ -8,6 +8,7 @@ include_config!(SETTINGS: Settings => [ // [app] "app.name" => "Sample", "app.description" => "Developed with the amazing PageTop framework.", + "app.language" => "en-US", "app.startup_banner" => "Slant", // [log] @@ -38,6 +39,8 @@ pub struct App { pub name: String, /// Breve descripción de la aplicación. pub description: String, + /// Idioma predeterminado (localización). + pub language: String, /// Banner ASCII mostrado al inicio: *"Off"* (desactivado), *"Slant"*, *"Small"*, *"Speed"* o /// *"Starwars"*. pub startup_banner: String, diff --git a/src/lib.rs b/src/lib.rs index b9b2a4bc..07b99347 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,6 +36,8 @@ pub use pagetop_macros::{html, main, test, AutoDefault}; // API ********************************************************************************************* +// Funciones y macros útiles. +pub mod util; // Carga las opciones de configuración. pub mod config; // Opciones de configuración globales. @@ -44,6 +46,8 @@ pub mod global; pub mod trace; // HTML en código. pub mod html; +// Localización. +pub mod locale; // Gestión del servidor y servicios web. pub mod service; // Prepara y ejecuta la aplicación. diff --git a/src/locale.rs b/src/locale.rs new file mode 100644 index 00000000..064481f0 --- /dev/null +++ b/src/locale.rs @@ -0,0 +1,364 @@ +//! Localización (L10n). +//! +//! `PageTop` utiliza las especificaciones de [Fluent](https://www.projectfluent.org/) para la +//! localización de aplicaciones, y aprovecha [fluent-templates](https://docs.rs/fluent-templates/) +//! para integrar los recursos de traducción directamente en el binario de la aplicación. +//! +//! # Sintaxis Fluent (FTL) +//! +//! El formato empleado para describir los recursos de traducción se denomina +//! [FTL](https://www.projectfluent.org/fluent/guide/). Está diseñado para ser legible y expresivo, +//! permitiendo representar construcciones complejas del lenguaje natural como el género, el plural +//! o las conjugaciones verbales. +//! +//! # Recursos Fluent +//! +//! Por defecto, las traducciones se organizan en el directorio *src/locale*, con subdirectorios +//! para cada [Identificador de Idioma Unicode](https://docs.rs/unic-langid/) válido. Podríamos +//! tener una estructura como esta: +//! +//! ```text +//! src/locale/ +//! ├── common.ftl +//! ├── en-US/ +//! │ ├── default.ftl +//! │ └── main.ftl +//! ├── es-ES/ +//! │ ├── default.ftl +//! │ └── main.ftl +//! ├── es-MX/ +//! │ ├── default.ftl +//! │ └── main.ftl +//! └── fr/ +//! ├── default.ftl +//! └── main.ftl +//! ``` +//! +//! Ejemplo de un archivo *src/locale/en-US/main.ftl*: +//! +//! ```text +//! hello-world = Hello world! +//! hello-user = Hello, {$userName}! +//! shared-photos = +//! {$userName} {$photoCount -> +//! [one] added a new photo +//! *[other] added {$photoCount} new photos +//! } of {$userGender -> +//! [male] him and his family +//! [female] her and her family +//! *[other] the family +//! }. +//! ``` +//! +//! Y su archivo equivalente para español *src/locale/es-ES/main.ftl*: +//! +//! ```text +//! hello-world = Hola mundo! +//! hello-user = ¡Hola, {$userName}! +//! shared-photos = +//! {$userName} {$photoCount -> +//! [one] ha añadido una nueva foto +//! *[other] ha añadido {$photoCount} nuevas fotos +//! } de {$userGender -> +//! [male] él y su familia +//! [female] ella y su familia +//! *[other] la familia +//! }. +//! ``` +//! +//! +//! # Cómo aplicar la localización en tu código +//! +//! Una vez creado el directorio con los recursos FTL, basta con utilizar la macro +//! [`include_locales!`](crate::include_locales) para integrarlos en la aplicación. +//! +//! Si los recursos se encuentran en el directorio `"src/locale"`, sólo hay que declarar: +//! +//! ```rust +//! use pagetop::prelude::*; +//! +//! include_locales!(LOCALES_SAMPLE); +//! ``` +//! +//! Pero si están ubicados en otro directorio, entonces se pueden incluir usando: +//! +//! ```rust,ignore +//! include_locales!(LOCALES_SAMPLE from "ruta/a/las/traducciones"); +//! ``` + +use crate::html::{Markup, PreEscaped}; +use crate::{global, hm, AutoDefault}; + +pub use fluent_templates; +pub use unic_langid::{CharacterDirection, LanguageIdentifier}; + +use unic_langid::langid; + +use fluent_templates::Loader; +use fluent_templates::StaticLoader as Locales; + +use std::borrow::Cow; +use std::collections::HashMap; +use std::sync::LazyLock; + +use std::fmt; + +// Asocia cada código de idioma (como "en-US") con su respectivo [`LanguageIdentifier`] y la clave +// en *locale/.../languages.ftl* para obtener el nombre del idioma según la localización. +static LANGUAGES: LazyLock<HashMap<&str, (LanguageIdentifier, &str)>> = LazyLock::new(|| { + hm![ + "en" => ( langid!("en-US"), "english" ), + "en-GB" => ( langid!("en-GB"), "english_british" ), + "en-US" => ( langid!("en-US"), "english_united_states" ), + "es" => ( langid!("es-ES"), "spanish" ), + "es-ES" => ( langid!("es-ES"), "spanish_spain" ), + ] +}); + +// Identificador del idioma de **respaldo** (predefinido a `en-US`). +// +// Se usa cuando el valor del código de idioma en las traducciones no corresponde con ningún idioma +// soportado por la aplicación. +static FALLBACK_LANGID: LazyLock<LanguageIdentifier> = LazyLock::new(|| langid!("en-US")); + +// Identificador del idioma **por defecto** para la aplicación. +// +// Se resuelve a partir de [`global::SETTINGS.app.language`](global::SETTINGS). Si el código de +// idioma configurado no es válido o no está disponible entonces resuelve como [`FALLBACK_LANGID`]. +pub(crate) static DEFAULT_LANGID: LazyLock<&LanguageIdentifier> = + LazyLock::new(|| LangMatch::langid_or_fallback(&global::SETTINGS.app.language)); + +/// Comprueba si el idioma está soportado por `PageTop`. +/// +/// Útil para transformar un código de idioma en un [`LanguageIdentifier`] válido para `PageTop`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum LangMatch { + /// Cuando el código del idioma es una cadena vacía. + Empty, + /// Si encuentra un [`LanguageIdentifier`] que coincide exactamente o retrocediendo al idioma + /// base. + Found(&'static LanguageIdentifier), + /// Si el código del idioma no está entre los soportados por `PageTop`. + Unknown(String), +} + +impl LangMatch { + /// Resuelve `language` y devuelve el [`LangMatch`] apropiado. + pub fn resolve(language: impl AsRef<str>) -> Self { + let language = language.as_ref().trim(); + + // Rechaza cadenas vacías. + if language.is_empty() { + return Self::Empty; + } + + // Intenta aplicar coincidencia exacta con el código completo (p.ej. "es-MX"). + if let Some(langid) = LANGUAGES.get(language).map(|(langid, _)| langid) { + return Self::Found(langid); + } + + // Si la variante regional no existe, retrocede al idioma base (p.ej. "es"). + if let Some((base_lang, _)) = language.split_once('-') { + if let Some(langid) = LANGUAGES.get(base_lang).map(|(langid, _)| langid) { + return Self::Found(langid); + } + } + + // Devuelve desconocido si el idioma no está soportado. + Self::Unknown(language.to_string()) + } + + /// Devuelve siempre un [`LanguageIdentifier`] válido. + /// + /// Si `language` está vacío o es desconocido, devuelve el idioma de respaldo ("en-US"). + #[inline] + pub fn langid_or_fallback(language: impl AsRef<str>) -> &'static LanguageIdentifier { + match Self::resolve(language) { + Self::Found(l) => l, + _ => &FALLBACK_LANGID, + } + } + + /// Devuelve un [`LanguageIdentifier`] válido para la instancia. + /// + /// Si `language` está vacío o es desconocido, devuelve el idioma de respaldo ("en-US"). + #[inline] + pub fn as_langid(&self) -> &'static LanguageIdentifier { + match self { + LangMatch::Found(l) => l, + _ => &FALLBACK_LANGID, + } + } +} + +#[macro_export] +/// Define un conjunto de elementos de localización y textos de traducción local. +macro_rules! include_locales { + // Se eliminan las marcas de aislamiento Unicode en los argumentos para mejorar la legibilidad y + // la compatibilidad en ciertos contextos de renderizado. + ( $LOCALES:ident $(, $core_locales:literal)? ) => { + $crate::locale::fluent_templates::static_loader! { + static $LOCALES = { + locales: "src/locale", + $( core_locales: $core_locales, )? + fallback_language: "en-US", + // Elimina marcas de aislamiento Unicode en los argumentos. + customise: |bundle| bundle.set_use_isolating(false), + }; + } + }; + ( $LOCALES:ident from $dir_locales:literal $(, $core_locales:literal)? ) => { + $crate::locale::fluent_templates::static_loader! { + static $LOCALES = { + locales: $dir_locales, + $( core_locales: $core_locales, )? + fallback_language: "en-US", + // Elimina marcas de aislamiento Unicode en los argumentos. + customise: |bundle| bundle.set_use_isolating(false), + }; + } + }; +} + +include_locales!(LOCALES_PAGETOP); + +// Operación de localización a realizar. +// +// * `None` - No se aplica ninguna localización. +// * `Text` - Con una cadena literal que se devolverá tal cual. +// * `Translate` - Con la clave a resolver en el `Locales` indicado. +#[derive(AutoDefault)] +enum L10nOp { + #[default] + None, + Text(String), + Translate(String), +} + +/// Crea instancias para traducir textos localizados. +/// +/// Cada instancia puede representar: +/// +/// - Un texto puro (`n()`) que no requiere traducción. +/// - Una clave para traducir un texto de las traducciones por defecto de `PageTop` (`l()`). +/// - Una clave para traducir de un conjunto concreto de traducciones (`t()`). +/// +/// Los argumentos dinámicos se añaden mediante `with_arg()` o `with_args()`. +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// // Texto literal sin traducción. +/// let raw = L10n::n("© 2025 PageTop").get(); +/// +/// // Traducción simple con clave y argumentos. +/// let hello = L10n::l("greeting") +/// .with_arg("name", "Manuel") +/// .markup(); +/// ``` +/// +/// También para traducciones a idiomas concretos. +/// +/// ```rust,ignore +/// // Traducción con clave, conjunto de traducciones y código de idioma a usar. +/// let bye = L10n::t("goodbye", &LOCALES_CUSTOM).using(LangMatch::langid_or_fallback("it")); +/// ``` +#[derive(AutoDefault)] +pub struct L10n { + op: L10nOp, + #[default(&LOCALES_PAGETOP)] + locales: &'static Locales, + args: HashMap<String, String>, +} + +impl L10n { + /// **n** = *“native”*. Crea una instancia con una cadena literal sin traducción. + pub fn n(text: impl Into<String>) -> Self { + L10n { + op: L10nOp::Text(text.into()), + ..Default::default() + } + } + + /// **l** = *“lookup”*. Crea una instancia para traducir usando una clave de la tabla de + /// traducciones por defecto. + pub fn l(key: impl Into<String>) -> Self { + L10n { + op: L10nOp::Translate(key.into()), + ..Default::default() + } + } + + /// **t** = *“translate”*. Crea una instancia para traducir usando una clave de una tabla de + /// traducciones específica. + pub fn t(key: impl Into<String>, locales: &'static Locales) -> Self { + L10n { + op: L10nOp::Translate(key.into()), + locales, + ..Default::default() + } + } + + /// Añade un argumento `{$arg}` → `value` a la traducción. + pub fn with_arg(mut self, arg: impl Into<String>, value: impl Into<String>) -> Self { + self.args.insert(arg.into(), value.into()); + self + } + + /// Añade varios argumentos a la traducción de una sola vez (p.ej. usando la macro [`hm!`], + /// también vec![("k", "v")], incluso un array de duplas u otras colecciones). + pub fn with_args<I, K, V>(mut self, args: I) -> Self + where + I: IntoIterator<Item = (K, V)>, + K: Into<String>, + V: Into<String>, + { + self.args + .extend(args.into_iter().map(|(k, v)| (k.into(), v.into()))); + self + } + + /// Resuelve la traducción usando el idioma por defecto de la aplicación. Devuelve `None` si no + /// aplica o no encuentra una traducción. + pub fn get(&self) -> Option<String> { + self.using(&DEFAULT_LANGID) + } + + /// Resuelve la traducción usando el [`LanguageIdentifier`] indicado. Devuelve `None` si no + /// aplica o no encuentra una traducción. + pub fn using(&self, langid: &LanguageIdentifier) -> Option<String> { + match &self.op { + L10nOp::None => None, + L10nOp::Text(text) => Some(text.to_owned()), + L10nOp::Translate(key) => self.locales.try_lookup_with_args( + langid, + key, + &self.args.iter().fold(HashMap::new(), |mut arg, (k, v)| { + arg.insert(Cow::Owned(k.clone()), v.to_owned().into()); + arg + }), + ), + } + } + + /// 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 fmt::Display for L10n { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let content = match &self.op { + L10nOp::None => String::new(), + L10nOp::Text(text) => text.clone(), + L10nOp::Translate(key) => self.get().unwrap_or_else(|| format!("??<{}>", key)), + }; + write!(f, "{content}") + } +} diff --git a/src/locale/en-US/languages.ftl b/src/locale/en-US/languages.ftl new file mode 100644 index 00000000..1e816605 --- /dev/null +++ b/src/locale/en-US/languages.ftl @@ -0,0 +1,5 @@ +english = English +english_british = English (British) +english_united_states = English (United States) +spanish = Spanish +spanish_spain = Spanish (Spain) diff --git a/src/locale/en-US/test.ftl b/src/locale/en-US/test.ftl new file mode 100644 index 00000000..3c317fcb --- /dev/null +++ b/src/locale/en-US/test.ftl @@ -0,0 +1,11 @@ +test-hello-world = Hello world! +test-hello-user = Hello, { $userName }! +test-shared-photos = + { $userName } { $photoCount -> + [one] added a new photo + *[other] added { $photoCount } new photos + } of { $userGender -> + [male] him and his family + [female] her and her family + *[other] their family + }. diff --git a/src/locale/es-ES/languages.ftl b/src/locale/es-ES/languages.ftl new file mode 100644 index 00000000..ee74ec26 --- /dev/null +++ b/src/locale/es-ES/languages.ftl @@ -0,0 +1,5 @@ +english = Inglés +english_british = Inglés (Gran Bretaña) +english_united_states = Inglés (Estados Unidos) +spanish = Español +spanish_spain = Español (España) diff --git a/src/locale/es-ES/test.ftl b/src/locale/es-ES/test.ftl new file mode 100644 index 00000000..02cd22e3 --- /dev/null +++ b/src/locale/es-ES/test.ftl @@ -0,0 +1,11 @@ +test-hello-world = ¡Hola mundo! +test-hello-user = ¡Hola, { $userName }! +test-shared-photos = + { $userName } { $photoCount -> + [one] ha añadido una nueva foto + *[other] ha añadido { $photoCount } nuevas fotos + } de { $userGender -> + [male] él y su familia + [female] ella y su familia + *[other] la familia + }. diff --git a/src/prelude.rs b/src/prelude.rs index 872447aa..af29d376 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -8,17 +8,25 @@ pub use crate::AutoDefault; // MACROS. +// crate::util +pub use crate::hm; // crate::config pub use crate::include_config; +// crate::locale +pub use crate::include_locales; // API. +pub use crate::util; + pub use crate::global; pub use crate::trace; pub use crate::html::*; +pub use crate::locale::*; + pub use crate::service; pub use crate::app::Application; diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 00000000..07a6abdb --- /dev/null +++ b/src/util.rs @@ -0,0 +1,26 @@ +//! Funciones y macros útiles. + +// MACROS ÚTILES *********************************************************************************** + +#[macro_export] +/// Macro para construir una colección de pares clave-valor. +/// +/// ```rust +/// use pagetop::hm; +/// use std::collections::HashMap; +/// +/// let args:HashMap<&str, String> = hm![ +/// "userName" => "Roberto", +/// "photoCount" => "3", +/// "userGender" => "male", +/// ]; +/// ``` +macro_rules! hm { + ( $($key:expr => $value:expr),* $(,)? ) => {{ + let mut a = std::collections::HashMap::new(); + $( + a.insert($key.into(), $value.into()); + )* + a + }}; +} diff --git a/tests/locale.rs b/tests/locale.rs new file mode 100644 index 00000000..c723cd46 --- /dev/null +++ b/tests/locale.rs @@ -0,0 +1,58 @@ +use pagetop::prelude::*; + +#[pagetop::test] +async fn literal_text() { + let _app = service::test::init_service(Application::new().test()).await; + + let l10n = L10n::n("© 2025 PageTop"); + assert_eq!(l10n.get(), Some("© 2025 PageTop".to_string())); +} + +#[pagetop::test] +async fn translation_without_args() { + let _app = service::test::init_service(Application::new().test()).await; + + let l10n = L10n::l("test-hello-world"); + let translation = l10n.using(LangMatch::langid_or_fallback("es-ES")); + assert_eq!(translation, Some("¡Hola mundo!".to_string())); +} + +#[pagetop::test] +async fn translation_with_args() { + let _app = service::test::init_service(Application::new().test()).await; + + let l10n = L10n::l("test-hello-user").with_arg("userName", "Manuel"); + let translation = l10n.using(LangMatch::langid_or_fallback("es-ES")); + assert_eq!(translation, Some("¡Hola, Manuel!".to_string())); +} + +#[pagetop::test] +async fn translation_with_plural_and_select() { + let _app = service::test::init_service(Application::new().test()).await; + + let l10n = L10n::l("test-shared-photos").with_args(vec![ + ("userName", "Roberto"), + ("photoCount", "3"), + ("userGender", "male"), + ]); + let translation = l10n.using(LangMatch::langid_or_fallback("es-ES")).unwrap(); + assert!(translation.contains("añadido 3 nuevas fotos de él")); +} + +#[pagetop::test] +async fn check_fallback_language() { + let _app = service::test::init_service(Application::new().test()).await; + + let l10n = L10n::l("test-hello-world"); + let translation = l10n.using(LangMatch::langid_or_fallback("xx-YY")); // Fallback a "en-US". + assert_eq!(translation, Some("Hello world!".to_string())); +} + +#[pagetop::test] +async fn check_unknown_key() { + let _app = service::test::init_service(Application::new().test()).await; + + let l10n = L10n::l("non-existent-key"); + let translation = l10n.using(LangMatch::langid_or_fallback("en-US")); + assert_eq!(translation, None); +} From 22faea7d403d2ec531f3f94e709d37d470f958ec Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 9 Jul 2025 20:51:43 +0200 Subject: [PATCH 062/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20soporte=20para?= =?UTF-8?q?=20manejo=20de=20fechas=20y=20horas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 166 ++++++++++++++++++++++++++++++++++++++++++++---- Cargo.toml | 5 +- src/datetime.rs | 4 ++ src/lib.rs | 2 + src/prelude.rs | 2 + 5 files changed, 165 insertions(+), 14 deletions(-) create mode 100644 src/datetime.rs diff --git a/Cargo.lock b/Cargo.lock index 64073ea1..50660b36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -224,6 +224,21 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -335,6 +350,20 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + [[package]] name = "colored" version = "3.0.0" @@ -346,9 +375,9 @@ dependencies = [ [[package]] name = "config" -version = "0.15.11" +version = "0.15.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595aae20e65c3be792d05818e8c63025294ac3cb7e200f11459063a352a6ef80" +checksum = "5b1eb4fb07bc7f012422df02766c7bd5971effb894f573865642f06fa3265440" dependencies = [ "pathdiff", "serde", @@ -367,6 +396,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -736,6 +771,30 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "2.0.0" @@ -1047,6 +1106,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.36.7" @@ -1070,9 +1138,10 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.0.5" +version = "0.0.6" dependencies = [ "actix-web", + "chrono", "colored", "config", "figlet-rs", @@ -1443,9 +1512,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.9" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" dependencies = [ "serde", ] @@ -1677,14 +1746,15 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.23" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +checksum = "f271e09bde39ab52250160a67e88577e0559ad77e9085de6e9051a2c4353f8f8" dependencies = [ "serde", "serde_spanned", - "toml_datetime", - "toml_edit", + "toml_datetime 0.7.0", + "toml_parser", + "winnow", ] [[package]] @@ -1692,6 +1762,12 @@ name = "toml_datetime" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" + +[[package]] +name = "toml_datetime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" dependencies = [ "serde", ] @@ -1703,9 +1779,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", - "serde", - "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5c1c469eda89749d2230d8156a5969a69ffe0d6d01200581cdc6110674d293e" +dependencies = [ "winnow", ] @@ -2033,6 +2116,65 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index bcf1fd50..c2cfbd59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.5" +version = "0.0.6" edition = "2021" description = """\ @@ -15,8 +15,9 @@ license.workspace = true authors.workspace = true [dependencies] +chrono = "0.4.41" colored = "3.0.0" -config = { version = "0.15.11", default-features = false, features = ["toml"] } +config = { version = "0.15.13", default-features = false, features = ["toml"] } figlet-rs = "0.1.5" itoa = "1.0.15" serde.workspace = true diff --git a/src/datetime.rs b/src/datetime.rs new file mode 100644 index 00000000..2e8b6229 --- /dev/null +++ b/src/datetime.rs @@ -0,0 +1,4 @@ +//! Soporte a fechas y horas según estándar [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) +//! (basado en [chrono](https://docs.rs/chrono)). + +pub use chrono::prelude::*; diff --git a/src/lib.rs b/src/lib.rs index 07b99347..d7a97e25 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,6 +48,8 @@ pub mod trace; pub mod html; // Localización. pub mod locale; +// Soporte a fechas y horas. +pub mod datetime; // Gestión del servidor y servicios web. pub mod service; // Prepara y ejecuta la aplicación. diff --git a/src/prelude.rs b/src/prelude.rs index af29d376..cc38877a 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -27,6 +27,8 @@ pub use crate::html::*; pub use crate::locale::*; +pub use crate::datetime::*; + pub use crate::service; pub use crate::app::Application; From 835aacf1fa52569a4269562adf2c086e1ee77685 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 9 Jul 2025 21:59:09 +0200 Subject: [PATCH 063/244] =?UTF-8?q?=F0=9F=8D=B1=20A=C3=B1ade=20el=20banner?= =?UTF-8?q?=20de=20PageTop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/banner.png | Bin 0 -> 74026 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 static/banner.png diff --git a/static/banner.png b/static/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..422e493e0060ac723a13b5e13b8a9d64b2b257d1 GIT binary patch literal 74026 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 literal 0 HcmV?d00001 From 412524018a6551360b7d29a16eefb0b2e38981b1 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 9 Jul 2025 22:05:42 +0200 Subject: [PATCH 064/244] =?UTF-8?q?=F0=9F=93=9D=20Actualiza=20el=20banner?= =?UTF-8?q?=20en=20la=20documentaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 +++++++++ src/lib.rs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 159aabe0..94062a0e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ <div align="center"> +<img src="https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/banner.png" /> + <h1>PageTop</h1> <p>Un entorno para el desarrollo de soluciones web modulares, extensibles y configurables.</p> @@ -26,6 +28,13 @@ async fn main() -> std::io::Result<()> { ``` +# 🚧 Advertencia + +`PageTop` es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su +ecosistema. Su API está sujeta a cambios frecuentes. No se recomienda su uso en producción, al menos +hasta que se libere la versión **1.0.0**. + + # 📜 Licencia El código está disponible bajo una doble licencia: diff --git a/src/lib.rs b/src/lib.rs index d7a97e25..4519c440 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ //! <div align="center"> //! -//! <img src="https://raw.githubusercontent.com/manuelcillero/pagetop/main/static/banner.png" /> +//! <img src="https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/banner.png" /> //! //! <h1>PageTop</h1> //! From 8bc1d00cb9b9a74f6a80e8e6768f9ff4f3872233 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 10 Jul 2025 22:51:47 +0200 Subject: [PATCH 065/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20est=C3=A1ticos?= =?UTF-8?q?=20y=20SCSS=20compilados=20para=20binarios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Módulo auxiliar para ejecutar durante la compilación de proyectos de PageTop para incluir archivos estáticos o archivos SCSS compilados en los binarios de los proyectos. --- Cargo.toml | 15 +- helpers/pagetop-build/Cargo.toml | 20 +++ helpers/pagetop-build/README.md | 36 +++++ helpers/pagetop-build/src/lib.rs | 259 +++++++++++++++++++++++++++++++ 4 files changed, 323 insertions(+), 7 deletions(-) create mode 100644 helpers/pagetop-build/Cargo.toml create mode 100644 helpers/pagetop-build/README.md create mode 100644 helpers/pagetop-build/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index c2cfbd59..a91964bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.6" +version = "0.0.7" edition = "2021" description = """\ @@ -20,7 +20,7 @@ colored = "3.0.0" config = { version = "0.15.13", default-features = false, features = ["toml"] } figlet-rs = "0.1.5" itoa = "1.0.15" -serde.workspace = true +paste = { package = "pastey", version = "0.1.0" } substring = "1.4.5" terminal_size = "0.4.2" @@ -33,14 +33,18 @@ fluent-templates = "0.13.0" unic-langid = { version = "0.9.6", features = ["macros"] } actix-web = "4.11.0" +static-files.workspace = true -pagetop-macros.workspace = true +serde = { version = "1.0", features = ["derive"] } + +pagetop-macros = { version = "0.0", path = "helpers/pagetop-macros" } [workspace] resolver = "2" members = [ + "helpers/pagetop-build", "helpers/pagetop-macros", ] @@ -51,7 +55,4 @@ license = "MIT OR Apache-2.0" authors = ["Manuel Cillero <manuel@cillero.es>"] [workspace.dependencies] -serde = { version = "1.0", features = ["derive"] } - -# Helpers -pagetop-macros = { version = "0.0", path = "helpers/pagetop-macros" } +static-files = "0.2.5" diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml new file mode 100644 index 00000000..4b947b3e --- /dev/null +++ b/helpers/pagetop-build/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "pagetop-build" +version = "0.0.1" +edition = "2021" + +description = """\ + Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el \ + binario de un proyecto PageTop.\ +""" +categories = ["development-tools::build-utils", "web-programming"] +keywords = ["pagetop", "build", "assets", "resources", "static"] + +repository.workspace = true +homepage.workspace = true +license.workspace = true +authors.workspace = true + +[dependencies] +grass = "0.13.4" +static-files.workspace = true diff --git a/helpers/pagetop-build/README.md b/helpers/pagetop-build/README.md new file mode 100644 index 00000000..9f912e99 --- /dev/null +++ b/helpers/pagetop-build/README.md @@ -0,0 +1,36 @@ +<div align="center"> + +<h1>PageTop Build</h1> + +<p>Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el binario de un proyecto <strong>PageTop</strong>.</p> + +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) + +</div> + +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + + +# 🚧 Advertencia + +`PageTop` es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su +ecosistema. Su API está sujeta a cambios frecuentes. No se recomienda su uso en producción, al menos +hasta que se libere la versión **1.0.0**. + + +# 📜 Licencia + +El código está disponible bajo una doble licencia: + + * **Licencia MIT** + ([LICENSE-MIT](LICENSE-MIT) o también https://opensource.org/licenses/MIT) + + * **Licencia Apache, Versión 2.0** + ([LICENSE-APACHE](LICENSE-APACHE) o también https://www.apache.org/licenses/LICENSE-2.0) + +Puedes elegir la licencia que prefieras. Este enfoque de doble licencia es el estándar de facto en +el ecosistema Rust. diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs new file mode 100644 index 00000000..c48b21fc --- /dev/null +++ b/helpers/pagetop-build/src/lib.rs @@ -0,0 +1,259 @@ +//! <div align="center"> +//! +//! <h1>PageTop Build</h1> +//! +//! <p>Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el binario de un proyecto <strong>PageTop</strong>.</p> +//! +//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +//! +//! </div> +//! +//! ## Sobre PageTop +//! +//! [PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la +//! web clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles +//! y configurables, basadas en HTML, CSS y JavaScript. +//! +//! +//! # ⚡️ Guía rápida +//! +//! Añadir en el archivo `Cargo.toml` del proyecto: +//! +//! ```toml +//! [build-dependencies] +//! pagetop-build = { ... } +//! ``` +//! +//! Y crear un archivo `build.rs` a la altura de `Cargo.toml` para indicar cómo se van a incluir los +//! archivos estáticos o cómo se van a compilar los archivos SCSS para el proyecto. Casos de uso: +//! +//! ## Incluir archivos estáticos desde un directorio +//! +//! Hay que preparar una carpeta en el proyecto con todos los archivos que se quieren incluir, por +//! ejemplo `static`, y añadir el siguiente código en `build.rs` para crear el conjunto de recursos: +//! +//! ```rust,no_run +//! use pagetop_build::StaticFilesBundle; +//! +//! fn main() -> std::io::Result<()> { +//! StaticFilesBundle::from_dir("./static", None) +//! .with_name("guides") +//! .build() +//! } +//! ``` +//! +//! Si es necesario, se puede añadir un filtro para seleccionar archivos específicos de la carpeta, +//! por ejemplo: +//! +//! ```rust,no_run +//! use pagetop_build::StaticFilesBundle; +//! use std::path::Path; +//! +//! fn main() -> std::io::Result<()> { +//! fn only_pdf_files(path: &Path) -> bool { +//! // Selecciona únicamente los archivos con extensión `.pdf`. +//! path.extension().map_or(false, |ext| ext == "pdf") +//! } +//! +//! StaticFilesBundle::from_dir("./static", Some(only_pdf_files)) +//! .with_name("guides") +//! .build() +//! } +//! ``` +//! +//! ## Compilar archivos SCSS a CSS +//! +//! Se puede compilar un archivo SCSS, que podría importar otros a su vez, para preparar un recurso +//! con el archivo CSS minificado obtenido. Por ejemplo: +//! +//! ```rust,no_run +//! use pagetop_build::StaticFilesBundle; +//! +//! fn main() -> std::io::Result<()> { +//! StaticFilesBundle::from_scss("./styles/main.scss", "styles.min.css") +//! .with_name("main_styles") +//! .build() +//! } +//! ``` +//! +//! Este código compila el archivo `main.scss` de la carpeta `static` del proyecto, y prepara un +//! recurso llamado `main_styles` que contiene el archivo `styles.min.css` obtenido. +//! +//! +//! # 📦 Módulos generados +//! +//! Cada conjunto de recursos [`StaticFilesBundle`] genera un archivo en el directorio estándar +//! [OUT_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) +//! donde se incluyen los recursos necesarios para compilar el proyecto. Por ejemplo, para +//! `with_name("guides")` se crea un archivo llamado `guides.rs`. +//! +//! No hay ningún problema en generar más de un conjunto de recursos para cada proyecto. +//! +//! Normalmente no habrá que acceder a estos módulos; bastará con incluirlos en el proyecto con +//! [`include_files!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files.html), y luego con +//! [`include_files_service!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files_service.html) +//! configurar un servicio web para servir los recursos desde la ruta indicada: +//! +//! ```rust,ignore +//! use pagetop::prelude::*; +//! +//! include_files!(guides); +//! +//! pub struct MyExtension; +//! +//! impl ExtensionTrait for MyExtension { +//! // Servicio web que publica los recursos de `guides` en `/ruta/a/guides`. +//! fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { +//! include_files_service!(scfg, guides => "/ruta/a/guides"); +//! } +//! } +//! ``` +//! +//! También se puede acceder al conjunto de recursos declarando un `HashMap` estático global: +//! +//! ```rust,ignore +//! include_files!(HM_GUIDES => guides); +//! ``` + +use grass::{from_path, Options, OutputStyle}; +use static_files::{resource_dir, ResourceDir}; + +use std::fs::{create_dir_all, remove_dir_all, File}; +use std::io::Write; +use std::path::Path; + +/// Prepara un conjunto de recursos para ser incluidos en el binario del proyecto utilizando +/// [static_files](https://docs.rs/static-files/). +pub struct StaticFilesBundle { + resource_dir: ResourceDir, +} + +impl StaticFilesBundle { + /// Prepara el conjunto de recursos con los archivos de un directorio. Opcionalmente se puede + /// aplicar un filtro para seleccionar un subconjunto de los archivos. + /// + /// # Argumentos + /// + /// * `dir` - Directorio que contiene los archivos. + /// * `filter` - Una función opcional para aceptar o no un archivo según su ruta. + /// + /// # Ejemplo + /// + /// ```rust,no_run + /// use pagetop_build::StaticFilesBundle; + /// use std::path::Path; + /// + /// fn main() -> std::io::Result<()> { + /// fn only_images(path: &Path) -> bool { + /// matches!( + /// path.extension().and_then(|ext| ext.to_str()), + /// Some("jpg" | "png" | "gif") + /// ) + /// } + /// + /// StaticFilesBundle::from_dir("./static", Some(only_images)) + /// .with_name("images") + /// .build() + /// } + /// ``` + pub fn from_dir(dir: &'static str, filter: Option<fn(p: &Path) -> bool>) -> Self { + let mut resource_dir = resource_dir(dir); + + // Aplica el filtro si está definido. + if let Some(f) = filter { + resource_dir.with_filter(f); + } + + // Identifica el directorio temporal de recursos. + StaticFilesBundle { resource_dir } + } + + /// Prepara un recurso CSS minimizado a partir de la compilación de un archivo SCSS (que puede a + /// su vez importar otros archivos SCSS). + /// + /// # Argumentos + /// + /// * `path` - Archivo SCSS a compilar. + /// * `target_name` - Nombre para el archivo CSS. + /// + /// # Ejemplo + /// + /// ```rust,no_run + /// use pagetop_build::StaticFilesBundle; + /// + /// fn main() -> std::io::Result<()> { + /// StaticFilesBundle::from_scss("./bootstrap/scss/main.scss", "bootstrap.min.css") + /// .with_name("bootstrap_css") + /// .build() + /// } + /// ``` + pub fn from_scss<P>(path: P, target_name: &str) -> Self + where + P: AsRef<Path>, + { + // Crea un directorio temporal para el archivo CSS. + let out_dir = std::env::var("OUT_DIR").unwrap(); + let temp_dir = Path::new(&out_dir).join("from_scss_files"); + + // Limpia el directorio temporal de ejecuciones previas, si existe. + if temp_dir.exists() { + remove_dir_all(&temp_dir).unwrap_or_else(|e| { + panic!( + "Failed to clean temporary directory `{}`: {e}", + temp_dir.display() + ); + }); + } + create_dir_all(&temp_dir).unwrap_or_else(|e| { + panic!( + "Failed to create temporary directory `{}`: {e}", + temp_dir.display() + ); + }); + + // Compila SCSS a CSS. + let css_content = from_path( + path.as_ref(), + &Options::default().style(OutputStyle::Compressed), + ) + .unwrap_or_else(|e| { + panic!( + "Failed to compile SCSS file `{}`: {e}", + path.as_ref().display(), + ) + }); + + // Guarda el archivo CSS compilado en el directorio temporal. + let css_path = temp_dir.join(target_name); + File::create(&css_path) + .expect(&format!( + "Failed to create CSS file `{}`", + css_path.display() + )) + .write_all(css_content.as_bytes()) + .expect(&format!( + "Failed to write CSS content to `{}`", + css_path.display() + )); + + // Identifica el directorio temporal de recursos. + StaticFilesBundle { + resource_dir: resource_dir(temp_dir.to_str().unwrap()), + } + } + + /// Asigna un nombre al conjunto de recursos. + pub fn with_name(mut self, name: &'static str) -> Self { + let out_dir = std::env::var("OUT_DIR").unwrap(); + let filename = Path::new(&out_dir).join(format!("{name}.rs")); + self.resource_dir.with_generated_filename(filename); + self.resource_dir.with_module_name(format!("bundle_{name}")); + self.resource_dir.with_generated_fn(name); + self + } + + /// Contruye finalmente el conjunto de recursos para incluir en el binario de la aplicación. + pub fn build(self) -> std::io::Result<()> { + self.resource_dir.build() + } +} From f37a128044ef33fe0d2c479e5b1af76d621bb18c Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 11 Jul 2025 22:17:59 +0200 Subject: [PATCH 066/244] =?UTF-8?q?=F0=9F=9A=A9=20A=C3=B1ade=20feature=20"?= =?UTF-8?q?testing"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Permite desactivar trazas y registro de eventos al ejecutar tests. - Añade opción de configuración para activar o desactivar las trazas. --- .cargo/config.toml | 3 + Cargo.lock | 385 +++++++++++++++++++++++++++++- Cargo.toml | 9 +- README.md | 16 ++ helpers/pagetop-macros/src/lib.rs | 4 +- src/global.rs | 3 + src/trace.rs | 8 + 7 files changed, 416 insertions(+), 12 deletions(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..d29b0de3 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,3 @@ +[alias] +ts = ["test", "--features", "testing"] # cargo ts +tw = ["test", "--workspace", "--features", "testing"] # cargo tw diff --git a/Cargo.lock b/Cargo.lock index 50660b36..24c9616f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,7 +49,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand", + "rand 0.9.1", "sha1", "smallvec", "tokio", @@ -200,6 +200,18 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -224,6 +236,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -239,6 +257,56 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.59.0", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -350,6 +418,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +[[package]] +name = "change-detection" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "159fa412eae48a1d94d0b9ecdb85c97ce56eb2a347c62394d3fdbf221adabc1a" +dependencies = [ + "path-matchers", + "path-slash", +] + [[package]] name = "chrono" version = "0.4.41" @@ -364,6 +442,45 @@ dependencies = [ "windows-link", ] +[[package]] +name = "clap" +version = "4.5.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "codemap" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + [[package]] name = "colored" version = "3.0.0" @@ -515,6 +632,12 @@ dependencies = [ "syn", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -540,6 +663,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "figlet-rs" version = "0.1.5" @@ -692,6 +821,19 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", +] + [[package]] name = "getrandom" version = "0.3.3" @@ -710,6 +852,12 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + [[package]] name = "globset" version = "0.4.16" @@ -723,6 +871,31 @@ dependencies = [ "regex-syntax 0.8.5", ] +[[package]] +name = "grass" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a68216437ef68f0738e48d6c7bb9e6e6a92237e001b03d838314b068f33c94" +dependencies = [ + "clap", + "getrandom 0.2.16", + "grass_compiler", +] + +[[package]] +name = "grass_compiler" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d9e3df7f0222ce5184154973d247c591d9aadc28ce7a73c6cd31100c9facff6" +dependencies = [ + "codemap", + "indexmap", + "lasso", + "once_cell", + "phf", + "rand 0.8.5", +] + [[package]] name = "h2" version = "0.3.26" @@ -742,6 +915,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + [[package]] name = "hashbrown" version = "0.15.4" @@ -931,7 +1114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.4", ] [[package]] @@ -953,6 +1136,12 @@ dependencies = [ "unic-langid", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" version = "1.0.15" @@ -965,7 +1154,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom", + "getrandom 0.3.3", "libc", ] @@ -985,6 +1174,15 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" +[[package]] +name = "lasso" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e14eda50a3494b3bf7b9ce51c52434a761e383d7238ce1dd5dcec2fbc13e9fb" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1063,6 +1261,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1130,6 +1338,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "overload" version = "0.1.1" @@ -1138,18 +1352,22 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.0.6" +version = "0.0.8" dependencies = [ "actix-web", "chrono", "colored", "config", + "dunce", "figlet-rs", "fluent-templates", "itoa", "pagetop-macros", + "pastey", "serde", + "static-files", "substring", + "tempfile", "terminal_size", "tracing", "tracing-actix-web", @@ -1158,6 +1376,14 @@ dependencies = [ "unic-langid", ] +[[package]] +name = "pagetop-build" +version = "0.0.1" +dependencies = [ + "grass", + "static-files", +] + [[package]] name = "pagetop-macros" version = "0.0.3" @@ -1192,6 +1418,27 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "pastey" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a8cb46bdc156b1c90460339ae6bfd45ba0394e5effbaa640badb4987fdc261" + +[[package]] +name = "path-matchers" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36cd9b72a47679ec193a5f0229d9ab686b7bd45e1fbc59ccf953c9f3d83f7b2b" +dependencies = [ + "glob", +] + +[[package]] +name = "path-slash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498a099351efa4becc6a19c72aa9270598e8fd274ca47052e37455241c88b696" + [[package]] name = "pathdiff" version = "0.2.3" @@ -1204,6 +1451,48 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -1317,14 +1606,35 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ - "rand_chacha", - "rand_core", + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -1334,7 +1644,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", ] [[package]] @@ -1343,7 +1662,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom", + "getrandom 0.3.3", ] [[package]] @@ -1566,6 +1885,12 @@ dependencies = [ "libc", ] +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.10" @@ -1603,6 +1928,23 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static-files" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9c425c07353535ef55b45420f5a8b0a397cd9bc3d7e5236497ca0d90604aa9b" +dependencies = [ + "change-detection", + "mime_guess", + "path-slash", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "substring" version = "1.4.5" @@ -1634,6 +1976,19 @@ dependencies = [ "syn", ] +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "terminal_size" version = "0.4.2" @@ -1950,6 +2305,12 @@ dependencies = [ "unic-langid-impl", ] +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -1979,13 +2340,19 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ - "getrandom", + "getrandom 0.3.3", "js-sys", "wasm-bindgen", ] diff --git a/Cargo.toml b/Cargo.toml index a91964bb..3ef84687 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.7" +version = "0.0.8" edition = "2021" description = """\ @@ -39,6 +39,13 @@ serde = { version = "1.0", features = ["derive"] } pagetop-macros = { version = "0.0", path = "helpers/pagetop-macros" } +[features] +default = [] +testing = [] + +[dev-dependencies] +tempfile = "3.20.0" + [workspace] diff --git a/README.md b/README.md index 94062a0e..6b4aff0c 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,22 @@ async fn main() -> std::io::Result<()> { ``` +# 🧪 Pruebas + +Para simplificar el flujo de trabajo, el repositorio incluye varios **alias de Cargo** declarados en +`.cargo/config.toml`. Basta con ejecutarlos desde la raíz del proyecto: + +| Comando | Descripción | +| ------- | ----------- | +| `cargo ts` | Ejecuta los tests de `pagetop` (*unit + integration*) con la *feature* `testing`. | +| `cargo ts --test util` | Lanza sólo las pruebas de integración del módulo `util`. | +| `cargo tw` | Ejecuta los tests de **todos los paquetes** del *workspace*. | + +> **Nota** +> Estos alias ya compilan con la configuración adecuada. No requieren `--no-default-features`. +> Si quieres **activar** las trazas del registro de eventos entonces usa simplemente `cargo test`. + + # 🚧 Advertencia `PageTop` es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index eecebed3..776903c0 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -45,7 +45,7 @@ pub fn derive_auto_default(input: TokenStream) -> TokenStream { /// Define una función `main` asíncrona como punto de entrada de `PageTop`. /// -/// # Ejemplos +/// # Ejemplo /// /// ```rust,ignore /// #[pagetop::main] @@ -66,7 +66,7 @@ pub fn main(_: TokenStream, item: TokenStream) -> TokenStream { /// Define funciones de prueba asíncronas para usar con `PageTop`. /// -/// # Ejemplos +/// # Ejemplo /// /// ```rust,ignore /// #[pagetop::test] diff --git a/src/global.rs b/src/global.rs index a90aa86c..c3332d39 100644 --- a/src/global.rs +++ b/src/global.rs @@ -12,6 +12,7 @@ include_config!(SETTINGS: Settings => [ "app.startup_banner" => "Slant", // [log] + "log.enabled" => true, "log.tracing" => "Info", "log.rolling" => "Stdout", "log.path" => "log", @@ -52,6 +53,8 @@ pub struct App { #[derive(Debug, Deserialize)] /// Sección `[log]` de la configuración. Forma parte de [`Settings`]. pub struct Log { + /// Gestión de trazas y registro de eventos activado (`true`) o desactivado (`false`). + pub enabled: bool, /// Opciones, o combinación de opciones separadas por comas, para filtrar las trazas: *"Error"*, /// *"Warn"*, *"Info"*, *"Debug"* o *"Trace"*. /// Ejemplo: "Error,actix_server::builder=Info,tracing_actix_web=Debug". diff --git a/src/trace.rs b/src/trace.rs index bd8ce56d..c57c6a3c 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -35,6 +35,14 @@ use std::sync::LazyLock; /// envíen antes de finalizar la ejecución. #[rustfmt::skip] pub(crate) static TRACING: LazyLock<WorkerGuard> = LazyLock::new(|| { + if !global::SETTINGS.log.enabled || cfg!(test) || cfg!(feature = "testing") { + // Tracing desactivado, se instala un subscriber nulo. + tracing::subscriber::set_global_default(tracing::subscriber::NoSubscriber::default()) + .expect("Failed to install global NoSubscriber (tracing disabled)"); + let (_, guard) = tracing_appender::non_blocking(std::io::sink()); + return guard; + } + let env_filter = EnvFilter::try_new(&global::SETTINGS.log.tracing) .unwrap_or_else(|_| EnvFilter::new("Info")); From 4eadc8b257a0951bc327f27a6368e9ab5ebbecb0 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 12 Jul 2025 06:35:09 +0200 Subject: [PATCH 067/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20gesti=C3=B3n?= =?UTF-8?q?=20de=20recursos=20en=20binario=20o=20de=20disco?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Añade dosnuevas macros `include_files` y `include_files_service` para incluir los recursos preparados con `pagetop-build`. - Añade nueva función útil `absolute_dir` y sus tests correspondientes. --- Cargo.lock | 97 +++++++++++++++++++++++++++++++++---- Cargo.toml | 4 +- src/lib.rs | 3 ++ src/prelude.rs | 4 +- src/service.rs | 126 ++++++++++++++++++++++++++++++++++++++++++++++++- src/util.rs | 49 +++++++++++++++++++ tests/util.rs | 70 +++++++++++++++++++++++++++ 7 files changed, 340 insertions(+), 13 deletions(-) create mode 100644 tests/util.rs diff --git a/Cargo.lock b/Cargo.lock index 24c9616f..659ed18e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "actix-files" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0773d59061dedb49a8aed04c67291b9d8cf2fe0b60130a381aab53c6dd86e9be" +dependencies = [ + "actix-http", + "actix-service", + "actix-utils", + "actix-web", + "bitflags", + "bytes", + "derive_more 0.99.20", + "futures-core", + "http-range", + "log", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "v_htmlescape", +] + [[package]] name = "actix-http" version = "3.11.0" @@ -34,7 +57,7 @@ dependencies = [ "brotli", "bytes", "bytestring", - "derive_more", + "derive_more 2.0.1", "encoding_rs", "flate2", "foldhash", @@ -149,7 +172,7 @@ dependencies = [ "bytestring", "cfg-if", "cookie", - "derive_more", + "derive_more 2.0.1", "encoding_rs", "foldhash", "futures-core", @@ -185,6 +208,18 @@ dependencies = [ "syn", ] +[[package]] +name = "actix-web-static-files" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adf6d1ef6d7a60e084f9e0595e2a5234abda14e76c105ecf8e2d0e8800c41a1f" +dependencies = [ + "actix-web", + "derive_more 0.99.20", + "futures-util", + "static-files", +] + [[package]] name = "addr2line" version = "0.24.2" @@ -502,6 +537,12 @@ dependencies = [ "winnow", ] +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "cookie" version = "0.16.2" @@ -590,6 +631,19 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + [[package]] name = "derive_more" version = "2.0.1" @@ -632,12 +686,6 @@ dependencies = [ "syn", ] -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - [[package]] name = "encoding_rs" version = "0.8.35" @@ -809,6 +857,7 @@ dependencies = [ "futures-task", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -942,6 +991,12 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-range" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" + [[package]] name = "httparse" version = "1.10.1" @@ -1352,13 +1407,14 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.0.8" +version = "0.0.9" dependencies = [ + "actix-files", "actix-web", + "actix-web-static-files", "chrono", "colored", "config", - "dunce", "figlet-rs", "fluent-templates", "itoa", @@ -1742,6 +1798,15 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "1.0.7" @@ -1797,6 +1862,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + [[package]] name = "serde" version = "1.0.219" @@ -2357,6 +2428,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "v_htmlescape" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" + [[package]] name = "valuable" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index 3ef84687..851c620d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.8" +version = "0.0.9" edition = "2021" description = """\ @@ -33,6 +33,8 @@ fluent-templates = "0.13.0" unic-langid = { version = "0.9.6", features = ["macros"] } actix-web = "4.11.0" +actix-web-files = { package = "actix-files", version = "0.6.6" } +actix-web-static-files = "4.0.1" static-files.workspace = true serde = { version = "1.0", features = ["derive"] } diff --git a/src/lib.rs b/src/lib.rs index 4519c440..800f7830 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,9 @@ pub use pagetop_macros::{html, main, test, AutoDefault}; +/// Representa un conjunto de recursos asociados a `$STATIC` en [`include_files!`]. +pub type StaticResources = std::collections::HashMap<&'static str, static_files::Resource>; + // API ********************************************************************************************* // Funciones y macros útiles. diff --git a/src/prelude.rs b/src/prelude.rs index cc38877a..c27b997e 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -4,7 +4,7 @@ pub use crate::{html, main, test}; -pub use crate::AutoDefault; +pub use crate::{AutoDefault, StaticResources}; // MACROS. @@ -14,6 +14,8 @@ pub use crate::hm; pub use crate::include_config; // crate::locale pub use crate::include_locales; +// crate::service +pub use crate::{include_files, include_files_service}; // API. diff --git a/src/service.rs b/src/service.rs index 90b13758..1adaead8 100644 --- a/src/service.rs +++ b/src/service.rs @@ -5,5 +5,129 @@ pub use actix_web::dev::Server; pub use actix_web::dev::ServiceFactory as Factory; pub use actix_web::dev::ServiceRequest as Request; pub use actix_web::dev::ServiceResponse as Response; -pub use actix_web::{http, rt, test}; +pub use actix_web::{http, rt, web}; pub use actix_web::{App, Error, HttpServer}; + +#[doc(hidden)] +pub use actix_web::test; + +/// Incluye en código un conjunto de recursos previamente preparado con `build.rs`. +/// +/// # Formas de uso +/// +/// * `include_files!(media)` - Incluye el conjunto de recursos llamado `media`. Normalmente se +/// usará esta forma. +/// +/// * `include_files!(BLOG_HM => blog)` - Asigna a la variable estática `BLOG_HM` un conjunto de +/// recursos llamado `blog`. +/// +/// # Argumentos +/// +/// * `$bundle` – Nombre del conjunto de recursos generado por `build.rs` (consultar +/// [`pagetop_build`](https://docs.rs/pagetop-build)). +/// * `$STATIC` – Identificador para la variable estática de tipo +/// [`StaticResources`](`crate::StaticResources`). +/// +/// # Ejemplos +/// +/// ```rust,ignore +/// include_files!(assets); // Uso habitual. +/// +/// include_files!(STATIC_ASSETS => assets); +/// ``` +#[macro_export] +macro_rules! include_files { + // Forma 1: incluye un conjunto de recursos por nombre. + ( $bundle:ident ) => { + $crate::util::paste! { + mod [<static_files_ $bundle>] { + include!(concat!(env!("OUT_DIR"), "/", stringify!($bundle), ".rs")); + } + } + }; + // Forma 2: asigna a una variable estática $STATIC un conjunto de recursos. + ( $STATIC:ident => $bundle:ident ) => { + $crate::util::paste! { + mod [<static_files_ $bundle>] { + include!(concat!(env!("OUT_DIR"), "/", stringify!($bundle), ".rs")); + } + pub static $STATIC: std::sync::LazyLock<StaticResources> = std::sync::LazyLock::new( + [<static_files_ $bundle>]::$bundle + ); + } + }; +} + +/// Configura un servicio web para publicar los recursos embebidos con [`include_files!`]. +/// +/// El código expandido de la macro decide durante el arranque de la aplicación si debe servir los +/// archivos de los recursos embebidos o directamente desde el sistema de ficheros, si se ha +/// indicado una ruta válida a un directorio de recursos. +/// +/// # Argumentos +/// +/// * `$scfg` – Instancia de [`ServiceConfig`](crate::service::web::ServiceConfig) donde aplicar la +/// configuración del servicio web. +/// * `$bundle` – Nombre del conjunto de recursos incluido con [`include_files!`]. +/// * `$route` – Ruta URL de origen desde la que se servirán los archivos. +/// * `[ $root, $relative ]` *(opcional)* – Directorio raíz y ruta relativa para construir la ruta +/// absoluta donde buscar los archivos en el sistema de ficheros (ver +/// [`absolute_dir`](crate::util::absolute_dir)). Si no existe, se usarán los recursos embebidos. +/// +/// # Ejemplos +/// +/// ```rust,ignore +/// use pagetop::prelude::*; +/// +/// include_files!(assets); +/// +/// pub struct MyExtension; +/// +/// impl ExtensionTrait for MyExtension { +/// fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { +/// include_files_service!(scfg, assets => "/public"); +/// } +/// } +/// ``` +/// +/// Y para buscar los recursos en el sistema de ficheros (si existe la ruta absoluta): +/// +/// ```rust,ignore +/// include_files_service!(cfg, assets => "/public", ["/var/www", "assets"]); +/// +/// // También desde el directorio actual de ejecución. +/// include_files_service!(cfg, assets => "/public", ["", "static"]); +/// ``` +#[macro_export] +macro_rules! include_files_service { + ( $scfg:ident, $bundle:ident => $route:expr $(, [$root:expr, $relative:expr])? ) => {{ + $crate::util::paste! { + let span = $crate::trace::debug_span!("Configuring static files ", path = $route); + let _ = span.in_scope(|| { + // Determina si se sirven recursos embebidos (`true`) o desde disco (`false`). + #[allow(unused_mut)] + let mut serve_embedded:bool = true; + $( + // Si `$root` y `$relative` no están vacíos, se comprueba la ruta absoluta. + if !$root.is_empty() && !$relative.is_empty() { + if let Ok(absolute) = $crate::util::absolute_dir($root, $relative) { + // Servimos directamente desde el sistema de ficheros. + $scfg.service($crate::service::ActixFiles::new( + $route, + absolute, + ).show_files_listing()); + serve_embedded = false + } + } + )? + // Si no se localiza el directorio, se exponen entonces los recursos embebidos. + if serve_embedded { + $scfg.service($crate::service::ResourceFiles::new( + $route, + [<static_files_ $bundle>]::$bundle(), + )); + } + }); + } + }}; +} diff --git a/src/util.rs b/src/util.rs index 07a6abdb..7a48001f 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,7 +1,56 @@ //! Funciones y macros útiles. +use crate::trace; + +use std::io; +use std::path::{Path, PathBuf}; + + +/// Devuelve la ruta absoluta a un directorio existente. +/// +/// * Si `relative_path` es una ruta absoluta, entonces se ignora `root_path`. +/// * Si la ruta final es relativa, se convierte en absoluta respecto al directorio actual. +/// * Devuelve error si la ruta no existe o no es un directorio. +/// +/// # Ejemplo +/// +/// ```rust,no_run +/// use pagetop::prelude::*; +/// +/// let root = "/home/user"; +/// let rel = "documents"; +/// println!("{:#?}", util::absolute_dir(root, rel)); +/// ``` +pub fn absolute_dir<P, Q>(root_path: P, relative_path: Q) -> io::Result<PathBuf> +where + P: AsRef<Path>, + Q: AsRef<Path>, +{ + // Une ambas rutas: + // - Si `relative_path` es absoluta, el `join` la devuelve tal cual, descartando `root_path`. + // - Si el resultado es aún relativo, lo será respecto al directorio actual. + let candidate = root_path.as_ref().join(relative_path.as_ref()); + + // Resuelve `.`/`..`, enlaces simbólicos y obtiene la ruta absoluta en un único paso. + let absolute_dir = candidate.canonicalize()?; + + // Asegura que realmente es un directorio existente. + if absolute_dir.is_dir() { + Ok(absolute_dir) + } else { + Err({ + let msg = format!("Path \"{}\" is not a directory", absolute_dir.display()); + trace::warn!(msg); + io::Error::new(io::ErrorKind::InvalidInput, msg) + }) + } +} + // MACROS ÚTILES *********************************************************************************** +#[doc(hidden)] +pub use paste::paste; + #[macro_export] /// Macro para construir una colección de pares clave-valor. /// diff --git a/tests/util.rs b/tests/util.rs new file mode 100644 index 00000000..2d52064e --- /dev/null +++ b/tests/util.rs @@ -0,0 +1,70 @@ +use pagetop::prelude::*; + +use std::{fs, io}; +use tempfile::TempDir; + +#[cfg(unix)] +mod unix { + use super::*; + + #[pagetop::test] + async fn ok_absolute_dir() -> io::Result<()> { + let _app = service::test::init_service(Application::new().test()).await; + + // /tmp/<rand>/sub + let td = TempDir::new()?; + let root = td.path(); + let sub = root.join("sub"); + fs::create_dir(&sub)?; + + let abs = util::absolute_dir(root, "sub")?; + assert_eq!(abs, std::fs::canonicalize(&sub)?); + Ok(()) + } + + #[pagetop::test] + async fn error_not_a_directory() -> io::Result<()> { + let _app = service::test::init_service(Application::new().test()).await; + + let td = TempDir::new()?; + let file = td.path().join("foo.txt"); + fs::write(&file, b"data")?; + + let err = util::absolute_dir(td.path(), "foo.txt").unwrap_err(); + assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + Ok(()) + } +} + +#[cfg(windows)] +mod windows { + use super::*; + + #[pagetop::test] + async fn ok_absolute_dir() -> io::Result<()> { + let _app = service::test::init_service(Application::new().test()).await; + + // C:\Users\…\Temp\… + let td = TempDir::new()?; + let root = td.path(); + let sub = root.join("sub"); + fs::create_dir(&sub)?; + + let abs = util::absolute_dir(root, sub.as_path())?; + assert_eq!(abs, std::fs::canonicalize(&sub)?); + Ok(()) + } + + #[pagetop::test] + async fn error_not_a_directory() -> io::Result<()> { + let _app = service::test::init_service(Application::new().test()).await; + + let td = TempDir::new()?; + let file = td.path().join("foo.txt"); + fs::write(&file, b"data")?; + + let err = util::absolute_dir(td.path(), "foo.txt").unwrap_err(); + assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + Ok(()) + } +} From 2b1b31fbf004e227e76162f5b05bb657fde568ca Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 12 Jul 2025 12:04:37 +0200 Subject: [PATCH 068/244] =?UTF-8?q?=E2=9C=A8=20(macros):=20A=C3=B1ade=20ma?= =?UTF-8?q?cro=20`builder=5Ffn`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 4 +- Cargo.toml | 2 +- helpers/pagetop-macros/Cargo.toml | 2 +- helpers/pagetop-macros/src/lib.rs | 157 +++++++++++++++++++++++++++++- src/lib.rs | 2 +- src/prelude.rs | 2 +- 6 files changed, 161 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 659ed18e..49fe0074 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1407,7 +1407,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.0.9" +version = "0.0.10" dependencies = [ "actix-files", "actix-web", @@ -1442,7 +1442,7 @@ dependencies = [ [[package]] name = "pagetop-macros" -version = "0.0.3" +version = "0.0.4" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 851c620d..8212f62b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.9" +version = "0.0.10" edition = "2021" description = """\ diff --git a/helpers/pagetop-macros/Cargo.toml b/helpers/pagetop-macros/Cargo.toml index 9f914bfd..070e7784 100644 --- a/helpers/pagetop-macros/Cargo.toml +++ b/helpers/pagetop-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-macros" -version = "0.0.3" +version = "0.0.4" edition = "2021" description = """\ diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 776903c0..25105c2f 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -18,8 +18,8 @@ mod maud; mod smart_default; use proc_macro::TokenStream; -use quote::quote; -use syn::{parse_macro_input, DeriveInput}; +use quote::{quote, quote_spanned}; +use syn::{parse_macro_input, spanned::Spanned, DeriveInput, ItemFn}; /// Macro para escribir plantillas HTML (basada en [Maud](https://docs.rs/maud)). #[proc_macro] @@ -43,6 +43,159 @@ pub fn derive_auto_default(input: TokenStream) -> TokenStream { } } +/// Macro (*attribute*) que asocia un método *builder* `with_` con un método `alter_`. +/// +/// La macro añade automáticamente un método `alter_` para modificar la instancia actual usando +/// `&mut self`, y redefine el método *builder* `with_`, que consume la instancia (`mut self`), para +/// delegar la lógica de la modificación al nuevo método `alter_`, reutilizando así la misma +/// implementación. +/// +/// Esta macro emitirá un error en tiempo de compilación si la función anotada no cumple con la +/// firma esperada para el método *builder*: `pub fn with_...(mut self, ...) -> Self`. +/// +/// # Ejemplos +/// +/// Si defines un método `with_` como este: +/// +/// ```rust,ignore +/// #[builder_fn] +/// pub fn with_example(mut self, value: impl Into<String>) -> Self { +/// self.value = Some(value.into()); +/// self +/// } +/// ``` +/// +/// la macro generará automáticamente el siguiente método `alter_`: +/// +/// ```rust,ignore +/// pub fn alter_example(&mut self, value: impl Into<String>) -> &mut Self { +/// self.value = Some(value.into()); +/// self +/// } +/// ``` +/// +/// y reescribirá el método `with_` para delegar la modificación al método `alter_`: +/// +/// ```rust,ignore +/// pub fn with_example(mut self, value: impl Into<String>) -> Self { +/// self.alter_example(value); +/// self +/// } +/// ``` +/// +/// Así, cada método *builder* `with_...()` generará automáticamente su correspondiente método +/// `alter_...()`, que permitirá más adelante modificar instancias existentes. +#[proc_macro_attribute] +pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { + let fn_with = parse_macro_input!(item as ItemFn); + let fn_with_name = fn_with.sig.ident.clone(); + let fn_with_name_str = fn_with.sig.ident.to_string(); + + // Valida el nombre del método. + if !fn_with_name_str.starts_with("with_") { + let expanded = quote_spanned! { + fn_with.sig.ident.span() => + compile_error!("expected a \"pub fn with_...(mut self, ...) -> Self\" method"); + }; + return expanded.into(); + } + // Valida que el método sea público. + if !matches!(fn_with.vis, syn::Visibility::Public(_)) { + return quote_spanned! { + fn_with.sig.ident.span() => compile_error!("expected method to be `pub`"); + } + .into(); + } + // Valida que el método devuelva el tipo `Self`. + if let syn::ReturnType::Type(_, ty) = &fn_with.sig.output { + if let syn::Type::Path(type_path) = &**ty { + let ident = &type_path.path.segments.last().unwrap().ident; + if ident != "Self" { + return quote_spanned! { + fn_with.sig.output.span() => compile_error!("expected return type to be `Self`"); + }.into(); + } + } + } else { + return quote_spanned! { + fn_with.sig.output.span() => compile_error!("expected method to return `Self`"); + } + .into(); + } + // Valida que el primer argumento sea `mut self`. + if let Some(syn::FnArg::Receiver(receiver)) = fn_with.sig.inputs.first() { + if receiver.mutability.is_none() { + return quote_spanned! { + receiver.span() => compile_error!("expected `mut self` as the first argument"); + } + .into(); + } + } else { + return quote_spanned! { + fn_with.sig.ident.span() => compile_error!("expected `mut self` as the first argument"); + } + .into(); + } + + // Genera el nombre del método alter_...(). + let fn_alter_name_str = fn_with_name_str.replace("with_", "alter_"); + let fn_alter_name = syn::Ident::new(&fn_alter_name_str, fn_with.sig.ident.span()); + + // Extrae genéricos y cláusulas where. + let fn_generics = &fn_with.sig.generics; + let where_clause = &fn_with.sig.generics.where_clause; + + // Extrae argumentos y parámetros de llamada. + let args: Vec<_> = fn_with.sig.inputs.iter().skip(1).collect(); + let params: Vec<_> = fn_with + .sig + .inputs + .iter() + .skip(1) + .map(|arg| match arg { + syn::FnArg::Typed(pat) => &pat.pat, + _ => panic!("unexpected argument type"), + }) + .collect(); + + // Extrae bloque del método. + let fn_with_block = &fn_with.block; + + // Extrae documentación y otros atributos del método. + let fn_with_attrs = &fn_with.attrs; + + // Genera el método alter_...() con el código del método with_...(). + let fn_alter_doc = format!( + "Modifica la instancia en los mismos términos que para el patrón <em>builder</em> hace el \ + método asociado `{}()`.", + fn_with_name_str, + ); + let fn_alter = quote! { + #[doc = #fn_alter_doc] + pub fn #fn_alter_name #fn_generics(&mut self, #(#args),*) -> &mut Self #where_clause { + #fn_with_block + } + }; + + // Redefine el método with_...() para que llame a alter_...(). + let fn_with = quote! { + #(#fn_with_attrs)* + #[inline] + pub fn #fn_with_name #fn_generics(mut self, #(#args),*) -> Self #where_clause { + self.#fn_alter_name(#(#params),*); + self + } + }; + + // Genera el código final. + let expanded = quote! { + #fn_with + #[inline] + #fn_alter + }; + expanded.into() +} + /// Define una función `main` asíncrona como punto de entrada de `PageTop`. /// /// # Ejemplo diff --git a/src/lib.rs b/src/lib.rs index 800f7830..d64cf55c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,7 @@ // RE-EXPORTED ************************************************************************************* -pub use pagetop_macros::{html, main, test, AutoDefault}; +pub use pagetop_macros::{builder_fn, html, main, test, AutoDefault}; /// Representa un conjunto de recursos asociados a `$STATIC` en [`include_files!`]. pub type StaticResources = std::collections::HashMap<&'static str, static_files::Resource>; diff --git a/src/prelude.rs b/src/prelude.rs index c27b997e..e4aabf55 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -2,7 +2,7 @@ // RE-EXPORTED. -pub use crate::{html, main, test}; +pub use crate::{builder_fn, html, main, test}; pub use crate::{AutoDefault, StaticResources}; From f6b4cb936ca7a9695460c82d0195647e906b327b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 13 Jul 2025 11:10:06 +0200 Subject: [PATCH 069/244] =?UTF-8?q?=F0=9F=8E=A8=20Mejora=20definici=C3=B3n?= =?UTF-8?q?=20encapsulando=20uso=20de=20recursos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-build/src/lib.rs | 4 ++-- src/lib.rs | 25 +++++++++++++++++++++++-- src/service.rs | 17 +++++++++-------- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index c48b21fc..98c8ef87 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -109,10 +109,10 @@ //! } //! ``` //! -//! También se puede acceder al conjunto de recursos declarando un `HashMap` estático global: +//! También se puede asignar el conjunto de recursos a una variable global; p.ej. `GUIDES`: //! //! ```rust,ignore -//! include_files!(HM_GUIDES => guides); +//! include_files!(GUIDES => guides); //! ``` use grass::{from_path, Options, OutputStyle}; diff --git a/src/lib.rs b/src/lib.rs index d64cf55c..1ae35895 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,12 +30,33 @@ #![cfg_attr(docsrs, feature(doc_cfg))] +use std::collections::HashMap; +use std::ops::Deref; + // RE-EXPORTED ************************************************************************************* pub use pagetop_macros::{builder_fn, html, main, test, AutoDefault}; -/// Representa un conjunto de recursos asociados a `$STATIC` en [`include_files!`]. -pub type StaticResources = std::collections::HashMap<&'static str, static_files::Resource>; +/// Conjunto de recursos asociados a `$STATIC` en [`include_files!`](crate::include_files). +pub struct StaticResources { + bundle: HashMap<&'static str, static_files::Resource>, +} + +impl StaticResources { + /// Crea un contenedor para un conjunto de recursos generado por `build.rs` (consultar + /// [`pagetop_build`](https://docs.rs/pagetop-build)). + pub fn new(bundle: HashMap<&'static str, static_files::Resource>) -> Self { + Self { bundle } + } +} + +impl Deref for StaticResources { + type Target = HashMap<&'static str, static_files::Resource>; + + fn deref(&self) -> &Self::Target { + &self.bundle + } +} // API ********************************************************************************************* diff --git a/src/service.rs b/src/service.rs index 1adaead8..9e506fae 100644 --- a/src/service.rs +++ b/src/service.rs @@ -15,18 +15,18 @@ pub use actix_web::test; /// /// # Formas de uso /// -/// * `include_files!(media)` - Incluye el conjunto de recursos llamado `media`. Normalmente se +/// * `include_files!(media)` - Para incluir un conjunto de recursos llamado `media`. Normalmente se /// usará esta forma. /// -/// * `include_files!(BLOG_HM => blog)` - Asigna a la variable estática `BLOG_HM` un conjunto de -/// recursos llamado `blog`. +/// * `include_files!(BLOG => media)` - También se puede asignar el conjunto de recursos a una +/// variable global; p.ej. `BLOG`. /// /// # Argumentos /// /// * `$bundle` – Nombre del conjunto de recursos generado por `build.rs` (consultar /// [`pagetop_build`](https://docs.rs/pagetop-build)). -/// * `$STATIC` – Identificador para la variable estática de tipo -/// [`StaticResources`](`crate::StaticResources`). +/// * `$STATIC` – Asigna el conjunto de recursos a una variable global de tipo +/// [`StaticResources`](crate::StaticResources). /// /// # Ejemplos /// @@ -51,9 +51,10 @@ macro_rules! include_files { mod [<static_files_ $bundle>] { include!(concat!(env!("OUT_DIR"), "/", stringify!($bundle), ".rs")); } - pub static $STATIC: std::sync::LazyLock<StaticResources> = std::sync::LazyLock::new( - [<static_files_ $bundle>]::$bundle - ); + pub static $STATIC: std::sync::LazyLock<$crate::StaticResources> = + std::sync::LazyLock::new( + $crate::StaticResources::new([<static_files_ $bundle>]::$bundle) + ); } }; } From 5f60bc4845ba591ecf35bac46e134f4b6840b17f Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 15 Jul 2025 20:12:15 +0200 Subject: [PATCH 070/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20API=20para=20e?= =?UTF-8?q?xtensiones=20con=20funcionalidades?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Añade el interfaz común que debe implementar cualquier extensión de PageTop para añadir nuevas funcionalidades a la aplicación en forma de servicios web y API de uso. --- src/app.rs | 37 +++++- src/core.rs | 205 +++++++++++++++++++++++++++++++ src/core/extension.rs | 9 ++ src/core/extension/all.rs | 104 ++++++++++++++++ src/core/extension/definition.rs | 77 ++++++++++++ src/lib.rs | 2 + src/prelude.rs | 4 + 7 files changed, 436 insertions(+), 2 deletions(-) create mode 100644 src/core.rs create mode 100644 src/core/extension.rs create mode 100644 src/core/extension/all.rs create mode 100644 src/core/extension/definition.rs diff --git a/src/app.rs b/src/app.rs index b02b294a..0bcece8e 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,6 +2,7 @@ mod figfont; +use crate::core::{extension, extension::ExtensionRef}; use crate::{global, locale, service, trace}; use substring::Substring; @@ -9,6 +10,12 @@ use substring::Substring; use std::io::Error; use std::sync::LazyLock; +/// Punto de entrada de una aplicación `PageTop`. +/// +/// No almacena datos, pero **encapsula** el ciclo completo de configuración y puesta en marcha. +/// Para instanciarla se puede usar [`new`](Application::new) o [`prepare`](Application::prepare). +/// Después sólo hay que llamar a [`run`](Application::run) (o a [`test`](Application::test) si se +/// está preparando un entorno de pruebas). pub struct Application; impl Default for Application { @@ -20,6 +27,23 @@ impl Default for Application { impl Application { /// Crea una instancia de la aplicación. pub fn new() -> Self { + Self::internal_prepare(None) + } + + /// Prepara una instancia de la aplicación a partir de una extensión raíz. + /// + /// Esa extensión suele declarar: + /// + /// - Sus propias dependencias (que se habilitarán automáticamente). + /// - Una lista de extensiones que deben deshabilitarse si estuvieran activadas. + /// + /// Esto simplifica el arranque en escenarios complejos. + pub fn prepare(root_extension: ExtensionRef) -> Self { + Self::internal_prepare(Some(root_extension)) + } + + // Método interno para preparar la aplicación, opcionalmente con una extensión. + fn internal_prepare(root_extension: Option<ExtensionRef>) -> Self { // Al arrancar muestra una cabecera para la aplicación. Self::show_banner(); @@ -29,6 +53,12 @@ impl Application { // Valida el identificador de idioma por defecto. LazyLock::force(&locale::DEFAULT_LANGID); + // Registra las extensiones de la aplicación. + extension::all::register_extensions(root_extension); + + // Inicializa las extensiones. + extension::all::initialize_extensions(); + Self } @@ -73,7 +103,10 @@ impl Application { } } - /// Ejecuta el servidor web de la aplicación. + /// Arranca el servidor web de la aplicación. + /// + /// Devuelve [`std::io::Error`] si el *socket* no puede enlazarse (por puerto en uso, permisos, + /// etc.). pub fn run(self) -> Result<service::Server, Error> { // Prepara el servidor web. Ok(service::HttpServer::new(move || { @@ -112,6 +145,6 @@ impl Application { InitError = (), >, > { - service::App::new() + service::App::new().configure(extension::all::configure_services) } } diff --git a/src/core.rs b/src/core.rs new file mode 100644 index 00000000..5aebd1fa --- /dev/null +++ b/src/core.rs @@ -0,0 +1,205 @@ +//! Tipos y funciones esenciales para crear extensiones. + +use std::any::Any; + +/// Selector para identificar segmentos de la ruta de un tipo. +#[derive(Clone, Copy, Debug)] +pub enum TypeInfo { + /// Ruta completa tal y como la devuelve [`core::any::type_name`]. + FullName, + /// Último segmento de la ruta – por ejemplo `Vec<i32>` en lugar de `alloc::vec::Vec<i32>`. + ShortName, + /// Conserva todo **desde** `start` inclusive hasta el final. + NameFrom(isize), + /// Conserva todo **hasta e incluyendo** `end`. + NameTo(isize), + /// Conserva la subruta comprendida entre `start` y `end` (ambos inclusive). + PartialName(isize, isize), +} + +impl TypeInfo { + /// Devuelve el segmento solicitado de la ruta para el tipo `T`. + pub fn of<T: ?Sized>(&self) -> &'static str { + let type_name = std::any::type_name::<T>(); + match self { + TypeInfo::FullName => type_name, + TypeInfo::ShortName => Self::partial(type_name, -1, None), + TypeInfo::NameFrom(start) => Self::partial(type_name, *start, None), + TypeInfo::NameTo(end) => Self::partial(type_name, 0, Some(*end)), + TypeInfo::PartialName(start, end) => Self::partial(type_name, *start, Some(*end)), + } + } + + // Extrae un rango de segmentos de `type_name` (tokens separados por `::`). + // + // Los argumentos `start` y `end` identifican los índices de los segmentos teniendo en cuenta: + // + // * Los índices positivos cuentan **desde la izquierda**, empezando en `0`. + // * Los índices negativos cuentan **desde la derecha**, `-1` es el último. + // * Si `end` es `None`, el corte llega hasta el último segmento. + // * Si la selección resulta vacía por índices desordenados o segmento inexistente, se devuelve + // la cadena vacía. + // + // Ejemplos (con `type_name = "alloc::vec::Vec<i32>"`): + // + // | Llamada | Resultado | + // |------------------------------|--------------------------| + // | `partial(..., 0, None)` | `"alloc::vec::Vec<i32>"` | + // | `partial(..., 1, None)` | `"vec::Vec<i32>"` | + // | `partial(..., -1, None)` | `"Vec<i32>"` | + // | `partial(..., 0, Some(-2))` | `"alloc::vec"` | + // | `partial(..., -5, None)` | `"alloc::vec::Vec<i32>"` | + // + // La porción devuelta vive tanto como `'static` porque `type_name` es `'static` y sólo se + // presta. + fn partial(type_name: &'static str, start: isize, end: Option<isize>) -> &'static str { + let maxlen = type_name.len(); + + // Localiza los límites de cada segmento a nivel 0 de `<…>`. + let mut segments = Vec::new(); + let mut segment_start = 0; // Posición inicial del segmento actual. + let mut angle_brackets = 0; // Profundidad dentro de '<…>'. + let mut previous_char = '\0'; // Se inicializa a carácter nulo, no hay aún carácter previo. + + for (idx, c) in type_name.char_indices() { + match c { + ':' if angle_brackets == 0 => { + if previous_char == ':' { + if segment_start < idx - 1 { + segments.push((segment_start, idx - 1)); // No incluye último '::'. + } + segment_start = idx + 1; // Nuevo segmento tras '::'. + } + } + '<' => angle_brackets += 1, + '>' => angle_brackets -= 1, + _ => {} + } + previous_char = c; + } + + // Incluye el último segmento si lo hubiese. + if segment_start < maxlen { + segments.push((segment_start, maxlen)); + } + + // Calcula la posición inicial. + let start_pos = segments + .get(if start >= 0 { + start as usize + } else { + segments.len().saturating_sub(start.unsigned_abs()) + }) + .map_or(0, |&(s, _)| s); + + // Calcula la posición final. + let end_pos = segments + .get(if let Some(end) = end { + if end >= 0 { + end as usize + } else { + segments.len().saturating_sub(end.unsigned_abs()) + } + } else { + segments.len() - 1 + }) + .map_or(maxlen, |&(_, e)| e); + + // Devuelve la cadena parcial basada en las posiciones calculadas. + if start_pos >= end_pos { + return ""; + } + &type_name[start_pos..end_pos] + } +} + +/// Proporciona información de tipo en tiempo de ejecución y conversión dinámica de tipos. +/// +/// Este *trait* se implementa automáticamente para **todos** los tipos que implementen [`Any`], de +/// modo que basta con traer [`AnyInfo`] al ámbito (`use crate::AnyInfo;`) para disponer de estos +/// métodos adicionales, o usar el [`prelude`](crate::prelude) de `PageTop`. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// let n = 3u32; +/// assert_eq!(n.type_name(), "u32"); +/// ``` +pub trait AnyInfo: Any { + /// Devuelve el nombre totalmente cualificado del tipo. + fn type_name(&self) -> &'static str; + + /// Devuelve el nombre corto del tipo (último segmento del nombre). + fn short_name(&self) -> &'static str; + + /// Devuelve una referencia a `dyn Any` para la conversión dinámica de tipos. + fn as_any_ref(&self) -> &dyn Any; + + /// Devuelve una referencia mutable a `dyn Any` para la conversión dinámica de tipos. + fn as_any_mut(&mut self) -> &mut dyn Any; +} + +impl<T: Any> AnyInfo for T { + #[inline] + fn type_name(&self) -> &'static str { + TypeInfo::FullName.of::<T>() + } + + #[inline] + fn short_name(&self) -> &'static str { + TypeInfo::ShortName.of::<T>() + } + + #[inline] + fn as_any_ref(&self) -> &dyn Any { + self + } + + #[inline] + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + +/// Extiende [`AnyInfo`] con utilidades de *downcasting* para conversión de tipos. +/// +/// Preferible a usar directamente `Any::downcast_ref` porque conserva el *trait bound* [`AnyInfo`], +/// lo que permite seguir llamando a `type_name`, etc. +pub trait AnyCast: AnyInfo { + /// Comprueba si la instancia subyacente es de tipo `T`. + #[inline] + fn is<T>(&self) -> bool + where + T: AnyInfo, + { + self.as_any_ref().is::<T>() + } + + /// Intenta hacer *downcast* de un objeto para obtener una referencia de tipo `T`. + #[inline] + #[must_use] + fn downcast_ref<T>(&self) -> Option<&T> + where + T: AnyInfo, + { + self.as_any_ref().downcast_ref() + } + + /// Intenta hacer *downcast* de un objeto para obtener una referencia mutable de tipo `T`. + #[inline] + #[must_use] + fn downcast_mut<T>(&mut self) -> Option<&mut T> + where + T: AnyInfo, + { + self.as_any_mut().downcast_mut() + } +} + +/// Implementación automática para cualquier tipo que ya cumpla [`AnyInfo`]. +impl<T: ?Sized + AnyInfo> AnyCast for T {} + +// Infraestructura para ampliar funcionalidades mediante extensiones. +pub mod extension; diff --git a/src/core/extension.rs b/src/core/extension.rs new file mode 100644 index 00000000..9eb3bd24 --- /dev/null +++ b/src/core/extension.rs @@ -0,0 +1,9 @@ +//! Infraestructura para ampliar funcionalidades mediante extensiones. +//! +//! Cada funcionalidad adicional que quiera incorporarse a una aplicación `PageTop` se debe modelar +//! como una **extensión**. Todas comparten la misma interfaz declarada en [`ExtensionTrait`]. + +mod definition; +pub use definition::{ExtensionRef, ExtensionTrait}; + +pub(crate) mod all; diff --git a/src/core/extension/all.rs b/src/core/extension/all.rs new file mode 100644 index 00000000..d5bebdad --- /dev/null +++ b/src/core/extension/all.rs @@ -0,0 +1,104 @@ +use crate::core::extension::ExtensionRef; +use crate::{service, trace}; + +use std::sync::{LazyLock, RwLock}; + +// EXTENSIONES ************************************************************************************* + +static ENABLED_EXTENSIONS: LazyLock<RwLock<Vec<ExtensionRef>>> = + LazyLock::new(|| RwLock::new(Vec::new())); + +static DROPPED_EXTENSIONS: LazyLock<RwLock<Vec<ExtensionRef>>> = + LazyLock::new(|| RwLock::new(Vec::new())); + +// REGISTRO DE LAS EXTENSIONES ********************************************************************* + +pub fn register_extensions(root_extension: Option<ExtensionRef>) { + // Prepara la lista de extensiones habilitadas. + let mut enabled_list: Vec<ExtensionRef> = Vec::new(); + + // Si se proporciona una extensión raíz inicial, se añade a la lista de extensiones habilitadas. + if let Some(extension) = root_extension { + add_to_enabled(&mut enabled_list, extension); + } + + // Guarda la lista final de extensiones habilitadas. + ENABLED_EXTENSIONS + .write() + .unwrap() + .append(&mut enabled_list); + + // Prepara una lista de extensiones deshabilitadas. + let mut dropped_list: Vec<ExtensionRef> = Vec::new(); + + // Si se proporciona una extensión raíz, analiza su lista de dependencias. + if let Some(extension) = root_extension { + add_to_dropped(&mut dropped_list, extension); + } + + // Guarda la lista final de extensiones deshabilitadas. + DROPPED_EXTENSIONS + .write() + .unwrap() + .append(&mut dropped_list); +} + +fn add_to_enabled(list: &mut Vec<ExtensionRef>, extension: ExtensionRef) { + // Verifica que la extensión no esté en la lista para evitar duplicados. + if !list.iter().any(|e| e.type_id() == extension.type_id()) { + // Añade primero (en orden inverso) las dependencias de la extensión. + for d in extension.dependencies().iter().rev() { + add_to_enabled(list, *d); + } + + // Añade la propia extensión a la lista. + list.push(extension); + } +} + +fn add_to_dropped(list: &mut Vec<ExtensionRef>, extension: ExtensionRef) { + // Recorre las extensiones que la actual recomienda deshabilitar. + for d in &extension.drop_extensions() { + // Verifica que la extensión no esté ya en la lista. + if !list.iter().any(|e| e.type_id() == d.type_id()) { + // Comprueba si la extensión está habilitada. Si es así, registra una advertencia. + if ENABLED_EXTENSIONS + .read() + .unwrap() + .iter() + .any(|e| e.type_id() == extension.type_id()) + { + trace::warn!( + "Trying to drop \"{}\" extension which is enabled", + extension.short_name() + ); + } else { + // Si la extensión no está habilitada, se añade a la lista y registra la acción. + list.push(*d); + trace::debug!("Extension \"{}\" dropped", d.short_name()); + // Añade recursivamente las dependencias de la extensión eliminada. + // De este modo, todas las dependencias se tienen en cuenta para ser deshabilitadas. + for dependency in &extension.dependencies() { + add_to_dropped(list, *dependency); + } + } + } + } +} + +// INICIALIZA LAS EXTENSIONES ********************************************************************** + +pub fn initialize_extensions() { + trace::info!("Calling application bootstrap"); + for extension in ENABLED_EXTENSIONS.read().unwrap().iter() { + extension.initialize(); + } +} + +// CONFIGURA LOS SERVICIOS ************************************************************************* + +pub fn configure_services(scfg: &mut service::web::ServiceConfig) { + for extension in ENABLED_EXTENSIONS.read().unwrap().iter() { + extension.configure_service(scfg); + } +} diff --git a/src/core/extension/definition.rs b/src/core/extension/definition.rs new file mode 100644 index 00000000..761fceea --- /dev/null +++ b/src/core/extension/definition.rs @@ -0,0 +1,77 @@ +use crate::core::AnyInfo; +use crate::locale::L10n; +use crate::service; + +/// Representa una referencia a una extensión. +/// +/// Las extensiones se definen como instancias estáticas globales para poder acceder a ellas desde +/// cualquier hilo de la ejecución sin necesidad de sincronización adicional. +pub type ExtensionRef = &'static dyn ExtensionTrait; + +/// Interfaz común que debe implementar cualquier extensión de `PageTop`. +/// +/// Este *trait* es fácil de implementar, basta con declarar la estructura de la extensión y +/// sobreescribir los métodos que sea necesario. +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// pub struct Blog; +/// +/// impl ExtensionTrait for Blog { +/// fn name(&self) -> L10n { L10n::n("Blog") } +/// fn description(&self) -> L10n { L10n::n("Sistema de blogs") } +/// } +/// ``` +pub trait ExtensionTrait: AnyInfo + Send + Sync { + /// Nombre legible para el usuario. + /// + /// Predeterminado por el [`short_name`](AnyInfo::short_name) del tipo asociado a la extensión. + fn name(&self) -> L10n { + L10n::n(self.short_name()) + } + + /// Descripción corta para paneles, listados, etc. + fn description(&self) -> L10n { + L10n::default() + } + + /// Otras extensiones que deben habilitarse **antes** de esta. + /// + /// `PageTop` las resolverá automáticamente respetando el orden durante el arranque de la + /// aplicación. + fn dependencies(&self) -> Vec<ExtensionRef> { + vec![] + } + + /// Inicializa la extensión durante la lógica de arranque de la aplicación. + /// + /// Se llama una sola vez, después de que todas las dependencias se han inicializado y antes de + /// aceptar cualquier petición HTTP. + fn initialize(&self) {} + + /// Configura los servicios web de la extensión, como rutas, *middleware*, acceso a ficheros + /// estáticos, etc., usando [`ServiceConfig`](crate::service::web::ServiceConfig). + /// + /// ```rust,ignore + /// use pagetop::prelude::*; + /// + /// pub struct ExtensionSample; + /// + /// impl ExtensionTrait for ExtensionSample { + /// fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + /// scfg.route("/sample", web::get().to(route_sample)); + /// } + /// } + /// ``` + #[allow(unused_variables)] + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) {} + + /// Permite crear extensiones para deshabilitar y desinstalar los recursos de otras extensiones + /// utilizadas en versiones anteriores de la aplicación. + /// + /// Actualmente no se usa, pero se deja como *placeholder* para futuras implementaciones. + fn drop_extensions(&self) -> Vec<ExtensionRef> { + vec![] + } +} diff --git a/src/lib.rs b/src/lib.rs index 1ae35895..04a99397 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,6 +74,8 @@ pub mod html; pub mod locale; // Soporte a fechas y horas. pub mod datetime; +// Tipos y funciones esenciales para crear extensiones. +pub mod core; // Gestión del servidor y servicios web. pub mod service; // Prepara y ejecuta la aplicación. diff --git a/src/prelude.rs b/src/prelude.rs index e4aabf55..c391de8c 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -33,4 +33,8 @@ pub use crate::datetime::*; pub use crate::service; +pub use crate::core::{AnyCast, AnyInfo, TypeInfo}; + +pub use crate::core::extension::*; + pub use crate::app::Application; From 4b281a1e96b71facf0a3992d90c1598c536314be Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 16 Jul 2025 00:45:05 +0200 Subject: [PATCH 071/244] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20A?= =?UTF-8?q?=C3=B1ade=20macros=20para=20concatenar=20cadenas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 9 ++- Cargo.toml | 3 +- src/prelude.rs | 2 +- src/util.rs | 161 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 49fe0074..cde64db7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -525,6 +525,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "concat-string" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7439becb5fafc780b6f4de382b1a7a3e70234afe783854a4702ee8adbb838609" + [[package]] name = "config" version = "0.15.13" @@ -1407,13 +1413,14 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.0.10" +version = "0.0.11" dependencies = [ "actix-files", "actix-web", "actix-web-static-files", "chrono", "colored", + "concat-string", "config", "figlet-rs", "fluent-templates", diff --git a/Cargo.toml b/Cargo.toml index 8212f62b..b6f844f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.10" +version = "0.0.11" edition = "2021" description = """\ @@ -17,6 +17,7 @@ authors.workspace = true [dependencies] chrono = "0.4.41" colored = "3.0.0" +concat-string = "1.0.1" config = { version = "0.15.13", default-features = false, features = ["toml"] } figlet-rs = "0.1.5" itoa = "1.0.15" diff --git a/src/prelude.rs b/src/prelude.rs index c391de8c..6506aaf9 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -9,7 +9,7 @@ pub use crate::{AutoDefault, StaticResources}; // MACROS. // crate::util -pub use crate::hm; +pub use crate::{hm, join, join_opt, join_pair, join_strict}; // crate::config pub use crate::include_config; // crate::locale diff --git a/src/util.rs b/src/util.rs index 7a48001f..b605125f 100644 --- a/src/util.rs +++ b/src/util.rs @@ -5,6 +5,7 @@ use crate::trace; use std::io; use std::path::{Path, PathBuf}; +// FUNCIONES ÚTILES ******************************************************************************** /// Devuelve la ruta absoluta a un directorio existente. /// @@ -51,6 +52,9 @@ where #[doc(hidden)] pub use paste::paste; +#[doc(hidden)] +pub use concat_string::concat_string; + #[macro_export] /// Macro para construir una colección de pares clave-valor. /// @@ -73,3 +77,160 @@ macro_rules! hm { a }}; } + +/// Concatena eficientemente varios fragmentos en un [`String`]. +/// +/// Esta macro exporta [`concat_string!`](https://docs.rs/concat-string). Acepta cualquier número de +/// fragmentos que implementen [`AsRef<str>`] y construye un [`String`] con el tamaño óptimo, de +/// forma eficiente y evitando el uso de cadenas de formato que penalicen el rendimiento. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// // Concatena todos los fragmentos directamente. +/// let result = join!("Hello", " ", "World"); +/// assert_eq!(result, String::from("Hello World")); +/// +/// // También funciona con valores vacíos. +/// let result_with_empty = join!("Hello", "", "World"); +/// assert_eq!(result_with_empty, String::from("HelloWorld")); +/// +/// // Un único fragmento devuelve el mismo valor. +/// let single_result = join!("Hello"); +/// assert_eq!(single_result, String::from("Hello")); +/// ``` +#[macro_export] +macro_rules! join { + ($($arg:tt)*) => { + $crate::util::concat_string!($($arg)*) + }; +} + +/// Concatena los fragmentos no vacíos en un [`Option<String>`] con un separador opcional. +/// +/// Esta macro acepta cualquier número de fragmentos que implementen [`AsRef<str>`] para concatenar +/// todos los fragmentos no vacíos usando opcionalmente un separador. +/// +/// Si todos los fragmentos están vacíos, devuelve [`None`]. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// // Concatena los fragmentos no vacíos con un espacio como separador. +/// let result_with_separator = join_opt!(["Hello", "", "World"]; " "); +/// assert_eq!(result_with_separator, Some(String::from("Hello World"))); +/// +/// // Concatena los fragmentos no vacíos sin un separador. +/// let result_without_separator = join_opt!(["Hello", "", "World"]); +/// assert_eq!(result_without_separator, Some(String::from("HelloWorld"))); +/// +/// // Devuelve `None` si todos los fragmentos están vacíos. +/// let result_empty = join_opt!(["", "", ""]); +/// assert_eq!(result_empty, None); +/// ``` +#[macro_export] +macro_rules! join_opt { + ([$($arg:expr),* $(,)?]) => {{ + let s = $crate::util::concat_string!($($arg),*); + (!s.is_empty()).then_some(s) + }}; + ([$($arg:expr),* $(,)?]; $separator:expr) => {{ + let s = [$($arg),*] + .iter() + .filter(|&item| !item.is_empty()) + .cloned() + .collect::<Vec<_>>() + .join($separator); + (!s.is_empty()).then_some(s) + }}; +} + +/// Concatena dos fragmentos en un [`String`] usando un separador. +/// +/// Une los dos fragmentos, que deben implementar [`AsRef<str>`], usando el separador proporcionado. +/// Si uno de ellos está vacío, devuelve directamente el otro; y si ambos están vacíos devuelve un +/// [`String`] vacío. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// let first = "Hello"; +/// let separator = "-"; +/// let second = "World"; +/// +/// // Concatena los dos fragmentos cuando ambos no están vacíos. +/// let result = join_pair!(first, separator, second); +/// assert_eq!(result, String::from("Hello-World")); +/// +/// // Si el primer fragmento está vacío, devuelve el segundo. +/// let result_empty_first = join_pair!("", separator, second); +/// assert_eq!(result_empty_first, String::from("World")); +/// +/// // Si el segundo fragmento está vacío, devuelve el primero. +/// let result_empty_second = join_pair!(first, separator, ""); +/// assert_eq!(result_empty_second, String::from("Hello")); +/// +/// // Si ambos fragmentos están vacíos, devuelve una cadena vacía. +/// let result_both_empty = join_pair!("", separator, ""); +/// assert_eq!(result_both_empty, String::from("")); +/// ``` +#[macro_export] +macro_rules! join_pair { + ($first:expr, $separator:expr, $second:expr) => {{ + if $first.is_empty() { + String::from($second) + } else if $second.is_empty() { + String::from($first) + } else { + $crate::util::concat_string!($first, $separator, $second) + } + }}; +} + +/// Concatena varios fragmentos en un [`Option<String>`] si ninguno está vacío. +/// +/// Si alguno de los fragmentos, que deben implementar [`AsRef<str>`], está vacío, devuelve +/// [`None`]. Opcionalmente se puede indicar un separador entre los fragmentos concatenados. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// // Concatena los fragmentos. +/// let result = join_strict!(["Hello", "World"]); +/// assert_eq!(result, Some(String::from("HelloWorld"))); +/// +/// // Concatena los fragmentos con un separador. +/// let result_with_separator = join_strict!(["Hello", "World"]; " "); +/// assert_eq!(result_with_separator, Some(String::from("Hello World"))); +/// +/// // Devuelve `None` si alguno de los fragmentos está vacío. +/// let result_with_empty = join_strict!(["Hello", "", "World"]); +/// assert_eq!(result_with_empty, None); +/// ``` +#[macro_export] +macro_rules! join_strict { + ([$($arg:expr),* $(,)?]) => {{ + let fragments = [$($arg),*]; + if fragments.iter().any(|&item| item.is_empty()) { + None + } else { + Some(fragments.concat()) + } + }}; + ([$($arg:expr),* $(,)?]; $separator:expr) => {{ + let fragments = [$($arg),*]; + if fragments.iter().any(|&item| item.is_empty()) { + None + } else { + Some(fragments.join($separator)) + } + }}; +} From 9bfdf2e9ac49ebbf3983d4e4424c042d8bbf9f67 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 16 Jul 2025 01:04:36 +0200 Subject: [PATCH 072/244] =?UTF-8?q?=F0=9F=93=9D=20Actualiza=20documentaci?= =?UTF-8?q?=C3=B3n=20con=20favicon=20propio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-build/src/lib.rs | 4 ++++ helpers/pagetop-macros/src/lib.rs | 4 ++++ src/lib.rs | 4 ++++ static/favicon.ico | Bin 0 -> 10206 bytes 4 files changed, 12 insertions(+) create mode 100644 static/favicon.ico diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index 98c8ef87..3816c658 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -115,6 +115,10 @@ //! include_files!(GUIDES => guides); //! ``` +#![doc( + html_favicon_url = "https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/favicon.ico" +)] + use grass::{from_path, Options, OutputStyle}; use static_files::{resource_dir, ResourceDir}; diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 25105c2f..62b6e886 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -14,6 +14,10 @@ //! web clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles //! y configurables, basadas en HTML, CSS y JavaScript. +#![doc( + html_favicon_url = "https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/favicon.ico" +)] + mod maud; mod smart_default; diff --git a/src/lib.rs b/src/lib.rs index 04a99397..0fd3250c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,10 @@ #![cfg_attr(docsrs, feature(doc_cfg))] +#![doc( + html_favicon_url = "https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/favicon.ico" +)] + use std::collections::HashMap; use std::ops::Deref; diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..95e1affa748f69b77f95490649836e9861036325 GIT binary patch literal 10206 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 Yo2E{c#pzo8UZDq&kyMnZ6f+L`AAO+n{{R30 literal 0 HcmV?d00001 From 17f52efb7274bc64c680c27f7d9981f02697fc77 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 16 Jul 2025 02:53:49 +0200 Subject: [PATCH 073/244] =?UTF-8?q?=F0=9F=9A=91=20(macros):=20Corrige=20ru?= =?UTF-8?q?tas=20absolutas=20en=20html!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Mantiene fijas las rutas absolutas en las funciones de la macro html!. - Introduce un alias interno del crate (`extern crate self as pagetop;`) en `src/lib.rs` para que las expansiones funcionen uniformemente en tests, ejemplos y dependencias externas. --- Cargo.lock | 31 ++------------------- helpers/pagetop-macros/Cargo.toml | 3 +- helpers/pagetop-macros/src/maud.rs | 12 +------- helpers/pagetop-macros/src/maud/generate.rs | 14 ++-------- src/html/maud.rs | 6 ++-- src/lib.rs | 4 +++ 6 files changed, 14 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cde64db7..ab7b20a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1449,9 +1449,8 @@ dependencies = [ [[package]] name = "pagetop-macros" -version = "0.0.4" +version = "0.0.5" dependencies = [ - "proc-macro-crate", "proc-macro2", "proc-macro2-diagnostics", "quote", @@ -1618,15 +1617,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "proc-macro-crate" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" -dependencies = [ - "toml_edit", -] - [[package]] name = "proc-macro-hack" version = "0.5.20+deprecated" @@ -2185,17 +2175,11 @@ checksum = "f271e09bde39ab52250160a67e88577e0559ad77e9085de6e9051a2c4353f8f8" dependencies = [ "serde", "serde_spanned", - "toml_datetime 0.7.0", + "toml_datetime", "toml_parser", "winnow", ] -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" - [[package]] name = "toml_datetime" version = "0.7.0" @@ -2205,17 +2189,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap", - "toml_datetime 0.6.11", - "winnow", -] - [[package]] name = "toml_parser" version = "1.0.0" diff --git a/helpers/pagetop-macros/Cargo.toml b/helpers/pagetop-macros/Cargo.toml index 070e7784..3a7fd950 100644 --- a/helpers/pagetop-macros/Cargo.toml +++ b/helpers/pagetop-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-macros" -version = "0.0.4" +version = "0.0.5" edition = "2021" description = """\ @@ -20,6 +20,5 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.95" proc-macro2-diagnostics = { version = "0.10.1", default-features = false } -proc-macro-crate = "3.3.0" quote = "1.0.40" syn = { version = "2.0.104", features = ["full"] } diff --git a/helpers/pagetop-macros/src/maud.rs b/helpers/pagetop-macros/src/maud.rs index 9077dbb9..2c763cd0 100644 --- a/helpers/pagetop-macros/src/maud.rs +++ b/helpers/pagetop-macros/src/maud.rs @@ -10,7 +10,6 @@ mod generate; use ast::DiagnosticParse; use proc_macro2::{Ident, Span, TokenStream}; use proc_macro2_diagnostics::Diagnostic; -use proc_macro_crate::{crate_name, FoundCrate}; use quote::quote; use syn::parse::{ParseStream, Parser}; @@ -41,20 +40,11 @@ pub fn expand(input: TokenStream) -> TokenStream { let output_ident = Ident::new("__maud_output", Span::mixed_site()); let stmts = generate::generate(markups, output_ident.clone()); - let found_crate = crate_name("pagetop").expect("pagetop must be in Cargo.toml"); - let crate_ident = match found_crate { - FoundCrate::Itself => Ident::new("pagetop", Span::call_site()), - FoundCrate::Name(ref name) => Ident::new(name, Span::call_site()), - }; - let pre_escaped = quote! { - #crate_ident::html::PreEscaped(#output_ident) - }; - quote! {{ extern crate alloc; let mut #output_ident = alloc::string::String::with_capacity(#size_hint); #stmts #(#diag_tokens)* - #pre_escaped + pagetop::html::PreEscaped(#output_ident) }} } diff --git a/helpers/pagetop-macros/src/maud/generate.rs b/helpers/pagetop-macros/src/maud/generate.rs index 1f825783..19ff3d76 100644 --- a/helpers/pagetop-macros/src/maud/generate.rs +++ b/helpers/pagetop-macros/src/maud/generate.rs @@ -4,8 +4,6 @@ use syn::{parse_quote, token::Brace, Expr, Local}; use crate::maud::{ast::*, escape}; -use proc_macro_crate::{crate_name, FoundCrate}; - pub fn generate(markups: Markups<Element>, output_ident: Ident) -> TokenStream { let mut build = Builder::new(output_ident.clone()); Generator::new(output_ident).markups(markups, &mut build); @@ -68,15 +66,9 @@ impl Generator { fn splice(&self, expr: Expr, build: &mut Builder) { let output_ident = &self.output_ident; - - let found_crate = crate_name("pagetop").expect("pagetop debe existir en Cargo.toml"); - let crate_ident = match found_crate { - FoundCrate::Itself => Ident::new("pagetop", Span::call_site()), - FoundCrate::Name(name) => Ident::new(&name, Span::call_site()), - }; - build.push_tokens(quote! { - #crate_ident::html::html_private::render_to!(&(#expr), &mut #output_ident); - }); + build.push_tokens( + quote!(pagetop::html::html_private::render_to!(&(#expr), &mut #output_ident);), + ); } fn element(&self, element: Element, build: &mut Builder) { diff --git a/src/html/maud.rs b/src/html/maud.rs index 19429869..39cb2c20 100644 --- a/src/html/maud.rs +++ b/src/html/maud.rs @@ -73,7 +73,7 @@ impl fmt::Write for Escaper<'_> { /// # Example /// /// ```rust -/// use pagetop::html::{html, Markup, Render}; +/// use pagetop::prelude::*; /// /// /// Provides a shorthand for linking to a CSS stylesheet. /// pub struct Stylesheet(&'static str); @@ -195,7 +195,7 @@ impl_render_with_itoa! { /// # Example /// /// ```rust -/// use pagetop::html::{display, html}; +/// use pagetop::prelude::*; /// use std::net::Ipv4Addr; /// /// let ip_address = Ipv4Addr::new(127, 0, 0, 1); @@ -266,7 +266,7 @@ impl<T: Default> Default for PreEscaped<T> { /// A minimal web page: /// /// ```rust -/// use pagetop::html::{DOCTYPE, html}; +/// use pagetop::prelude::*; /// /// let markup = html! { /// (DOCTYPE) diff --git a/src/lib.rs b/src/lib.rs index 0fd3250c..248ba6d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,10 @@ html_favicon_url = "https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/favicon.ico" )] +// Alias para que las rutas absolutas `::pagetop::…` generadas por las macros funcionen en el propio +// *crate*, en *crates* externos y en *doctests*. +extern crate self as pagetop; + use std::collections::HashMap; use std::ops::Deref; From de37724835863ffb028d990dc1a7095e6931ee9c Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 19 Jul 2025 00:13:49 +0200 Subject: [PATCH 074/244] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Mej?= =?UTF-8?q?ora=20uso=20y=20doc.=20de=20la=20API=20de=20localizaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/locale.rs | 127 +++++++++++++++++++++++++++++++++++------------- tests/locale.rs | 10 ++-- 2 files changed, 98 insertions(+), 39 deletions(-) diff --git a/src/locale.rs b/src/locale.rs index 064481f0..ab1f5efc 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -13,9 +13,9 @@ //! //! # Recursos Fluent //! -//! Por defecto, las traducciones se organizan en el directorio *src/locale*, con subdirectorios -//! para cada [Identificador de Idioma Unicode](https://docs.rs/unic-langid/) válido. Podríamos -//! tener una estructura como esta: +//! Por defecto las traducciones están en el directorio `src/locale`, con subdirectorios para cada +//! [Identificador de Idioma Unicode](https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier) +//! válido. Podríamos tener una estructura como esta: //! //! ```text //! src/locale/ @@ -29,12 +29,12 @@ //! ├── es-MX/ //! │ ├── default.ftl //! │ └── main.ftl -//! └── fr/ +//! └── fr-FR/ //! ├── default.ftl //! └── main.ftl //! ``` //! -//! Ejemplo de un archivo *src/locale/en-US/main.ftl*: +//! Ejemplo de un archivo en `src/locale/en-US/main.ftl` //! //! ```text //! hello-world = Hello world! @@ -50,7 +50,7 @@ //! }. //! ``` //! -//! Y su archivo equivalente para español *src/locale/es-ES/main.ftl*: +//! Y su archivo equivalente para español en `src/locale/es-ES/main.ftl`: //! //! ```text //! hello-world = Hola mundo! @@ -69,10 +69,11 @@ //! //! # Cómo aplicar la localización en tu código //! -//! Una vez creado el directorio con los recursos FTL, basta con utilizar la macro +//! Una vez creado el directorio con los recursos FTL, basta con usar la macro //! [`include_locales!`](crate::include_locales) para integrarlos en la aplicación. //! -//! Si los recursos se encuentran en el directorio `"src/locale"`, sólo hay que declarar: +//! Si los recursos se encuentran en el directorio por defecto `src/locale` del *crate*, sólo hay +//! que declarar: //! //! ```rust //! use pagetop::prelude::*; @@ -80,11 +81,14 @@ //! include_locales!(LOCALES_SAMPLE); //! ``` //! -//! Pero si están ubicados en otro directorio, entonces se pueden incluir usando: +//! Si están ubicados en otro directorio se puede usar la forma: //! //! ```rust,ignore //! include_locales!(LOCALES_SAMPLE from "ruta/a/las/traducciones"); //! ``` +//! +//! 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::{global, hm, AutoDefault}; @@ -128,28 +132,69 @@ static FALLBACK_LANGID: LazyLock<LanguageIdentifier> = LazyLock::new(|| langid!( pub(crate) static DEFAULT_LANGID: LazyLock<&LanguageIdentifier> = LazyLock::new(|| LangMatch::langid_or_fallback(&global::SETTINGS.app.language)); -/// Comprueba si el idioma está soportado por `PageTop`. +/// Operaciones con los idiomas soportados por `PageTop`. /// -/// Útil para transformar un código de idioma en un [`LanguageIdentifier`] válido para `PageTop`. +/// Utiliza [`LangMatch`] para transformar un código de idioma en un [`LanguageIdentifier`] +/// soportado por `PageTop`. +/// +/// # Ejemplos +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// // Coincidencia exacta. +/// let lang = LangMatch::resolve("es-ES"); +/// assert_eq!(lang.as_langid().to_string(), "es-ES"); +/// +/// // Coincidencia parcial (con el idioma base). +/// let lang = LangMatch::resolve("es-EC"); +/// assert_eq!(lang.as_langid().to_string(), "es-ES"); // Porque "es-EC" no está soportado. +/// +/// // Idioma no especificado. +/// let lang = LangMatch::resolve(""); +/// assert_eq!(lang, LangMatch::Unspecified); +/// +/// // Idioma no soportado. +/// let lang = LangMatch::resolve("ja-JP"); +/// assert_eq!(lang, LangMatch::Unsupported("ja-JP".to_string())); +/// ``` +/// +/// Las siguientes instrucciones devuelven siempre un [`LanguageIdentifier`] válido, ya sea porque +/// resuelven un idioma soportado o porque aplican el idioma por defecto o de respaldo: +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// // Idioma por defecto si no resuelve. +/// let lang = LangMatch::resolve("it-IT"); +/// let langid = lang.as_langid(); +/// +/// // Idioma por defecto si no se encuentra. +/// let langid = LangMatch::langid_or_default("es-MX"); +/// +/// // Idioma de respaldo ("en-US") si no se encuentra. +/// let langid = LangMatch::langid_or_fallback("es-MX"); +/// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub enum LangMatch { /// Cuando el código del idioma es una cadena vacía. - Empty, - /// Si encuentra un [`LanguageIdentifier`] que coincide exactamente o retrocediendo al idioma - /// base. + Unspecified, + /// Si encuentra un [`LanguageIdentifier`] en la lista de idiomas soportados por `PageTop` que + /// coincide exactamente con el código del idioma (p.ej. "es-ES"), o con el código del idioma + /// base (p.ej. "es"). Found(&'static LanguageIdentifier), /// Si el código del idioma no está entre los soportados por `PageTop`. - Unknown(String), + Unsupported(String), } impl LangMatch { - /// Resuelve `language` y devuelve el [`LangMatch`] apropiado. + /// Resuelve `language` y devuelve la variante [`LangMatch`] apropiada. pub fn resolve(language: impl AsRef<str>) -> Self { let language = language.as_ref().trim(); // Rechaza cadenas vacías. if language.is_empty() { - return Self::Empty; + return Self::Unspecified; } // Intenta aplicar coincidencia exacta con el código completo (p.ej. "es-MX"). @@ -164,28 +209,40 @@ impl LangMatch { } } - // Devuelve desconocido si el idioma no está soportado. - Self::Unknown(language.to_string()) + // En otro caso indica que el idioma no está soportado. + Self::Unsupported(language.to_string()) } - /// Devuelve siempre un [`LanguageIdentifier`] válido. + /// Devuelve el idioma de la variante de la instancia, o el idioma por defecto si no está + /// soportado. /// - /// Si `language` está vacío o es desconocido, devuelve el idioma de respaldo ("en-US"). - #[inline] - pub fn langid_or_fallback(language: impl AsRef<str>) -> &'static LanguageIdentifier { - match Self::resolve(language) { - Self::Found(l) => l, - _ => &FALLBACK_LANGID, - } - } - - /// Devuelve un [`LanguageIdentifier`] válido para la instancia. - /// - /// Si `language` está vacío o es desconocido, devuelve el idioma de respaldo ("en-US"). + /// Siempre devuelve un [`LanguageIdentifier`] válido. #[inline] pub fn as_langid(&self) -> &'static LanguageIdentifier { match self { LangMatch::Found(l) => l, + _ => &DEFAULT_LANGID, + } + } + + /// Si `language` está vacío o no está soportado, devuelve el idioma por defecto. + /// + /// Siempre devuelve un [`LanguageIdentifier`] válido. + #[inline] + pub fn langid_or_default(language: impl AsRef<str>) -> &'static LanguageIdentifier { + match Self::resolve(language) { + Self::Found(l) => l, + _ => &DEFAULT_LANGID, + } + } + + /// Si `language` está vacío o no está soportado, devuelve el idioma de respaldo ("en-US"). + /// + /// Siempre devuelve un [`LanguageIdentifier`] válido. + #[inline] + pub fn langid_or_fallback(language: impl AsRef<str>) -> &'static LanguageIdentifier { + match Self::resolve(language) { + Self::Found(l) => l, _ => &FALLBACK_LANGID, } } @@ -243,7 +300,9 @@ enum L10nOp { /// - Una clave para traducir un texto de las traducciones por defecto de `PageTop` (`l()`). /// - Una clave para traducir de un conjunto concreto de traducciones (`t()`). /// -/// Los argumentos dinámicos se añaden mediante `with_arg()` o `with_args()`. +/// # Ejemplo +/// +/// Los argumentos dinámicos se añaden usando `with_arg()` o `with_args()`. /// /// ```rust /// use pagetop::prelude::*; @@ -261,7 +320,7 @@ enum L10nOp { /// /// ```rust,ignore /// // Traducción con clave, conjunto de traducciones y código de idioma a usar. -/// let bye = L10n::t("goodbye", &LOCALES_CUSTOM).using(LangMatch::langid_or_fallback("it")); +/// let bye = L10n::t("goodbye", &LOCALES_CUSTOM).using(LangMatch::langid_or_default("it")); /// ``` #[derive(AutoDefault)] pub struct L10n { diff --git a/tests/locale.rs b/tests/locale.rs index c723cd46..420914d8 100644 --- a/tests/locale.rs +++ b/tests/locale.rs @@ -13,7 +13,7 @@ async fn translation_without_args() { let _app = service::test::init_service(Application::new().test()).await; let l10n = L10n::l("test-hello-world"); - let translation = l10n.using(LangMatch::langid_or_fallback("es-ES")); + let translation = l10n.using(LangMatch::langid_or_default("es-ES")); assert_eq!(translation, Some("¡Hola mundo!".to_string())); } @@ -22,7 +22,7 @@ async fn translation_with_args() { let _app = service::test::init_service(Application::new().test()).await; let l10n = L10n::l("test-hello-user").with_arg("userName", "Manuel"); - let translation = l10n.using(LangMatch::langid_or_fallback("es-ES")); + let translation = l10n.using(LangMatch::langid_or_default("es-ES")); assert_eq!(translation, Some("¡Hola, Manuel!".to_string())); } @@ -35,7 +35,7 @@ async fn translation_with_plural_and_select() { ("photoCount", "3"), ("userGender", "male"), ]); - let translation = l10n.using(LangMatch::langid_or_fallback("es-ES")).unwrap(); + let translation = l10n.using(LangMatch::langid_or_default("es-ES")).unwrap(); assert!(translation.contains("añadido 3 nuevas fotos de él")); } @@ -44,7 +44,7 @@ async fn check_fallback_language() { let _app = service::test::init_service(Application::new().test()).await; let l10n = L10n::l("test-hello-world"); - let translation = l10n.using(LangMatch::langid_or_fallback("xx-YY")); // Fallback a "en-US". + let translation = l10n.using(LangMatch::langid_or_fallback("xx-YY")); // Retrocede a "en-US". assert_eq!(translation, Some("Hello world!".to_string())); } @@ -53,6 +53,6 @@ async fn check_unknown_key() { let _app = service::test::init_service(Application::new().test()).await; let l10n = L10n::l("non-existent-key"); - let translation = l10n.using(LangMatch::langid_or_fallback("en-US")); + let translation = l10n.using(LangMatch::langid_or_default("en-US")); assert_eq!(translation, None); } From a19587c39c073591ed0770840f6b8f6c80d97547 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 20 Jul 2025 11:58:17 +0200 Subject: [PATCH 075/244] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20(bu?= =?UTF-8?q?ild):=20M=C3=A1s=20opciones=20de=20tipo=20para=20funciones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cambia parámetros de tipo en las funciones `from_dir` y `with_name` para aceptar referencias a cadenas. --- helpers/pagetop-build/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index 3816c658..e125c591 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -160,8 +160,8 @@ impl StaticFilesBundle { /// .build() /// } /// ``` - pub fn from_dir(dir: &'static str, filter: Option<fn(p: &Path) -> bool>) -> Self { - let mut resource_dir = resource_dir(dir); + pub fn from_dir(dir: impl AsRef<str>, filter: Option<fn(p: &Path) -> bool>) -> Self { + let mut resource_dir = resource_dir(dir.as_ref()); // Aplica el filtro si está definido. if let Some(f) = filter { @@ -247,7 +247,8 @@ impl StaticFilesBundle { } /// Asigna un nombre al conjunto de recursos. - pub fn with_name(mut self, name: &'static str) -> Self { + pub fn with_name(mut self, name: impl AsRef<str>) -> Self { + let name = name.as_ref(); let out_dir = std::env::var("OUT_DIR").unwrap(); let filename = Path::new(&out_dir).join(format!("{name}.rs")); self.resource_dir.with_generated_filename(filename); From b3ed8e07af1d1b6318701eedd43b86f4471fae3a Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 20 Jul 2025 14:24:19 +0200 Subject: [PATCH 076/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20soporte=20para?= =?UTF-8?q?=20recursos=20en=20documentos=20HTML?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Incluye los recursos favicon, hojas de estilo y scripts JavaScript. - Se introduce una estructura de contexto que, además de gestionar el idioma y el uso de parámetros contextuales, permite administrar estos recursos en documentos HTML. --- src/html.rs | 74 ++++++++++++ src/html/assets.rs | 63 ++++++++++ src/html/assets/favicon.rs | 165 ++++++++++++++++++++++++++ src/html/assets/javascript.rs | 178 ++++++++++++++++++++++++++++ src/html/assets/stylesheet.rs | 174 +++++++++++++++++++++++++++ src/html/context.rs | 216 ++++++++++++++++++++++++++++++++++ src/html/maud.rs | 12 +- src/lib.rs | 6 + src/prelude.rs | 5 +- src/service.rs | 2 +- tests/html.rs | 17 +++ 11 files changed, 904 insertions(+), 8 deletions(-) create mode 100644 src/html/assets.rs create mode 100644 src/html/assets/favicon.rs create mode 100644 src/html/assets/javascript.rs create mode 100644 src/html/assets/stylesheet.rs create mode 100644 src/html/context.rs create mode 100644 tests/html.rs diff --git a/src/html.rs b/src/html.rs index 14e72b94..14a89edd 100644 --- a/src/html.rs +++ b/src/html.rs @@ -2,3 +2,77 @@ mod maud; pub use maud::{display, html, html_private, Escaper, Markup, PreEscaped, Render, DOCTYPE}; + +mod assets; +pub use assets::favicon::Favicon; +pub use assets::javascript::JavaScript; +pub use assets::stylesheet::{StyleSheet, TargetMedia}; +pub(crate) use assets::Assets; + +mod context; +pub use context::{Context, ErrorParam}; + +use crate::AutoDefault; + +/// Prepara contenido HTML para su conversión a [`Markup`]. +/// +/// Este tipo encapsula distintos orígenes de contenido HTML (texto plano, HTML escapado o marcado +/// ya procesado) para renderizar de forma homogénea en plantillas sin interferir con el uso +/// estándar de [`Markup`]. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// let fragment = PrepareMarkup::Text(String::from("Hola <b>mundo</b>")); +/// assert_eq!(fragment.render().into_string(), "Hola &lt;b&gt;mundo&lt;/b&gt;"); +/// +/// let raw_html = PrepareMarkup::Escaped(String::from("<b>negrita</b>")); +/// assert_eq!(raw_html.render().into_string(), "<b>negrita</b>"); +/// +/// let prepared = PrepareMarkup::With(html! { +/// h2 { "Título de ejemplo" } +/// p { "Este es un párrafo con contenido dinámico." } +/// }); +/// assert_eq!( +/// prepared.render().into_string(), +/// "<h2>Título de ejemplo</h2><p>Este es un párrafo con contenido dinámico.</p>" +/// ); +/// ``` +#[derive(AutoDefault)] +pub enum PrepareMarkup { + /// No se genera contenido HTML (devuelve `html! {}`). + #[default] + None, + /// Texto estático que se escapará automáticamente para no ser interpretado como HTML. + Text(String), + /// Contenido sin escapado adicional, útil para HTML generado externamente. + Escaped(String), + /// Fragmento HTML ya preparado como [`Markup`], listo para insertarse directamente. + With(Markup), +} + +impl PrepareMarkup { + /// Devuelve `true` si el contenido está vacío y no generará HTML al renderizar. + pub fn is_empty(&self) -> bool { + match self { + PrepareMarkup::None => true, + PrepareMarkup::Text(text) => text.is_empty(), + PrepareMarkup::Escaped(string) => string.is_empty(), + PrepareMarkup::With(markup) => markup.is_empty(), + } + } +} + +impl Render for PrepareMarkup { + /// Integra el renderizado fácilmente en la macro [`html!`]. + fn render(&self) -> Markup { + match self { + PrepareMarkup::None => html! {}, + PrepareMarkup::Text(text) => html! { (text) }, + PrepareMarkup::Escaped(string) => html! { (PreEscaped(string)) }, + PrepareMarkup::With(markup) => html! { (markup) }, + } + } +} diff --git a/src/html/assets.rs b/src/html/assets.rs new file mode 100644 index 00000000..894b7e84 --- /dev/null +++ b/src/html/assets.rs @@ -0,0 +1,63 @@ +pub mod favicon; +pub mod javascript; +pub mod stylesheet; + +use crate::html::{html, Markup, Render}; +use crate::{AutoDefault, Weight}; + +pub trait AssetsTrait: Render { + // Devuelve el nombre del recurso, utilizado como clave única. + fn name(&self) -> &str; + + // Devuelve el peso del recurso, durante el renderizado se procesan de menor a mayor peso. + fn weight(&self) -> Weight; +} + +#[derive(AutoDefault)] +pub(crate) struct Assets<T>(Vec<T>); + +impl<T: AssetsTrait> Assets<T> { + pub fn new() -> Self { + Assets::<T>(Vec::<T>::new()) + } + + pub fn add(&mut self, asset: T) -> bool { + match self.0.iter().position(|x| x.name() == asset.name()) { + Some(index) => { + if self.0[index].weight() > asset.weight() { + self.0.remove(index); + self.0.push(asset); + true + } else { + false + } + } + _ => { + self.0.push(asset); + true + } + } + } + + pub fn remove(&mut self, name: impl AsRef<str>) -> bool { + if let Some(index) = self.0.iter().position(|x| x.name() == name.as_ref()) { + self.0.remove(index); + true + } else { + false + } + } +} + +impl<T: AssetsTrait> Render for Assets<T> { + fn render(&self) -> Markup { + let mut assets = self.0.iter().collect::<Vec<_>>(); + assets.sort_by_key(|a| a.weight()); + + html! { + @for a in assets { + (a.render()) + } + } + } +} diff --git a/src/html/assets/favicon.rs b/src/html/assets/favicon.rs new file mode 100644 index 00000000..97a44e86 --- /dev/null +++ b/src/html/assets/favicon.rs @@ -0,0 +1,165 @@ +use crate::html::{html, Markup, Render}; +use crate::AutoDefault; + +/// Un **Favicon** es un recurso gráfico que usa el navegador como icono asociado al sitio. +/// +/// Es universalmente aceptado para mostrar el icono del sitio (`.ico`, `.png`, `.svg`, …) en +/// pestañas, marcadores o accesos directos. +/// +/// Este tipo permite construir de forma fluida las distintas variantes de un *favicon*, ya sea un +/// icono estándar, un icono Apple para la pantalla de inicio, o un icono para Safari con color. +/// También puede aplicar colores al tema o configuraciones específicas para *tiles* de Windows. +/// +/// > **Nota** +/// > Los archivos de los iconos deben estar disponibles en el servidor web de la aplicación. Pueden +/// > incluirse en el proyecto utilizando [`include_files`](crate::include_files) y servirse con +/// > [`include_files_service`](crate::include_files_service). +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// let favicon = Favicon::new() +/// // Estándar de facto admitido por todos los navegadores. +/// .with_icon("/icons/favicon.ico") +/// +/// // Variante del favicon con tamaños explícitos: 32×32 y 16×16. +/// .with_icon_for_sizes("/icons/favicon-32.png", "32x32") +/// .with_icon_for_sizes("/icons/favicon-16.png", "16x16") +/// +/// // Icono específico para accesos directos en la pantalla de inicio de iOS. +/// .with_apple_touch_icon("/icons/apple-touch-icon.png", "180x180") +/// +/// // Icono vectorial con color dinámico para pestañas ancladas en Safari. +/// .with_mask_icon("/icons/safari-pinned-tab.svg", "#5bbad5") +/// +/// // Personaliza la barra superior del navegador en Android Chrome (y soportado en otros). +/// .with_theme_color("#ffffff") +/// +/// // Personalizaciones específicas para "tiles" en Windows. +/// .with_ms_tile_color("#da532c") +/// .with_ms_tile_image("/icons/mstile-144x144.png"); +/// ``` +#[derive(AutoDefault)] +pub struct Favicon(Vec<Markup>); + +impl Favicon { + /// Crea un nuevo `Favicon` vacío. + /// + /// Equivalente a `Favicon::default()`. Se recomienda iniciar la secuencia de configuración + /// desde aquí. + pub fn new() -> Self { + Favicon::default() + } + + // Favicon BUILDER ***************************************************************************** + + /// Le añade un icono genérico apuntando a `image`. El tipo MIME se infiere automáticamente a + /// partir de la extensión. + pub fn with_icon(self, image: impl Into<String>) -> Self { + self.add_icon_item("icon", image.into(), None, None) + } + + /// Le añade un icono genérico con atributo `sizes`, útil para indicar resoluciones específicas. + /// + /// El atributo `sizes` informa al navegador de las dimensiones de la imagen para que seleccione + /// el recurso más adecuado. Puede enumerar varias dimensiones separadas por espacios, p.ej. + /// `"16x16 32x32 48x48"` o usar `any` para iconos escalables (SVG). + /// + /// No es imprescindible, pero puede mejorar la selección del icono más adecuado. + pub fn with_icon_for_sizes(self, image: impl Into<String>, sizes: impl Into<String>) -> Self { + self.add_icon_item("icon", image.into(), Some(sizes.into()), None) + } + + /// Le añade un *Apple Touch Icon*, usado por dispositivos iOS para las pantallas de inicio. + /// + /// Se recomienda indicar también el tamaño, p.ej. `"256x256"`. + pub fn with_apple_touch_icon(self, image: impl Into<String>, sizes: impl Into<String>) -> Self { + self.add_icon_item("apple-touch-icon", image.into(), Some(sizes.into()), None) + } + + /// Le añade un icono para el navegador Safari, con un color dinámico. + /// + /// El atributo `color` lo usa Safari para colorear el trazado SVG cuando el icono se muestra en + /// modo *Pinned Tab*. Aunque Safari 12+ acepta *favicons normales*, este método garantiza + /// compatibilidad con versiones anteriores. + pub fn with_mask_icon(self, image: impl Into<String>, color: impl Into<String>) -> Self { + self.add_icon_item("mask-icon", image.into(), None, Some(color.into())) + } + + /// Define el color del tema (`<meta name="theme-color">`). + /// + /// Lo usan algunos navegadores para colorear la barra de direcciones o interfaces. + pub fn with_theme_color(mut self, color: impl Into<String>) -> Self { + self.0.push(html! { + meta name="theme-color" content=(color.into()); + }); + self + } + + /// Define el color del *tile* en Windows (`<meta name="msapplication-TileColor">`). + pub fn with_ms_tile_color(mut self, color: impl Into<String>) -> Self { + self.0.push(html! { + meta name="msapplication-TileColor" content=(color.into()); + }); + self + } + + /// Define la imagen del *tile* en Windows (`<meta name="msapplication-TileImage">`). + pub fn with_ms_tile_image(mut self, image: impl Into<String>) -> Self { + self.0.push(html! { + meta name="msapplication-TileImage" content=(image.into()); + }); + self + } + + // Función interna que centraliza la creación de las etiquetas `<link>`. + // + // - `icon_rel`: indica el tipo de recurso (`"icon"`, `"apple-touch-icon"`, etc.). + // - `icon_source`: URL del recurso. + // - `icon_sizes`: tamaños opcionales. + // - `icon_color`: color opcional (solo relevante para `mask-icon`). + // + // También infiere automáticamente el tipo MIME (`type`) según la extensión del archivo. + fn add_icon_item( + mut self, + icon_rel: &str, + icon_source: String, + icon_sizes: Option<String>, + icon_color: Option<String>, + ) -> Self { + let icon_type = match icon_source.rfind('.') { + Some(i) => match icon_source[i..].to_owned().to_lowercase().as_str() { + ".avif" => Some("image/avif"), + ".gif" => Some("image/gif"), + ".ico" => Some("image/x-icon"), + ".jpg" | ".jpeg" => Some("image/jpeg"), + ".png" => Some("image/png"), + ".svg" => Some("image/svg+xml"), + ".webp" => Some("image/webp"), + _ => None, + }, + _ => None, + }; + self.0.push(html! { + link + rel=(icon_rel) + type=[(icon_type)] + sizes=[(icon_sizes)] + color=[(icon_color)] + href=(icon_source); + }); + self + } +} + +impl Render for Favicon { + fn render(&self) -> Markup { + html! { + @for item in &self.0 { + (item) + } + } + } +} diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs new file mode 100644 index 00000000..fb0a1b64 --- /dev/null +++ b/src/html/assets/javascript.rs @@ -0,0 +1,178 @@ +use crate::html::assets::AssetsTrait; +use crate::html::{html, Markup, Render}; +use crate::{join, join_pair, AutoDefault, Weight}; + +// Define el origen del recurso JavaScript y cómo debe cargarse en el navegador. +// +// Los distintos modos de carga permiten optimizar el rendimiento y controlar el comportamiento del +// script. +// +// - [`From`] – Carga el script de forma estándar con la etiqueta `<script src="...">`. +// - [`Defer`] – Igual que [`From`], pero con el atributo `defer`. +// - [`Async`] – Igual que [`From`], pero con el atributo `async`. +// - [`Inline`] – Inserta el código directamente en la etiqueta `<script>`. +// - [`OnLoad`] – Inserta el código JavaScript y lo ejecuta tras el evento `DOMContentLoaded`. +#[derive(AutoDefault)] +enum Source { + #[default] + From(String), + Defer(String), + Async(String), + Inline(String, String), + OnLoad(String, String), +} + +/// Define un recurso **JavaScript** para incluir en un documento HTML. +/// +/// Este tipo permite añadir *scripts* externos o embebidos con distintas estrategias de carga +/// (`defer`, `async`, *inline*, etc.) y [pesos](crate::Weight) para controlar el orden de inserción +/// en el documento. +/// +/// > **Nota** +/// > Los archivos de los *scripts* deben estar disponibles en el servidor web de la aplicación. +/// > Pueden incluirse en el proyecto utilizando [`include_files`](crate::include_files) y servirse +/// > con [`include_files_service`](crate::include_files_service). +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// // Script externo con carga diferida, versión para control de caché y prioriza el renderizado. +/// let script = JavaScript::defer("/assets/js/app.js") +/// .with_version("1.2.3") +/// .with_weight(-10); +/// +/// // Script embebido que se ejecuta tras la carga del documento. +/// let script = JavaScript::on_load("init_tooltips", r#" +/// const tooltips = document.querySelectorAll('[data-tooltip]'); +/// for (const el of tooltips) { +/// el.addEventListener('mouseenter', showTooltip); +/// } +/// "#); +/// ``` +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct JavaScript { + source : Source, // Fuente y modo de carga del script. + version: String, // Versión del recurso para la caché del navegador. + weight : Weight, // Peso que determina el orden. +} + +impl JavaScript { + /// Crea un **script externo** que se carga y ejecuta de forma inmediata, en orden con el resto + /// del documento HTML. + /// + /// Equivale a `<script src="...">`. + pub fn from(path: impl Into<String>) -> Self { + JavaScript { + source: Source::From(path.into()), + ..Default::default() + } + } + + /// Crea un **script externo** con el atributo `defer`, que se carga en segundo plano y se + /// ejecuta tras analizar completamente el documento HTML. + /// + /// Equivale a `<script src="..." defer>`. Útil para mantener el orden de ejecución y evitar + /// bloquear el análisis del documento HTML. + pub fn defer(path: impl Into<String>) -> Self { + JavaScript { + source: Source::Defer(path.into()), + ..Default::default() + } + } + + /// Crea un **script externo** con el atributo `async`, que se carga y ejecuta de forma + /// asíncrona tan pronto como esté disponible. + /// + /// Equivale a `<script src="..." async>`. La ejecución puede producirse fuera de orden respecto + /// a otros *scripts*. + pub fn asynchronous(path: impl Into<String>) -> Self { + JavaScript { + source: Source::Async(path.into()), + ..Default::default() + } + } + + /// Crea un **script embebido** directamente en el documento HTML. + /// + /// Equivale a `<script>…</script>`. El parámetro `name` se usa como identificador interno del + /// *script*. + pub fn inline(name: impl Into<String>, script: impl Into<String>) -> Self { + JavaScript { + source: Source::Inline(name.into(), script.into()), + ..Default::default() + } + } + + /// Crea un **script embebido** que se ejecuta automáticamente al terminar de cargarse el + /// documento HTML. + /// + /// El código se envuelve automáticamente en un `addEventListener('DOMContentLoaded', ...)`. El + /// parámetro `name` se usa como identificador interno del *script*. + pub fn on_load(name: impl Into<String>, script: impl Into<String>) -> Self { + JavaScript { + source: Source::OnLoad(name.into(), script.into()), + ..Default::default() + } + } + + // JavaScript BUILDER ************************************************************************** + + /// Asocia una versión al recurso (usada para control de la caché del navegador). + /// + /// Si `version` está vacío, no se añade ningún parámetro a la URL. + pub fn with_version(mut self, version: impl Into<String>) -> Self { + self.version = version.into(); + self + } + + /// Modifica el peso del recurso. + /// + /// Los recursos se renderizan de menor a mayor peso. Por defecto es `0`, que respeta el orden + /// de creación. + pub fn with_weight(mut self, value: Weight) -> Self { + self.weight = value; + self + } +} + +impl AssetsTrait for JavaScript { + // Para *scripts* externos es la ruta; para *scripts* embebidos, un identificador. + fn name(&self) -> &str { + match &self.source { + Source::From(path) => path, + Source::Defer(path) => path, + Source::Async(path) => path, + Source::Inline(name, _) => name, + Source::OnLoad(name, _) => name, + } + } + + fn weight(&self) -> Weight { + self.weight + } +} + +impl Render for JavaScript { + fn render(&self) -> Markup { + match &self.source { + Source::From(path) => html! { + script src=(join_pair!(path, "?v=", self.version.as_str())) {}; + }, + Source::Defer(path) => html! { + script src=(join_pair!(path, "?v=", self.version.as_str())) defer {}; + }, + Source::Async(path) => html! { + script src=(join_pair!(path, "?v=", self.version.as_str())) async {}; + }, + Source::Inline(_, code) => html! { + script { (code) }; + }, + Source::OnLoad(_, code) => html! { (join!( + "document.addEventListener('DOMContentLoaded',function(){", code, "});" + )) }, + } + } +} diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs new file mode 100644 index 00000000..7f64d187 --- /dev/null +++ b/src/html/assets/stylesheet.rs @@ -0,0 +1,174 @@ +use crate::html::assets::AssetsTrait; +use crate::html::{html, Markup, PreEscaped, Render}; +use crate::{join_pair, AutoDefault, Weight}; + +// Define el origen del recurso CSS y cómo se incluye en el documento. +// +// Los estilos pueden cargarse desde un archivo externo o estar embebidos directamente en una +// etiqueta `<style>`. +// +// - [`From`] – Carga la hoja de estilos desde un archivo externo, insertándola mediante una +// etiqueta `<link>` con `rel="stylesheet"`. +// - [`Inline`] – Inserta directamente el contenido CSS dentro de una etiqueta `<style>`. +#[derive(AutoDefault)] +enum Source { + #[default] + From(String), + Inline(String, String), +} + +/// Define el medio objetivo para la hoja de estilos. +/// +/// Permite especificar en qué contexto se aplica el CSS, adaptándose a diferentes dispositivos o +/// situaciones de impresión. +#[derive(AutoDefault)] +pub enum TargetMedia { + /// Se aplica en todos los casos (el atributo `media` se omite). + #[default] + Default, + /// Se aplica cuando el documento se imprime. + Print, + /// Se aplica en pantallas. + Screen, + /// Se aplica en dispositivos que convierten el texto a voz. + Speech, +} + +/// Devuelve el texto asociado al punto de interrupción usado por Bootstrap. +#[rustfmt::skip] +impl TargetMedia { + fn as_str_opt(&self) -> Option<&str> { + match self { + TargetMedia::Default => None, + TargetMedia::Print => Some("print"), + TargetMedia::Screen => Some("screen"), + TargetMedia::Speech => Some("speech"), + } + } +} + +/// Define un recurso **StyleSheet** para incluir en un documento HTML. +/// +/// Este tipo permite incluir hojas de estilo CSS externas o embebidas, con soporte para medios +/// específicos (`screen`, `print`, etc.) y [pesos](crate::Weight) que determinan el orden de +/// inserción en el documento. +/// +/// > **Nota** +/// > Las hojas de estilo CSS deben estar disponibles en el servidor web de la aplicación. Pueden +/// > incluirse en el proyecto utilizando [`include_files`](crate::include_files) y servirse con +/// > [`include_files_service`](crate::include_files_service). +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// // Crea una hoja de estilos externa con control de versión y medio específico (`screen`). +/// let stylesheet = StyleSheet::from("/assets/css/main.css") +/// .with_version("2.0.1") +/// .for_media(TargetMedia::Screen) +/// .with_weight(-10); +/// +/// // Crea una hoja de estilos embebida en el documento HTML. +/// let embedded = StyleSheet::inline("custom_theme", r#" +/// body { +/// background-color: #f5f5f5; +/// font-family: 'Segoe UI', sans-serif; +/// } +/// "#); +/// ``` +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct StyleSheet { + source : Source, // Fuente y modo de inclusión del CSS. + version: String, // Versión del recurso para la caché del navegador. + media : TargetMedia, // Medio objetivo para los estilos (`print`, `screen`, …). + weight : Weight, // Peso que determina el orden. +} + +impl StyleSheet { + /// Crea una hoja de estilos externa. + /// + /// Equivale a `<link rel="stylesheet" href="...">`. + pub fn from(path: impl Into<String>) -> Self { + StyleSheet { + source: Source::From(path.into()), + ..Default::default() + } + } + + /// Crea una hoja de estilos embebida directamente en el documento HTML. + /// + /// Equivale a `<style>…</style>`. El parámetro `name` se usa como identificador interno del + /// recurso. + pub fn inline(name: impl Into<String>, styles: impl Into<String>) -> Self { + StyleSheet { + source: Source::Inline(name.into(), styles.into()), + ..Default::default() + } + } + + // StyleSheet BUILDER ************************************************************************** + + /// Asocia una versión al recurso (usada para control de la caché del navegador). + /// + /// Si `version` está vacío, no se añade ningún parámetro a la URL. + pub fn with_version(mut self, version: impl Into<String>) -> Self { + self.version = version.into(); + self + } + + /// Modifica el peso del recurso. + /// + /// Los recursos se renderizan de menor a mayor peso. Por defecto es `0`, que respeta el orden + /// de creación. + pub fn with_weight(mut self, value: Weight) -> Self { + self.weight = value; + self + } + + // StyleSheet EXTRAS *************************************************************************** + + /// Especifica el medio donde se aplican los estilos. + /// + /// Según el argumento `media`: + /// + /// - `TargetMedia::Default` - Se aplica en todos los casos (medio por defecto). + /// - `TargetMedia::Print` - Se aplican cuando el documento se imprime. + /// - `TargetMedia::Screen` - Se aplican en pantallas. + /// - `TargetMedia::Speech` - Se aplican en dispositivos que convierten el texto a voz. + pub fn for_media(mut self, media: TargetMedia) -> Self { + self.media = media; + self + } +} + +impl AssetsTrait for StyleSheet { + // Para hojas de estilos externas es la ruta; para las embebidas, un identificador. + fn name(&self) -> &str { + match &self.source { + Source::From(path) => path, + Source::Inline(name, _) => name, + } + } + + fn weight(&self) -> Weight { + self.weight + } +} + +impl Render for StyleSheet { + fn render(&self) -> Markup { + match &self.source { + Source::From(path) => html! { + link + rel="stylesheet" + href=(join_pair!(path, "?v=", self.version.as_str())) + media=[self.media.as_str_opt()]; + }, + Source::Inline(_, code) => html! { + style { (PreEscaped(code)) }; + }, + } + } +} diff --git a/src/html/context.rs b/src/html/context.rs new file mode 100644 index 00000000..23e2be2b --- /dev/null +++ b/src/html/context.rs @@ -0,0 +1,216 @@ +use crate::core::TypeInfo; +use crate::html::{html, Markup, Render}; +use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; +use crate::join; +use crate::locale::{LanguageIdentifier, DEFAULT_LANGID}; +use crate::service::HttpRequest; + +use std::collections::HashMap; +use std::error::Error; +use std::str::FromStr; + +use std::fmt; + +/// Errores de lectura o conversión de parámetros almacenados en el contexto. +#[derive(Debug)] +pub enum ErrorParam { + /// El parámetro solicitado no existe. + NotFound, + /// El valor del parámetro no pudo convertirse al tipo requerido. + ParseError(String), +} + +impl fmt::Display for ErrorParam { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ErrorParam::NotFound => write!(f, "Parameter not found"), + ErrorParam::ParseError(e) => write!(f, "Parse error: {e}"), + } + } +} + +impl Error for ErrorParam {} + +/// Representa el contexto asociado a un documento HTML. +/// +/// Esta estructura se crea internamente para recoger información relativa al documento asociado, +/// como la solicitud HTTP de origen, el idioma y los recursos *favicon* ([`Favicon`]), las hojas de +/// estilo [`StyleSheet`], los *scripts* [`JavaScript`], o parámetros de contexto definidos en +/// tiempo de ejecución. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// fn configure_context(mut ctx: Context) { +/// // Establece el idioma del documento a español. +/// ctx.set_langid(LangMatch::langid_or_default("es-ES")); +/// +/// // Asigna un favicon. +/// ctx.set_favicon(Some(Favicon::new().with_icon("/icons/favicon.ico"))); +/// +/// // Añade una hoja de estilo externa. +/// ctx.add_stylesheet(StyleSheet::from("/css/style.css")); +/// +/// // Añade un script JavaScript. +/// ctx.add_javascript(JavaScript::defer("/js/main.js")); +/// +/// // Añade un parámetro dinámico al contexto. +/// ctx.set_param("usuario_id", 42); +/// +/// // Recupera el parámetro y lo convierte a su tipo original. +/// let id: i32 = ctx.get_param("usuario_id").unwrap(); +/// assert_eq!(id, 42); +/// +/// // Genera un identificador único para un componente de tipo `Menu`. +/// struct Menu; +/// let unique_id = ctx.required_id::<Menu>(None); +/// assert_eq!(unique_id, "menu-1"); // Si es el primero generado. +/// } +/// ``` +#[rustfmt::skip] +pub struct Context { + request : HttpRequest, // Solicitud HTTP de origen. + langid : &'static LanguageIdentifier, // Identificador del idioma. + favicon : Option<Favicon>, // Favicon, si se ha definido. + stylesheets: Assets<StyleSheet>, // Hojas de estilo CSS. + javascripts: Assets<JavaScript>, // Scripts JavaScript. + params : HashMap<String, String>, // Parámetros definidos en tiempo de ejecución. + id_counter : usize, // Contador para generar identificadores únicos. +} + +impl Context { + // Crea un nuevo contexto asociado a una solicitud HTTP. + // + // El contexto inicializa el idioma por defecto, sin favicon ni recursos cargados. + #[rustfmt::skip] + pub(crate) fn new(request: HttpRequest) -> Self { + Context { + request, + langid : &DEFAULT_LANGID, + favicon : None, + stylesheets: Assets::<StyleSheet>::new(), + javascripts: Assets::<JavaScript>::new(), + params : HashMap::<String, String>::new(), + id_counter : 0, + } + } + + /// Modifica el identificador de idioma del documento. + pub fn set_langid(&mut self, langid: &'static LanguageIdentifier) -> &mut Self { + self.langid = langid; + self + } + + /// Define el *favicon* del documento. Sobrescribe cualquier valor anterior. + pub fn set_favicon(&mut self, favicon: Option<Favicon>) -> &mut Self { + self.favicon = favicon; + self + } + + /// Define el *favicon* solo si no se ha establecido previamente. + pub fn set_favicon_if_none(&mut self, favicon: Favicon) -> &mut Self { + if self.favicon.is_none() { + self.favicon = Some(favicon); + } + self + } + + /// Añade una hoja de estilos CSS al documento. + pub fn add_stylesheet(&mut self, css: StyleSheet) -> &mut Self { + self.stylesheets.add(css); + self + } + + /// Elimina una hoja de estilos por su ruta o identificador. + pub fn remove_stylesheet(&mut self, name: impl AsRef<str>) -> &mut Self { + self.stylesheets.remove(name); + self + } + + /// Añade un *script* JavaScript al documento. + pub fn add_javascript(&mut self, js: JavaScript) -> &mut Self { + self.javascripts.add(js); + self + } + + /// Elimina un *script* por su ruta o identificador. + pub fn remove_javascript(&mut self, name: impl AsRef<str>) -> &mut Self { + self.javascripts.remove(name); + self + } + + /// Añade o modifica un parámetro del contexto almacenando el valor como [`String`]. + pub fn set_param<T: ToString>(&mut self, key: impl AsRef<str>, value: T) -> &mut Self { + self.params + .insert(key.as_ref().to_string(), value.to_string()); + self + } + + // Context GETTERS ***************************************************************************** + + /// Devuelve la solicitud HTTP asociada al documento. + pub fn request(&self) -> &HttpRequest { + &self.request + } + + /// Devuelve el identificador del idioma asociado al documento. + pub fn langid(&self) -> &LanguageIdentifier { + self.langid + } + + /// Recupera un parámetro del contexto convertido al tipo especificado. + /// + /// Devuelve un error si el parámetro no existe ([`ErrorParam::NotFound`]) o la conversión falla + /// ([`ErrorParam::ParseError`]). + pub fn get_param<T: FromStr>(&self, key: impl AsRef<str>) -> Result<T, ErrorParam> { + self.params + .get(key.as_ref()) + .ok_or(ErrorParam::NotFound) + .and_then(|v| T::from_str(v).map_err(|_| ErrorParam::ParseError(v.clone()))) + } + + // Context EXTRAS ****************************************************************************** + + /// Elimina un parámetro del contexto. Devuelve `true` si existía y se eliminó. + pub fn remove_param(&mut self, key: impl AsRef<str>) -> bool { + self.params.remove(key.as_ref()).is_some() + } + + /// Genera un identificador único si no se proporciona uno explícito. + /// + /// Si no se proporciona un `id`, se genera un identificador único en la forma `<tipo>-<número>` + /// donde `<tipo>` es el nombre corto del tipo en minúsculas (sin espacios) y `<número>` es un + /// contador interno incremental. + pub fn required_id<T>(&mut self, id: Option<String>) -> String { + if let Some(id) = id { + id + } else { + let prefix = TypeInfo::ShortName + .of::<T>() + .trim() + .replace(' ', "_") + .to_lowercase(); + let prefix = if prefix.is_empty() { + "prefix".to_owned() + } else { + prefix + }; + self.id_counter += 1; + join!(prefix, "-", self.id_counter.to_string()) + } + } +} + +impl Render for Context { + fn render(&self) -> Markup { + html! { + @if let Some(favicon) = &self.favicon { + (favicon) + } + (self.stylesheets) + (self.javascripts) + } + } +} diff --git a/src/html/maud.rs b/src/html/maud.rs index 39cb2c20..9bf179ec 100644 --- a/src/html/maud.rs +++ b/src/html/maud.rs @@ -18,7 +18,7 @@ pub use pagetop_macros::html; mod escape; -/// An adapter that escapes HTML special characters. +/// Adaptador que escapa los caracteres especiales de HTML. /// /// The following characters are escaped: /// @@ -57,7 +57,7 @@ impl fmt::Write for Escaper<'_> { } } -/// Represents a type that can be rendered as HTML. +/// Representa un tipo que puede renderizarse como HTML. /// /// To implement this for your own type, override either the `.render()` /// or `.render_to()` methods; since each is defined in terms of the @@ -190,7 +190,7 @@ impl_render_with_itoa! { u8 u16 u32 u64 u128 usize } -/// Renders a value using its [`Display`] impl. +/// Renderiza un valor usando su implementación de [`Display`]. /// /// # Example /// @@ -219,7 +219,7 @@ pub fn display(value: impl Display) -> impl Render { DisplayWrapper(value) } -/// A wrapper that renders the inner value without escaping. +/// Contenedor que renderiza el valor interno sin escapar. #[derive(Debug, Clone, Copy)] pub struct PreEscaped<T>(pub T); @@ -229,7 +229,7 @@ impl<T: AsRef<str>> Render for PreEscaped<T> { } } -/// A block of markup is a string that does not need to be escaped. +/// Un bloque de marcado es una cadena que no necesita ser escapada. /// /// The `html!` macro expands to an expression of this type. pub type Markup = PreEscaped<String>; @@ -259,7 +259,7 @@ impl<T: Default> Default for PreEscaped<T> { } } -/// The literal string `<!DOCTYPE html>`. +/// La cadena literal `<!DOCTYPE html>`. /// /// # Example /// diff --git a/src/lib.rs b/src/lib.rs index 248ba6d4..f3126212 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,6 +66,12 @@ impl Deref for StaticResources { } } +/// Representa el peso lógico de una instancia en una colección ordenada por pesos. +/// +/// Las instancias con pesos **más bajos**, incluyendo valores negativos (`-128..127`), se situarán +/// antes en la ordenación. +pub type Weight = i8; + // API ********************************************************************************************* // Funciones y macros útiles. diff --git a/src/prelude.rs b/src/prelude.rs index 6506aaf9..3a9f4f67 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -4,7 +4,7 @@ pub use crate::{builder_fn, html, main, test}; -pub use crate::{AutoDefault, StaticResources}; +pub use crate::{AutoDefault, StaticResources, Weight}; // MACROS. @@ -16,6 +16,8 @@ pub use crate::include_config; pub use crate::include_locales; // crate::service pub use crate::{include_files, include_files_service}; +// crate::core::action +//pub use crate::actions; // API. @@ -35,6 +37,7 @@ pub use crate::service; pub use crate::core::{AnyCast, AnyInfo, TypeInfo}; +//pub use crate::core::action::*; pub use crate::core::extension::*; pub use crate::app::Application; diff --git a/src/service.rs b/src/service.rs index 9e506fae..47e84224 100644 --- a/src/service.rs +++ b/src/service.rs @@ -6,7 +6,7 @@ pub use actix_web::dev::ServiceFactory as Factory; pub use actix_web::dev::ServiceRequest as Request; pub use actix_web::dev::ServiceResponse as Response; pub use actix_web::{http, rt, web}; -pub use actix_web::{App, Error, HttpServer}; +pub use actix_web::{App, Error, HttpRequest, HttpServer}; #[doc(hidden)] pub use actix_web::test; diff --git a/tests/html.rs b/tests/html.rs new file mode 100644 index 00000000..315f74ad --- /dev/null +++ b/tests/html.rs @@ -0,0 +1,17 @@ +use pagetop::prelude::*; + +#[pagetop::test] +async fn prepare_markup_is_empty() { + let _app = service::test::init_service(Application::new().test()).await; + + assert!(PrepareMarkup::None.is_empty()); + + assert!(PrepareMarkup::Text(String::from("")).is_empty()); + assert!(!PrepareMarkup::Text(String::from("x")).is_empty()); + + assert!(PrepareMarkup::Escaped(String::new()).is_empty()); + assert!(!PrepareMarkup::Escaped("a".into()).is_empty()); + + assert!(PrepareMarkup::With(html! {}).is_empty()); + assert!(!PrepareMarkup::With(html! { span { "!" } }).is_empty()); +} From 50b704fb6db8ace6fbb89f623b78968ec5845b95 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 20 Jul 2025 14:28:09 +0200 Subject: [PATCH 077/244] =?UTF-8?q?=F0=9F=93=9D=20Retoques=20en=20la=20doc?= =?UTF-8?q?umentaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core.rs | 2 +- src/core/extension.rs | 2 +- src/core/extension/definition.rs | 4 ++-- src/lib.rs | 1 - src/locale.rs | 30 +++++++++++++++--------------- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/core.rs b/src/core.rs index 5aebd1fa..4541fae6 100644 --- a/src/core.rs +++ b/src/core.rs @@ -201,5 +201,5 @@ pub trait AnyCast: AnyInfo { /// Implementación automática para cualquier tipo que ya cumpla [`AnyInfo`]. impl<T: ?Sized + AnyInfo> AnyCast for T {} -// Infraestructura para ampliar funcionalidades mediante extensiones. +// API para añadir nuevas funcionalidades usando extensiones. pub mod extension; diff --git a/src/core/extension.rs b/src/core/extension.rs index 9eb3bd24..c493cf5c 100644 --- a/src/core/extension.rs +++ b/src/core/extension.rs @@ -1,4 +1,4 @@ -//! Infraestructura para ampliar funcionalidades mediante extensiones. +//! API para añadir nuevas funcionalidades usando extensiones. //! //! Cada funcionalidad adicional que quiera incorporarse a una aplicación `PageTop` se debe modelar //! como una **extensión**. Todas comparten la misma interfaz declarada en [`ExtensionTrait`]. diff --git a/src/core/extension/definition.rs b/src/core/extension/definition.rs index 761fceea..625beba0 100644 --- a/src/core/extension/definition.rs +++ b/src/core/extension/definition.rs @@ -10,8 +10,8 @@ pub type ExtensionRef = &'static dyn ExtensionTrait; /// Interfaz común que debe implementar cualquier extensión de `PageTop`. /// -/// Este *trait* es fácil de implementar, basta con declarar la estructura de la extensión y -/// sobreescribir los métodos que sea necesario. +/// Este *trait* es fácil de implementar, basta con declarar una estructura de tamaño cero para la +/// extensión y sobreescribir los métodos que sea necesario. /// /// ```rust /// use pagetop::prelude::*; diff --git a/src/lib.rs b/src/lib.rs index f3126212..edc791cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,7 +29,6 @@ //! ``` #![cfg_attr(docsrs, feature(doc_cfg))] - #![doc( html_favicon_url = "https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/favicon.ico" )] diff --git a/src/locale.rs b/src/locale.rs index ab1f5efc..2dcf27e7 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -107,8 +107,8 @@ use std::sync::LazyLock; use std::fmt; -// Asocia cada código de idioma (como "en-US") con su respectivo [`LanguageIdentifier`] y la clave -// en *locale/.../languages.ftl* para obtener el nombre del idioma según la localización. +// Asocia cada identificador de idioma (como "en-US") con su respectivo [`LanguageIdentifier`] y la +// clave en *locale/.../languages.ftl* para obtener el nombre del idioma según la localización. static LANGUAGES: LazyLock<HashMap<&str, (LanguageIdentifier, &str)>> = LazyLock::new(|| { hm![ "en" => ( langid!("en-US"), "english" ), @@ -121,20 +121,20 @@ static LANGUAGES: LazyLock<HashMap<&str, (LanguageIdentifier, &str)>> = LazyLock // Identificador del idioma de **respaldo** (predefinido a `en-US`). // -// Se usa cuando el valor del código de idioma en las traducciones no corresponde con ningún idioma -// soportado por la aplicación. +// Se usa cuando el valor del identificador de idioma en las traducciones no corresponde con ningún +// idioma soportado por la aplicación. static FALLBACK_LANGID: LazyLock<LanguageIdentifier> = LazyLock::new(|| langid!("en-US")); // Identificador del idioma **por defecto** para la aplicación. // -// Se resuelve a partir de [`global::SETTINGS.app.language`](global::SETTINGS). Si el código de -// idioma configurado no es válido o no está disponible entonces resuelve como [`FALLBACK_LANGID`]. +// Se resuelve a partir de [`global::SETTINGS.app.language`](global::SETTINGS). Si el identificador +// de idioma no es válido o no está disponible entonces resuelve como [`FALLBACK_LANGID`]. pub(crate) static DEFAULT_LANGID: LazyLock<&LanguageIdentifier> = LazyLock::new(|| LangMatch::langid_or_fallback(&global::SETTINGS.app.language)); /// Operaciones con los idiomas soportados por `PageTop`. /// -/// Utiliza [`LangMatch`] para transformar un código de idioma en un [`LanguageIdentifier`] +/// Utiliza [`LangMatch`] para transformar un identificador de idioma en un [`LanguageIdentifier`] /// soportado por `PageTop`. /// /// # Ejemplos @@ -156,10 +156,10 @@ pub(crate) static DEFAULT_LANGID: LazyLock<&LanguageIdentifier> = /// /// // Idioma no soportado. /// let lang = LangMatch::resolve("ja-JP"); -/// assert_eq!(lang, LangMatch::Unsupported("ja-JP".to_string())); +/// assert_eq!(lang, LangMatch::Unsupported(String::from("ja-JP"))); /// ``` /// -/// Las siguientes instrucciones devuelven siempre un [`LanguageIdentifier`] válido, ya sea porque +/// Las siguientes líneas devuelven siempre un [`LanguageIdentifier`] válido, ya sea porque /// resuelven un idioma soportado o porque aplican el idioma por defecto o de respaldo: /// /// ```rust @@ -177,13 +177,13 @@ pub(crate) static DEFAULT_LANGID: LazyLock<&LanguageIdentifier> = /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub enum LangMatch { - /// Cuando el código del idioma es una cadena vacía. + /// Cuando el identificador del idioma es una cadena vacía. Unspecified, /// Si encuentra un [`LanguageIdentifier`] en la lista de idiomas soportados por `PageTop` que - /// coincide exactamente con el código del idioma (p.ej. "es-ES"), o con el código del idioma - /// base (p.ej. "es"). + /// coincide exactamente con el identificador del idioma (p.ej. "es-ES"), o con el identificador + /// del idioma base (p.ej. "es"). Found(&'static LanguageIdentifier), - /// Si el código del idioma no está entre los soportados por `PageTop`. + /// Si el identificador del idioma no está entre los soportados por `PageTop`. Unsupported(String), } @@ -210,7 +210,7 @@ impl LangMatch { } // En otro caso indica que el idioma no está soportado. - Self::Unsupported(language.to_string()) + Self::Unsupported(String::from(language)) } /// Devuelve el idioma de la variante de la instancia, o el idioma por defecto si no está @@ -319,7 +319,7 @@ enum L10nOp { /// También para traducciones a idiomas concretos. /// /// ```rust,ignore -/// // Traducción con clave, conjunto de traducciones y código de idioma a usar. +/// // Traducción con clave, conjunto de traducciones e identificador de idioma a usar. /// let bye = L10n::t("goodbye", &LOCALES_CUSTOM).using(LangMatch::langid_or_default("it")); /// ``` #[derive(AutoDefault)] From 861392430a5c4bb073e8de968e600c0ffa5a318a Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 20 Jul 2025 23:51:15 +0200 Subject: [PATCH 078/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20soporte=20a=20?= =?UTF-8?q?temas=20en=20la=20API=20de=20extensiones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Incluye una opción de configuración para definir el tema por defecto. - Añade un tema básico predeterminado. --- config/default.toml | 2 ++ src/base.rs | 3 +++ src/base/theme.rs | 4 ++++ src/base/theme/basic.rs | 14 ++++++++++++++ src/core.rs | 5 ++++- src/core/extension/all.rs | 19 +++++++++++++++++++ src/core/extension/definition.rs | 26 ++++++++++++++++++++++++++ src/core/theme.rs | 6 ++++++ src/core/theme/all.rs | 31 +++++++++++++++++++++++++++++++ src/core/theme/definition.rs | 30 ++++++++++++++++++++++++++++++ src/global.rs | 3 +++ src/lib.rs | 4 +++- src/prelude.rs | 6 +++--- 13 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 config/default.toml create mode 100644 src/base.rs create mode 100644 src/base/theme.rs create mode 100644 src/base/theme/basic.rs create mode 100644 src/core/theme.rs create mode 100644 src/core/theme/all.rs create mode 100644 src/core/theme/definition.rs diff --git a/config/default.toml b/config/default.toml new file mode 100644 index 00000000..3e254586 --- /dev/null +++ b/config/default.toml @@ -0,0 +1,2 @@ +[log] +tracing = "Info,pagetop=Debug" diff --git a/src/base.rs b/src/base.rs new file mode 100644 index 00000000..c50cc9e4 --- /dev/null +++ b/src/base.rs @@ -0,0 +1,3 @@ +//! Reúne temas listos para usar. + +pub mod theme; diff --git a/src/base/theme.rs b/src/base/theme.rs new file mode 100644 index 00000000..ea9eeb66 --- /dev/null +++ b/src/base/theme.rs @@ -0,0 +1,4 @@ +//! Temas básicos soportados por `PageTop`. + +mod basic; +pub use basic::Basic; diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs new file mode 100644 index 00000000..0fc533c5 --- /dev/null +++ b/src/base/theme/basic.rs @@ -0,0 +1,14 @@ +//! Es el tema básico que incluye `PageTop` por defecto. + +use crate::prelude::*; + +/// Tema básico por defecto. +pub struct Basic; + +impl ExtensionTrait for Basic { + fn theme(&self) -> Option<ThemeRef> { + Some(&Self) + } +} + +impl ThemeTrait for Basic {} diff --git a/src/core.rs b/src/core.rs index 4541fae6..9f3d7b55 100644 --- a/src/core.rs +++ b/src/core.rs @@ -1,4 +1,4 @@ -//! Tipos y funciones esenciales para crear extensiones. +//! Tipos y funciones esenciales para crear extensiones y temas. use std::any::Any; @@ -203,3 +203,6 @@ impl<T: ?Sized + AnyInfo> AnyCast for T {} // API para añadir nuevas funcionalidades usando extensiones. pub mod extension; + +// API para añadir y gestionar nuevos temas. +pub mod theme; diff --git a/src/core/extension/all.rs b/src/core/extension/all.rs index d5bebdad..63a178c9 100644 --- a/src/core/extension/all.rs +++ b/src/core/extension/all.rs @@ -1,4 +1,5 @@ use crate::core::extension::ExtensionRef; +use crate::core::theme::all::THEMES; use crate::{service, trace}; use std::sync::{LazyLock, RwLock}; @@ -17,6 +18,9 @@ pub fn register_extensions(root_extension: Option<ExtensionRef>) { // Prepara la lista de extensiones habilitadas. let mut enabled_list: Vec<ExtensionRef> = Vec::new(); + // Primero añade el tema básico a la lista de extensiones habilitadas. + add_to_enabled(&mut enabled_list, &crate::base::theme::Basic); + // Si se proporciona una extensión raíz inicial, se añade a la lista de extensiones habilitadas. if let Some(extension) = root_extension { add_to_enabled(&mut enabled_list, extension); @@ -53,6 +57,21 @@ fn add_to_enabled(list: &mut Vec<ExtensionRef>, extension: ExtensionRef) { // Añade la propia extensión a la lista. list.push(extension); + + // Comprueba si la extensión tiene un tema asociado que deba registrarse. + if let Some(theme) = extension.theme() { + let mut registered_themes = THEMES.write().unwrap(); + // Asegura que el tema no esté ya registrado para evitar duplicados. + if !registered_themes + .iter() + .any(|t| t.type_id() == theme.type_id()) + { + registered_themes.push(theme); + trace::debug!("Enabling \"{}\" theme", theme.short_name()); + } + } else { + trace::debug!("Enabling \"{}\" extension", extension.short_name()); + } } } diff --git a/src/core/extension/definition.rs b/src/core/extension/definition.rs index 625beba0..6b963a24 100644 --- a/src/core/extension/definition.rs +++ b/src/core/extension/definition.rs @@ -1,3 +1,4 @@ +use crate::core::theme::ThemeRef; use crate::core::AnyInfo; use crate::locale::L10n; use crate::service; @@ -36,6 +37,31 @@ pub trait ExtensionTrait: AnyInfo + Send + Sync { L10n::default() } + /// Los temas son extensiones que implementan [`ExtensionTrait`] y también + /// [`ThemeTrait`](crate::core::theme::ThemeTrait). + /// + /// Si la extensión no es un tema, este método devuelve `None` por defecto. + /// + /// En caso contrario, este método debe implementarse para devolver una referencia de sí mismo + /// como tema. Por ejemplo: + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// pub struct MyTheme; + /// + /// impl ExtensionTrait for MyTheme { + /// fn theme(&self) -> Option<ThemeRef> { + /// Some(&Self) + /// } + /// } + /// + /// impl ThemeTrait for MyTheme {} + /// ``` + fn theme(&self) -> Option<ThemeRef> { + None + } + /// Otras extensiones que deben habilitarse **antes** de esta. /// /// `PageTop` las resolverá automáticamente respetando el orden durante el arranque de la diff --git a/src/core/theme.rs b/src/core/theme.rs new file mode 100644 index 00000000..d741cf80 --- /dev/null +++ b/src/core/theme.rs @@ -0,0 +1,6 @@ +//! API para añadir y gestionar nuevos temas. + +mod definition; +pub use definition::{ThemeRef, ThemeTrait}; + +pub(crate) mod all; diff --git a/src/core/theme/all.rs b/src/core/theme/all.rs new file mode 100644 index 00000000..3516107e --- /dev/null +++ b/src/core/theme/all.rs @@ -0,0 +1,31 @@ +use crate::core::theme::ThemeRef; +use crate::global; + +use std::sync::{LazyLock, RwLock}; + +// TEMAS ******************************************************************************************* + +pub static THEMES: LazyLock<RwLock<Vec<ThemeRef>>> = LazyLock::new(|| RwLock::new(Vec::new())); + +// TEMA PREDETERMINADO ***************************************************************************** + +pub static DEFAULT_THEME: LazyLock<ThemeRef> = + LazyLock::new(|| match theme_by_short_name(&global::SETTINGS.app.theme) { + Some(theme) => theme, + None => &crate::base::theme::Basic, + }); + +// TEMA POR NOMBRE ********************************************************************************* + +pub fn theme_by_short_name(short_name: impl AsRef<str>) -> Option<ThemeRef> { + let short_name = short_name.as_ref().to_lowercase(); + match THEMES + .read() + .unwrap() + .iter() + .find(|t| t.short_name().to_lowercase() == short_name) + { + Some(theme) => Some(*theme), + _ => None, + } +} diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs new file mode 100644 index 00000000..13fe2824 --- /dev/null +++ b/src/core/theme/definition.rs @@ -0,0 +1,30 @@ +use crate::core::extension::ExtensionTrait; + +/// Representa una referencia a un tema. +/// +/// Los temas son también extensiones. Por tanto se deben definir igual, es decir, como instancias +/// estáticas globales que implementan [`ThemeTrait`], pero también [`ExtensionTrait`]. +pub type ThemeRef = &'static dyn ThemeTrait; + +/// Interfaz común que debe implementar cualquier tema de `PageTop`. +/// +/// Un tema implementará [`ThemeTrait`] y los métodos que sean necesarios de [`ExtensionTrait`], +/// aunque el único obligatorio es [`theme()`](crate::core::extension::ExtensionTrait#method.theme). +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// pub struct MyTheme; +/// +/// impl ExtensionTrait for MyTheme { +/// fn name(&self) -> L10n { L10n::n("My theme") } +/// fn description(&self) -> L10n { L10n::n("Un tema personal") } +/// +/// fn theme(&self) -> Option<ThemeRef> { +/// Some(&Self) +/// } +/// } +/// +/// impl ThemeTrait for MyTheme {} +/// ``` +pub trait ThemeTrait: ExtensionTrait + Send + Sync {} diff --git a/src/global.rs b/src/global.rs index c3332d39..e8f50658 100644 --- a/src/global.rs +++ b/src/global.rs @@ -8,6 +8,7 @@ include_config!(SETTINGS: Settings => [ // [app] "app.name" => "Sample", "app.description" => "Developed with the amazing PageTop framework.", + "app.theme" => "Basic", "app.language" => "en-US", "app.startup_banner" => "Slant", @@ -40,6 +41,8 @@ pub struct App { pub name: String, /// Breve descripción de la aplicación. pub description: String, + /// Tema predeterminado. + pub theme: String, /// Idioma predeterminado (localización). pub language: String, /// Banner ASCII mostrado al inicio: *"Off"* (desactivado), *"Slant"*, *"Small"*, *"Speed"* o diff --git a/src/lib.rs b/src/lib.rs index edc791cd..264fdbc4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,10 +87,12 @@ pub mod html; pub mod locale; // Soporte a fechas y horas. pub mod datetime; -// Tipos y funciones esenciales para crear extensiones. +// Tipos y funciones esenciales para crear extensiones y temas. pub mod core; // Gestión del servidor y servicios web. pub mod service; +// Reúne temas listos para usar. +pub mod base; // Prepara y ejecuta la aplicación. pub mod app; diff --git a/src/prelude.rs b/src/prelude.rs index 3a9f4f67..7244b912 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -16,8 +16,6 @@ pub use crate::include_config; pub use crate::include_locales; // crate::service pub use crate::{include_files, include_files_service}; -// crate::core::action -//pub use crate::actions; // API. @@ -37,7 +35,9 @@ pub use crate::service; pub use crate::core::{AnyCast, AnyInfo, TypeInfo}; -//pub use crate::core::action::*; pub use crate::core::extension::*; +pub use crate::core::theme::*; + +pub use crate::base::theme; pub use crate::app::Application; From c89d4bb5fc609be3f0d040a68b2df1727469e0df Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 21 Jul 2025 08:58:09 +0200 Subject: [PATCH 079/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20soporte=20para?= =?UTF-8?q?=20inyectar=20acciones=20en=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.rs | 3 + src/core.rs | 5 +- src/core/action.rs | 66 ++++++++++++++++++++ src/core/action/all.rs | 66 ++++++++++++++++++++ src/core/action/definition.rs | 102 +++++++++++++++++++++++++++++++ src/core/action/list.rs | 43 +++++++++++++ src/core/extension/all.rs | 11 ++++ src/core/extension/definition.rs | 12 +++- src/lib.rs | 7 ++- src/prelude.rs | 5 +- 10 files changed, 316 insertions(+), 4 deletions(-) create mode 100644 src/core/action.rs create mode 100644 src/core/action/all.rs create mode 100644 src/core/action/definition.rs create mode 100644 src/core/action/list.rs diff --git a/src/app.rs b/src/app.rs index 0bcece8e..b6b5a716 100644 --- a/src/app.rs +++ b/src/app.rs @@ -56,6 +56,9 @@ impl Application { // Registra las extensiones de la aplicación. extension::all::register_extensions(root_extension); + // Registra las acciones de las extensiones. + extension::all::register_actions(); + // Inicializa las extensiones. extension::all::initialize_extensions(); diff --git a/src/core.rs b/src/core.rs index 9f3d7b55..4b857fc4 100644 --- a/src/core.rs +++ b/src/core.rs @@ -1,4 +1,4 @@ -//! Tipos y funciones esenciales para crear extensiones y temas. +//! Tipos y funciones esenciales para crear acciones, extensiones y temas. use std::any::Any; @@ -201,6 +201,9 @@ pub trait AnyCast: AnyInfo { /// Implementación automática para cualquier tipo que ya cumpla [`AnyInfo`]. impl<T: ?Sized + AnyInfo> AnyCast for T {} +// API para definir acciones que alteran el comportamiento predeterminado del código. +pub mod action; + // API para añadir nuevas funcionalidades usando extensiones. pub mod extension; diff --git a/src/core/action.rs b/src/core/action.rs new file mode 100644 index 00000000..8503ae90 --- /dev/null +++ b/src/core/action.rs @@ -0,0 +1,66 @@ +//! API para definir acciones que inyectan código en el flujo de la aplicación. +//! +//! Permite crear acciones en las librerías para que otros *crates* puedan inyectar código usando +//! funciones *ad hoc* que modifican el comportamiento predefinido en puntos concretos del flujo de +//! ejecución de la aplicación. + +mod definition; +pub use definition::{ActionBase, ActionBox, ActionKey, ActionTrait}; + +mod list; +use list::ActionsList; + +mod all; +pub(crate) use all::add_action; +pub use all::dispatch_actions; + +/// Crea una lista de acciones para facilitar la implementación del método +/// [`actions`](crate::core::extension::ExtensionTrait#method.actions). +/// +/// Esta macro crea vectores de [`ActionBox`], el tipo dinámico que encapsula cualquier acción que +/// implemente [`ActionTrait`]. Evita escribir repetidamente `Box::new(...)` para cada acción +/// inyectada, manteniendo el código más limpio. +/// +/// # Ejemplos +/// +/// Puede llamarse sin argumentos para crear un vector vacío: +/// +/// ```rust,ignore +/// let my_actions = inject_actions![]; +/// ``` +/// +/// O con una lista de acciones concretas: +/// +/// ```rust,ignore +/// let my_actions = inject_actions![ +/// MyFirstAction::new(), +/// MySecondAction::new().with_weight(10), +/// ]; +/// ``` +/// +/// Internamente, expande a un `vec![Box::new(...), ...]`. +/// +/// # Ejemplo típico en una extensión +/// +/// ```rust,ignore +/// impl ExtensionTrait for MyExtension { +/// fn actions(&self) -> Vec<ActionBox> { +/// inject_actions![ +/// CustomizeLoginAction::new(), +/// ModifyHeaderAction::new().with_weight(-5), +/// ] +/// } +/// } +/// ``` +/// +/// Así, `PageTop` podrá registrar todas estas acciones durante la inicialización de la extensión y +/// posteriormente despacharlas según corresponda. +#[macro_export] +macro_rules! inject_actions { + () => { + Vec::<ActionBox>::new() + }; + ( $($action:expr),+ $(,)? ) => {{ + vec![$(Box::new($action),)+] + }}; +} diff --git a/src/core/action/all.rs b/src/core/action/all.rs new file mode 100644 index 00000000..4dcb68df --- /dev/null +++ b/src/core/action/all.rs @@ -0,0 +1,66 @@ +use crate::core::action::{ActionBox, ActionKey, ActionTrait, ActionsList}; + +use std::collections::HashMap; +use std::sync::{LazyLock, RwLock}; + +// ACCIONES **************************************************************************************** + +static ACTIONS: LazyLock<RwLock<HashMap<ActionKey, ActionsList>>> = + LazyLock::new(|| RwLock::new(HashMap::new())); + +// AÑADIR ACCIONES ********************************************************************************* + +// Registra una nueva acción en el sistema. +// +// Si ya existen acciones con la misma `ActionKey`, la acción se añade a la lista existente. Si no, +// se crea una nueva lista. +// +// # Uso típico +// +// Las extensiones llamarán a esta función durante su inicialización para instalar acciones +// personalizadas que modifiquen el comportamiento del núcleo o de otros componentes. +// +// ```rust,ignore +// add_action(Box::new(MyCustomAction::new())); +// ``` +pub fn add_action(action: ActionBox) { + let key = action.key(); + let mut actions = ACTIONS.write().unwrap(); + if let Some(list) = actions.get_mut(&key) { + list.add(action); + } else { + let mut list = ActionsList::new(); + list.add(action); + actions.insert(key, list); + } +} + +// DESPLEGAR ACCIONES ****************************************************************************** + +/// Despacha las funciones asociadas a un [`ActionKey`] y las ejecuta. +/// +/// Permite recorrer de forma segura y ordenada (por peso) la lista de funciones asociadas a una +/// acción específica. +/// +/// # Parámetros genéricos +/// - `A`: Tipo de acción que esperamos procesar. Debe implementar [`ActionTrait`]. +/// - `F`: Función o cierre que recibe cada acción y devuelve un valor de tipo `B`. +/// +/// # Ejemplo de uso +/// ```rust,ignore +/// dispatch_actions::<MyCustomAction, _>(&some_key, |action| { +/// action.do_something(); +/// }); +/// ``` +/// +/// Esto permite a PageTop o a otros módulos aplicar lógica específica a las acciones de un contexto +/// determinado, manteniendo la flexibilidad del sistema. +pub fn dispatch_actions<A, B, F>(key: &ActionKey, f: F) +where + A: ActionTrait, + F: FnMut(&A) -> B, +{ + if let Some(list) = ACTIONS.read().unwrap().get(key) { + list.iter_map(f); + } +} diff --git a/src/core/action/definition.rs b/src/core/action/definition.rs new file mode 100644 index 00000000..d662b2b6 --- /dev/null +++ b/src/core/action/definition.rs @@ -0,0 +1,102 @@ +use crate::core::AnyInfo; +use crate::{UniqueId, Weight}; + +/// Tipo dinámico para encapsular cualquier acción que implementa [`ActionTrait`]. +pub type ActionBox = Box<dyn ActionTrait>; + +/// Identifica una acción con una clave que define las condiciones de selección de las funciones +/// asociadas a esa acción. +/// +/// Las funciones seleccionadas se van a [despachar](crate::core::action::dispatch_actions) y +/// ejecutar en un punto concreto del flujo de ejecución. +/// +/// # Campos +/// +/// - `action_type_id`: Tipo de la acción. +/// - `theme_type_id`: Opcional, filtra las funciones para un tema dado. +/// - `referer_type_id`: Opcional, filtra las funciones para un tipo dado (p.ej. para un tipo de +/// componente). +/// - `referer_id`: Opcional, filtra las funciones por el identificador de una instancia (p.ej. para +/// un formulario concreto). +#[derive(Eq, PartialEq, Hash)] +pub struct ActionKey { + action_type_id: UniqueId, + theme_type_id: Option<UniqueId>, + referer_type_id: Option<UniqueId>, + referer_id: Option<String>, +} + +impl ActionKey { + /// Crea una nueva clave para un tipo de acción. + /// + /// Esta clave permite seleccionar las funciones a ejecutar para ese tipo de acción con filtros + /// opcionales por tema, un tipo de referencia, o una instancia concreta según su identificador. + pub fn new( + action_type_id: UniqueId, + theme_type_id: Option<UniqueId>, + referer_type_id: Option<UniqueId>, + referer_id: Option<String>, + ) -> Self { + ActionKey { + action_type_id, + theme_type_id, + referer_type_id, + referer_id, + } + } +} + +/// Trait base que permite obtener la clave ([`ActionKey`]) asociada a una acción. +/// +/// Implementado automáticamente para cualquier tipo que cumpla [`ActionTrait`]. +pub trait ActionBase { + fn key(&self) -> ActionKey; +} + +/// Interfaz común que deben implementar las acciones del código que pueden ser modificadas. +/// +/// Este trait combina: +/// - [`AnyInfo`] para identificación única del tipo en tiempo de ejecución. +/// - `Send + Sync` para permitir uso concurrente seguro. +/// +/// # Métodos personalizables +/// - `theme_type_id()`: Asocia la acción a un tipo concreto de tema (si aplica). +/// - `referer_type_id()`: Asocia la acción a un tipo de objeto referente (si aplica). +/// - `referer_id()`: Asocia la acción a un identificador concreto. +/// - `weight()`: Controla el orden de aplicación de acciones; valores más bajos se ejecutan antes. +pub trait ActionTrait: ActionBase + AnyInfo + Send + Sync { + /// Especifica el tipo de tema asociado. Por defecto `None`. + fn theme_type_id(&self) -> Option<UniqueId> { + None + } + + /// Especifica el tipo del objeto referente. Por defecto `None`. + fn referer_type_id(&self) -> Option<UniqueId> { + None + } + + /// Especifica un identificador único del objeto referente. Por defecto `None`. + fn referer_id(&self) -> Option<String> { + None + } + + /// Define el peso lógico de la acción para determinar el orden de aplicación. + /// + /// Acciones con pesos más bajos se aplicarán antes. Se pueden usar valores negativos. Por + /// defecto es `0`. + fn weight(&self) -> Weight { + 0 + } +} + +// Implementación automática que construye la clave `ActionKey` a partir de los métodos definidos. +impl<A: ActionTrait> ActionBase for A { + fn key(&self) -> ActionKey { + ActionKey { + action_type_id: self.type_id(), + theme_type_id: self.theme_type_id(), + referer_type_id: self.referer_type_id(), + referer_id: self.referer_id(), + } + } +} diff --git a/src/core/action/list.rs b/src/core/action/list.rs new file mode 100644 index 00000000..ec8149be --- /dev/null +++ b/src/core/action/list.rs @@ -0,0 +1,43 @@ +use crate::core::action::{ActionBox, ActionTrait}; +use crate::core::AnyCast; +use crate::trace; +use crate::AutoDefault; + +use std::sync::RwLock; + +#[derive(AutoDefault)] +pub struct ActionsList(RwLock<Vec<ActionBox>>); + +impl ActionsList { + pub fn new() -> Self { + ActionsList::default() + } + + pub fn add(&mut self, action: ActionBox) { + let mut list = self.0.write().unwrap(); + list.push(action); + list.sort_by_key(|a| a.weight()); + } + + pub fn iter_map<A, B, F>(&self, mut f: F) + where + Self: Sized, + A: ActionTrait, + F: FnMut(&A) -> B, + { + let _: Vec<_> = self + .0 + .read() + .unwrap() + .iter() + .rev() + .map(|a| { + if let Some(action) = (**a).downcast_ref::<A>() { + f(action); + } else { + trace::error!("Failed to downcast action of type {}", (**a).type_name()); + } + }) + .collect(); + } +} diff --git a/src/core/extension/all.rs b/src/core/extension/all.rs index 63a178c9..9012234f 100644 --- a/src/core/extension/all.rs +++ b/src/core/extension/all.rs @@ -1,3 +1,4 @@ +use crate::core::action::add_action; use crate::core::extension::ExtensionRef; use crate::core::theme::all::THEMES; use crate::{service, trace}; @@ -105,6 +106,16 @@ fn add_to_dropped(list: &mut Vec<ExtensionRef>, extension: ExtensionRef) { } } +// REGISTRO DE LAS ACCIONES ************************************************************************ + +pub fn register_actions() { + for extension in ENABLED_EXTENSIONS.read().unwrap().iter() { + for a in extension.actions().into_iter() { + add_action(a); + } + } +} + // INICIALIZA LAS EXTENSIONES ********************************************************************** pub fn initialize_extensions() { diff --git a/src/core/extension/definition.rs b/src/core/extension/definition.rs index 6b963a24..645afc80 100644 --- a/src/core/extension/definition.rs +++ b/src/core/extension/definition.rs @@ -1,7 +1,8 @@ +use crate::core::action::ActionBox; use crate::core::theme::ThemeRef; use crate::core::AnyInfo; use crate::locale::L10n; -use crate::service; +use crate::{inject_actions, service}; /// Representa una referencia a una extensión. /// @@ -70,6 +71,15 @@ pub trait ExtensionTrait: AnyInfo + Send + Sync { vec![] } + /// Devuelve la lista de acciones que la extensión va a registrar. + /// + /// Estas [acciones](crate::core::action) se despachan por orden de registro o por + /// [peso](crate::Weight), permitiendo personalizar el comportamiento de la aplicación en puntos + /// específicos. + fn actions(&self) -> Vec<ActionBox> { + inject_actions![] + } + /// Inicializa la extensión durante la lógica de arranque de la aplicación. /// /// Se llama una sola vez, después de que todas las dependencias se han inicializado y antes de diff --git a/src/lib.rs b/src/lib.rs index 264fdbc4..4ab3c6e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,6 +65,11 @@ impl Deref for StaticResources { } } +/// Identificador único de un tipo estático durante la ejecución de la aplicación. +/// +/// **Nota:** El valor es único sólo dentro del proceso actual y cambia en cada compilación. +pub type UniqueId = std::any::TypeId; + /// Representa el peso lógico de una instancia en una colección ordenada por pesos. /// /// Las instancias con pesos **más bajos**, incluyendo valores negativos (`-128..127`), se situarán @@ -87,7 +92,7 @@ pub mod html; pub mod locale; // Soporte a fechas y horas. pub mod datetime; -// Tipos y funciones esenciales para crear extensiones y temas. +// Tipos y funciones esenciales para crear acciones, extensiones y temas. pub mod core; // Gestión del servidor y servicios web. pub mod service; diff --git a/src/prelude.rs b/src/prelude.rs index 7244b912..22d9ea0e 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -4,7 +4,7 @@ pub use crate::{builder_fn, html, main, test}; -pub use crate::{AutoDefault, StaticResources, Weight}; +pub use crate::{AutoDefault, StaticResources, UniqueId, Weight}; // MACROS. @@ -16,6 +16,8 @@ pub use crate::include_config; pub use crate::include_locales; // crate::service pub use crate::{include_files, include_files_service}; +// crate::core::action +pub use crate::inject_actions; // API. @@ -35,6 +37,7 @@ pub use crate::service; pub use crate::core::{AnyCast, AnyInfo, TypeInfo}; +pub use crate::core::action::*; pub use crate::core::extension::*; pub use crate::core::theme::*; From 4f56d4441ff37417b9ba53718aaf0d8ad49ba2a5 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 21 Jul 2025 20:52:45 +0200 Subject: [PATCH 080/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20tipos=20para?= =?UTF-8?q?=20renderizar=20atributos=20HTML?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html.rs | 15 +++++ src/html/opt_classes.rs | 130 +++++++++++++++++++++++++++++++++++++ src/html/opt_id.rs | 57 ++++++++++++++++ src/html/opt_name.rs | 57 ++++++++++++++++ src/html/opt_string.rs | 56 ++++++++++++++++ src/html/opt_translated.rs | 65 +++++++++++++++++++ src/locale.rs | 15 ++++- 7 files changed, 393 insertions(+), 2 deletions(-) create mode 100644 src/html/opt_classes.rs create mode 100644 src/html/opt_id.rs create mode 100644 src/html/opt_name.rs create mode 100644 src/html/opt_string.rs create mode 100644 src/html/opt_translated.rs diff --git a/src/html.rs b/src/html.rs index 14a89edd..4fc9b3e5 100644 --- a/src/html.rs +++ b/src/html.rs @@ -12,6 +12,21 @@ pub(crate) use assets::Assets; mod context; pub use context::{Context, ErrorParam}; +mod opt_id; +pub use opt_id::OptionId; + +mod opt_name; +pub use opt_name::OptionName; + +mod opt_string; +pub use opt_string::OptionString; + +mod opt_translated; +pub use opt_translated::OptionTranslated; + +mod opt_classes; +pub use opt_classes::{ClassesOp, OptionClasses}; + use crate::AutoDefault; /// Prepara contenido HTML para su conversión a [`Markup`]. diff --git a/src/html/opt_classes.rs b/src/html/opt_classes.rs new file mode 100644 index 00000000..bcec9372 --- /dev/null +++ b/src/html/opt_classes.rs @@ -0,0 +1,130 @@ +use crate::{builder_fn, AutoDefault}; + +/// Operaciones disponibles sobre la lista de clases en [`OptionClasses`]. +pub enum ClassesOp { + /// Añade al final (si no existe). + Add, + /// Añade al principio. + Prepend, + /// Elimina coincidencias. + Remove, + /// Sustituye una o varias por las nuevas (`Replace("old other")`). + Replace(String), + /// Alterna presencia/ausencia. + Toggle, + /// Sustituye toda la lista. + Set, +} + +/// Cadena de clases CSS normalizadas para el atributo `class` de HTML. +/// +/// Permite construir y modificar dinámicamente con [`ClassesOp`] una lista de clases CSS +/// normalizadas. +/// +/// ### Normalización +/// - El [orden de las clases no es relevante](https://stackoverflow.com/a/1321712) en CSS. +/// - No se permiten clases duplicadas. +/// - Las clases vacías se ignoran. +/// +/// # Ejemplo +/// ```rust +/// use pagetop::prelude::*; +/// +/// let classes = OptionClasses::new("btn btn-primary") +/// .with_value(ClassesOp::Add, "active") +/// .with_value(ClassesOp::Remove, "btn-primary"); +/// +/// assert_eq!(classes.get(), Some(String::from("btn active"))); +/// assert!(classes.contains("active")); +/// ``` +#[derive(AutoDefault, Clone, Debug)] +pub struct OptionClasses(Vec<String>); + +impl OptionClasses { + pub fn new(classes: impl AsRef<str>) -> Self { + OptionClasses::default().with_value(ClassesOp::Prepend, classes) + } + + // OptionClasses BUILDER *********************************************************************** + + #[builder_fn] + pub fn with_value(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + let classes: &str = classes.as_ref(); + let classes: Vec<&str> = classes.split_ascii_whitespace().collect(); + + if classes.is_empty() { + return self; + } + + match op { + ClassesOp::Add => { + self.add(&classes, self.0.len()); + } + ClassesOp::Prepend => { + self.add(&classes, 0); + } + ClassesOp::Remove => { + for class in classes { + self.0.retain(|c| c.ne(&class.to_string())); + } + } + ClassesOp::Replace(classes_to_replace) => { + let mut pos = self.0.len(); + let replace: Vec<&str> = classes_to_replace.split_ascii_whitespace().collect(); + for class in replace { + if let Some(replace_pos) = self.0.iter().position(|c| c.eq(class)) { + self.0.remove(replace_pos); + if pos > replace_pos { + pos = replace_pos; + } + } + } + self.add(&classes, pos); + } + ClassesOp::Toggle => { + for class in classes { + if !class.is_empty() { + if let Some(pos) = self.0.iter().position(|c| c.eq(class)) { + self.0.remove(pos); + } else { + self.0.push(class.to_string()); + } + } + } + } + ClassesOp::Set => { + self.0.clear(); + self.add(&classes, 0); + } + } + + self + } + + #[inline] + fn add(&mut self, classes: &[&str], mut pos: usize) { + for &class in classes { + if !class.is_empty() && !self.0.iter().any(|c| c == class) { + self.0.insert(pos, class.to_string()); + pos += 1; + } + } + } + + // OptionClasses GETTERS *********************************************************************** + + /// Devuele la cadena de clases, si existe. + pub fn get(&self) -> Option<String> { + if self.0.is_empty() { + None + } else { + Some(self.0.join(" ")) + } + } + + /// Devuelve `true` si la clase está presente. + pub fn contains(&self, class: impl AsRef<str>) -> bool { + let class = class.as_ref(); + self.0.iter().any(|c| c == class) + } +} diff --git a/src/html/opt_id.rs b/src/html/opt_id.rs new file mode 100644 index 00000000..6f166b95 --- /dev/null +++ b/src/html/opt_id.rs @@ -0,0 +1,57 @@ +use crate::{builder_fn, AutoDefault}; + +/// Identificador normalizado para el atributo `id` o similar de HTML. +/// +/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso. +/// +/// # Normalización +/// - Se eliminan los espacios al principio y al final. +/// - Se sustituyen los espacios intermedios por guiones bajos (`_`). +/// - Si el resultado es una cadena vacía, se guarda `None`. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// let id = OptionId::new("main section"); +/// assert_eq!(id.get(), Some(String::from("main_section"))); +/// +/// let empty = OptionId::default(); +/// assert_eq!(empty.get(), None); +/// ``` +#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)] +pub struct OptionId(Option<String>); + +impl OptionId { + /// Crea un nuevo [`OptionId`]. + /// + /// El valor se normaliza automáticamente. + pub fn new(value: impl AsRef<str>) -> Self { + OptionId::default().with_value(value) + } + + // OptionId BUILDER **************************************************************************** + + /// Establece un identificador nuevo. + /// + /// El valor se normaliza automáticamente. + #[builder_fn] + pub fn with_value(mut self, value: impl AsRef<str>) -> Self { + let value = value.as_ref().trim().replace(' ', "_"); + self.0 = (!value.is_empty()).then_some(value); + self + } + + // OptionId GETTERS **************************************************************************** + + /// Devuelve el identificador, si existe. + pub fn get(&self) -> Option<String> { + if let Some(value) = &self.0 { + if !value.is_empty() { + return Some(value.to_owned()); + } + } + None + } +} diff --git a/src/html/opt_name.rs b/src/html/opt_name.rs new file mode 100644 index 00000000..c4e2e2e0 --- /dev/null +++ b/src/html/opt_name.rs @@ -0,0 +1,57 @@ +use crate::{builder_fn, AutoDefault}; + +/// Nombre normalizado para el atributo `name` o similar de HTML. +/// +/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso. +/// +/// # Normalización +/// - Se eliminan los espacios al principio y al final. +/// - Se sustituyen los espacios intermedios por guiones bajos (`_`). +/// - Si el resultado es una cadena vacía, se guarda `None`. +/// +/// ## Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// let name = OptionName::new(" display name "); +/// assert_eq!(name.get(), Some(String::from("display_name"))); +/// +/// let empty = OptionName::default(); +/// assert_eq!(empty.get(), None); +/// ``` +#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)] +pub struct OptionName(Option<String>); + +impl OptionName { + /// Crea un nuevo [`OptionName`]. + /// + /// El valor se normaliza automáticamente. + pub fn new(value: impl AsRef<str>) -> Self { + OptionName::default().with_value(value) + } + + // OptionName BUILDER ************************************************************************** + + /// Establece un nombre nuevo. + /// + /// El valor se normaliza automáticamente. + #[builder_fn] + pub fn with_value(mut self, value: impl AsRef<str>) -> Self { + let value = value.as_ref().trim().replace(' ', "_"); + self.0 = (!value.is_empty()).then_some(value); + self + } + + // OptionName GETTERS ************************************************************************** + + /// Devuelve el nombre, si existe. + pub fn get(&self) -> Option<String> { + if let Some(value) = &self.0 { + if !value.is_empty() { + return Some(value.to_owned()); + } + } + None + } +} diff --git a/src/html/opt_string.rs b/src/html/opt_string.rs new file mode 100644 index 00000000..5379597e --- /dev/null +++ b/src/html/opt_string.rs @@ -0,0 +1,56 @@ +use crate::{builder_fn, AutoDefault}; + +/// Cadena normalizada para renderizar en atributos HTML. +/// +/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso. +/// +/// # Normalización +/// - Se eliminan los espacios al principio y al final. +/// - Si el resultado es una cadena vacía, se guarda `None`. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// let s = OptionString::new(" a new string "); +/// assert_eq!(s.get(), Some(String::from("a new string"))); +/// +/// let empty = OptionString::default(); +/// assert_eq!(empty.get(), None); +/// ``` +#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)] +pub struct OptionString(Option<String>); + +impl OptionString { + /// Crea un nuevo [`OptionString`]. + /// + /// El valor se normaliza automáticamente. + pub fn new(value: impl AsRef<str>) -> Self { + OptionString::default().with_value(value) + } + + // OptionString BUILDER ************************************************************************ + + /// Establece una cadena nueva. + /// + /// El valor se normaliza automáticamente. + #[builder_fn] + pub fn with_value(mut self, value: impl AsRef<str>) -> Self { + let value = value.as_ref().trim().to_owned(); + self.0 = (!value.is_empty()).then_some(value); + self + } + + // OptionString GETTERS ************************************************************************ + + /// Devuelve la cadena, si existe. + pub fn get(&self) -> Option<String> { + if let Some(value) = &self.0 { + if !value.is_empty() { + return Some(value.to_owned()); + } + } + None + } +} diff --git a/src/html/opt_translated.rs b/src/html/opt_translated.rs new file mode 100644 index 00000000..ba60a0f8 --- /dev/null +++ b/src/html/opt_translated.rs @@ -0,0 +1,65 @@ +use crate::html::Markup; +use crate::locale::{L10n, LanguageIdentifier}; +use crate::{builder_fn, AutoDefault}; + +/// Cadena para traducir al renderizar ([`locale`](crate::locale)). +/// +/// Encapsula un tipo [`L10n`] para manejar traducciones de forma segura. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// // Traducción por clave en las locales por defecto de PageTop. +/// let hello = OptionTranslated::new(L10n::l("test-hello-world")); +/// +/// // Español disponible. +/// assert_eq!( +/// hello.using(LangMatch::langid_or_default("es-ES")), +/// Some(String::from("¡Hola mundo!")) +/// ); +/// +/// // Japonés no disponible, traduce al idioma de respaldo ("en-US"). +/// assert_eq!( +/// hello.using(LangMatch::langid_or_fallback("ja-JP")), +/// Some(String::from("Hello world!")) +/// ); +/// +/// // Para incrustar en HTML escapado: +/// let markup = hello.escaped(LangMatch::langid_or_default("es-ES")); +/// assert_eq!(markup.into_string(), "¡Hola mundo!"); +/// ``` +#[derive(AutoDefault, Clone, Debug)] +pub struct OptionTranslated(L10n); + +impl OptionTranslated { + /// Crea una nueva instancia [`OptionTranslated`]. + pub fn new(value: L10n) -> Self { + OptionTranslated(value) + } + + // OptionTranslated BUILDER ******************************************************************** + + /// Establece una traducción nueva. + #[builder_fn] + pub fn with_value(mut self, value: L10n) -> Self { + self.0 = value; + self + } + + // OptionTranslated GETTERS ******************************************************************** + + /// Devuelve la traducción para `langid`, si existe. + pub fn using(&self, langid: &LanguageIdentifier) -> Option<String> { + self.0.using(langid) + } + + /// Devuelve la traducción *escapada* como [`Markup`] para `langid`, si existe. + /// + /// Útil para incrustar el texto directamente en plantillas HTML sin riesgo de inyección de + /// contenido. + pub fn escaped(&self, langid: &LanguageIdentifier) -> Markup { + self.0.escaped(langid) + } +} diff --git a/src/locale.rs b/src/locale.rs index 2dcf27e7..9af83f58 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -284,7 +284,7 @@ include_locales!(LOCALES_PAGETOP); // * `None` - No se aplica ninguna localización. // * `Text` - Con una cadena literal que se devolverá tal cual. // * `Translate` - Con la clave a resolver en el `Locales` indicado. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Debug)] enum L10nOp { #[default] None, @@ -322,7 +322,7 @@ enum L10nOp { /// // Traducción con clave, conjunto de traducciones e identificador de idioma a usar. /// let bye = L10n::t("goodbye", &LOCALES_CUSTOM).using(LangMatch::langid_or_default("it")); /// ``` -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone)] pub struct L10n { op: L10nOp, #[default(&LOCALES_PAGETOP)] @@ -411,6 +411,17 @@ impl L10n { } } +impl fmt::Debug for L10n { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("L10n") + .field("op", &self.op) + .field("args", &self.args) + // No se puede mostrar `locales`. Se representa con un texto fijo. + .field("locales", &"<StaticLoader>") + .finish() + } +} + impl fmt::Display for L10n { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let content = match &self.op { From 36ddbd7ecf4d8eec677de79da17142272a98aaa9 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 21 Jul 2025 21:17:40 +0200 Subject: [PATCH 081/244] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=20A=C3=B1ade=20el?= =?UTF-8?q?=20tema=20para=20renderizar=20en=20contexto=20HTML?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html/context.rs | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/html/context.rs b/src/html/context.rs index 23e2be2b..b3622501 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -1,3 +1,5 @@ +use crate::core::theme::all::{theme_by_short_name, DEFAULT_THEME}; +use crate::core::theme::ThemeRef; use crate::core::TypeInfo; use crate::html::{html, Markup, Render}; use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; @@ -34,9 +36,9 @@ impl Error for ErrorParam {} /// Representa el contexto asociado a un documento HTML. /// /// Esta estructura se crea internamente para recoger información relativa al documento asociado, -/// como la solicitud HTTP de origen, el idioma y los recursos *favicon* ([`Favicon`]), las hojas de -/// estilo [`StyleSheet`], los *scripts* [`JavaScript`], o parámetros de contexto definidos en -/// tiempo de ejecución. +/// como la solicitud HTTP de origen, el idioma, el tema para renderizar ([`ThemeRef`]), y los +/// recursos *favicon* ([`Favicon`]), las hojas de estilo ([`StyleSheet`]) y los *scripts* +/// ([`JavaScript`]). También admite parámetros de contexto definidos en tiempo de ejecución. /// /// # Ejemplo /// @@ -47,6 +49,9 @@ impl Error for ErrorParam {} /// // Establece el idioma del documento a español. /// ctx.set_langid(LangMatch::langid_or_default("es-ES")); /// +/// // Selecciona un tema (por su nombre corto). +/// ctx.set_theme("aliner"); +/// /// // Asigna un favicon. /// ctx.set_favicon(Some(Favicon::new().with_icon("/icons/favicon.ico"))); /// @@ -63,6 +68,10 @@ impl Error for ErrorParam {} /// let id: i32 = ctx.get_param("usuario_id").unwrap(); /// assert_eq!(id, 42); /// +/// // Recupera el tema seleccionado. +/// let active_theme = ctx.theme(); +/// assert_eq!(active_theme.short_name(), "aliner"); +/// /// // Genera un identificador único para un componente de tipo `Menu`. /// struct Menu; /// let unique_id = ctx.required_id::<Menu>(None); @@ -73,6 +82,7 @@ impl Error for ErrorParam {} pub struct Context { request : HttpRequest, // Solicitud HTTP de origen. langid : &'static LanguageIdentifier, // Identificador del idioma. + theme : ThemeRef, // Referencia al tema para renderizar. favicon : Option<Favicon>, // Favicon, si se ha definido. stylesheets: Assets<StyleSheet>, // Hojas de estilo CSS. javascripts: Assets<JavaScript>, // Scripts JavaScript. @@ -89,6 +99,7 @@ impl Context { Context { request, langid : &DEFAULT_LANGID, + theme : *DEFAULT_THEME, favicon : None, stylesheets: Assets::<StyleSheet>::new(), javascripts: Assets::<JavaScript>::new(), @@ -103,6 +114,15 @@ impl Context { self } + /// Establece el tema que se usará para renderizar el documento. + /// + /// Localiza el tema por su [`short_name`](crate::core::AnyInfo::short_name), y si no aplica + /// ninguno entonces usará el tema por defecto. + pub fn set_theme(&mut self, short_name: impl AsRef<str>) -> &mut Self { + self.theme = theme_by_short_name(short_name).unwrap_or(*DEFAULT_THEME); + self + } + /// Define el *favicon* del documento. Sobrescribe cualquier valor anterior. pub fn set_favicon(&mut self, favicon: Option<Favicon>) -> &mut Self { self.favicon = favicon; @@ -160,6 +180,11 @@ impl Context { self.langid } + /// Devuelve el tema que se usará para renderizar el documento. + pub fn theme(&self) -> ThemeRef { + self.theme + } + /// Recupera un parámetro del contexto convertido al tipo especificado. /// /// Devuelve un error si el parámetro no existe ([`ErrorParam::NotFound`]) o la conversión falla From 8e67065aae51343d8d91b9cebba3827688572f54 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 24 Jul 2025 08:38:17 +0200 Subject: [PATCH 082/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20acciones=20bas?= =?UTF-8?q?e=20y=20renderizado=20de=20componentes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Añade acciones BeforeRender y AfterRender para ejecutar código personalizado antes y después de renderizar un componente. - Introduce la acción PrepareRender para personalizar totalmente el renderizado de un componente. - Se actualizan las definiciones de acciones para utilizar el nuevo "trait" ActionDispatcher. - Se crea un nuevo trait ComponentTrait para definir componentes renderizables. - Se implementan las estructuras Children y Child para gestionar componentes hijos dentro de un componente padre. - Se añade OptionComponent para encapsular de forma segura componentes opcionales y poder usarlos en otros componentes. --- Cargo.lock | 7 +- Cargo.toml | 5 +- src/base.rs | 4 +- src/base/action.rs | 15 + src/base/action/component.rs | 10 + .../component/after_render_component.rs | 81 +++++ .../component/before_render_component.rs | 81 +++++ src/base/action/component/is_renderable.rs | 96 +++++ src/base/action/theme.rs | 10 + .../action/theme/after_render_component.rs | 50 +++ .../action/theme/before_render_component.rs | 50 +++ src/base/action/theme/prepare_render.rs | 63 ++++ src/core.rs | 5 +- src/core/action.rs | 56 ++- src/core/action/all.rs | 54 +-- src/core/action/definition.rs | 72 ++-- src/core/action/list.rs | 9 +- src/core/component.rs | 9 + src/core/component/children.rs | 327 ++++++++++++++++++ src/core/component/definition.rs | 121 +++++++ src/core/extension/all.rs | 33 +- src/core/extension/definition.rs | 4 +- src/core/theme/all.rs | 6 +- src/core/theme/definition.rs | 2 +- src/html.rs | 3 + src/html/opt_component.rs | 68 ++++ src/lib.rs | 4 +- src/prelude.rs | 4 +- 28 files changed, 1102 insertions(+), 147 deletions(-) create mode 100644 src/base/action.rs create mode 100644 src/base/action/component.rs create mode 100644 src/base/action/component/after_render_component.rs create mode 100644 src/base/action/component/before_render_component.rs create mode 100644 src/base/action/component/is_renderable.rs create mode 100644 src/base/action/theme.rs create mode 100644 src/base/action/theme/after_render_component.rs create mode 100644 src/base/action/theme/before_render_component.rs create mode 100644 src/base/action/theme/prepare_render.rs create mode 100644 src/core/component.rs create mode 100644 src/core/component/children.rs create mode 100644 src/core/component/definition.rs create mode 100644 src/html/opt_component.rs diff --git a/Cargo.lock b/Cargo.lock index ab7b20a5..b03e9808 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1413,7 +1413,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.0.11" +version = "0.0.12" dependencies = [ "actix-files", "actix-web", @@ -1426,6 +1426,7 @@ dependencies = [ "fluent-templates", "itoa", "pagetop-macros", + "parking_lot", "pastey", "serde", "static-files", @@ -2212,9 +2213,9 @@ dependencies = [ [[package]] name = "tracing-actix-web" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2340b7722695166c7fc9b3e3cd1166e7c74fedb9075b8f0c74d3822d2e41caf5" +checksum = "5360edd490ec8dee9fedfc6a9fd83ac2f01b3e1996e3261b9ad18a61971fe064" dependencies = [ "actix-web", "mutually_exclusive_features", diff --git a/Cargo.toml b/Cargo.toml index b6f844f1..049c258c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.11" +version = "0.0.12" edition = "2021" description = """\ @@ -21,6 +21,7 @@ concat-string = "1.0.1" config = { version = "0.15.13", default-features = false, features = ["toml"] } figlet-rs = "0.1.5" itoa = "1.0.15" +parking_lot = "0.12.4" paste = { package = "pastey", version = "0.1.0" } substring = "1.4.5" terminal_size = "0.4.2" @@ -28,7 +29,7 @@ terminal_size = "0.4.2" tracing = "0.1.41" tracing-appender = "0.2.3" tracing-subscriber = { version = "0.3.19", features = ["json", "env-filter"] } -tracing-actix-web = "0.7.18" +tracing-actix-web = "0.7.19" fluent-templates = "0.13.0" unic-langid = { version = "0.9.6", features = ["macros"] } diff --git a/src/base.rs b/src/base.rs index c50cc9e4..491223e6 100644 --- a/src/base.rs +++ b/src/base.rs @@ -1,3 +1,5 @@ -//! Reúne temas listos para usar. +//! Reúne acciones y temas listos para usar. + +pub mod action; pub mod theme; diff --git a/src/base/action.rs b/src/base/action.rs new file mode 100644 index 00000000..119a7eaa --- /dev/null +++ b/src/base/action.rs @@ -0,0 +1,15 @@ +//! Acciones predefinidas para alterar el funcionamiento interno de `PageTop`. + +use crate::prelude::*; + +/// Tipo de función para manipular componentes y su contexto de renderizado. +/// +/// Se usa en acciones definidas en [`component`] y [`theme`] para alterar el comportamiento de los +/// componentes. +/// +/// Recibe referencias mutables (`&mut`) del componente `component` y del contexto `cx`. +pub type FnActionWithComponent<C> = fn(component: &mut C, cx: &mut Context); + +pub mod component; + +pub mod theme; diff --git a/src/base/action/component.rs b/src/base/action/component.rs new file mode 100644 index 00000000..aaef1ce9 --- /dev/null +++ b/src/base/action/component.rs @@ -0,0 +1,10 @@ +//! Acciones que operan sobre componentes. + +mod is_renderable; +pub use is_renderable::*; + +mod before_render_component; +pub use before_render_component::*; + +mod after_render_component; +pub use after_render_component::*; diff --git a/src/base/action/component/after_render_component.rs b/src/base/action/component/after_render_component.rs new file mode 100644 index 00000000..3c8ead9a --- /dev/null +++ b/src/base/action/component/after_render_component.rs @@ -0,0 +1,81 @@ +use crate::prelude::*; + +use crate::base::action::FnActionWithComponent; + +/// Ejecuta [`FnActionWithComponent`] después de renderizar un componente. +pub struct AfterRender<C: ComponentTrait> { + f: FnActionWithComponent<C>, + referer_type_id: Option<UniqueId>, + referer_id: OptionId, + weight: Weight, +} + +/// Filtro para despachar [`FnActionWithComponent`] después de renderizar un componente `C`. +impl<C: ComponentTrait> ActionDispatcher for AfterRender<C> { + /// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`. + fn referer_type_id(&self) -> Option<UniqueId> { + self.referer_type_id + } + + /// Devuelve el identificador del componente. + fn referer_id(&self) -> Option<String> { + self.referer_id.get() + } + + /// Devuelve el peso para definir el orden de aplicación. + fn weight(&self) -> Weight { + self.weight + } +} + +impl<C: ComponentTrait> AfterRender<C> { + /// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnActionWithComponent`]. + pub fn new(f: FnActionWithComponent<C>) -> Self { + AfterRender { + f, + referer_type_id: Some(UniqueId::of::<C>()), + referer_id: OptionId::default(), + weight: 0, + } + } + + /// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente + /// `C` con identificador `id`. + pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self { + self.referer_id.alter_value(id); + self + } + + /// Opcional. Acciones con pesos más bajos se aplican antes. Se pueden usar valores negativos. + pub fn with_weight(mut self, value: Weight) -> Self { + self.weight = value; + self + } + + // Despacha las acciones. + #[inline] + pub(crate) fn dispatch(component: &mut C, cx: &mut Context) { + // Primero despacha las acciones para el tipo de componente. + dispatch_actions( + &ActionKey::new( + UniqueId::of::<Self>(), + None, + Some(UniqueId::of::<C>()), + None, + ), + |action: &Self| (action.f)(component, cx), + ); + // Y luego despacha las acciones para el tipo de componente con un identificador dado. + if let Some(id) = component.id() { + dispatch_actions( + &ActionKey::new( + UniqueId::of::<Self>(), + None, + Some(UniqueId::of::<C>()), + Some(id), + ), + |action: &Self| (action.f)(component, cx), + ); + } + } +} diff --git a/src/base/action/component/before_render_component.rs b/src/base/action/component/before_render_component.rs new file mode 100644 index 00000000..0ebe4092 --- /dev/null +++ b/src/base/action/component/before_render_component.rs @@ -0,0 +1,81 @@ +use crate::prelude::*; + +use crate::base::action::FnActionWithComponent; + +/// Ejecuta [`FnActionWithComponent`] antes de renderizar el componente. +pub struct BeforeRender<C: ComponentTrait> { + f: FnActionWithComponent<C>, + referer_type_id: Option<UniqueId>, + referer_id: OptionId, + weight: Weight, +} + +/// Filtro para despachar [`FnActionWithComponent`] antes de renderizar un componente `C`. +impl<C: ComponentTrait> ActionDispatcher for BeforeRender<C> { + /// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`. + fn referer_type_id(&self) -> Option<UniqueId> { + self.referer_type_id + } + + /// Devuelve el identificador del componente. + fn referer_id(&self) -> Option<String> { + self.referer_id.get() + } + + /// Devuelve el peso para definir el orden de aplicación. + fn weight(&self) -> Weight { + self.weight + } +} + +impl<C: ComponentTrait> BeforeRender<C> { + /// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnActionWithComponent`]. + pub fn new(f: FnActionWithComponent<C>) -> Self { + BeforeRender { + f, + referer_type_id: Some(UniqueId::of::<C>()), + referer_id: OptionId::default(), + weight: 0, + } + } + + /// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente + /// `C` con identificador `id`. + pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self { + self.referer_id.alter_value(id); + self + } + + /// Opcional. Acciones con pesos más bajos se aplican antes. Se pueden usar valores negativos. + pub fn with_weight(mut self, value: Weight) -> Self { + self.weight = value; + self + } + + // Despacha las acciones. + #[inline] + pub(crate) fn dispatch(component: &mut C, cx: &mut Context) { + // Primero despacha las acciones para el tipo de componente. + dispatch_actions( + &ActionKey::new( + UniqueId::of::<Self>(), + None, + Some(UniqueId::of::<C>()), + None, + ), + |action: &Self| (action.f)(component, cx), + ); + // Y luego despacha las aciones para el tipo de componente con un identificador dado. + if let Some(id) = component.id() { + dispatch_actions( + &ActionKey::new( + UniqueId::of::<Self>(), + None, + Some(UniqueId::of::<C>()), + Some(id), + ), + |action: &Self| (action.f)(component, cx), + ); + } + } +} diff --git a/src/base/action/component/is_renderable.rs b/src/base/action/component/is_renderable.rs new file mode 100644 index 00000000..7ba7d53c --- /dev/null +++ b/src/base/action/component/is_renderable.rs @@ -0,0 +1,96 @@ +use crate::prelude::*; + +/// Tipo de función para determinar si un componente se renderiza o no. +/// +/// Se usa en la acción [`IsRenderable`] para controlar dinámicamente la visibilidad del componente +/// `component` según el contexto `cx`. El componente **no se renderiza** en cuanto una de las +/// funciones devuelva `false`. +pub type FnIsRenderable<C> = fn(component: &C, cx: &Context) -> bool; + +/// Con la función [`FnIsRenderable`] se puede decidir si se renderiza o no un componente. +pub struct IsRenderable<C: ComponentTrait> { + f: FnIsRenderable<C>, + referer_type_id: Option<UniqueId>, + referer_id: OptionId, + weight: Weight, +} + +/// Filtro para despachar [`FnIsRenderable`] para decidir si se renderiza o no un componente `C`. +impl<C: ComponentTrait> ActionDispatcher for IsRenderable<C> { + /// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`. + fn referer_type_id(&self) -> Option<UniqueId> { + self.referer_type_id + } + + /// Devuelve el identificador del componente. + fn referer_id(&self) -> Option<String> { + self.referer_id.get() + } + + /// Devuelve el peso para definir el orden de aplicación. + fn weight(&self) -> Weight { + self.weight + } +} + +impl<C: ComponentTrait> IsRenderable<C> { + /// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnIsRenderable`]. + pub fn new(f: FnIsRenderable<C>) -> Self { + IsRenderable { + f, + referer_type_id: Some(UniqueId::of::<C>()), + referer_id: OptionId::default(), + weight: 0, + } + } + + /// Afina el registro para ejecutar la acción [`FnIsRenderable`] sólo para el componente `C` + /// con identificador `id`. + pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self { + self.referer_id.alter_value(id); + self + } + + /// Opcional. Acciones con pesos más bajos se aplican antes. Se pueden usar valores negativos. + pub fn with_weight(mut self, value: Weight) -> Self { + self.weight = value; + self + } + + // Despacha las acciones. Se detiene en cuanto una [`FnIsRenderable`] devuelve `false`. + #[inline] + pub(crate) fn dispatch(component: &C, cx: &mut Context) -> bool { + let mut renderable = true; + dispatch_actions( + &ActionKey::new( + UniqueId::of::<Self>(), + None, + Some(UniqueId::of::<C>()), + None, + ), + |action: &Self| { + if renderable && !(action.f)(component, cx) { + renderable = false; + } + }, + ); + if renderable { + if let Some(id) = component.id() { + dispatch_actions( + &ActionKey::new( + UniqueId::of::<Self>(), + None, + Some(UniqueId::of::<C>()), + Some(id), + ), + |action: &Self| { + if renderable && !(action.f)(component, cx) { + renderable = false; + } + }, + ); + } + } + renderable + } +} diff --git a/src/base/action/theme.rs b/src/base/action/theme.rs new file mode 100644 index 00000000..40988574 --- /dev/null +++ b/src/base/action/theme.rs @@ -0,0 +1,10 @@ +//! Acciones lanzadas desde los temas. + +mod before_render_component; +pub use before_render_component::*; + +mod after_render_component; +pub use after_render_component::*; + +mod prepare_render; +pub use prepare_render::*; diff --git a/src/base/action/theme/after_render_component.rs b/src/base/action/theme/after_render_component.rs new file mode 100644 index 00000000..d33e0d2d --- /dev/null +++ b/src/base/action/theme/after_render_component.rs @@ -0,0 +1,50 @@ +use crate::prelude::*; + +use crate::base::action::FnActionWithComponent; + +/// Ejecuta [`FnActionWithComponent`] después de que un tema renderice el componente. +pub struct AfterRender<C: ComponentTrait> { + f: FnActionWithComponent<C>, + theme_type_id: Option<UniqueId>, + referer_type_id: Option<UniqueId>, +} + +/// Filtro para despachar [`FnActionWithComponent`] después de que un tema renderice el componente +/// `C`. +impl<C: ComponentTrait> ActionDispatcher for AfterRender<C> { + /// Devuelve el identificador de tipo ([`UniqueId`]) del tema. + fn theme_type_id(&self) -> Option<UniqueId> { + self.theme_type_id + } + + /// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`. + fn referer_type_id(&self) -> Option<UniqueId> { + self.referer_type_id + } +} + +impl<C: ComponentTrait> AfterRender<C> { + /// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnActionWithComponent`] para + /// un tema dado. + pub fn new(theme: ThemeRef, f: FnActionWithComponent<C>) -> Self { + AfterRender { + f, + theme_type_id: Some(theme.type_id()), + referer_type_id: Some(UniqueId::of::<C>()), + } + } + + // Despacha las acciones. + #[inline] + pub(crate) fn dispatch(component: &mut C, cx: &mut Context) { + dispatch_actions( + &ActionKey::new( + UniqueId::of::<Self>(), + Some(cx.theme().type_id()), + Some(UniqueId::of::<C>()), + None, + ), + |action: &Self| (action.f)(component, cx), + ); + } +} diff --git a/src/base/action/theme/before_render_component.rs b/src/base/action/theme/before_render_component.rs new file mode 100644 index 00000000..76f6cd22 --- /dev/null +++ b/src/base/action/theme/before_render_component.rs @@ -0,0 +1,50 @@ +use crate::prelude::*; + +use crate::base::action::FnActionWithComponent; + +/// Ejecuta [`FnActionWithComponent`] antes de que un tema renderice el componente. +pub struct BeforeRender<C: ComponentTrait> { + f: FnActionWithComponent<C>, + theme_type_id: Option<UniqueId>, + referer_type_id: Option<UniqueId>, +} + +/// Filtro para despachar [`FnActionWithComponent`] antes de que un tema renderice el componente +/// `C`. +impl<C: ComponentTrait> ActionDispatcher for BeforeRender<C> { + /// Devuelve el identificador de tipo ([`UniqueId`]) del tema. + fn theme_type_id(&self) -> Option<UniqueId> { + self.theme_type_id + } + + /// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`. + fn referer_type_id(&self) -> Option<UniqueId> { + self.referer_type_id + } +} + +impl<C: ComponentTrait> BeforeRender<C> { + /// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnActionWithComponent`] para + /// un tema dado. + pub fn new(theme: ThemeRef, f: FnActionWithComponent<C>) -> Self { + BeforeRender { + f, + theme_type_id: Some(theme.type_id()), + referer_type_id: Some(UniqueId::of::<C>()), + } + } + + // Despacha las acciones. + #[inline] + pub(crate) fn dispatch(component: &mut C, cx: &mut Context) { + dispatch_actions( + &ActionKey::new( + UniqueId::of::<Self>(), + Some(cx.theme().type_id()), + Some(UniqueId::of::<C>()), + None, + ), + |action: &Self| (action.f)(component, cx), + ); + } +} diff --git a/src/base/action/theme/prepare_render.rs b/src/base/action/theme/prepare_render.rs new file mode 100644 index 00000000..9d3e2612 --- /dev/null +++ b/src/base/action/theme/prepare_render.rs @@ -0,0 +1,63 @@ +use crate::prelude::*; + +/// Tipo de función para alterar el renderizado de un componente. +/// +/// Permite a un [tema](crate::base::action::theme) sobreescribir el renderizado predeterminado de +/// los componentes. +/// +/// Recibe una referencia al componente `component` y una referencia mutable al contexto `cx`. +pub type FnPrepareRender<C> = fn(component: &C, cx: &mut Context) -> PrepareMarkup; + +/// Ejecuta [`FnPrepareRender`] para preparar el renderizado de un componente. +/// +/// Permite a un tema hacer una implementación nueva del renderizado de un componente. +pub struct PrepareRender<C: ComponentTrait> { + f: FnPrepareRender<C>, + theme_type_id: Option<UniqueId>, + referer_type_id: Option<UniqueId>, +} + +/// Filtro para despachar [`FnPrepareRender`] que modifica el renderizado de un componente `C`. +impl<C: ComponentTrait> ActionDispatcher for PrepareRender<C> { + /// Devuelve el identificador de tipo ([`UniqueId`]) del tema. + fn theme_type_id(&self) -> Option<UniqueId> { + self.theme_type_id + } + + /// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`. + fn referer_type_id(&self) -> Option<UniqueId> { + self.referer_type_id + } +} + +impl<C: ComponentTrait> PrepareRender<C> { + /// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnPrepareRender`] para un + /// tema dado. + pub fn new(theme: ThemeRef, f: FnPrepareRender<C>) -> Self { + PrepareRender { + f, + theme_type_id: Some(theme.type_id()), + referer_type_id: Some(UniqueId::of::<C>()), + } + } + + // Despacha las acciones. Se detiene en cuanto una renderiza. + #[inline] + pub(crate) fn dispatch(component: &C, cx: &mut Context) -> PrepareMarkup { + let mut render_component = PrepareMarkup::None; + dispatch_actions( + &ActionKey::new( + UniqueId::of::<Self>(), + Some(cx.theme().type_id()), + Some(UniqueId::of::<C>()), + None, + ), + |action: &Self| { + if render_component.is_empty() { + render_component = (action.f)(component, cx); + } + }, + ); + render_component + } +} diff --git a/src/core.rs b/src/core.rs index 4b857fc4..2168c932 100644 --- a/src/core.rs +++ b/src/core.rs @@ -1,4 +1,4 @@ -//! Tipos y funciones esenciales para crear acciones, extensiones y temas. +//! Tipos y funciones esenciales para crear acciones, componentes, extensiones y temas. use std::any::Any; @@ -204,6 +204,9 @@ impl<T: ?Sized + AnyInfo> AnyCast for T {} // API para definir acciones que alteran el comportamiento predeterminado del código. pub mod action; +// API para construir nuevos componentes. +pub mod component; + // API para añadir nuevas funcionalidades usando extensiones. pub mod extension; diff --git a/src/core/action.rs b/src/core/action.rs index 8503ae90..f5dc11c5 100644 --- a/src/core/action.rs +++ b/src/core/action.rs @@ -1,11 +1,11 @@ //! API para definir acciones que inyectan código en el flujo de la aplicación. //! -//! Permite crear acciones en las librerías para que otros *crates* puedan inyectar código usando -//! funciones *ad hoc* que modifican el comportamiento predefinido en puntos concretos del flujo de -//! ejecución de la aplicación. +//! Permite crear acciones para que otros *crates* puedan inyectar código usando funciones *ad hoc* +//! que modifican el comportamiento predefinido en puntos concretos del flujo de ejecución de la +//! aplicación. mod definition; -pub use definition::{ActionBase, ActionBox, ActionKey, ActionTrait}; +pub use definition::{ActionBox, ActionDispatcher, ActionKey}; mod list; use list::ActionsList; @@ -14,49 +14,33 @@ mod all; pub(crate) use all::add_action; pub use all::dispatch_actions; -/// Crea una lista de acciones para facilitar la implementación del método -/// [`actions`](crate::core::extension::ExtensionTrait#method.actions). +/// Facilita la implementación del método +/// [`actions()`](crate::core::extension::ExtensionTrait::actions). /// -/// Esta macro crea vectores de [`ActionBox`], el tipo dinámico que encapsula cualquier acción que -/// implemente [`ActionTrait`]. Evita escribir repetidamente `Box::new(...)` para cada acción -/// inyectada, manteniendo el código más limpio. +/// Evita escribir repetidamente `Box::new(...)` para cada acción de la lista, manteniendo el código +/// más limpio. /// -/// # Ejemplos -/// -/// Puede llamarse sin argumentos para crear un vector vacío: +/// # Ejemplo /// /// ```rust,ignore -/// let my_actions = inject_actions![]; -/// ``` +/// use pagetop::prelude::*; /// -/// O con una lista de acciones concretas: -/// -/// ```rust,ignore -/// let my_actions = inject_actions![ -/// MyFirstAction::new(), -/// MySecondAction::new().with_weight(10), -/// ]; -/// ``` -/// -/// Internamente, expande a un `vec![Box::new(...), ...]`. -/// -/// # Ejemplo típico en una extensión -/// -/// ```rust,ignore -/// impl ExtensionTrait for MyExtension { +/// impl ExtensionTrait for MyTheme { /// fn actions(&self) -> Vec<ActionBox> { -/// inject_actions![ -/// CustomizeLoginAction::new(), -/// ModifyHeaderAction::new().with_weight(-5), +/// actions_boxed![ +/// action::theme::BeforeRender::<Button>::new(&Self, before_render_button), +/// action::theme::PrepareRender::<Error404>::new(&Self, render_error404), /// ] /// } /// } -/// ``` /// -/// Así, `PageTop` podrá registrar todas estas acciones durante la inicialización de la extensión y -/// posteriormente despacharlas según corresponda. +/// impl ThemeTrait for MyTheme {} +/// +/// fn before_render_button(c: &mut Button, cx: &mut Context) { todo!() } +/// fn render_error404(c: &Error404, cx: &mut Context) -> PrepareMarkup { todo!() } +/// ``` #[macro_export] -macro_rules! inject_actions { +macro_rules! actions_boxed { () => { Vec::<ActionBox>::new() }; diff --git a/src/core/action/all.rs b/src/core/action/all.rs index 4dcb68df..ffee9f56 100644 --- a/src/core/action/all.rs +++ b/src/core/action/all.rs @@ -1,7 +1,9 @@ -use crate::core::action::{ActionBox, ActionKey, ActionTrait, ActionsList}; +use crate::core::action::{ActionBox, ActionDispatcher, ActionKey, ActionsList}; + +use parking_lot::RwLock; use std::collections::HashMap; -use std::sync::{LazyLock, RwLock}; +use std::sync::LazyLock; // ACCIONES **************************************************************************************** @@ -12,20 +14,19 @@ static ACTIONS: LazyLock<RwLock<HashMap<ActionKey, ActionsList>>> = // Registra una nueva acción en el sistema. // -// Si ya existen acciones con la misma `ActionKey`, la acción se añade a la lista existente. Si no, -// se crea una nueva lista. -// -// # Uso típico +// Si ya existen acciones con la misma `ActionKey`, la acción se añade a la misma lista. Si no, se +// crea una nueva lista. // // Las extensiones llamarán a esta función durante su inicialización para instalar acciones -// personalizadas que modifiquen el comportamiento del núcleo o de otros componentes. -// -// ```rust,ignore -// add_action(Box::new(MyCustomAction::new())); -// ``` +// personalizadas que modifiquen el comportamiento del *core* o de otros componentes. pub fn add_action(action: ActionBox) { - let key = action.key(); - let mut actions = ACTIONS.write().unwrap(); + let key = ActionKey::new( + action.type_id(), + action.theme_type_id(), + action.referer_type_id(), + action.referer_id(), + ); + let mut actions = ACTIONS.write(); if let Some(list) = actions.get_mut(&key) { list.add(action); } else { @@ -37,30 +38,35 @@ pub fn add_action(action: ActionBox) { // DESPLEGAR ACCIONES ****************************************************************************** -/// Despacha las funciones asociadas a un [`ActionKey`] y las ejecuta. +/// Despacha y ejecuta las funciones asociadas a una [`ActionKey`]. /// /// Permite recorrer de forma segura y ordenada (por peso) la lista de funciones asociadas a una /// acción específica. /// /// # Parámetros genéricos -/// - `A`: Tipo de acción que esperamos procesar. Debe implementar [`ActionTrait`]. -/// - `F`: Función o cierre que recibe cada acción y devuelve un valor de tipo `B`. +/// - `A`: Tipo de acción que esperamos procesar. Debe implementar [`ActionDispatcher`]. +/// - `F`: Función asociada a cada acción, devuelve un valor de tipo `B`. /// /// # Ejemplo de uso /// ```rust,ignore -/// dispatch_actions::<MyCustomAction, _>(&some_key, |action| { -/// action.do_something(); -/// }); +/// pub(crate) fn dispatch(component: &mut C, cx: &mut Context) { +/// dispatch_actions( +/// &ActionKey::new( +/// UniqueId::of::<Self>(), +/// Some(cx.theme().type_id()), +/// Some(UniqueId::of::<C>()), +/// None, +/// ), +/// |action: &Self| (action.f)(component, cx), +/// ); +/// } /// ``` -/// -/// Esto permite a PageTop o a otros módulos aplicar lógica específica a las acciones de un contexto -/// determinado, manteniendo la flexibilidad del sistema. pub fn dispatch_actions<A, B, F>(key: &ActionKey, f: F) where - A: ActionTrait, + A: ActionDispatcher, F: FnMut(&A) -> B, { - if let Some(list) = ACTIONS.read().unwrap().get(key) { + if let Some(list) = ACTIONS.read().get(key) { list.iter_map(f); } } diff --git a/src/core/action/definition.rs b/src/core/action/definition.rs index d662b2b6..9ec9af1f 100644 --- a/src/core/action/definition.rs +++ b/src/core/action/definition.rs @@ -1,23 +1,13 @@ use crate::core::AnyInfo; use crate::{UniqueId, Weight}; -/// Tipo dinámico para encapsular cualquier acción que implementa [`ActionTrait`]. -pub type ActionBox = Box<dyn ActionTrait>; +/// Tipo dinámico para encapsular cualquier acción que implementa [`ActionDispatcher`]. +pub type ActionBox = Box<dyn ActionDispatcher>; -/// Identifica una acción con una clave que define las condiciones de selección de las funciones -/// asociadas a esa acción. +/// Clave para registrar las acciones y seleccionar las funciones asociadas. /// /// Las funciones seleccionadas se van a [despachar](crate::core::action::dispatch_actions) y /// ejecutar en un punto concreto del flujo de ejecución. -/// -/// # Campos -/// -/// - `action_type_id`: Tipo de la acción. -/// - `theme_type_id`: Opcional, filtra las funciones para un tema dado. -/// - `referer_type_id`: Opcional, filtra las funciones para un tipo dado (p.ej. para un tipo de -/// componente). -/// - `referer_id`: Opcional, filtra las funciones por el identificador de una instancia (p.ej. para -/// un formulario concreto). #[derive(Eq, PartialEq, Hash)] pub struct ActionKey { action_type_id: UniqueId, @@ -29,8 +19,15 @@ pub struct ActionKey { impl ActionKey { /// Crea una nueva clave para un tipo de acción. /// - /// Esta clave permite seleccionar las funciones a ejecutar para ese tipo de acción con filtros - /// opcionales por tema, un tipo de referencia, o una instancia concreta según su identificador. + /// Se crea con los siguientes campos: + /// + /// - `action_type_id`: Tipo de la acción. + /// - `theme_type_id`: Opcional, identificador de tipo ([`UniqueId`]) del tema asociado. + /// - `referer_type_id`: Opcional, identificador de tipo ([`UniqueId`]) del componente referido. + /// - `referer_id`: Opcional, identificador de la instancia (p.ej. para un formulario concreto). + /// + /// Esta clave permitirá seleccionar las funciones a ejecutar para ese tipo de acción, con + /// filtros opcionales por tema, componente, o una instancia concreta según su identificador. pub fn new( action_type_id: UniqueId, theme_type_id: Option<UniqueId>, @@ -46,57 +43,28 @@ impl ActionKey { } } -/// Trait base que permite obtener la clave ([`ActionKey`]) asociada a una acción. +/// Implementa el filtro predeterminado para despachar las funciones de una acción dada. /// -/// Implementado automáticamente para cualquier tipo que cumpla [`ActionTrait`]. -pub trait ActionBase { - fn key(&self) -> ActionKey; -} - -/// Interfaz común que deben implementar las acciones del código que pueden ser modificadas. -/// -/// Este trait combina: -/// - [`AnyInfo`] para identificación única del tipo en tiempo de ejecución. -/// - `Send + Sync` para permitir uso concurrente seguro. -/// -/// # Métodos personalizables -/// - `theme_type_id()`: Asocia la acción a un tipo concreto de tema (si aplica). -/// - `referer_type_id()`: Asocia la acción a un tipo de objeto referente (si aplica). -/// - `referer_id()`: Asocia la acción a un identificador concreto. -/// - `weight()`: Controla el orden de aplicación de acciones; valores más bajos se ejecutan antes. -pub trait ActionTrait: ActionBase + AnyInfo + Send + Sync { - /// Especifica el tipo de tema asociado. Por defecto `None`. +/// Las acciones tienen que sobrescribir los métodos para el filtro que apliquen. Por defecto +/// implementa un filtro nulo. +pub trait ActionDispatcher: AnyInfo + Send + Sync { + /// Identificador de tipo ([`UniqueId`]) del tema asociado. En este caso devuelve `None`. fn theme_type_id(&self) -> Option<UniqueId> { None } - /// Especifica el tipo del objeto referente. Por defecto `None`. + /// Identificador de tipo ([`UniqueId`]) del objeto referido. En este caso devuelve `None`. fn referer_type_id(&self) -> Option<UniqueId> { None } - /// Especifica un identificador único del objeto referente. Por defecto `None`. + /// Identificador del objeto referido. En este caso devuelve `None`. fn referer_id(&self) -> Option<String> { None } - /// Define el peso lógico de la acción para determinar el orden de aplicación. - /// - /// Acciones con pesos más bajos se aplicarán antes. Se pueden usar valores negativos. Por - /// defecto es `0`. + /// Funciones con pesos más bajos se aplican antes. En este caso siempre devuelve `0`. fn weight(&self) -> Weight { 0 } } - -// Implementación automática que construye la clave `ActionKey` a partir de los métodos definidos. -impl<A: ActionTrait> ActionBase for A { - fn key(&self) -> ActionKey { - ActionKey { - action_type_id: self.type_id(), - theme_type_id: self.theme_type_id(), - referer_type_id: self.referer_type_id(), - referer_id: self.referer_id(), - } - } -} diff --git a/src/core/action/list.rs b/src/core/action/list.rs index ec8149be..57c89fe6 100644 --- a/src/core/action/list.rs +++ b/src/core/action/list.rs @@ -1,9 +1,9 @@ -use crate::core::action::{ActionBox, ActionTrait}; +use crate::core::action::{ActionBox, ActionDispatcher}; use crate::core::AnyCast; use crate::trace; use crate::AutoDefault; -use std::sync::RwLock; +use parking_lot::RwLock; #[derive(AutoDefault)] pub struct ActionsList(RwLock<Vec<ActionBox>>); @@ -14,7 +14,7 @@ impl ActionsList { } pub fn add(&mut self, action: ActionBox) { - let mut list = self.0.write().unwrap(); + let mut list = self.0.write(); list.push(action); list.sort_by_key(|a| a.weight()); } @@ -22,13 +22,12 @@ impl ActionsList { pub fn iter_map<A, B, F>(&self, mut f: F) where Self: Sized, - A: ActionTrait, + A: ActionDispatcher, F: FnMut(&A) -> B, { let _: Vec<_> = self .0 .read() - .unwrap() .iter() .rev() .map(|a| { diff --git a/src/core/component.rs b/src/core/component.rs new file mode 100644 index 00000000..36c789a8 --- /dev/null +++ b/src/core/component.rs @@ -0,0 +1,9 @@ +//! API para construir nuevos componentes. + +mod definition; +pub use definition::{ComponentRender, ComponentTrait}; + +mod children; +pub use children::Children; +pub use children::{Child, ChildOp}; +pub use children::{Typed, TypedOp}; diff --git a/src/core/component/children.rs b/src/core/component/children.rs new file mode 100644 index 00000000..38a626b2 --- /dev/null +++ b/src/core/component/children.rs @@ -0,0 +1,327 @@ +use crate::core::component::ComponentTrait; +use crate::html::{html, Context, Markup}; +use crate::{builder_fn, UniqueId}; + +use parking_lot::RwLock; + +use std::sync::Arc; +use std::vec::IntoIter; + +/// Representa un componente encapsulado de forma segura y compartida. +/// +/// Esta estructura permite manipular y renderizar cualquier tipo que implemente [`ComponentTrait`], +/// garantizando acceso concurrente a través de [`Arc<RwLock<_>>`]. +#[derive(Clone)] +pub struct Child(Arc<RwLock<dyn ComponentTrait>>); + +impl Child { + /// Crea un nuevo [`Child`] a partir de un componente. + pub fn with(component: impl ComponentTrait) -> Self { + Child(Arc::new(RwLock::new(component))) + } + + // Child GETTERS ******************************************************************************* + + /// Devuelve el identificador del componente, si está definido. + pub fn id(&self) -> Option<String> { + self.0.read().id() + } + + // Child RENDER ******************************************************************************** + + /// Renderiza el componente con el contexto proporcionado. + pub fn render(&self, cx: &mut Context) -> Markup { + self.0.write().render(cx) + } + + // Child HELPERS ******************************************************************************* + + // Devuelve el [`UniqueId`] del tipo del componente. + fn type_id(&self) -> UniqueId { + self.0.read().type_id() + } +} + +// ************************************************************************************************* + +/// Variante tipada de [`Child`] para evitar conversiones durante el uso. +/// +/// Facilita el acceso a componentes del mismo tipo sin necesidad de hacer `downcast`. +pub struct Typed<C: ComponentTrait>(Arc<RwLock<C>>); + +impl<C: ComponentTrait> Clone for Typed<C> { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl<C: ComponentTrait> Typed<C> { + /// Crea un nuevo [`Typed`] a partir de un componente. + pub fn with(component: C) -> Self { + Typed(Arc::new(RwLock::new(component))) + } + + // Typed GETTERS ******************************************************************************* + + /// Devuelve el identificador del componente, si está definido. + pub fn id(&self) -> Option<String> { + self.0.read().id() + } + + // Typed RENDER ******************************************************************************** + + /// Renderiza el componente con el contexto proporcionado. + pub fn render(&self, cx: &mut Context) -> Markup { + self.0.write().render(cx) + } + + // Typed HELPERS ******************************************************************************* + + /// Convierte el componente tipado en un [`Child`]. + fn to_child(&self) -> Child { + Child(self.0.clone()) + } +} + +// ************************************************************************************************* + +/// Operaciones con un componente [`Child`] en una lista [`Children`]. +pub enum ChildOp { + Add(Child), + InsertAfterId(&'static str, Child), + InsertBeforeId(&'static str, Child), + Prepend(Child), + RemoveById(&'static str), + ReplaceById(&'static str, Child), + Reset, +} + +/// Operaciones con un componente tipado [`Typed<C>`] en una lista [`Children`]. +pub enum TypedOp<C: ComponentTrait> { + Add(Typed<C>), + InsertAfterId(&'static str, Typed<C>), + InsertBeforeId(&'static str, Typed<C>), + Prepend(Typed<C>), + RemoveById(&'static str), + ReplaceById(&'static str, Typed<C>), + Reset, +} + +/// Lista ordenada de los componentes hijo ([`Child`]) asociados a un componente padre. +/// +/// Esta colección permite añadir, modificar, renderizar y consultar componentes hijos en orden de +/// inserción, soportando operaciones avanzadas como inserción relativa o reemplazo por +/// identificador. +#[derive(Clone, Default)] +pub struct Children(Vec<Child>); + +impl Children { + /// Crea una lista vacía. + pub fn new() -> Self { + Children::default() + } + + /// Crea una lista con un único hijo inicial. + pub fn with(child: Child) -> Self { + Children::default().with_child(ChildOp::Add(child)) + } + + // Fusiona varias listas de `Children` en una sola. + pub(crate) fn merge(mixes: &[Option<&Children>]) -> Self { + let mut opt = Children::default(); + for m in mixes.iter().flatten() { + opt.0.extend(m.0.iter().cloned()); + } + opt + } + + // Children BUILDER **************************************************************************** + + /// Ejecuta una operación con [`ChildOp`] en la lista. + #[builder_fn] + pub fn with_child(mut self, op: ChildOp) -> Self { + match op { + ChildOp::Add(any) => self.add(any), + ChildOp::InsertAfterId(id, any) => self.insert_after_id(id, any), + ChildOp::InsertBeforeId(id, any) => self.insert_before_id(id, any), + ChildOp::Prepend(any) => self.prepend(any), + ChildOp::RemoveById(id) => self.remove_by_id(id), + ChildOp::ReplaceById(id, any) => self.replace_by_id(id, any), + ChildOp::Reset => self.reset(), + } + } + + /// Ejecuta una operación con [`TypedOp`] en la lista. + #[builder_fn] + pub fn with_typed<C: ComponentTrait + Default>(mut self, op: TypedOp<C>) -> Self { + match op { + TypedOp::Add(typed) => self.add(typed.to_child()), + TypedOp::InsertAfterId(id, typed) => self.insert_after_id(id, typed.to_child()), + TypedOp::InsertBeforeId(id, typed) => self.insert_before_id(id, typed.to_child()), + TypedOp::Prepend(typed) => self.prepend(typed.to_child()), + TypedOp::RemoveById(id) => self.remove_by_id(id), + TypedOp::ReplaceById(id, typed) => self.replace_by_id(id, typed.to_child()), + TypedOp::Reset => self.reset(), + } + } + + /// Añade un hijo al final de la lista. + #[inline] + pub fn add(&mut self, child: Child) -> &mut Self { + self.0.push(child); + self + } + + // Inserta un hijo después del componente con el `id` dado, o al final si no se encuentra. + #[inline] + fn insert_after_id(&mut self, id: impl AsRef<str>, child: Child) -> &mut Self { + let id = Some(id.as_ref()); + match self.0.iter().position(|c| c.id().as_deref() == id) { + Some(index) => self.0.insert(index + 1, child), + _ => self.0.push(child), + }; + self + } + + // Inserta un hijo antes del componente con el `id` dado, o al principio si no se encuentra. + #[inline] + fn insert_before_id(&mut self, id: impl AsRef<str>, child: Child) -> &mut Self { + let id = Some(id.as_ref()); + match self.0.iter().position(|c| c.id().as_deref() == id) { + Some(index) => self.0.insert(index, child), + _ => self.0.insert(0, child), + }; + self + } + + // Inserta un hijo al principio de la colección. + #[inline] + fn prepend(&mut self, child: Child) -> &mut Self { + self.0.insert(0, child); + self + } + + // Elimina el primer hijo con el `id` dado. + #[inline] + fn remove_by_id(&mut self, id: impl AsRef<str>) -> &mut Self { + let id = Some(id.as_ref()); + if let Some(index) = self.0.iter().position(|c| c.id().as_deref() == id) { + self.0.remove(index); + } + self + } + + // Sustituye el primer hijo con el `id` dado por otro componente. + #[inline] + fn replace_by_id(&mut self, id: impl AsRef<str>, child: Child) -> &mut Self { + let id = Some(id.as_ref()); + for c in &mut self.0 { + if c.id().as_deref() == id { + *c = child; + break; + } + } + self + } + + // Elimina todos los componentes hijo de la lista. + #[inline] + fn reset(&mut self) -> &mut Self { + self.0.clear(); + self + } + + // Children GETTERS **************************************************************************** + + /// Devuelve el número de componentes hijo de la lista. + pub fn len(&self) -> usize { + self.0.len() + } + + /// Indica si la lista está vacía. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Devuelve el primer componente hijo con el identificador indicado, si existe. + pub fn get_by_id(&self, id: impl AsRef<str>) -> Option<&Child> { + let id = Some(id.as_ref()); + self.0.iter().find(|c| c.id().as_deref() == id) + } + + /// Devuelve un iterador sobre los componentes hijo con el identificador indicado. + pub fn iter_by_id<'a>(&'a self, id: &'a str) -> impl Iterator<Item = &'a Child> + 'a { + self.0.iter().filter(move |c| c.id().as_deref() == Some(id)) + } + + /// Devuelve un iterador sobre los componentes hijo con el identificador tipo ([`UniqueId`]) + /// indicado. + pub fn iter_by_type_id(&self, type_id: UniqueId) -> impl Iterator<Item = &Child> { + self.0.iter().filter(move |&c| c.type_id() == type_id) + } + + // Children RENDER ***************************************************************************** + + /// Renderiza todos los componentes hijo, en orden. + pub fn render(&self, cx: &mut Context) -> Markup { + html! { + @for c in &self.0 { + (c.render(cx)) + } + } + } +} + +impl IntoIterator for Children { + type Item = Child; + type IntoIter = IntoIter<Child>; + + /// Consume la estructura `Children`, devolviendo un iterador que consume los elementos. + /// + /// ### Ejemplo de uso: + /// ```rust#ignore + /// let children = Children::new().with(child1).with(child2); + /// for child in children { + /// println!("{:?}", child.id()); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'a> IntoIterator for &'a Children { + type Item = &'a Child; + type IntoIter = std::slice::Iter<'a, Child>; + + /// Itera sobre una referencia inmutable de `Children`, devolviendo un iterador de referencia. + /// + /// ### Ejemplo de uso: + /// ```rust#ignore + /// let children = Children::new().with(child1).with(child2); + /// for child in &children { + /// println!("{:?}", child.id()); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl<'a> IntoIterator for &'a mut Children { + type Item = &'a mut Child; + type IntoIter = std::slice::IterMut<'a, Child>; + + /// Itera sobre una referencia mutable de `Children`, devolviendo un iterador mutable. + /// + /// ### Ejemplo de uso: + /// ```rust#ignore + /// let mut children = Children::new().with(child1).with(child2); + /// for child in &mut children { + /// child.render(&mut context); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + self.0.iter_mut() + } +} diff --git a/src/core/component/definition.rs b/src/core/component/definition.rs new file mode 100644 index 00000000..4c93960a --- /dev/null +++ b/src/core/component/definition.rs @@ -0,0 +1,121 @@ +use crate::base::action; +use crate::core::{AnyInfo, TypeInfo}; +use crate::html::{html, Context, Markup, PrepareMarkup, Render}; + +/// Define la función de renderizado para todos los componentes. +/// +/// Este *trait* se implementa automáticamente en cualquier tipo (componente) que implemente +/// [`ComponentTrait`], por lo que no requiere ninguna codificación manual. +pub trait ComponentRender { + /// Renderiza el componente usando el contexto proporcionado. + fn render(&mut self, cx: &mut Context) -> Markup; +} + +/// Interfaz común que debe implementar un componente renderizable en `PageTop`. +/// +/// Se recomienda que los componentes deriven [`AutoDefault`](crate::AutoDefault). También deben +/// implementar el método [`new`](Self::new) y pueden sobrescribir los otros métodos para +/// personalizar su comportamiento. +pub trait ComponentTrait: AnyInfo + ComponentRender + Send + Sync { + /// Crea una nueva instancia del componente. + /// + /// Este método debe implementarse explícitamente. + fn new() -> Self + where + Self: Sized; + + /// Devuelve el nombre del componente. + /// + /// Por defecto se obtiene del nombre corto del tipo usando [`TypeInfo::ShortName`]. + fn name(&self) -> &'static str { + TypeInfo::ShortName.of::<Self>() + } + + /// Devuelve una descripción opcional del componente. + /// + /// Por defecto, no se proporciona ninguna descripción (`None`). + fn description(&self) -> Option<String> { + None + } + + /// Devuelve un identificador opcional para el componente. + /// + /// Este identificador puede usarse para referenciar el componente en el HTML. Por defecto, no + /// tiene ningún identificador (`None`). + fn id(&self) -> Option<String> { + None + } + + /// Configura el componente justo antes de preparar el renderizado. + /// + /// Este método puede sobrescribirse para modificar la estructura interna del componente o el + /// contexto antes de preparar la renderización del componente. Por defecto no hace nada. + #[allow(unused_variables)] + fn setup_before_prepare(&mut self, cx: &mut Context) {} + + /// Devuelve la representación estructurada del componente lista para renderizar. + /// + /// Puede sobrescribirse para generar dinámicamente el contenido HTML. Por defecto, devuelve + /// [`PrepareMarkup::None`]. + #[allow(unused_variables)] + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + PrepareMarkup::None + } +} + +/// Implementa [`render()`](ComponentRender::render) para todos los componentes. +/// +/// Y para cada componente ejecuta la siguiente secuencia: +/// +/// 1. Despacha [`action::component::IsRenderable`](crate::base::action::component::IsRenderable) +/// para ver si se puede renderizar. Si no es así, devuelve un [`Markup`] vacío. +/// 2. Ejecuta [`setup_before_prepare()`](ComponentTrait::setup_before_prepare) para que el +/// componente pueda ajustar su estructura interna o modificar el contexto. +/// 3. Despacha [`action::theme::BeforeRender<C>`](crate::base::action::theme::BeforeRender) para +/// que el tema pueda hacer ajustes en el componente o el contexto. +/// 4. Despacha [`action::component::BeforeRender<C>`](crate::base::action::component::BeforeRender) +/// para que otras extensiones puedan hacer ajustes. +/// 5. **Prepara el renderizado del componente**: +/// - Despacha [`action::theme::PrepareRender<C>`](crate::base::action::theme::PrepareRender) +/// para permitir al tema preparar un renderizado diferente al predefinido. +/// - Si no es así, ejecuta [`prepare_component()`](ComponentTrait::prepare_component) para +/// preparar el renderizado predefinido del componente. +/// 6. Despacha [`action::theme::AfterRender<C>`](crate::base::action::theme::AfterRender) para +/// que el tema pueda hacer sus últimos ajustes. +/// 7. Despacha [`action::component::AfterRender<C>`](crate::base::action::component::AfterRender) +/// para que otras extensiones puedan hacer sus últimos ajustes. +/// 8. Finalmente devuelve un [`Markup`] del renderizado preparado en el paso 5. +impl<C: ComponentTrait> ComponentRender for C { + fn render(&mut self, cx: &mut Context) -> Markup { + // Si no es renderizable, devuelve un bloque HTML vacío. + if !action::component::IsRenderable::dispatch(self, cx) { + return html! {}; + } + + // Configura el componente antes de preparar. + self.setup_before_prepare(cx); + + // Acciones específicas del tema antes de renderizar el componente. + action::theme::BeforeRender::dispatch(self, cx); + + // Acciones de las extensiones antes de renderizar el componente. + action::component::BeforeRender::dispatch(self, cx); + + // Prepara el renderizado del componente. + let prepare = action::theme::PrepareRender::dispatch(self, cx); + let prepare = if prepare.is_empty() { + self.prepare_component(cx) + } else { + prepare + }; + + // Acciones específicas del tema después de renderizar el componente. + action::theme::AfterRender::dispatch(self, cx); + + // Acciones de las extensiones después de renderizar el componente. + action::component::AfterRender::dispatch(self, cx); + + // Devuelve el marcado final. + prepare.render() + } +} diff --git a/src/core/extension/all.rs b/src/core/extension/all.rs index 9012234f..d5c452af 100644 --- a/src/core/extension/all.rs +++ b/src/core/extension/all.rs @@ -1,9 +1,11 @@ use crate::core::action::add_action; use crate::core::extension::ExtensionRef; use crate::core::theme::all::THEMES; -use crate::{service, trace}; +use crate::{/*global, include_files, include_files_service, */ service, trace}; -use std::sync::{LazyLock, RwLock}; +use parking_lot::RwLock; + +use std::sync::LazyLock; // EXTENSIONES ************************************************************************************* @@ -27,11 +29,11 @@ pub fn register_extensions(root_extension: Option<ExtensionRef>) { 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); */ + // Guarda la lista final de extensiones habilitadas. - ENABLED_EXTENSIONS - .write() - .unwrap() - .append(&mut enabled_list); + ENABLED_EXTENSIONS.write().append(&mut enabled_list); // Prepara una lista de extensiones deshabilitadas. let mut dropped_list: Vec<ExtensionRef> = Vec::new(); @@ -42,10 +44,7 @@ pub fn register_extensions(root_extension: Option<ExtensionRef>) { } // Guarda la lista final de extensiones deshabilitadas. - DROPPED_EXTENSIONS - .write() - .unwrap() - .append(&mut dropped_list); + DROPPED_EXTENSIONS.write().append(&mut dropped_list); } fn add_to_enabled(list: &mut Vec<ExtensionRef>, extension: ExtensionRef) { @@ -61,7 +60,7 @@ fn add_to_enabled(list: &mut Vec<ExtensionRef>, extension: ExtensionRef) { // Comprueba si la extensión tiene un tema asociado que deba registrarse. if let Some(theme) = extension.theme() { - let mut registered_themes = THEMES.write().unwrap(); + let mut registered_themes = THEMES.write(); // Asegura que el tema no esté ya registrado para evitar duplicados. if !registered_themes .iter() @@ -84,7 +83,6 @@ fn add_to_dropped(list: &mut Vec<ExtensionRef>, extension: ExtensionRef) { // Comprueba si la extensión está habilitada. Si es así, registra una advertencia. if ENABLED_EXTENSIONS .read() - .unwrap() .iter() .any(|e| e.type_id() == extension.type_id()) { @@ -109,7 +107,7 @@ fn add_to_dropped(list: &mut Vec<ExtensionRef>, extension: ExtensionRef) { // REGISTRO DE LAS ACCIONES ************************************************************************ pub fn register_actions() { - for extension in ENABLED_EXTENSIONS.read().unwrap().iter() { + for extension in ENABLED_EXTENSIONS.read().iter() { for a in extension.actions().into_iter() { add_action(a); } @@ -120,15 +118,20 @@ pub fn register_actions() { pub fn initialize_extensions() { trace::info!("Calling application bootstrap"); - for extension in ENABLED_EXTENSIONS.read().unwrap().iter() { + for extension in ENABLED_EXTENSIONS.read().iter() { extension.initialize(); } } // CONFIGURA LOS SERVICIOS ************************************************************************* +//include_files!(assets); + pub fn configure_services(scfg: &mut service::web::ServiceConfig) { - for extension in ENABLED_EXTENSIONS.read().unwrap().iter() { + 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/core/extension/definition.rs b/src/core/extension/definition.rs index 645afc80..2d9f6dda 100644 --- a/src/core/extension/definition.rs +++ b/src/core/extension/definition.rs @@ -2,7 +2,7 @@ use crate::core::action::ActionBox; use crate::core::theme::ThemeRef; use crate::core::AnyInfo; use crate::locale::L10n; -use crate::{inject_actions, service}; +use crate::{actions_boxed, service}; /// Representa una referencia a una extensión. /// @@ -77,7 +77,7 @@ pub trait ExtensionTrait: AnyInfo + Send + Sync { /// [peso](crate::Weight), permitiendo personalizar el comportamiento de la aplicación en puntos /// específicos. fn actions(&self) -> Vec<ActionBox> { - inject_actions![] + actions_boxed![] } /// Inicializa la extensión durante la lógica de arranque de la aplicación. diff --git a/src/core/theme/all.rs b/src/core/theme/all.rs index 3516107e..1b982680 100644 --- a/src/core/theme/all.rs +++ b/src/core/theme/all.rs @@ -1,7 +1,9 @@ use crate::core::theme::ThemeRef; use crate::global; -use std::sync::{LazyLock, RwLock}; +use parking_lot::RwLock; + +use std::sync::LazyLock; // TEMAS ******************************************************************************************* @@ -17,11 +19,11 @@ pub static DEFAULT_THEME: LazyLock<ThemeRef> = // TEMA POR NOMBRE ********************************************************************************* +/// Devuelve el tema identificado por su [`short_name`](AnyInfo::short_name). pub fn theme_by_short_name(short_name: impl AsRef<str>) -> Option<ThemeRef> { let short_name = short_name.as_ref().to_lowercase(); match THEMES .read() - .unwrap() .iter() .find(|t| t.short_name().to_lowercase() == short_name) { diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 13fe2824..e32ac482 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -9,7 +9,7 @@ pub type ThemeRef = &'static dyn ThemeTrait; /// Interfaz común que debe implementar cualquier tema de `PageTop`. /// /// Un tema implementará [`ThemeTrait`] y los métodos que sean necesarios de [`ExtensionTrait`], -/// aunque el único obligatorio es [`theme()`](crate::core::extension::ExtensionTrait#method.theme). +/// aunque el único obligatorio es [`theme()`](ExtensionTrait::theme). /// /// ```rust /// use pagetop::prelude::*; diff --git a/src/html.rs b/src/html.rs index 4fc9b3e5..3c9c7962 100644 --- a/src/html.rs +++ b/src/html.rs @@ -27,6 +27,9 @@ pub use opt_translated::OptionTranslated; mod opt_classes; pub use opt_classes::{ClassesOp, OptionClasses}; +mod opt_component; +pub use opt_component::OptionComponent; + use crate::AutoDefault; /// Prepara contenido HTML para su conversión a [`Markup`]. diff --git a/src/html/opt_component.rs b/src/html/opt_component.rs new file mode 100644 index 00000000..9e116cd2 --- /dev/null +++ b/src/html/opt_component.rs @@ -0,0 +1,68 @@ +use crate::builder_fn; +use crate::core::component::{ComponentTrait, Typed}; +use crate::html::{html, Context, Markup}; + +/// Contenedor de componente para incluir en otros componentes. +/// +/// Este tipo encapsula `Option<Typed<C>>` para incluir un componente de manera segura en otros +/// componentes, útil para representar estructuras complejas. +/// +/// # Ejemplo +/// +/// ```rust,ignore +/// use pagetop::prelude::*; +/// +/// let comp = MyComponent::new(); +/// let opt = OptionComponent::new(comp); +/// assert!(opt.get().is_some()); +/// ``` +pub struct OptionComponent<C: ComponentTrait>(Option<Typed<C>>); + +impl<C: ComponentTrait> Default for OptionComponent<C> { + fn default() -> Self { + OptionComponent(None) + } +} + +impl<C: ComponentTrait> OptionComponent<C> { + /// Crea un nuevo [`OptionComponent`]. + /// + /// El componente se envuelve automáticamente en un [`Typed`] y se almacena. + pub fn new(component: C) -> Self { + OptionComponent::default().with_value(Some(component)) + } + + // OptionComponent BUILDER ********************************************************************* + + /// Establece un componente nuevo, o lo vacía. + /// + /// Si se proporciona `Some(component)`, se guarda en [`Typed`]; y si es `None`, se limpia. + #[builder_fn] + pub fn with_value(mut self, component: Option<C>) -> Self { + if let Some(component) = component { + self.0 = Some(Typed::with(component)); + } else { + self.0 = None; + } + self + } + + // OptionComponent GETTERS ********************************************************************* + + /// Devuelve el componente, si existe. + pub fn get(&self) -> Option<Typed<C>> { + if let Some(value) = &self.0 { + return Some(value.clone()); + } + None + } + + /// Renderiza el componente, si existe. + pub fn render(&self, cx: &mut Context) -> Markup { + if let Some(component) = &self.0 { + component.render(cx) + } else { + html! {} + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 4ab3c6e4..03bae53e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,11 +92,11 @@ pub mod html; pub mod locale; // Soporte a fechas y horas. pub mod datetime; -// Tipos y funciones esenciales para crear acciones, extensiones y temas. +// Tipos y funciones esenciales para crear acciones, componentes, extensiones y temas. pub mod core; // Gestión del servidor y servicios web. pub mod service; -// Reúne temas listos para usar. +// Reúne acciones y temas listos para usar. pub mod base; // Prepara y ejecuta la aplicación. pub mod app; diff --git a/src/prelude.rs b/src/prelude.rs index 22d9ea0e..fe84e28a 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -17,7 +17,7 @@ pub use crate::include_locales; // crate::service pub use crate::{include_files, include_files_service}; // crate::core::action -pub use crate::inject_actions; +pub use crate::actions_boxed; // API. @@ -38,9 +38,11 @@ pub use crate::service; pub use crate::core::{AnyCast, AnyInfo, TypeInfo}; pub use crate::core::action::*; +pub use crate::core::component::*; pub use crate::core::extension::*; pub use crate::core::theme::*; +pub use crate::base::action; pub use crate::base::theme; pub use crate::app::Application; From cf1e8bbc0243f0657076af87c972ac4d3bfdf693 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 24 Jul 2025 09:11:29 +0200 Subject: [PATCH 083/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20el=20primer=20?= =?UTF-8?q?componente=20b=C3=A1sico=20nativo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Este componente renderiza directamente código HTML durante el renderizado del documento. --- src/base.rs | 4 +++- src/base/component.rs | 4 ++++ src/base/component/html.rs | 28 ++++++++++++++++++++++++++++ src/core/component/definition.rs | 8 +++----- src/lib.rs | 2 +- src/prelude.rs | 1 + 6 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 src/base/component.rs create mode 100644 src/base/component/html.rs diff --git a/src/base.rs b/src/base.rs index 491223e6..6f22dd72 100644 --- a/src/base.rs +++ b/src/base.rs @@ -1,5 +1,7 @@ -//! Reúne acciones y temas listos para usar. +//! Reúne acciones, componentes y temas listos para usar. pub mod action; +pub mod component; + pub mod theme; diff --git a/src/base/component.rs b/src/base/component.rs new file mode 100644 index 00000000..27f0f739 --- /dev/null +++ b/src/base/component.rs @@ -0,0 +1,4 @@ +//! Componentes nativos proporcionados por `PageTop`. + +mod html; +pub use html::Html; diff --git a/src/base/component/html.rs b/src/base/component/html.rs new file mode 100644 index 00000000..09376059 --- /dev/null +++ b/src/base/component/html.rs @@ -0,0 +1,28 @@ +use crate::prelude::*; + +/// Componente básico para renderizar directamente código HTML. +#[derive(AutoDefault)] +pub struct Html(Markup); + +impl ComponentTrait for Html { + fn new() -> Self { + Html::default() + } + + fn prepare_component(&self, _cx: &mut Context) -> PrepareMarkup { + PrepareMarkup::With(html! { (self.0) }) + } +} + +impl Html { + /// Crear una instancia con el código HTML del argumento. + pub fn with(html: Markup) -> Self { + Html(html) + } + + /// Modifica el código HTML de la instancia con el nuevo código del argumento. + pub fn alter_html(&mut self, html: Markup) -> &mut Self { + self.0 = html; + self + } +} diff --git a/src/core/component/definition.rs b/src/core/component/definition.rs index 4c93960a..63264b7a 100644 --- a/src/core/component/definition.rs +++ b/src/core/component/definition.rs @@ -14,12 +14,10 @@ pub trait ComponentRender { /// Interfaz común que debe implementar un componente renderizable en `PageTop`. /// /// Se recomienda que los componentes deriven [`AutoDefault`](crate::AutoDefault). También deben -/// implementar el método [`new`](Self::new) y pueden sobrescribir los otros métodos para -/// personalizar su comportamiento. +/// implementar explícitamente el método [`new`](Self::new) y pueden sobrescribir los otros métodos +/// para personalizar su comportamiento. pub trait ComponentTrait: AnyInfo + ComponentRender + Send + Sync { /// Crea una nueva instancia del componente. - /// - /// Este método debe implementarse explícitamente. fn new() -> Self where Self: Sized; @@ -53,7 +51,7 @@ pub trait ComponentTrait: AnyInfo + ComponentRender + Send + Sync { #[allow(unused_variables)] fn setup_before_prepare(&mut self, cx: &mut Context) {} - /// Devuelve la representación estructurada del componente lista para renderizar. + /// Devuelve una representación estructurada del componente lista para renderizar. /// /// Puede sobrescribirse para generar dinámicamente el contenido HTML. Por defecto, devuelve /// [`PrepareMarkup::None`]. diff --git a/src/lib.rs b/src/lib.rs index 03bae53e..0818be6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,7 +96,7 @@ pub mod datetime; pub mod core; // Gestión del servidor y servicios web. pub mod service; -// Reúne acciones y temas listos para usar. +// Reúne acciones, componentes y temas listos para usar. pub mod base; // Prepara y ejecuta la aplicación. pub mod app; diff --git a/src/prelude.rs b/src/prelude.rs index fe84e28a..11c785f4 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -43,6 +43,7 @@ pub use crate::core::extension::*; pub use crate::core::theme::*; pub use crate::base::action; +pub use crate::base::component::*; pub use crate::base::theme; pub use crate::app::Application; From c379ac28792f4f8613f2e75dfdd4591c5c6a1a7a Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 24 Jul 2025 13:16:39 +0200 Subject: [PATCH 084/244] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Mej?= =?UTF-8?q?ora=20las=20operaciones=20de=20cambio=20en=20contexto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html.rs | 2 +- src/html/context.rs | 165 ++++++++++++++++++++++++++------------------ 2 files changed, 98 insertions(+), 69 deletions(-) diff --git a/src/html.rs b/src/html.rs index 3c9c7962..7f18ee89 100644 --- a/src/html.rs +++ b/src/html.rs @@ -10,7 +10,7 @@ pub use assets::stylesheet::{StyleSheet, TargetMedia}; pub(crate) use assets::Assets; mod context; -pub use context::{Context, ErrorParam}; +pub use context::{Context, ContextOp, ErrorParam}; mod opt_id; pub use opt_id::OptionId; diff --git a/src/html/context.rs b/src/html/context.rs index b3622501..4374b14f 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -13,6 +13,37 @@ use std::str::FromStr; use std::fmt; +/// Operaciones para modificar el contexto ([`Context`]) del documento. +pub enum ContextOp { + /// Modifica el identificador de idioma del documento. + LangId(&'static LanguageIdentifier), + /// Establece el tema que se usará para renderizar el documento. + /// + /// Localiza el tema por su [`short_name`](crate::core::AnyInfo::short_name), y si no aplica + /// ninguno entonces usará el tema por defecto. + Theme(&'static str), + /// Define el tipo de composición usado para renderizar el documento. + Layout(&'static str), + + // Favicon. + /// Define el *favicon* del documento. Sobrescribe cualquier valor anterior. + SetFavicon(Option<Favicon>), + /// Define el *favicon* solo si no se ha establecido previamente. + SetFaviconIfNone(Favicon), + + // Stylesheets. + /// Añade una hoja de estilos CSS al documento. + AddStyleSheet(StyleSheet), + /// Elimina una hoja de estilos por su ruta o identificador. + RemoveStyleSheet(&'static str), + + // JavaScripts. + /// Añade un *script* JavaScript al documento. + AddJavaScript(JavaScript), + /// Elimina un *script* por su ruta o identificador. + RemoveJavaScript(&'static str), +} + /// Errores de lectura o conversión de parámetros almacenados en el contexto. #[derive(Debug)] pub enum ErrorParam { @@ -33,48 +64,52 @@ impl fmt::Display for ErrorParam { impl Error for ErrorParam {} -/// Representa el contexto asociado a un documento HTML. +/// Representa el contexto de un documento HTML. /// -/// Esta estructura se crea internamente para recoger información relativa al documento asociado, -/// como la solicitud HTTP de origen, el idioma, el tema para renderizar ([`ThemeRef`]), y los -/// recursos *favicon* ([`Favicon`]), las hojas de estilo ([`StyleSheet`]) y los *scripts* -/// ([`JavaScript`]). También admite parámetros de contexto definidos en tiempo de ejecución. +/// Se crea internamente para manejar información relevante del documento, como la solicitud HTTP de +/// origen, el idioma, tema y composición para el renderizado, los recursos *favicon* ([`Favicon`]), +/// hojas de estilo ([`StyleSheet`]) y *scripts* ([`JavaScript`]), así como parámetros de contexto +/// definidos en tiempo de ejecución. /// /// # Ejemplo /// /// ```rust /// use pagetop::prelude::*; /// -/// fn configure_context(mut ctx: Context) { +/// fn configure_context(mut cx: Context) { /// // Establece el idioma del documento a español. -/// ctx.set_langid(LangMatch::langid_or_default("es-ES")); -/// +/// cx.alter_assets(ContextOp::LangId( +/// LangMatch::langid_or_default("es-ES") +/// )) /// // Selecciona un tema (por su nombre corto). -/// ctx.set_theme("aliner"); -/// +/// .alter_assets(ContextOp::Theme("aliner")) /// // Asigna un favicon. -/// ctx.set_favicon(Some(Favicon::new().with_icon("/icons/favicon.ico"))); -/// +/// .alter_assets(ContextOp::SetFavicon(Some( +/// Favicon::new().with_icon("/icons/favicon.ico") +/// ))) /// // Añade una hoja de estilo externa. -/// ctx.add_stylesheet(StyleSheet::from("/css/style.css")); -/// +/// .alter_assets(ContextOp::AddStyleSheet( +/// StyleSheet::from("/css/style.css") +/// )) /// // Añade un script JavaScript. -/// ctx.add_javascript(JavaScript::defer("/js/main.js")); +/// .alter_assets(ContextOp::AddJavaScript( +/// JavaScript::defer("/js/main.js") +/// )); /// /// // Añade un parámetro dinámico al contexto. -/// ctx.set_param("usuario_id", 42); +/// cx.set_param("usuario_id", 42); /// /// // Recupera el parámetro y lo convierte a su tipo original. -/// let id: i32 = ctx.get_param("usuario_id").unwrap(); +/// let id: i32 = cx.get_param("usuario_id").unwrap(); /// assert_eq!(id, 42); /// /// // Recupera el tema seleccionado. -/// let active_theme = ctx.theme(); +/// let active_theme = cx.theme(); /// assert_eq!(active_theme.short_name(), "aliner"); /// /// // Genera un identificador único para un componente de tipo `Menu`. /// struct Menu; -/// let unique_id = ctx.required_id::<Menu>(None); +/// let unique_id = cx.required_id::<Menu>(None); /// assert_eq!(unique_id, "menu-1"); // Si es el primero generado. /// } /// ``` @@ -83,6 +118,7 @@ pub struct Context { request : HttpRequest, // Solicitud HTTP de origen. langid : &'static LanguageIdentifier, // Identificador del idioma. theme : ThemeRef, // Referencia al tema para renderizar. + layout : &'static str, // Composición del documento para renderizar. favicon : Option<Favicon>, // Favicon, si se ha definido. stylesheets: Assets<StyleSheet>, // Hojas de estilo CSS. javascripts: Assets<JavaScript>, // Scripts JavaScript. @@ -100,6 +136,7 @@ impl Context { request, langid : &DEFAULT_LANGID, theme : *DEFAULT_THEME, + layout : "default", favicon : None, stylesheets: Assets::<StyleSheet>::new(), javascripts: Assets::<JavaScript>::new(), @@ -108,59 +145,45 @@ impl Context { } } - /// Modifica el identificador de idioma del documento. - pub fn set_langid(&mut self, langid: &'static LanguageIdentifier) -> &mut Self { - self.langid = langid; - self - } - - /// Establece el tema que se usará para renderizar el documento. - /// - /// Localiza el tema por su [`short_name`](crate::core::AnyInfo::short_name), y si no aplica - /// ninguno entonces usará el tema por defecto. - pub fn set_theme(&mut self, short_name: impl AsRef<str>) -> &mut Self { - self.theme = theme_by_short_name(short_name).unwrap_or(*DEFAULT_THEME); - self - } - - /// Define el *favicon* del documento. Sobrescribe cualquier valor anterior. - pub fn set_favicon(&mut self, favicon: Option<Favicon>) -> &mut Self { - self.favicon = favicon; - self - } - - /// Define el *favicon* solo si no se ha establecido previamente. - pub fn set_favicon_if_none(&mut self, favicon: Favicon) -> &mut Self { - if self.favicon.is_none() { - self.favicon = Some(favicon); + /// Modifica información o recursos del contexto usando [`ContextOp`]. + pub fn alter_assets(&mut self, op: ContextOp) -> &mut Self { + match op { + ContextOp::LangId(langid) => { + self.langid = langid; + } + ContextOp::Theme(theme_name) => { + self.theme = theme_by_short_name(theme_name).unwrap_or(*DEFAULT_THEME); + } + ContextOp::Layout(layout) => { + self.layout = layout; + } + // Favicon. + ContextOp::SetFavicon(favicon) => { + self.favicon = favicon; + } + ContextOp::SetFaviconIfNone(icon) => { + if self.favicon.is_none() { + self.favicon = Some(icon); + } + } + // Stylesheets. + ContextOp::AddStyleSheet(css) => { + self.stylesheets.add(css); + } + ContextOp::RemoveStyleSheet(path) => { + self.stylesheets.remove(path); + } + // JavaScripts. + ContextOp::AddJavaScript(js) => { + self.javascripts.add(js); + } + ContextOp::RemoveJavaScript(path) => { + self.javascripts.remove(path); + } } self } - /// Añade una hoja de estilos CSS al documento. - pub fn add_stylesheet(&mut self, css: StyleSheet) -> &mut Self { - self.stylesheets.add(css); - self - } - - /// Elimina una hoja de estilos por su ruta o identificador. - pub fn remove_stylesheet(&mut self, name: impl AsRef<str>) -> &mut Self { - self.stylesheets.remove(name); - self - } - - /// Añade un *script* JavaScript al documento. - pub fn add_javascript(&mut self, js: JavaScript) -> &mut Self { - self.javascripts.add(js); - self - } - - /// Elimina un *script* por su ruta o identificador. - pub fn remove_javascript(&mut self, name: impl AsRef<str>) -> &mut Self { - self.javascripts.remove(name); - self - } - /// Añade o modifica un parámetro del contexto almacenando el valor como [`String`]. pub fn set_param<T: ToString>(&mut self, key: impl AsRef<str>, value: T) -> &mut Self { self.params @@ -185,6 +208,12 @@ impl Context { self.theme } + /// Devuelve el tipo de composición usado para renderizar el documento. El valor predeterminado + /// es `"default"`. + pub fn layout(&self) -> &str { + self.layout + } + /// Recupera un parámetro del contexto convertido al tipo especificado. /// /// Devuelve un error si el parámetro no existe ([`ErrorParam::NotFound`]) o la conversión falla From 3397553ba75a8cf674927f34f6b7ea468886d36b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 24 Jul 2025 21:20:35 +0200 Subject: [PATCH 085/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20gesti=C3=B3n?= =?UTF-8?q?=20de=20regiones=20en=20temas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/theme.rs | 18 ++++++ src/core/theme/definition.rs | 7 ++- src/core/theme/regions.rs | 111 +++++++++++++++++++++++++++++++++++ src/locale/en-US/theme.ftl | 1 + src/locale/es-ES/theme.ftl | 1 + 5 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/core/theme/regions.rs create mode 100644 src/locale/en-US/theme.ftl create mode 100644 src/locale/es-ES/theme.ftl diff --git a/src/core/theme.rs b/src/core/theme.rs index d741cf80..d67a4457 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -1,6 +1,24 @@ //! API para añadir y gestionar nuevos temas. +//! +//! En `PageTop` un tema es la *piel* de la aplicación, decide cómo se muestra cada documento HTML, +//! especialmente las páginas de contenido ([`Page`](crate::response::page::Page)), sin alterar la +//! lógica interna de sus componentes. +//! +//! Un tema **declara las regiones** (*cabecera*, *barra lateral*, *pie*, etc.) que estarán +//! disponibles para colocar contenido. Los temas son responsables últimos de los estilos, +//! tipografías, espaciados y cualquier otro detalle visual o de comportamiento (como animaciones, +//! *scripts* de interfaz, etc.). +//! +//! Es una extensión más (implementando [`ExtensionTrait`](crate::core::extension::ExtensionTrait)). +//! Se instala, activa y declara dependencias igual que el resto de extensiones; y se señala a sí +//! misma como tema (implementando [`theme()`](crate::core::extension::ExtensionTrait::theme) +//! y [`ThemeTrait`]). mod definition; pub use definition::{ThemeRef, ThemeTrait}; +mod regions; +pub(crate) use regions::ChildrenInRegions; +pub use regions::InRegion; + pub(crate) mod all; diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index e32ac482..6f1e54a1 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -1,4 +1,5 @@ use crate::core::extension::ExtensionTrait; +use crate::locale::L10n; /// Representa una referencia a un tema. /// @@ -27,4 +28,8 @@ pub type ThemeRef = &'static dyn ThemeTrait; /// /// impl ThemeTrait for MyTheme {} /// ``` -pub trait ThemeTrait: ExtensionTrait + Send + Sync {} +pub trait ThemeTrait: ExtensionTrait + Send + Sync { + fn regions(&self) -> Vec<(&'static str, L10n)> { + vec![("content", L10n::l("content"))] + } +} diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs new file mode 100644 index 00000000..5beee25a --- /dev/null +++ b/src/core/theme/regions.rs @@ -0,0 +1,111 @@ +use crate::core::component::{Child, ChildOp, Children}; +use crate::core::theme::ThemeRef; +use crate::{builder_fn, AutoDefault, UniqueId}; + +use parking_lot::RwLock; + +use std::collections::HashMap; +use std::sync::LazyLock; + +static THEME_REGIONS: LazyLock<RwLock<HashMap<UniqueId, ChildrenInRegions>>> = + LazyLock::new(|| RwLock::new(HashMap::new())); + +static COMMON_REGIONS: LazyLock<RwLock<ChildrenInRegions>> = + LazyLock::new(|| RwLock::new(ChildrenInRegions::default())); + +// Estructura interna para mantener los componentes de cada región dada. +#[derive(AutoDefault)] +pub struct ChildrenInRegions(HashMap<&'static str, Children>); + +impl ChildrenInRegions { + pub fn new() -> Self { + ChildrenInRegions::default() + } + + pub fn with(region_id: &'static str, child: Child) -> Self { + ChildrenInRegions::default().with_in_region(region_id, ChildOp::Add(child)) + } + + #[builder_fn] + pub fn with_in_region(mut self, region_id: &'static str, op: ChildOp) -> Self { + if let Some(region) = self.0.get_mut(region_id) { + region.alter_child(op); + } else { + self.0.insert(region_id, Children::new().with_child(op)); + } + self + } + + pub fn all_in_region(&self, theme: ThemeRef, region_id: &str) -> Children { + let common = COMMON_REGIONS.read(); + if let Some(r) = THEME_REGIONS.read().get(&theme.type_id()) { + Children::merge(&[ + common.0.get(region_id), + self.0.get(region_id), + r.0.get(region_id), + ]) + } else { + Children::merge(&[common.0.get(region_id), self.0.get(region_id)]) + } + } +} + +/// Permite añadir componentes a regiones globales o regiones de temas concretos. +/// +/// Dada una región, según la variante seleccionada, se le podrán añadir ([`add()`](Self::add)) +/// componentes que se mantendrán durante la ejecución de la aplicación. +/// +/// Estas estructuras de componentes se renderizarán automáticamente al procesar los documentos HTML +/// que las usan, como las páginas de contenido ([`Page`](crate::response::page::Page)), por +/// ejemplo. +pub enum InRegion { + /// Representa la región por defecto en la que se pueden añadir componentes. + Content, + /// Representa la región con el nombre del argumento. + Named(&'static str), + /// Representa la región con el nombre y del tema especificado en los argumentos. + OfTheme(&'static str, ThemeRef), +} + +impl InRegion { + /// Permite añadir un componente en la región de la variante seleccionada. + /// + /// # Ejemplo + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// // Banner global, en la región por defecto de cualquier página. + /// InRegion::Content.add(Child::with(Html::with( + /// html! { ("🎉 ¡Bienvenido!") } + /// ))); + /// + /// // Texto en la región "sidebar". + /// InRegion::Named("sidebar").add(Child::with(Html::with( + /// html! { ("Publicidad") } + /// ))); + /// ``` + pub fn add(&self, child: Child) -> &Self { + match self { + InRegion::Content => { + COMMON_REGIONS + .write() + .alter_in_region("region-content", ChildOp::Add(child)); + } + InRegion::Named(name) => { + COMMON_REGIONS + .write() + .alter_in_region(name, ChildOp::Add(child)); + } + InRegion::OfTheme(region, theme) => { + let mut regions = THEME_REGIONS.write(); + if let Some(r) = regions.get_mut(&theme.type_id()) { + r.alter_in_region(region, ChildOp::Add(child)); + } else { + regions.insert(theme.type_id(), ChildrenInRegions::with(region, child)); + } + } + } + self + } +} diff --git a/src/locale/en-US/theme.ftl b/src/locale/en-US/theme.ftl new file mode 100644 index 00000000..fd7f228d --- /dev/null +++ b/src/locale/en-US/theme.ftl @@ -0,0 +1 @@ +content = Content diff --git a/src/locale/es-ES/theme.ftl b/src/locale/es-ES/theme.ftl new file mode 100644 index 00000000..c2026c6f --- /dev/null +++ b/src/locale/es-ES/theme.ftl @@ -0,0 +1 @@ +content = Contenido From 2566bd6e58fe61da8ded884bff38d33ccf262e13 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 25 Jul 2025 18:25:42 +0200 Subject: [PATCH 086/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20respuestas=20w?= =?UTF-8?q?eb=20con=20redirecciones=20HTTP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 2 + src/prelude.rs | 3 ++ src/response.rs | 5 ++ src/response/redirect.rs | 98 ++++++++++++++++++++++++++++++++++++++++ src/service.rs | 2 +- 5 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/response.rs create mode 100644 src/response/redirect.rs diff --git a/src/lib.rs b/src/lib.rs index 0818be6a..e2d39754 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,6 +94,8 @@ pub mod locale; pub mod datetime; // Tipos y funciones esenciales para crear acciones, componentes, extensiones y temas. pub mod core; +// Respuestas a peticiones web en sus diferentes formatos. +pub mod response; // Gestión del servidor y servicios web. pub mod service; // Reúne acciones, componentes y temas listos para usar. diff --git a/src/prelude.rs b/src/prelude.rs index 11c785f4..7baa687a 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -34,6 +34,7 @@ pub use crate::locale::*; pub use crate::datetime::*; pub use crate::service; +pub use crate::service::HttpRequest; pub use crate::core::{AnyCast, AnyInfo, TypeInfo}; @@ -42,6 +43,8 @@ pub use crate::core::component::*; pub use crate::core::extension::*; pub use crate::core::theme::*; +pub use crate::response::{redirect::*, ResponseError}; + pub use crate::base::action; pub use crate::base::component::*; pub use crate::base::theme; diff --git a/src/response.rs b/src/response.rs new file mode 100644 index 00000000..cf18377c --- /dev/null +++ b/src/response.rs @@ -0,0 +1,5 @@ +//! Respuestas a las peticiones web en sus diferentes formatos. + +pub use actix_web::ResponseError; + +pub mod redirect; diff --git a/src/response/redirect.rs b/src/response/redirect.rs new file mode 100644 index 00000000..bb3020da --- /dev/null +++ b/src/response/redirect.rs @@ -0,0 +1,98 @@ +//! Realiza redirecciones HTTP. +//! +//! **La redirección de URL** (o *URL forwarding*) es una técnica que permite asignar más de una +//! dirección a un mismo recurso web. HTTP define respuestas ***HTTP redirect*** para ello (ver +//! *[Redirections in HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections)*). +//! +//! Existen varios tipos de redirección, agrupados en tres grandes categorías: +//! +//! - **Redirecciones permanentes**. Se usan cuando el cambio de ubicación es definitivo. Indican +//! que la URL original ya no debe emplearse y que ha sido sustituida por la nueva. Los robots de +//! los buscadores, lectores RSS y otros *crawlers* suelen actualizar sus índices con la nueva +//! dirección. +//! +//! - **Redirecciones temporales**. Se aplican cuando el recurso no puede servirse desde su +//! ubicación canónica pero sí desde otra provisional. En este caso los buscadores **no** deben +//! memorizar la URL alternativa. También son útiles para mostrar páginas de progreso al crear, +//! actualizar o eliminar recursos. +//! +//! - **Respuestas especiales**. + +use crate::service::HttpResponse; + +/// Funciones predefinidas para generar respuestas HTTP de redirección. +/// +/// Ofrece atajos para construir respuestas con el código de estado apropiado, añade la cabecera +/// `Location` y la cierra con `.finish()`, evitando repetir la misma secuencia en cada controlador. +pub struct Redirect; + +impl Redirect { + /// Redirección **permanente**. Código de estado **301**. El método GET se conserva tal cual. + /// Otros métodos pueden degradarse a GET. Es una redirección típica para la reorganización de + /// un sitio o aplicación web. + /// + /// Emplear cuando un recurso se ha movido de forma definitiva y la URL antigua debe dejar de + /// usarse. + #[must_use] + pub fn moved(redirect_to_url: &str) -> HttpResponse { + HttpResponse::MovedPermanently() + .append_header(("Location", redirect_to_url)) + .finish() + } + + /// Redirección **permanente**. Código de estado **308**. Mantiene método y cuerpo sin cambios. + /// + /// Indicada para reorganizaciones de un sitio o aplicación web en las que también existen + /// métodos distintos de GET (POST, PUT, …) que no deben degradarse a GET. + #[must_use] + pub fn permanent(redirect_to_url: &str) -> HttpResponse { + HttpResponse::PermanentRedirect() + .append_header(("Location", redirect_to_url)) + .finish() + } + + /// Redirección **temporal**. Código de estado **302**. El método GET (y normalmente HEAD) se + /// mantiene tal cual. Otros métodos pueden degradarse a GET. + /// + /// Útil cuando un recurso está fuera de servicio de forma imprevista (mantenimiento breve, + /// sobrecarga, …). + #[must_use] + pub fn found(redirect_to_url: &str) -> HttpResponse { + HttpResponse::Found() + .append_header(("Location", redirect_to_url)) + .finish() + } + + /// Redirección **temporal**. Código de estado **303**. Método GET se mantiene tal cual. Los + /// demás métodos se cambian a GET (se pierde el cuerpo). + /// + /// Se usa típicamente tras un POST o PUT para aplicar el patrón *Post/Redirect/Get*, permite + /// recargar la página de resultados sin volver a ejecutar la operación. + #[must_use] + pub fn see_other(redirect_to_url: &str) -> HttpResponse { + HttpResponse::SeeOther() + .append_header(("Location", redirect_to_url)) + .finish() + } + + /// Redirección **temporal**. Código de estado **307**. Conserva método y cuerpo íntegros. + /// + /// Preferible a [`found`](Self::found) cuando el sitio expone operaciones diferentes de GET que + /// deben respetarse durante la redirección. + #[must_use] + pub fn temporary(redirect_to_url: &str) -> HttpResponse { + HttpResponse::TemporaryRedirect() + .append_header(("Location", redirect_to_url)) + .finish() + } + + /// Respuesta **especial**. Código de estado **304**. Se envía tras una petición condicional, + /// para indicar que la copia en caché sigue siendo válida y puede utilizarse, evitando + /// transferir de nuevo el recurso. + /// + /// No es una redirección, el cliente debe reutilizar su copia local. + #[must_use] + pub fn not_modified() -> HttpResponse { + HttpResponse::NotModified().finish() + } +} diff --git a/src/service.rs b/src/service.rs index 47e84224..cc32d56e 100644 --- a/src/service.rs +++ b/src/service.rs @@ -6,7 +6,7 @@ pub use actix_web::dev::ServiceFactory as Factory; pub use actix_web::dev::ServiceRequest as Request; pub use actix_web::dev::ServiceResponse as Response; pub use actix_web::{http, rt, web}; -pub use actix_web::{App, Error, HttpRequest, HttpServer}; +pub use actix_web::{App, Error, HttpRequest, HttpResponse, HttpServer}; #[doc(hidden)] pub use actix_web::test; From a1b5155703b648661ac6cf486c9bfe58f421fa05 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 25 Jul 2025 19:18:06 +0200 Subject: [PATCH 087/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20soporte=20a=20?= =?UTF-8?q?respuestas=20JSON?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prelude.rs | 4 ++-- src/response.rs | 2 ++ src/response/json.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/response/json.rs diff --git a/src/prelude.rs b/src/prelude.rs index 7baa687a..9334f189 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -34,7 +34,7 @@ pub use crate::locale::*; pub use crate::datetime::*; pub use crate::service; -pub use crate::service::HttpRequest; +pub use crate::service::{HttpRequest, HttpResponse}; pub use crate::core::{AnyCast, AnyInfo, TypeInfo}; @@ -43,7 +43,7 @@ pub use crate::core::component::*; pub use crate::core::extension::*; pub use crate::core::theme::*; -pub use crate::response::{redirect::*, ResponseError}; +pub use crate::response::{json::*, redirect::*, ResponseError}; pub use crate::base::action; pub use crate::base::component::*; diff --git a/src/response.rs b/src/response.rs index cf18377c..1fce663f 100644 --- a/src/response.rs +++ b/src/response.rs @@ -2,4 +2,6 @@ pub use actix_web::ResponseError; +pub mod json; + pub mod redirect; diff --git a/src/response/json.rs b/src/response/json.rs new file mode 100644 index 00000000..fee4c121 --- /dev/null +++ b/src/response/json.rs @@ -0,0 +1,41 @@ +//! Extractor y generador de respuestas JSON (reexporta [`actix_web::web::Json`]). +//! +//! # Uso como extractor JSON +//! +//! Convierte automáticamente el cuerpo de una petición con `Content-Type: application/json` en un +//! tipo Rust fuertemente tipado, validando el formato y deserializando con *serde*. +//! +//! ```rust +//! use pagetop::prelude::*; +//! +//! #[derive(serde::Deserialize)] +//! struct NuevoUsuario { nombre: String, email: String } +//! +//! // Manejador configurado para la ruta POST "/usuarios". +//! async fn crear_usuario(payload: Json<NuevoUsuario>) -> HttpResponse { +//! // `payload` ya es `NuevoUsuario`; si la deserialización falla, +//! // devolverá automáticamente 400 Bad Request con un cuerpo JSON que describe el error. +//! HttpResponse::Ok().finish() +//! } +//! ``` +//! +//! # Uso como generador de respuestas JSON +//! +//! Serializa valores Rust a JSON y genera una respuesta HTTP con el encabezado apropiado +//! `application/json; charset=utf-8`, todo con una llamada compacta. +//! +//! ```rust +//! use pagetop::prelude::*; +//! +//! #[derive(serde::Serialize)] +//! struct Usuario { id: u32, nombre: String } +//! +//! async fn obtener_usuario() -> Json<Usuario> { +//! Json(Usuario { id: 1, nombre: "Ada".into() }) +//! } +//! ``` +//! +//! `Json<T>` funciona con cualquier tipo que implemente `serde::Serialize` (para respuestas) y/o +//! `serde::Deserialize` (para peticiones). + +pub use actix_web::web::Json; From cf6bb24ed6e7e1d69f1e395d31e2c28160af69e1 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 25 Jul 2025 23:05:53 +0200 Subject: [PATCH 088/244] =?UTF-8?q?=F0=9F=92=A1=20Normaliza=20comentarios?= =?UTF-8?q?=20en=20varios=20archivos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config.rs | 8 ++++---- src/core/action/all.rs | 2 ++ src/core/component/children.rs | 9 ++++++--- src/html/opt_classes.rs | 4 +++- src/html/opt_id.rs | 1 + src/html/opt_name.rs | 3 ++- src/html/opt_string.rs | 1 + 7 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/config.rs b/src/config.rs index d532ba14..ed37d550 100644 --- a/src/config.rs +++ b/src/config.rs @@ -162,7 +162,7 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( /// Incluye los ajustes necesarios de la configuración anticipando valores por defecto. /// -/// ### Sintaxis +/// # Sintaxis /// /// Hay que añadir en nuestra librería el siguiente código: /// @@ -182,7 +182,7 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( /// * **Lista de pares** con las claves TOML que requieran valores por defecto. Siguen la notación /// `"seccion.subclave"` para coincidir con el árbol TOML. /// -/// ### Ejemplo básico +/// # Ejemplo básico /// /// ```rust,no_run /// use pagetop::prelude::*; @@ -212,7 +212,7 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( /// } /// ``` /// -/// ### Buenas prácticas +/// # Buenas prácticas /// /// * **Valores por defecto**. Declara un valor por defecto para cada clave obligatoria. Las claves /// opcionales pueden ser `Option<T>`. @@ -227,7 +227,7 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( /// * **Errores explícitos**. Si la deserialización falla, la macro lanzará un `panic!` con un /// mensaje que indica la estructura problemática, facilitando la depuración. /// -/// ### Requisitos +/// # Requisitos /// /// * Dependencia `serde` con la *feature* `derive`. /// * Las claves deben coincidir con los campos (*snake case*) de tu estructura `Settings_Type`. diff --git a/src/core/action/all.rs b/src/core/action/all.rs index ffee9f56..7fff970c 100644 --- a/src/core/action/all.rs +++ b/src/core/action/all.rs @@ -44,10 +44,12 @@ pub fn add_action(action: ActionBox) { /// acción específica. /// /// # Parámetros genéricos +/// /// - `A`: Tipo de acción que esperamos procesar. Debe implementar [`ActionDispatcher`]. /// - `F`: Función asociada a cada acción, devuelve un valor de tipo `B`. /// /// # Ejemplo de uso +/// /// ```rust,ignore /// pub(crate) fn dispatch(component: &mut C, cx: &mut Context) { /// dispatch_actions( diff --git a/src/core/component/children.rs b/src/core/component/children.rs index 38a626b2..cba8c39f 100644 --- a/src/core/component/children.rs +++ b/src/core/component/children.rs @@ -278,7 +278,8 @@ impl IntoIterator for Children { /// Consume la estructura `Children`, devolviendo un iterador que consume los elementos. /// - /// ### Ejemplo de uso: + /// # Ejemplo de uso: + /// /// ```rust#ignore /// let children = Children::new().with(child1).with(child2); /// for child in children { @@ -296,7 +297,8 @@ impl<'a> IntoIterator for &'a Children { /// Itera sobre una referencia inmutable de `Children`, devolviendo un iterador de referencia. /// - /// ### Ejemplo de uso: + /// # Ejemplo de uso: + /// /// ```rust#ignore /// let children = Children::new().with(child1).with(child2); /// for child in &children { @@ -314,7 +316,8 @@ impl<'a> IntoIterator for &'a mut Children { /// Itera sobre una referencia mutable de `Children`, devolviendo un iterador mutable. /// - /// ### Ejemplo de uso: + /// # Ejemplo de uso: + /// /// ```rust#ignore /// let mut children = Children::new().with(child1).with(child2); /// for child in &mut children { diff --git a/src/html/opt_classes.rs b/src/html/opt_classes.rs index bcec9372..abb3ba48 100644 --- a/src/html/opt_classes.rs +++ b/src/html/opt_classes.rs @@ -21,12 +21,14 @@ pub enum ClassesOp { /// Permite construir y modificar dinámicamente con [`ClassesOp`] una lista de clases CSS /// normalizadas. /// -/// ### Normalización +/// # Normalización +/// /// - El [orden de las clases no es relevante](https://stackoverflow.com/a/1321712) en CSS. /// - No se permiten clases duplicadas. /// - Las clases vacías se ignoran. /// /// # Ejemplo +/// /// ```rust /// use pagetop::prelude::*; /// diff --git a/src/html/opt_id.rs b/src/html/opt_id.rs index 6f166b95..893ac6d3 100644 --- a/src/html/opt_id.rs +++ b/src/html/opt_id.rs @@ -5,6 +5,7 @@ use crate::{builder_fn, AutoDefault}; /// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso. /// /// # Normalización +/// /// - Se eliminan los espacios al principio y al final. /// - Se sustituyen los espacios intermedios por guiones bajos (`_`). /// - Si el resultado es una cadena vacía, se guarda `None`. diff --git a/src/html/opt_name.rs b/src/html/opt_name.rs index c4e2e2e0..aa74e3b9 100644 --- a/src/html/opt_name.rs +++ b/src/html/opt_name.rs @@ -5,11 +5,12 @@ use crate::{builder_fn, AutoDefault}; /// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso. /// /// # Normalización +/// /// - Se eliminan los espacios al principio y al final. /// - Se sustituyen los espacios intermedios por guiones bajos (`_`). /// - Si el resultado es una cadena vacía, se guarda `None`. /// -/// ## Ejemplo +/// # Ejemplo /// /// ```rust /// use pagetop::prelude::*; diff --git a/src/html/opt_string.rs b/src/html/opt_string.rs index 5379597e..5bfd9c71 100644 --- a/src/html/opt_string.rs +++ b/src/html/opt_string.rs @@ -5,6 +5,7 @@ use crate::{builder_fn, AutoDefault}; /// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso. /// /// # Normalización +/// /// - Se eliminan los espacios al principio y al final. /// - Si el resultado es una cadena vacía, se guarda `None`. /// From d7485c8311d79752fea06ca00c8040de9e1fc6ee Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 25 Jul 2025 23:29:16 +0200 Subject: [PATCH 089/244] =?UTF-8?q?=F0=9F=92=A1=20(macros):=20Mejora=20com?= =?UTF-8?q?entario=20en=20m=C3=A9todos=20"alter=5F"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-macros/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 62b6e886..ecca395d 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -170,8 +170,7 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { // Genera el método alter_...() con el código del método with_...(). let fn_alter_doc = format!( - "Modifica la instancia en los mismos términos que para el patrón <em>builder</em> hace el \ - método asociado `{}()`.", + "Equivale a invocar el método `{}()` cuando se aplica el patrón builder.", fn_with_name_str, ); let fn_alter = quote! { From 4af558289eb51feba1eb91b9b99c2995bc024167 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 27 Jul 2025 00:27:11 +0200 Subject: [PATCH 090/244] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Reemplaza=20Contex?= =?UTF-8?q?tOp=20por=20AssetsOp=20en=20el=20contexto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html.rs | 2 +- src/html/context.rs | 151 +++++++++++++++++++++++--------------------- 2 files changed, 80 insertions(+), 73 deletions(-) diff --git a/src/html.rs b/src/html.rs index 7f18ee89..82fa906b 100644 --- a/src/html.rs +++ b/src/html.rs @@ -10,7 +10,7 @@ pub use assets::stylesheet::{StyleSheet, TargetMedia}; pub(crate) use assets::Assets; mod context; -pub use context::{Context, ContextOp, ErrorParam}; +pub use context::{AssetsOp, Context, ErrorParam}; mod opt_id; pub use opt_id::OptionId; diff --git a/src/html/context.rs b/src/html/context.rs index 4374b14f..a8d634a6 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -1,11 +1,11 @@ use crate::core::theme::all::{theme_by_short_name, DEFAULT_THEME}; use crate::core::theme::ThemeRef; use crate::core::TypeInfo; -use crate::html::{html, Markup, Render}; +use crate::html::{html, Markup}; use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; -use crate::join; use crate::locale::{LanguageIdentifier, DEFAULT_LANGID}; use crate::service::HttpRequest; +use crate::{builder_fn, join}; use std::collections::HashMap; use std::error::Error; @@ -14,17 +14,7 @@ use std::str::FromStr; use std::fmt; /// Operaciones para modificar el contexto ([`Context`]) del documento. -pub enum ContextOp { - /// Modifica el identificador de idioma del documento. - LangId(&'static LanguageIdentifier), - /// Establece el tema que se usará para renderizar el documento. - /// - /// Localiza el tema por su [`short_name`](crate::core::AnyInfo::short_name), y si no aplica - /// ninguno entonces usará el tema por defecto. - Theme(&'static str), - /// Define el tipo de composición usado para renderizar el documento. - Layout(&'static str), - +pub enum AssetsOp { // Favicon. /// Define el *favicon* del documento. Sobrescribe cualquier valor anterior. SetFavicon(Option<Favicon>), @@ -76,38 +66,35 @@ impl Error for ErrorParam {} /// ```rust /// use pagetop::prelude::*; /// -/// fn configure_context(mut cx: Context) { +/// fn configure_context(cx: &mut Context) { /// // Establece el idioma del documento a español. -/// cx.alter_assets(ContextOp::LangId( -/// LangMatch::langid_or_default("es-ES") -/// )) +/// cx.alter_langid(LangMatch::langid_or_default("es-ES")) /// // Selecciona un tema (por su nombre corto). -/// .alter_assets(ContextOp::Theme("aliner")) +/// .alter_theme("aliner") +/// // Añade un parámetro dinámico al contexto. +/// .alter_param("usuario_id", 42) /// // Asigna un favicon. -/// .alter_assets(ContextOp::SetFavicon(Some( +/// .alter_assets(AssetsOp::SetFavicon(Some( /// Favicon::new().with_icon("/icons/favicon.ico") /// ))) /// // Añade una hoja de estilo externa. -/// .alter_assets(ContextOp::AddStyleSheet( +/// .alter_assets(AssetsOp::AddStyleSheet( /// StyleSheet::from("/css/style.css") /// )) /// // Añade un script JavaScript. -/// .alter_assets(ContextOp::AddJavaScript( +/// .alter_assets(AssetsOp::AddJavaScript( /// JavaScript::defer("/js/main.js") /// )); /// -/// // Añade un parámetro dinámico al contexto. -/// cx.set_param("usuario_id", 42); -/// -/// // Recupera el parámetro y lo convierte a su tipo original. -/// let id: i32 = cx.get_param("usuario_id").unwrap(); -/// assert_eq!(id, 42); -/// /// // Recupera el tema seleccionado. /// let active_theme = cx.theme(); /// assert_eq!(active_theme.short_name(), "aliner"); /// -/// // Genera un identificador único para un componente de tipo `Menu`. +/// // Recupera el parámetro a su tipo original. +/// let id: i32 = cx.param("usuario_id").unwrap(); +/// assert_eq!(id, 42); +/// +/// // Genera un identificador para un componente de tipo `Menu`. /// struct Menu; /// let unique_id = cx.required_id::<Menu>(None); /// assert_eq!(unique_id, "menu-1"); // Si es el primero generado. @@ -119,10 +106,10 @@ pub struct Context { langid : &'static LanguageIdentifier, // Identificador del idioma. theme : ThemeRef, // Referencia al tema para renderizar. layout : &'static str, // Composición del documento para renderizar. + params : HashMap<String, String>, // Parámetros definidos en tiempo de ejecución. favicon : Option<Favicon>, // Favicon, si se ha definido. stylesheets: Assets<StyleSheet>, // Hojas de estilo CSS. javascripts: Assets<JavaScript>, // Scripts JavaScript. - params : HashMap<String, String>, // Parámetros definidos en tiempo de ejecución. id_counter : usize, // Contador para generar identificadores únicos. } @@ -137,60 +124,84 @@ impl Context { langid : &DEFAULT_LANGID, theme : *DEFAULT_THEME, layout : "default", + params : HashMap::<String, String>::new(), favicon : None, stylesheets: Assets::<StyleSheet>::new(), javascripts: Assets::<JavaScript>::new(), - params : HashMap::<String, String>::new(), id_counter : 0, } } - /// Modifica información o recursos del contexto usando [`ContextOp`]. - pub fn alter_assets(&mut self, op: ContextOp) -> &mut Self { + // Context BUILDER ***************************************************************************** + + /// Modifica el identificador de idioma del documento. + #[builder_fn] + pub fn with_langid(&mut self, langid: &'static LanguageIdentifier) -> &mut Self { + self.langid = langid; + self + } + + /// Establece el tema que se usará para renderizar el documento. + /// + /// Localiza el tema por su [`short_name`](crate::core::AnyInfo::short_name), y si no aplica + /// ninguno entonces usará el tema por defecto. + #[builder_fn] + pub fn with_theme(&mut self, theme_name: impl AsRef<str>) -> &mut Self { + self.theme = theme_by_short_name(theme_name).unwrap_or(*DEFAULT_THEME); + self + } + + /// Define el tipo de composición usado para renderizar el documento. + #[builder_fn] + pub fn with_layout(&mut self, layout_name: &'static str) -> &mut Self { + self.layout = layout_name; + self + } + + /// Añade o modifica un parámetro del contexto almacenando el valor como [`String`]. + #[builder_fn] + pub fn with_param<T: ToString>(&mut self, key: impl AsRef<str>, value: T) -> &mut Self { + self.params + .insert(key.as_ref().to_string(), value.to_string()); + self + } + + /// Elimina un parámetro del contexto. Devuelve `true` si existía y se eliminó. + pub fn remove_param(&mut self, key: impl AsRef<str>) -> bool { + self.params.remove(key.as_ref()).is_some() + } + + /// Modifica información o recursos del contexto usando [`AssetsOp`]. + #[builder_fn] + pub fn with_assets(&mut self, op: AssetsOp) -> &mut Self { match op { - ContextOp::LangId(langid) => { - self.langid = langid; - } - ContextOp::Theme(theme_name) => { - self.theme = theme_by_short_name(theme_name).unwrap_or(*DEFAULT_THEME); - } - ContextOp::Layout(layout) => { - self.layout = layout; - } // Favicon. - ContextOp::SetFavicon(favicon) => { + AssetsOp::SetFavicon(favicon) => { self.favicon = favicon; } - ContextOp::SetFaviconIfNone(icon) => { + AssetsOp::SetFaviconIfNone(icon) => { if self.favicon.is_none() { self.favicon = Some(icon); } } // Stylesheets. - ContextOp::AddStyleSheet(css) => { + AssetsOp::AddStyleSheet(css) => { self.stylesheets.add(css); } - ContextOp::RemoveStyleSheet(path) => { + AssetsOp::RemoveStyleSheet(path) => { self.stylesheets.remove(path); } // JavaScripts. - ContextOp::AddJavaScript(js) => { + AssetsOp::AddJavaScript(js) => { self.javascripts.add(js); } - ContextOp::RemoveJavaScript(path) => { + AssetsOp::RemoveJavaScript(path) => { self.javascripts.remove(path); } } self } - /// Añade o modifica un parámetro del contexto almacenando el valor como [`String`]. - pub fn set_param<T: ToString>(&mut self, key: impl AsRef<str>, value: T) -> &mut Self { - self.params - .insert(key.as_ref().to_string(), value.to_string()); - self - } - // Context GETTERS ***************************************************************************** /// Devuelve la solicitud HTTP asociada al documento. @@ -218,20 +229,28 @@ impl Context { /// /// Devuelve un error si el parámetro no existe ([`ErrorParam::NotFound`]) o la conversión falla /// ([`ErrorParam::ParseError`]). - pub fn get_param<T: FromStr>(&self, key: impl AsRef<str>) -> Result<T, ErrorParam> { + pub fn param<T: FromStr>(&self, key: impl AsRef<str>) -> Result<T, ErrorParam> { self.params .get(key.as_ref()) .ok_or(ErrorParam::NotFound) .and_then(|v| T::from_str(v).map_err(|_| ErrorParam::ParseError(v.clone()))) } - // Context EXTRAS ****************************************************************************** + // Context RENDER ****************************************************************************** - /// Elimina un parámetro del contexto. Devuelve `true` si existía y se eliminó. - pub fn remove_param(&mut self, key: impl AsRef<str>) -> bool { - self.params.remove(key.as_ref()).is_some() + /// Renderiza los recursos del contexto. + pub fn render_assets(&self) -> Markup { + html! { + @if let Some(favicon) = &self.favicon { + (favicon) + } + (self.stylesheets) + (self.javascripts) + } } + // Context EXTRAS ****************************************************************************** + /// Genera un identificador único si no se proporciona uno explícito. /// /// Si no se proporciona un `id`, se genera un identificador único en la forma `<tipo>-<número>` @@ -256,15 +275,3 @@ impl Context { } } } - -impl Render for Context { - fn render(&self) -> Markup { - html! { - @if let Some(favicon) = &self.favicon { - (favicon) - } - (self.stylesheets) - (self.javascripts) - } - } -} From 05f523ee51e3e80b5b6cb451055bb9f8f68f0eaf Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 27 Jul 2025 00:33:32 +0200 Subject: [PATCH 091/244] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Corrige=20las=20re?= =?UTF-8?q?ferencias=20"builder"=20a=20self/Self?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html/context.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/html/context.rs b/src/html/context.rs index a8d634a6..0035b265 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -136,7 +136,7 @@ impl Context { /// Modifica el identificador de idioma del documento. #[builder_fn] - pub fn with_langid(&mut self, langid: &'static LanguageIdentifier) -> &mut Self { + pub fn with_langid(mut self, langid: &'static LanguageIdentifier) -> Self { self.langid = langid; self } @@ -146,21 +146,21 @@ impl Context { /// Localiza el tema por su [`short_name`](crate::core::AnyInfo::short_name), y si no aplica /// ninguno entonces usará el tema por defecto. #[builder_fn] - pub fn with_theme(&mut self, theme_name: impl AsRef<str>) -> &mut Self { + pub fn with_theme(mut self, theme_name: impl AsRef<str>) -> Self { self.theme = theme_by_short_name(theme_name).unwrap_or(*DEFAULT_THEME); self } /// Define el tipo de composición usado para renderizar el documento. #[builder_fn] - pub fn with_layout(&mut self, layout_name: &'static str) -> &mut Self { + pub fn with_layout(mut self, layout_name: &'static str) -> Self { self.layout = layout_name; self } /// Añade o modifica un parámetro del contexto almacenando el valor como [`String`]. #[builder_fn] - pub fn with_param<T: ToString>(&mut self, key: impl AsRef<str>, value: T) -> &mut Self { + pub fn with_param<T: ToString>(mut self, key: impl AsRef<str>, value: T) -> Self { self.params .insert(key.as_ref().to_string(), value.to_string()); self @@ -173,7 +173,7 @@ impl Context { /// Modifica información o recursos del contexto usando [`AssetsOp`]. #[builder_fn] - pub fn with_assets(&mut self, op: AssetsOp) -> &mut Self { + pub fn with_assets(mut self, op: AssetsOp) -> Self { match op { // Favicon. AssetsOp::SetFavicon(favicon) => { From 00563fa268707237d09b3c6a73d11105a8d4e2cd Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 27 Jul 2025 01:19:16 +0200 Subject: [PATCH 092/244] =?UTF-8?q?=F0=9F=90=9B=20Corrige=20validaci=C3=B3?= =?UTF-8?q?n=20"mut=20self"=20y=20retorno=20de=20Self?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-macros/src/lib.rs | 43 +++++++++++++++++-------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index ecca395d..d9533fe5 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -103,32 +103,16 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { }; return expanded.into(); } - // Valida que el método sea público. + // Valida que el método es público. if !matches!(fn_with.vis, syn::Visibility::Public(_)) { return quote_spanned! { fn_with.sig.ident.span() => compile_error!("expected method to be `pub`"); } .into(); } - // Valida que el método devuelva el tipo `Self`. - if let syn::ReturnType::Type(_, ty) = &fn_with.sig.output { - if let syn::Type::Path(type_path) = &**ty { - let ident = &type_path.path.segments.last().unwrap().ident; - if ident != "Self" { - return quote_spanned! { - fn_with.sig.output.span() => compile_error!("expected return type to be `Self`"); - }.into(); - } - } - } else { - return quote_spanned! { - fn_with.sig.output.span() => compile_error!("expected method to return `Self`"); - } - .into(); - } - // Valida que el primer argumento sea `mut self`. + // Valida que el primer argumento es exactamente `mut self`. if let Some(syn::FnArg::Receiver(receiver)) = fn_with.sig.inputs.first() { - if receiver.mutability.is_none() { + if receiver.mutability.is_none() || receiver.reference.is_some() { return quote_spanned! { receiver.span() => compile_error!("expected `mut self` as the first argument"); } @@ -140,6 +124,27 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { } .into(); } + // Valida que el método devuelve exactamente `Self`. + if let syn::ReturnType::Type(_, ty) = &fn_with.sig.output { + if let syn::Type::Path(type_path) = ty.as_ref() { + if type_path.qself.is_some() || !type_path.path.is_ident("Self") { + return quote_spanned! { ty.span() => + compile_error!("expected return type to be exactly `Self`"); + } + .into(); + } + } else { + return quote_spanned! { ty.span() => + compile_error!("expected return type to be exactly `Self`"); + } + .into(); + } + } else { + return quote_spanned! { + fn_with.sig.output.span() => compile_error!("expected method to return `Self`"); + } + .into(); + } // Genera el nombre del método alter_...(). let fn_alter_name_str = fn_with_name_str.replace("with_", "alter_"); From 94c3d4398ae92513419d6ea51b4e9d84d9853bd2 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 27 Jul 2025 13:51:49 +0200 Subject: [PATCH 093/244] =?UTF-8?q?=F0=9F=92=A1=20Simplifica=20documentaci?= =?UTF-8?q?=C3=B3n=20de=20m=C3=A9todos=20`alter=5F=E2=80=A6()`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-macros/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index d9533fe5..301f4831 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -175,7 +175,7 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { // Genera el método alter_...() con el código del método with_...(). let fn_alter_doc = format!( - "Equivale a invocar el método `{}()` cuando se aplica el patrón builder.", + "Igual que [`{0}()`](Self::{0}), pero sin usar el patrón *builder*.", fn_with_name_str, ); let fn_alter = quote! { From b837346bf84befa430f5f266f0b1acb217f67b19 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 27 Jul 2025 13:55:28 +0200 Subject: [PATCH 094/244] =?UTF-8?q?=F0=9F=92=A1=20Mejora=20los=20comentari?= =?UTF-8?q?os=20para=20normalizar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config.rs | 2 +- src/core.rs | 4 ++-- src/core/component/children.rs | 14 ++++++++------ src/html/assets/favicon.rs | 2 +- src/html/assets/javascript.rs | 2 +- src/html/assets/stylesheet.rs | 4 ++-- src/lib.rs | 4 ++-- src/locale.rs | 10 +++++----- src/response/redirect.rs | 4 ++-- tests/util.rs | 2 +- 10 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/config.rs b/src/config.rs index ed37d550..5dc05a16 100644 --- a/src/config.rs +++ b/src/config.rs @@ -169,7 +169,7 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( /// ```rust,ignore /// include_config!(SETTINGS: Settings => [ /// "ruta.clave" => valor, -/// // … +/// // ... /// ]); /// ``` /// diff --git a/src/core.rs b/src/core.rs index 2168c932..0c8aa21f 100644 --- a/src/core.rs +++ b/src/core.rs @@ -55,10 +55,10 @@ impl TypeInfo { fn partial(type_name: &'static str, start: isize, end: Option<isize>) -> &'static str { let maxlen = type_name.len(); - // Localiza los límites de cada segmento a nivel 0 de `<…>`. + // Localiza los límites de cada segmento a nivel 0 de `<...>`. let mut segments = Vec::new(); let mut segment_start = 0; // Posición inicial del segmento actual. - let mut angle_brackets = 0; // Profundidad dentro de '<…>'. + let mut angle_brackets = 0; // Profundidad dentro de '<...>'. let mut previous_char = '\0'; // Se inicializa a carácter nulo, no hay aún carácter previo. for (idx, c) in type_name.char_indices() { diff --git a/src/core/component/children.rs b/src/core/component/children.rs index cba8c39f..cc3a8643 100644 --- a/src/core/component/children.rs +++ b/src/core/component/children.rs @@ -85,7 +85,7 @@ impl<C: ComponentTrait> Typed<C> { // ************************************************************************************************* -/// Operaciones con un componente [`Child`] en una lista [`Children`]. +/// Operaciones con un componente hijo [`Child`] en una lista [`Children`]. pub enum ChildOp { Add(Child), InsertAfterId(&'static str, Child), @@ -96,7 +96,7 @@ pub enum ChildOp { Reset, } -/// Operaciones con un componente tipado [`Typed<C>`] en una lista [`Children`]. +/// Operaciones con un componente hijo tipado [`Typed<C>`] en una lista [`Children`]. pub enum TypedOp<C: ComponentTrait> { Add(Typed<C>), InsertAfterId(&'static str, Typed<C>), @@ -107,9 +107,9 @@ pub enum TypedOp<C: ComponentTrait> { Reset, } -/// Lista ordenada de los componentes hijo ([`Child`]) asociados a un componente padre. +/// Lista ordenada de componentes hijo ([`Child`]) mantenida por un componente padre. /// -/// Esta colección permite añadir, modificar, renderizar y consultar componentes hijos en orden de +/// Esta lista permite añadir, modificar, renderizar y consultar componentes hijo en orden de /// inserción, soportando operaciones avanzadas como inserción relativa o reemplazo por /// identificador. #[derive(Clone, Default)] @@ -121,7 +121,7 @@ impl Children { Children::default() } - /// Crea una lista con un único hijo inicial. + /// Crea una lista con un componente hijo inicial. pub fn with(child: Child) -> Self { Children::default().with_child(ChildOp::Add(child)) } @@ -165,7 +165,9 @@ impl Children { } } - /// Añade un hijo al final de la lista. + /// Añade un componente hijo al final de la lista. + /// + /// Es un atajo para `children.alter_child(ChildOp::Add(child))`. #[inline] pub fn add(&mut self, child: Child) -> &mut Self { self.0.push(child); diff --git a/src/html/assets/favicon.rs b/src/html/assets/favicon.rs index 97a44e86..d02794eb 100644 --- a/src/html/assets/favicon.rs +++ b/src/html/assets/favicon.rs @@ -3,7 +3,7 @@ use crate::AutoDefault; /// Un **Favicon** es un recurso gráfico que usa el navegador como icono asociado al sitio. /// -/// Es universalmente aceptado para mostrar el icono del sitio (`.ico`, `.png`, `.svg`, …) en +/// Es universalmente aceptado para mostrar el icono del sitio (`.ico`, `.png`, `.svg`, ...) en /// pestañas, marcadores o accesos directos. /// /// Este tipo permite construir de forma fluida las distintas variantes de un *favicon*, ya sea un diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs index fb0a1b64..882b3aff 100644 --- a/src/html/assets/javascript.rs +++ b/src/html/assets/javascript.rs @@ -97,7 +97,7 @@ impl JavaScript { /// Crea un **script embebido** directamente en el documento HTML. /// - /// Equivale a `<script>…</script>`. El parámetro `name` se usa como identificador interno del + /// Equivale a `<script>...</script>`. El parámetro `name` se usa como identificador interno del /// *script*. pub fn inline(name: impl Into<String>, script: impl Into<String>) -> Self { JavaScript { diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index 7f64d187..dca5d869 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -82,7 +82,7 @@ impl TargetMedia { pub struct StyleSheet { source : Source, // Fuente y modo de inclusión del CSS. version: String, // Versión del recurso para la caché del navegador. - media : TargetMedia, // Medio objetivo para los estilos (`print`, `screen`, …). + media : TargetMedia, // Medio objetivo para los estilos (`print`, `screen`, ...). weight : Weight, // Peso que determina el orden. } @@ -99,7 +99,7 @@ impl StyleSheet { /// Crea una hoja de estilos embebida directamente en el documento HTML. /// - /// Equivale a `<style>…</style>`. El parámetro `name` se usa como identificador interno del + /// Equivale a `<style>...</style>`. El parámetro `name` se usa como identificador interno del /// recurso. pub fn inline(name: impl Into<String>, styles: impl Into<String>) -> Self { StyleSheet { diff --git a/src/lib.rs b/src/lib.rs index e2d39754..63ca6a55 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,8 +33,8 @@ html_favicon_url = "https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/favicon.ico" )] -// Alias para que las rutas absolutas `::pagetop::…` generadas por las macros funcionen en el propio -// *crate*, en *crates* externos y en *doctests*. +// Alias para que las rutas absolutas `::pagetop::...` generadas por las macros funcionen en el +// propio *crate*, en *crates* externos y en *doctests*. extern crate self as pagetop; use std::collections::HashMap; diff --git a/src/locale.rs b/src/locale.rs index 9af83f58..298b3508 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -119,13 +119,13 @@ static LANGUAGES: LazyLock<HashMap<&str, (LanguageIdentifier, &str)>> = LazyLock ] }); -// Identificador del idioma de **respaldo** (predefinido a `en-US`). +// Identificador de idioma de **respaldo** (predefinido a `en-US`). // // Se usa cuando el valor del identificador de idioma en las traducciones no corresponde con ningún // idioma soportado por la aplicación. static FALLBACK_LANGID: LazyLock<LanguageIdentifier> = LazyLock::new(|| langid!("en-US")); -// Identificador del idioma **por defecto** para la aplicación. +// Identificador de idioma **por defecto** para la aplicación. // // Se resuelve a partir de [`global::SETTINGS.app.language`](global::SETTINGS). Si el identificador // de idioma no es válido o no está disponible entonces resuelve como [`FALLBACK_LANGID`]. @@ -177,13 +177,13 @@ pub(crate) static DEFAULT_LANGID: LazyLock<&LanguageIdentifier> = /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub enum LangMatch { - /// Cuando el identificador del idioma es una cadena vacía. + /// Cuando el identificador de idioma es una cadena vacía. Unspecified, /// Si encuentra un [`LanguageIdentifier`] en la lista de idiomas soportados por `PageTop` que - /// coincide exactamente con el identificador del idioma (p.ej. "es-ES"), o con el identificador + /// coincide exactamente con el identificador de idioma (p.ej. "es-ES"), o con el identificador /// del idioma base (p.ej. "es"). Found(&'static LanguageIdentifier), - /// Si el identificador del idioma no está entre los soportados por `PageTop`. + /// Si el identificador de idioma no está entre los soportados por `PageTop`. Unsupported(String), } diff --git a/src/response/redirect.rs b/src/response/redirect.rs index bb3020da..a3bec0cd 100644 --- a/src/response/redirect.rs +++ b/src/response/redirect.rs @@ -43,7 +43,7 @@ impl Redirect { /// Redirección **permanente**. Código de estado **308**. Mantiene método y cuerpo sin cambios. /// /// Indicada para reorganizaciones de un sitio o aplicación web en las que también existen - /// métodos distintos de GET (POST, PUT, …) que no deben degradarse a GET. + /// métodos distintos de GET (POST, PUT, ...) que no deben degradarse a GET. #[must_use] pub fn permanent(redirect_to_url: &str) -> HttpResponse { HttpResponse::PermanentRedirect() @@ -55,7 +55,7 @@ impl Redirect { /// mantiene tal cual. Otros métodos pueden degradarse a GET. /// /// Útil cuando un recurso está fuera de servicio de forma imprevista (mantenimiento breve, - /// sobrecarga, …). + /// sobrecarga, ...). #[must_use] pub fn found(redirect_to_url: &str) -> HttpResponse { HttpResponse::Found() diff --git a/tests/util.rs b/tests/util.rs index 2d52064e..6e0896ff 100644 --- a/tests/util.rs +++ b/tests/util.rs @@ -44,7 +44,7 @@ mod windows { async fn ok_absolute_dir() -> io::Result<()> { let _app = service::test::init_service(Application::new().test()).await; - // C:\Users\…\Temp\… + // C:\Users\...\Temp\... let td = TempDir::new()?; let root = td.path(); let sub = root.join("sub"); From 5d58d2d934373a878780e1c2ad9688dee5b0b4b1 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 27 Jul 2025 21:24:49 +0200 Subject: [PATCH 095/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20soporte=20para?= =?UTF-8?q?=20responder=20p=C3=A1ginas=20HTML?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Amplia la estructura "Page" para trabajar el renderizado con regiones de componentes para componer la página. - Añade acciones "BeforeRenderBody" y "AfterRenderBody" para alterar el contenido de la página antes y después del renderizado. - Actualiza "Context" para admitir parámetros dinámicos y mejorar la gestión de temas. - Implementa el manejo de errores HTTP respondiendo páginas. - Mejora la documentación y reorganiza el código en varios módulos. --- src/base/action.rs | 2 + .../component/after_render_component.rs | 2 +- .../component/before_render_component.rs | 2 +- src/base/action/component/is_renderable.rs | 2 +- src/base/action/page.rs | 17 ++ src/base/action/page/after_render_body.rs | 46 ++++ src/base/action/page/before_render_body.rs | 46 ++++ src/core/component/children.rs | 96 +++---- src/core/theme.rs | 3 + src/core/theme/all.rs | 4 +- src/core/theme/definition.rs | 66 ++++- src/core/theme/regions.rs | 47 ++-- src/html/context.rs | 138 +++++----- src/prelude.rs | 2 +- src/response.rs | 2 + src/response/page.rs | 249 ++++++++++++++++++ src/response/page/error.rs | 88 +++++++ 17 files changed, 669 insertions(+), 143 deletions(-) create mode 100644 src/base/action/page.rs create mode 100644 src/base/action/page/after_render_body.rs create mode 100644 src/base/action/page/before_render_body.rs create mode 100644 src/response/page.rs create mode 100644 src/response/page/error.rs diff --git a/src/base/action.rs b/src/base/action.rs index 119a7eaa..be35e922 100644 --- a/src/base/action.rs +++ b/src/base/action.rs @@ -13,3 +13,5 @@ pub type FnActionWithComponent<C> = fn(component: &mut C, cx: &mut Context); pub mod component; pub mod theme; + +pub mod page; diff --git a/src/base/action/component/after_render_component.rs b/src/base/action/component/after_render_component.rs index 3c8ead9a..48873f76 100644 --- a/src/base/action/component/after_render_component.rs +++ b/src/base/action/component/after_render_component.rs @@ -22,7 +22,7 @@ impl<C: ComponentTrait> ActionDispatcher for AfterRender<C> { self.referer_id.get() } - /// Devuelve el peso para definir el orden de aplicación. + /// Devuelve el peso para definir el orden de ejecución. fn weight(&self) -> Weight { self.weight } diff --git a/src/base/action/component/before_render_component.rs b/src/base/action/component/before_render_component.rs index 0ebe4092..483b9160 100644 --- a/src/base/action/component/before_render_component.rs +++ b/src/base/action/component/before_render_component.rs @@ -22,7 +22,7 @@ impl<C: ComponentTrait> ActionDispatcher for BeforeRender<C> { self.referer_id.get() } - /// Devuelve el peso para definir el orden de aplicación. + /// Devuelve el peso para definir el orden de ejecución. fn weight(&self) -> Weight { self.weight } diff --git a/src/base/action/component/is_renderable.rs b/src/base/action/component/is_renderable.rs index 7ba7d53c..3f0f1638 100644 --- a/src/base/action/component/is_renderable.rs +++ b/src/base/action/component/is_renderable.rs @@ -27,7 +27,7 @@ impl<C: ComponentTrait> ActionDispatcher for IsRenderable<C> { self.referer_id.get() } - /// Devuelve el peso para definir el orden de aplicación. + /// Devuelve el peso para definir el orden de ejecución. fn weight(&self) -> Weight { self.weight } diff --git a/src/base/action/page.rs b/src/base/action/page.rs new file mode 100644 index 00000000..b6dbe9ab --- /dev/null +++ b/src/base/action/page.rs @@ -0,0 +1,17 @@ +//! Acciones para alterar el contenido de las páginas a renderizar. + +use crate::response::page::Page; + +/// Tipo de función para manipular una página durante su construcción o renderizado. +/// +/// Se emplea en acciones orientadas a modificar o inspeccionar una instancia de [`Page`] +/// directamente, sin acceder a los componentes individuales ni al contexto de renderizado. +/// +/// Recibe una referencia mutable (`&mut`) a la página en cuestión. +pub type FnActionWithPage = fn(page: &mut Page); + +mod before_render_body; +pub use before_render_body::*; + +mod after_render_body; +pub use after_render_body::*; diff --git a/src/base/action/page/after_render_body.rs b/src/base/action/page/after_render_body.rs new file mode 100644 index 00000000..081b9aa4 --- /dev/null +++ b/src/base/action/page/after_render_body.rs @@ -0,0 +1,46 @@ +use crate::prelude::*; + +use crate::base::action::page::FnActionWithPage; + +/// Ejecuta [`FnActionWithPage`](crate::base::action::page::FnActionWithPage) después de renderizar +/// el cuerpo de la página. +/// +/// Este tipo de acción se despacha después de renderizar el contenido principal de la página +/// (`<body>`), permitiendo ajustes finales sobre la instancia [`Page`]. +/// +/// Las acciones se ejecutan en orden según el [`Weight`] asignado. +pub struct AfterRenderBody { + f: FnActionWithPage, + weight: Weight, +} + +impl ActionDispatcher for AfterRenderBody { + /// Devuelve el peso para definir el orden de ejecución. + fn weight(&self) -> Weight { + self.weight + } +} + +impl AfterRenderBody { + /// Permite [registrar](ExtensionTrait::actions) una nueva acción + /// [`FnActionWithPage`](crate::base::action::page::FnActionWithPage). + pub fn new(f: FnActionWithPage) -> Self { + AfterRenderBody { f, weight: 0 } + } + + /// Opcional. Acciones con pesos más bajos se aplican antes. Se pueden usar valores negativos. + pub fn with_weight(mut self, value: Weight) -> Self { + self.weight = value; + self + } + + // Despacha las acciones. + #[inline(always)] + #[allow(clippy::inline_always)] + pub(crate) fn dispatch(page: &mut Page) { + dispatch_actions( + &ActionKey::new(UniqueId::of::<Self>(), None, None, None), + |action: &Self| (action.f)(page), + ); + } +} diff --git a/src/base/action/page/before_render_body.rs b/src/base/action/page/before_render_body.rs new file mode 100644 index 00000000..a6e5c565 --- /dev/null +++ b/src/base/action/page/before_render_body.rs @@ -0,0 +1,46 @@ +use crate::prelude::*; + +use crate::base::action::page::FnActionWithPage; + +/// Ejecuta [`FnActionWithPage`](crate::base::action::page::FnActionWithPage) antes de renderizar +/// el cuerpo de la página. +/// +/// Este tipo de acción se despacha antes de renderizar el contenido principal de la página +/// (`<body>`), permitiendo ajustes sobre la instancia [`Page`]. +/// +/// Las acciones se ejecutan en orden según el [`Weight`] asignado. +pub struct BeforeRenderBody { + f: FnActionWithPage, + weight: Weight, +} + +impl ActionDispatcher for BeforeRenderBody { + /// Devuelve el peso para definir el orden de ejecución. + fn weight(&self) -> Weight { + self.weight + } +} + +impl BeforeRenderBody { + /// Permite [registrar](ExtensionTrait::actions) una nueva acción + /// [`FnActionWithPage`](crate::base::action::page::FnActionWithPage). + pub fn new(f: FnActionWithPage) -> Self { + BeforeRenderBody { f, weight: 0 } + } + + /// Opcional. Acciones con pesos más bajos se aplican antes. Se pueden usar valores negativos. + pub fn with_weight(mut self, value: Weight) -> Self { + self.weight = value; + self + } + + // Despacha las acciones. + #[inline(always)] + #[allow(clippy::inline_always)] + pub(crate) fn dispatch(page: &mut Page) { + dispatch_actions( + &ActionKey::new(UniqueId::of::<Self>(), None, None, None), + |action: &Self| (action.f)(page), + ); + } +} diff --git a/src/core/component/children.rs b/src/core/component/children.rs index cc3a8643..c5b65a26 100644 --- a/src/core/component/children.rs +++ b/src/core/component/children.rs @@ -77,8 +77,8 @@ impl<C: ComponentTrait> Typed<C> { // Typed HELPERS ******************************************************************************* - /// Convierte el componente tipado en un [`Child`]. - fn to_child(&self) -> Child { + // Convierte el componente tipado en un [`Child`]. + fn into_child(self) -> Child { Child(self.0.clone()) } } @@ -155,12 +155,12 @@ impl Children { #[builder_fn] pub fn with_typed<C: ComponentTrait + Default>(mut self, op: TypedOp<C>) -> Self { match op { - TypedOp::Add(typed) => self.add(typed.to_child()), - TypedOp::InsertAfterId(id, typed) => self.insert_after_id(id, typed.to_child()), - TypedOp::InsertBeforeId(id, typed) => self.insert_before_id(id, typed.to_child()), - TypedOp::Prepend(typed) => self.prepend(typed.to_child()), + TypedOp::Add(typed) => self.add(typed.into_child()), + TypedOp::InsertAfterId(id, typed) => self.insert_after_id(id, typed.into_child()), + TypedOp::InsertBeforeId(id, typed) => self.insert_before_id(id, typed.into_child()), + TypedOp::Prepend(typed) => self.prepend(typed.into_child()), TypedOp::RemoveById(id) => self.remove_by_id(id), - TypedOp::ReplaceById(id, typed) => self.replace_by_id(id, typed.to_child()), + TypedOp::ReplaceById(id, typed) => self.replace_by_id(id, typed.into_child()), TypedOp::Reset => self.reset(), } } @@ -174,6 +174,48 @@ impl Children { self } + // Children GETTERS **************************************************************************** + + /// Devuelve el número de componentes hijo de la lista. + pub fn len(&self) -> usize { + self.0.len() + } + + /// Indica si la lista está vacía. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Devuelve el primer componente hijo con el identificador indicado, si existe. + pub fn get_by_id(&self, id: impl AsRef<str>) -> Option<&Child> { + let id = Some(id.as_ref()); + self.0.iter().find(|c| c.id().as_deref() == id) + } + + /// Devuelve un iterador sobre los componentes hijo con el identificador indicado. + pub fn iter_by_id<'a>(&'a self, id: &'a str) -> impl Iterator<Item = &'a Child> + 'a { + self.0.iter().filter(move |c| c.id().as_deref() == Some(id)) + } + + /// Devuelve un iterador sobre los componentes hijo con el identificador de tipo ([`UniqueId`]) + /// indicado. + pub fn iter_by_type_id(&self, type_id: UniqueId) -> impl Iterator<Item = &Child> { + self.0.iter().filter(move |&c| c.type_id() == type_id) + } + + // Children RENDER ***************************************************************************** + + /// Renderiza todos los componentes hijo, en orden. + pub fn render(&self, cx: &mut Context) -> Markup { + html! { + @for c in &self.0 { + (c.render(cx)) + } + } + } + + // Children HELPERS **************************************************************************** + // Inserta un hijo después del componente con el `id` dado, o al final si no se encuentra. #[inline] fn insert_after_id(&mut self, id: impl AsRef<str>, child: Child) -> &mut Self { @@ -232,46 +274,6 @@ impl Children { self.0.clear(); self } - - // Children GETTERS **************************************************************************** - - /// Devuelve el número de componentes hijo de la lista. - pub fn len(&self) -> usize { - self.0.len() - } - - /// Indica si la lista está vacía. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// Devuelve el primer componente hijo con el identificador indicado, si existe. - pub fn get_by_id(&self, id: impl AsRef<str>) -> Option<&Child> { - let id = Some(id.as_ref()); - self.0.iter().find(|c| c.id().as_deref() == id) - } - - /// Devuelve un iterador sobre los componentes hijo con el identificador indicado. - pub fn iter_by_id<'a>(&'a self, id: &'a str) -> impl Iterator<Item = &'a Child> + 'a { - self.0.iter().filter(move |c| c.id().as_deref() == Some(id)) - } - - /// Devuelve un iterador sobre los componentes hijo con el identificador tipo ([`UniqueId`]) - /// indicado. - pub fn iter_by_type_id(&self, type_id: UniqueId) -> impl Iterator<Item = &Child> { - self.0.iter().filter(move |&c| c.type_id() == type_id) - } - - // Children RENDER ***************************************************************************** - - /// Renderiza todos los componentes hijo, en orden. - pub fn render(&self, cx: &mut Context) -> Markup { - html! { - @for c in &self.0 { - (c.render(cx)) - } - } - } } impl IntoIterator for Children { diff --git a/src/core/theme.rs b/src/core/theme.rs index d67a4457..35d9887d 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -22,3 +22,6 @@ pub(crate) use regions::ChildrenInRegions; pub use regions::InRegion; pub(crate) mod all; + +/// Nombre de la región por defecto: `content`. +pub const CONTENT_REGION_NAME: &str = "content"; diff --git a/src/core/theme/all.rs b/src/core/theme/all.rs index 1b982680..787e0c9d 100644 --- a/src/core/theme/all.rs +++ b/src/core/theme/all.rs @@ -20,8 +20,8 @@ pub static DEFAULT_THEME: LazyLock<ThemeRef> = // TEMA POR NOMBRE ********************************************************************************* /// Devuelve el tema identificado por su [`short_name`](AnyInfo::short_name). -pub fn theme_by_short_name(short_name: impl AsRef<str>) -> Option<ThemeRef> { - let short_name = short_name.as_ref().to_lowercase(); +pub fn theme_by_short_name(short_name: &'static str) -> Option<ThemeRef> { + let short_name = short_name.to_lowercase(); match THEMES .read() .iter() diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 6f1e54a1..075ce204 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -1,5 +1,9 @@ use crate::core::extension::ExtensionTrait; +use crate::core::theme::CONTENT_REGION_NAME; +use crate::global; +use crate::html::{html, Markup}; use crate::locale::L10n; +use crate::response::page::Page; /// Representa una referencia a un tema. /// @@ -30,6 +34,66 @@ pub type ThemeRef = &'static dyn ThemeTrait; /// ``` pub trait ThemeTrait: ExtensionTrait + Send + Sync { fn regions(&self) -> Vec<(&'static str, L10n)> { - vec![("content", L10n::l("content"))] + vec![(CONTENT_REGION_NAME, L10n::l("content"))] + } + + #[allow(unused_variables)] + fn before_render_page_body(&self, page: &mut Page) {} + + fn render_page_body(&self, page: &mut Page) -> Markup { + html! { + body id=[page.body_id().get()] class=[page.body_classes().get()] { + @for (region_name, _) in self.regions() { + @let output = page.render_region(region_name); + @if !output.is_empty() { + div id=(region_name) class={ "region-container region-" (region_name) } { + (output) + } + } + } + } + } + } + + #[allow(unused_variables)] + fn after_render_page_body(&self, page: &mut Page) {} + + fn render_page_head(&self, page: &mut Page) -> Markup { + let viewport = "width=device-width, initial-scale=1, shrink-to-fit=no"; + html! { + head { + meta charset="utf-8"; + + @if let Some(title) = page.title() { + title { (global::SETTINGS.app.name) (" | ") (title) } + } @else { + title { (global::SETTINGS.app.name) } + } + + @if let Some(description) = page.description() { + meta name="description" content=(description); + } + + meta name="viewport" content=(viewport); + @for (name, content) in page.metadata() { + meta name=(name) content=(content) {} + } + + meta http-equiv="X-UA-Compatible" content="IE=edge"; + @for (property, content) in page.properties() { + meta property=(property) content=(content) {} + } + + (page.render_assets()) + } + } + } + + fn error403(&self, _page: &mut Page) -> Markup { + html! { div { h1 { ("FORBIDDEN ACCESS") } } } + } + + fn error404(&self, _page: &mut Page) -> Markup { + html! { div { h1 { ("RESOURCE NOT FOUND") } } } } } diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index 5beee25a..5e0186ad 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -1,5 +1,5 @@ use crate::core::component::{Child, ChildOp, Children}; -use crate::core::theme::ThemeRef; +use crate::core::theme::{ThemeRef, CONTENT_REGION_NAME}; use crate::{builder_fn, AutoDefault, UniqueId}; use parking_lot::RwLock; @@ -7,45 +7,43 @@ use parking_lot::RwLock; use std::collections::HashMap; use std::sync::LazyLock; +// Regiones globales con componentes para un tema dado. static THEME_REGIONS: LazyLock<RwLock<HashMap<UniqueId, ChildrenInRegions>>> = LazyLock::new(|| RwLock::new(HashMap::new())); +// Regiones globales con componentes para cualquier tema. static COMMON_REGIONS: LazyLock<RwLock<ChildrenInRegions>> = LazyLock::new(|| RwLock::new(ChildrenInRegions::default())); -// Estructura interna para mantener los componentes de cada región dada. +// Estructura interna para mantener los componentes de una región. #[derive(AutoDefault)] pub struct ChildrenInRegions(HashMap<&'static str, Children>); impl ChildrenInRegions { - pub fn new() -> Self { - ChildrenInRegions::default() - } - - pub fn with(region_id: &'static str, child: Child) -> Self { - ChildrenInRegions::default().with_in_region(region_id, ChildOp::Add(child)) + pub fn with(region_name: &'static str, child: Child) -> Self { + ChildrenInRegions::default().with_child_in_region(region_name, ChildOp::Add(child)) } #[builder_fn] - pub fn with_in_region(mut self, region_id: &'static str, op: ChildOp) -> Self { - if let Some(region) = self.0.get_mut(region_id) { + pub fn with_child_in_region(mut self, region_name: &'static str, op: ChildOp) -> Self { + if let Some(region) = self.0.get_mut(region_name) { region.alter_child(op); } else { - self.0.insert(region_id, Children::new().with_child(op)); + self.0.insert(region_name, Children::new().with_child(op)); } self } - pub fn all_in_region(&self, theme: ThemeRef, region_id: &str) -> Children { + pub fn merge_all_components(&self, theme_ref: ThemeRef, region_name: &'static str) -> Children { let common = COMMON_REGIONS.read(); - if let Some(r) = THEME_REGIONS.read().get(&theme.type_id()) { + if let Some(r) = THEME_REGIONS.read().get(&theme_ref.type_id()) { Children::merge(&[ - common.0.get(region_id), - self.0.get(region_id), - r.0.get(region_id), + common.0.get(region_name), + self.0.get(region_name), + r.0.get(region_name), ]) } else { - Children::merge(&[common.0.get(region_id), self.0.get(region_id)]) + Children::merge(&[common.0.get(region_name), self.0.get(region_name)]) } } } @@ -90,19 +88,22 @@ impl InRegion { InRegion::Content => { COMMON_REGIONS .write() - .alter_in_region("region-content", ChildOp::Add(child)); + .alter_child_in_region(CONTENT_REGION_NAME, ChildOp::Add(child)); } InRegion::Named(name) => { COMMON_REGIONS .write() - .alter_in_region(name, ChildOp::Add(child)); + .alter_child_in_region(name, ChildOp::Add(child)); } - InRegion::OfTheme(region, theme) => { + InRegion::OfTheme(region_name, theme_ref) => { let mut regions = THEME_REGIONS.write(); - if let Some(r) = regions.get_mut(&theme.type_id()) { - r.alter_in_region(region, ChildOp::Add(child)); + if let Some(r) = regions.get_mut(&theme_ref.type_id()) { + r.alter_child_in_region(region_name, ChildOp::Add(child)); } else { - regions.insert(theme.type_id(), ChildrenInRegions::with(region, child)); + regions.insert( + theme_ref.type_id(), + ChildrenInRegions::with(region_name, child), + ); } } } diff --git a/src/html/context.rs b/src/html/context.rs index 0035b265..a1df9879 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -61,37 +61,42 @@ impl Error for ErrorParam {} /// hojas de estilo ([`StyleSheet`]) y *scripts* ([`JavaScript`]), así como parámetros de contexto /// definidos en tiempo de ejecución. /// -/// # Ejemplo +/// # Ejemplos +/// +/// Crea un nuevo contexto asociado a una solicitud HTTP: /// /// ```rust /// use pagetop::prelude::*; /// -/// fn configure_context(cx: &mut Context) { -/// // Establece el idioma del documento a español. -/// cx.alter_langid(LangMatch::langid_or_default("es-ES")) -/// // Selecciona un tema (por su nombre corto). -/// .alter_theme("aliner") -/// // Añade un parámetro dinámico al contexto. -/// .alter_param("usuario_id", 42) -/// // Asigna un favicon. -/// .alter_assets(AssetsOp::SetFavicon(Some( -/// Favicon::new().with_icon("/icons/favicon.ico") -/// ))) -/// // Añade una hoja de estilo externa. -/// .alter_assets(AssetsOp::AddStyleSheet( -/// StyleSheet::from("/css/style.css") -/// )) -/// // Añade un script JavaScript. -/// .alter_assets(AssetsOp::AddJavaScript( -/// JavaScript::defer("/js/main.js") -/// )); +/// fn new_context(request: HttpRequest) -> Context { +/// Context::new(request) +/// // Establece el idioma del documento a español. +/// .with_langid(LangMatch::langid_or_default("es-ES")) +/// // Selecciona un tema (por su nombre corto). +/// .with_theme("aliner") +/// // Asigna un favicon. +/// .with_assets(AssetsOp::SetFavicon(Some(Favicon::new().with_icon("/favicon.ico")))) +/// // Añade una hoja de estilo externa. +/// .with_assets(AssetsOp::AddStyleSheet(StyleSheet::from("/css/style.css"))) +/// // Añade un script JavaScript. +/// .with_assets(AssetsOp::AddJavaScript(JavaScript::defer("/js/main.js"))) +/// // Añade un parámetro dinámico al contexto. +/// .with_param("usuario_id", 42) +/// } +/// ``` /// +/// Y hace operaciones con un contexto dado: +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// fn use_context(cx: &mut Context) { /// // Recupera el tema seleccionado. /// let active_theme = cx.theme(); /// assert_eq!(active_theme.short_name(), "aliner"); /// /// // Recupera el parámetro a su tipo original. -/// let id: i32 = cx.param("usuario_id").unwrap(); +/// let id: i32 = cx.get_param("usuario_id").unwrap(); /// assert_eq!(id, 42); /// /// // Genera un identificador para un componente de tipo `Menu`. @@ -102,32 +107,33 @@ impl Error for ErrorParam {} /// ``` #[rustfmt::skip] pub struct Context { - request : HttpRequest, // Solicitud HTTP de origen. - langid : &'static LanguageIdentifier, // Identificador del idioma. - theme : ThemeRef, // Referencia al tema para renderizar. - layout : &'static str, // Composición del documento para renderizar. - params : HashMap<String, String>, // Parámetros definidos en tiempo de ejecución. - favicon : Option<Favicon>, // Favicon, si se ha definido. - stylesheets: Assets<StyleSheet>, // Hojas de estilo CSS. - javascripts: Assets<JavaScript>, // Scripts JavaScript. - id_counter : usize, // Contador para generar identificadores únicos. + request : HttpRequest, // Solicitud HTTP de origen. + langid : &'static LanguageIdentifier, // Identificador de idioma. + theme : ThemeRef, // Referencia al tema para renderizar. + layout : &'static str, // Composición del documento para renderizar. + favicon : Option<Favicon>, // Favicon, si se ha definido. + stylesheets: Assets<StyleSheet>, // Hojas de estilo CSS. + javascripts: Assets<JavaScript>, // Scripts JavaScript. + params : HashMap<&'static str, String>, // Parámetros definidos en tiempo de ejecución. + id_counter : usize, // Contador para generar identificadores únicos. } impl Context { - // Crea un nuevo contexto asociado a una solicitud HTTP. - // - // El contexto inicializa el idioma por defecto, sin favicon ni recursos cargados. + /// Crea un nuevo contexto asociado a una solicitud HTTP. + /// + /// El contexto inicializa el idioma, tema y composición por defecto, sin favicon ni recursos + /// cargados. #[rustfmt::skip] - pub(crate) fn new(request: HttpRequest) -> Self { + pub fn new(request: HttpRequest) -> Self { Context { request, langid : &DEFAULT_LANGID, theme : *DEFAULT_THEME, layout : "default", - params : HashMap::<String, String>::new(), favicon : None, stylesheets: Assets::<StyleSheet>::new(), javascripts: Assets::<JavaScript>::new(), + params : HashMap::<&str, String>::new(), id_counter : 0, } } @@ -141,37 +147,24 @@ impl Context { self } - /// Establece el tema que se usará para renderizar el documento. + /// Modifica el tema que se usará para renderizar el documento. /// /// Localiza el tema por su [`short_name`](crate::core::AnyInfo::short_name), y si no aplica /// ninguno entonces usará el tema por defecto. #[builder_fn] - pub fn with_theme(mut self, theme_name: impl AsRef<str>) -> Self { + pub fn with_theme(mut self, theme_name: &'static str) -> Self { self.theme = theme_by_short_name(theme_name).unwrap_or(*DEFAULT_THEME); self } - /// Define el tipo de composición usado para renderizar el documento. + /// Modifica la composición para renderizar el documento. #[builder_fn] pub fn with_layout(mut self, layout_name: &'static str) -> Self { self.layout = layout_name; self } - /// Añade o modifica un parámetro del contexto almacenando el valor como [`String`]. - #[builder_fn] - pub fn with_param<T: ToString>(mut self, key: impl AsRef<str>, value: T) -> Self { - self.params - .insert(key.as_ref().to_string(), value.to_string()); - self - } - - /// Elimina un parámetro del contexto. Devuelve `true` si existía y se eliminó. - pub fn remove_param(&mut self, key: impl AsRef<str>) -> bool { - self.params.remove(key.as_ref()).is_some() - } - - /// Modifica información o recursos del contexto usando [`AssetsOp`]. + /// Define los recursos del contexto usando [`AssetsOp`]. #[builder_fn] pub fn with_assets(mut self, op: AssetsOp) -> Self { match op { @@ -209,7 +202,7 @@ impl Context { &self.request } - /// Devuelve el identificador del idioma asociado al documento. + /// Devuelve el identificador de idioma asociado al documento. pub fn langid(&self) -> &LanguageIdentifier { self.langid } @@ -219,23 +212,11 @@ impl Context { self.theme } - /// Devuelve el tipo de composición usado para renderizar el documento. El valor predeterminado - /// es `"default"`. + /// Devuelve la composición para renderizar el documento. Por defecto es `"default"`. pub fn layout(&self) -> &str { self.layout } - /// Recupera un parámetro del contexto convertido al tipo especificado. - /// - /// Devuelve un error si el parámetro no existe ([`ErrorParam::NotFound`]) o la conversión falla - /// ([`ErrorParam::ParseError`]). - pub fn param<T: FromStr>(&self, key: impl AsRef<str>) -> Result<T, ErrorParam> { - self.params - .get(key.as_ref()) - .ok_or(ErrorParam::NotFound) - .and_then(|v| T::from_str(v).map_err(|_| ErrorParam::ParseError(v.clone()))) - } - // Context RENDER ****************************************************************************** /// Renderiza los recursos del contexto. @@ -249,6 +230,31 @@ impl Context { } } + // Context PARAMS ****************************************************************************** + + /// Añade o modifica un parámetro del contexto almacenando el valor como [`String`]. + #[builder_fn] + pub fn with_param<T: ToString>(mut self, key: &'static str, value: T) -> Self { + self.params.insert(key, value.to_string()); + self + } + + /// Recupera un parámetro del contexto convertido al tipo especificado. + /// + /// Devuelve un error si el parámetro no existe ([`ErrorParam::NotFound`]) o la conversión falla + /// ([`ErrorParam::ParseError`]). + pub fn get_param<T: FromStr>(&self, key: &'static str) -> Result<T, ErrorParam> { + self.params + .get(key) + .ok_or(ErrorParam::NotFound) + .and_then(|v| T::from_str(v).map_err(|_| ErrorParam::ParseError(v.clone()))) + } + + /// Elimina un parámetro del contexto. Devuelve `true` si existía y se eliminó. + pub fn remove_param(&mut self, key: &'static str) -> bool { + self.params.remove(key).is_some() + } + // Context EXTRAS ****************************************************************************** /// Genera un identificador único si no se proporciona uno explícito. diff --git a/src/prelude.rs b/src/prelude.rs index 9334f189..af2f5110 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -43,7 +43,7 @@ pub use crate::core::component::*; pub use crate::core::extension::*; pub use crate::core::theme::*; -pub use crate::response::{json::*, redirect::*, ResponseError}; +pub use crate::response::{json::*, page::*, redirect::*, ResponseError}; pub use crate::base::action; pub use crate::base::component::*; diff --git a/src/response.rs b/src/response.rs index 1fce663f..4078d420 100644 --- a/src/response.rs +++ b/src/response.rs @@ -2,6 +2,8 @@ pub use actix_web::ResponseError; +pub mod page; + pub mod json; pub mod redirect; diff --git a/src/response/page.rs b/src/response/page.rs new file mode 100644 index 00000000..b2528487 --- /dev/null +++ b/src/response/page.rs @@ -0,0 +1,249 @@ +mod error; +pub use error::ErrorPage; + +pub use actix_web::Result as ResultPage; + +use crate::base::action; +use crate::builder_fn; +use crate::core::component::{Child, ChildOp, ComponentTrait}; +use crate::core::theme::{ChildrenInRegions, ThemeRef, CONTENT_REGION_NAME}; +use crate::html::{html, AssetsOp, Context, Markup, DOCTYPE}; +use crate::html::{ClassesOp, OptionClasses, OptionId, OptionTranslated}; +use crate::locale::{CharacterDirection, L10n, LanguageIdentifier}; +use crate::service::HttpRequest; + +/// Representa una página HTML completa lista para renderizar. +/// +/// Una instancia de `Page` se compone dinámicamente permitiendo establecer título, descripción, +/// regiones donde disponer los componentes, atributos de `<body>` y otros aspectos del contexto de +/// renderizado. +#[rustfmt::skip] +pub struct Page { + title : OptionTranslated, + description : OptionTranslated, + metadata : Vec<(&'static str, &'static str)>, + properties : Vec<(&'static str, &'static str)>, + context : Context, + body_id : OptionId, + body_classes: OptionClasses, + regions : ChildrenInRegions, +} + +impl Page { + /// Crea una nueva instancia de página con contexto basado en la petición HTTP. + #[rustfmt::skip] + pub fn new(request: HttpRequest) -> Self { + Page { + title : OptionTranslated::default(), + description : OptionTranslated::default(), + metadata : Vec::default(), + properties : Vec::default(), + context : Context::new(request), + body_id : OptionId::default(), + body_classes: OptionClasses::default(), + regions : ChildrenInRegions::default(), + } + } + + // Page BUILDER ******************************************************************************** + + /// Establece el título de la página como un valor traducible. + #[builder_fn] + pub fn with_title(mut self, title: L10n) -> Self { + self.title.alter_value(title); + self + } + + /// Establece la descripción de la página como un valor traducible. + #[builder_fn] + pub fn with_description(mut self, description: L10n) -> Self { + self.description.alter_value(description); + self + } + + /// Añade una entrada `<meta name="..." content="...">` al `<head>`. + #[builder_fn] + pub fn with_metadata(mut self, name: &'static str, content: &'static str) -> Self { + self.metadata.push((name, content)); + self + } + + /// Añade una entrada `<meta property="..." content="...">` al `<head>`. + #[builder_fn] + pub fn with_property(mut self, property: &'static str, content: &'static str) -> Self { + self.metadata.push((property, content)); + self + } + + /// Modifica el identificador de idioma de la página ([`Context::with_langid`]). + #[builder_fn] + pub fn with_langid(mut self, langid: &'static LanguageIdentifier) -> Self { + self.context.alter_langid(langid); + self + } + + /// Modifica el tema que se usará para renderizar la página ([`Context::with_theme`]). + #[builder_fn] + pub fn with_theme(mut self, theme_name: &'static str) -> Self { + self.context.alter_theme(theme_name); + self + } + + /// Modifica la composición para renderizar la página ([`Context::with_layout`]). + #[builder_fn] + pub fn with_layout(mut self, layout_name: &'static str) -> Self { + self.context.alter_layout(layout_name); + self + } + + /// Define los recursos de la página usando [`AssetsOp`]. + #[builder_fn] + pub fn with_assets(mut self, op: AssetsOp) -> Self { + self.context.alter_assets(op); + self + } + + /// Establece el atributo `id` del elemento `<body>`. + #[builder_fn] + pub fn with_body_id(mut self, id: impl AsRef<str>) -> Self { + self.body_id.alter_value(id); + self + } + + /// Modifica las clases CSS del elemento `<body>` con una operación sobre [`OptionClasses`]. + #[builder_fn] + pub fn with_body_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.body_classes.alter_value(op, classes); + self + } + + /// Añade un componente a la región de contenido por defecto. + pub fn with_component(mut self, component: impl ComponentTrait) -> Self { + self.regions + .alter_child_in_region(CONTENT_REGION_NAME, ChildOp::Add(Child::with(component))); + self + } + + /// Añade un componente en una región (`region_name`) de la página. + pub fn with_component_in( + mut self, + region_name: &'static str, + component: impl ComponentTrait, + ) -> Self { + self.regions + .alter_child_in_region(region_name, ChildOp::Add(Child::with(component))); + self + } + + /// Opera con [`ChildOp`] en una región (`region_name`) de la página. + #[builder_fn] + pub fn with_child_in_region(mut self, region_name: &'static str, op: ChildOp) -> Self { + self.regions.alter_child_in_region(region_name, op); + self + } + + // Page GETTERS ******************************************************************************** + + /// Devuelve el título traducido para el idioma activo, si existe. + pub fn title(&mut self) -> Option<String> { + self.title.using(self.context.langid()) + } + + /// Devuelve la descripción traducida para el idioma activo, si existe. + pub fn description(&mut self) -> Option<String> { + self.description.using(self.context.langid()) + } + + /// Devuelve la lista de metadatos `<meta name=...>`. + pub fn metadata(&self) -> &Vec<(&str, &str)> { + &self.metadata + } + + /// Devuelve la lista de propiedades `<meta property=...>`. + pub fn properties(&self) -> &Vec<(&str, &str)> { + &self.properties + } + + /// Devuelve la solicitud HTTP asociada. + pub fn request(&self) -> &HttpRequest { + self.context.request() + } + + /// Devuelve el identificador de idioma asociado. + pub fn langid(&self) -> &LanguageIdentifier { + self.context.langid() + } + + /// Devuelve el tema que se usará para renderizar la página. + pub fn theme(&self) -> ThemeRef { + self.context.theme() + } + + /// Devuelve la composición para renderizar la página. Por defecto es `"default"`. + pub fn layout(&self) -> &str { + self.context.layout() + } + + /// Devuelve el identificador del elemento `<body>`. + pub fn body_id(&self) -> &OptionId { + &self.body_id + } + + /// Devuelve las clases CSS del elemento `<body>`. + pub fn body_classes(&self) -> &OptionClasses { + &self.body_classes + } + + // Page RENDER ********************************************************************************* + + /// Renderiza los componentes de una región (`regiona_name`) de la página. + pub fn render_region(&mut self, region_name: &'static str) -> Markup { + self.regions + .merge_all_components(self.context.theme(), region_name) + .render(&mut self.context) + } + + /// Renderiza los recursos de la página. + pub fn render_assets(&self) -> Markup { + self.context.render_assets() + } + + /// Renderiza la página completa en formato HTML. + /// + /// Ejecuta las acciones correspondientes antes y después de renderizar el `<body>`, + /// así como del `<head>`, e inserta los atributos `lang` y `dir` en la etiqueta `<html>`. + pub fn render(&mut self) -> ResultPage<Markup, ErrorPage> { + // Acciones específicas del tema antes de renderizar el <body>. + self.context.theme().before_render_page_body(self); + + // Acciones de las extensiones antes de renderizar el <body>. + action::page::BeforeRenderBody::dispatch(self); + + // Renderiza el <body>. + let body = self.context.theme().render_page_body(self); + + // Acciones específicas del tema después de renderizar el <body>. + self.context.theme().after_render_page_body(self); + + // Acciones de las extensiones después de renderizar el <body>. + action::page::AfterRenderBody::dispatch(self); + + // Renderiza el <head>. + let head = self.context.theme().render_page_head(self); + + // Compone la página incluyendo los atributos de idioma y dirección del texto. + let lang = &self.context.langid().language; + let dir = match self.context.langid().character_direction() { + CharacterDirection::LTR => "ltr", + CharacterDirection::RTL => "rtl", + CharacterDirection::TTB => "auto", + }; + Ok(html! { + (DOCTYPE) + html lang=(lang) dir=(dir) { + (head) + (body) + } + }) + } +} diff --git a/src/response/page/error.rs b/src/response/page/error.rs new file mode 100644 index 00000000..3d952c62 --- /dev/null +++ b/src/response/page/error.rs @@ -0,0 +1,88 @@ +use crate::base::component::Html; +use crate::locale::L10n; +use crate::response::ResponseError; +use crate::service::http::{header::ContentType, StatusCode}; +use crate::service::{HttpRequest, HttpResponse}; + +use super::Page; + +use std::fmt; + +#[derive(Debug)] +pub enum ErrorPage { + NotModified(HttpRequest), + BadRequest(HttpRequest), + AccessDenied(HttpRequest), + NotFound(HttpRequest), + PreconditionFailed(HttpRequest), + InternalError(HttpRequest), + Timeout(HttpRequest), +} + +impl fmt::Display for ErrorPage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + // Error 304. + ErrorPage::NotModified(_) => write!(f, "Not Modified"), + // Error 400. + ErrorPage::BadRequest(_) => write!(f, "Bad Client Data"), + // Error 403. + ErrorPage::AccessDenied(request) => { + let mut error_page = Page::new(request.clone()); + let error403 = error_page.theme().error403(&mut error_page); + if let Ok(page) = error_page + .with_title(L10n::n("Error FORBIDDEN")) + .with_layout("error") + .with_component(Html::with(error403)) + .render() + { + write!(f, "{}", page.into_string()) + } else { + write!(f, "Access Denied") + } + } + // Error 404. + ErrorPage::NotFound(request) => { + let mut error_page = Page::new(request.clone()); + let error404 = error_page.theme().error404(&mut error_page); + if let Ok(page) = error_page + .with_title(L10n::n("Error RESOURCE NOT FOUND")) + .with_layout("error") + .with_component(Html::with(error404)) + .render() + { + write!(f, "{}", page.into_string()) + } else { + write!(f, "Not Found") + } + } + // Error 412. + ErrorPage::PreconditionFailed(_) => write!(f, "Precondition Failed"), + // Error 500. + ErrorPage::InternalError(_) => write!(f, "Internal Error"), + // Error 504. + ErrorPage::Timeout(_) => write!(f, "Timeout"), + } + } +} + +impl ResponseError for ErrorPage { + fn error_response(&self) -> HttpResponse { + HttpResponse::build(self.status_code()) + .insert_header(ContentType::html()) + .body(self.to_string()) + } + + #[rustfmt::skip] + fn status_code(&self) -> StatusCode { + match self { + ErrorPage::NotModified(_) => StatusCode::NOT_MODIFIED, + ErrorPage::BadRequest(_) => StatusCode::BAD_REQUEST, + ErrorPage::AccessDenied(_) => StatusCode::FORBIDDEN, + ErrorPage::NotFound(_) => StatusCode::NOT_FOUND, + ErrorPage::PreconditionFailed(_) => StatusCode::PRECONDITION_FAILED, + ErrorPage::InternalError(_) => StatusCode::INTERNAL_SERVER_ERROR, + ErrorPage::Timeout(_) => StatusCode::GATEWAY_TIMEOUT, + } + } +} From c715935cbbb27a19962c84620b63a2e88ae20e48 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 27 Jul 2025 22:55:14 +0200 Subject: [PATCH 096/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20soporte=20para?= =?UTF-8?q?=20sesiones=20y=20cookies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 202 ++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 3 +- src/app.rs | 24 +++++- src/global.rs | 31 ++++---- src/prelude.rs | 2 +- src/service.rs | 5 +- 6 files changed, 246 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b03e9808..b3cb7b25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,7 +52,7 @@ dependencies = [ "actix-rt", "actix-service", "actix-utils", - "base64", + "base64 0.22.1", "bitflags", "brotli", "bytes", @@ -143,6 +143,23 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "actix-session" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efe6976a74f34f1b6d07a6c05aadc0ed0359304a7781c367fa5b4029418db08f" +dependencies = [ + "actix-service", + "actix-utils", + "actix-web", + "anyhow", + "derive_more 1.0.0", + "rand 0.8.5", + "serde", + "serde_json", + "tracing", +] + [[package]] name = "actix-utils" version = "3.0.1" @@ -235,6 +252,41 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.8.12" @@ -342,6 +394,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + [[package]] name = "autocfg" version = "1.5.0" @@ -363,6 +421,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "base64" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" + [[package]] name = "base64" version = "0.22.1" @@ -477,6 +541,16 @@ dependencies = [ "windows-link", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.5.41" @@ -555,7 +629,14 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" dependencies = [ + "aes-gcm", + "base64 0.20.0", + "hkdf", + "hmac", "percent-encoding", + "rand 0.8.5", + "sha2", + "subtle", "time", "version_check", ] @@ -625,9 +706,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "deranged" version = "0.4.0" @@ -650,13 +741,34 @@ dependencies = [ "syn", ] +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl 1.0.0", +] + [[package]] name = "derive_more" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" dependencies = [ - "derive_more-impl", + "derive_more-impl 2.0.1", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", ] [[package]] @@ -679,6 +791,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -901,6 +1014,16 @@ dependencies = [ "wasi 0.14.2+wasi-0.2.4", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.31.1" @@ -986,6 +1109,24 @@ version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "http" version = "0.2.12" @@ -1178,6 +1319,15 @@ dependencies = [ "hashbrown 0.15.4", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "intl-memoizer" version = "0.5.3" @@ -1405,6 +1555,12 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "overload" version = "0.1.1" @@ -1413,9 +1569,10 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.0.12" +version = "0.0.13" dependencies = [ "actix-files", + "actix-session", "actix-web", "actix-web-static-files", "chrono", @@ -1594,6 +1751,18 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "potential_utf" version = "0.1.2" @@ -1930,6 +2099,17 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -2023,6 +2203,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.104" @@ -2375,6 +2561,16 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "url" version = "2.5.4" diff --git a/Cargo.toml b/Cargo.toml index 049c258c..87b7f697 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.12" +version = "0.0.13" edition = "2021" description = """\ @@ -35,6 +35,7 @@ fluent-templates = "0.13.0" unic-langid = { version = "0.9.6", features = ["macros"] } actix-web = "4.11.0" +actix-session = { version = "0.10.1", features = ["cookie-session"] } actix-web-files = { package = "actix-files", version = "0.6.6" } actix-web-static-files = "4.0.1" static-files.workspace = true diff --git a/src/app.rs b/src/app.rs index b6b5a716..6b11c0fd 100644 --- a/src/app.rs +++ b/src/app.rs @@ -5,6 +5,10 @@ mod figfont; use crate::core::{extension, extension::ExtensionRef}; use crate::{global, locale, service, trace}; +use actix_session::config::{BrowserSession, PersistentSession, SessionLifecycle}; +use actix_session::storage::CookieSessionStore; +use actix_session::SessionMiddleware; + use substring::Substring; use std::io::Error; @@ -111,9 +115,27 @@ impl Application { /// Devuelve [`std::io::Error`] si el *socket* no puede enlazarse (por puerto en uso, permisos, /// etc.). pub fn run(self) -> Result<service::Server, Error> { + // Genera clave secreta para firmar y verificar cookies. + let secret_key = service::cookie::Key::generate(); + // Prepara el servidor web. Ok(service::HttpServer::new(move || { - Self::service_app().wrap(tracing_actix_web::TracingLogger::default()) + Self::service_app() + .wrap(tracing_actix_web::TracingLogger::default()) + .wrap( + SessionMiddleware::builder(CookieSessionStore::default(), secret_key.clone()) + .session_lifecycle(match global::SETTINGS.server.session_lifetime { + 0 => SessionLifecycle::BrowserSession(BrowserSession::default()), + _ => SessionLifecycle::PersistentSession( + PersistentSession::default().session_ttl( + service::cookie::time::Duration::seconds( + global::SETTINGS.server.session_lifetime, + ), + ), + ), + }) + .build(), + ) }) .bind(format!( "{}:{}", diff --git a/src/global.rs b/src/global.rs index e8f50658..3f78b504 100644 --- a/src/global.rs +++ b/src/global.rs @@ -6,23 +6,24 @@ use serde::Deserialize; include_config!(SETTINGS: Settings => [ // [app] - "app.name" => "Sample", - "app.description" => "Developed with the amazing PageTop framework.", - "app.theme" => "Basic", - "app.language" => "en-US", - "app.startup_banner" => "Slant", + "app.name" => "Sample", + "app.description" => "Developed with the amazing PageTop framework.", + "app.theme" => "Basic", + "app.language" => "en-US", + "app.startup_banner" => "Slant", // [log] - "log.enabled" => true, - "log.tracing" => "Info", - "log.rolling" => "Stdout", - "log.path" => "log", - "log.prefix" => "tracing.log", - "log.format" => "Full", + "log.enabled" => true, + "log.tracing" => "Info", + "log.rolling" => "Stdout", + "log.path" => "log", + "log.prefix" => "tracing.log", + "log.format" => "Full", // [server] - "server.bind_address" => "localhost", - "server.bind_port" => 8080, + "server.bind_address" => "localhost", + "server.bind_port" => 8080, + "server.session_lifetime" => 604_800, ]); #[derive(Debug, Deserialize)] @@ -80,4 +81,8 @@ pub struct Server { pub bind_address: String, /// Puerto de escucha del servidor web. pub bind_port: u16, + /// Duración de la cookie de sesión en segundos (p.ej. `604_800` para una semana). + /// + /// El valor `0` indica que la cookie permanecerá activa hasta que se cierre el navegador. + pub session_lifetime: i64, } diff --git a/src/prelude.rs b/src/prelude.rs index af2f5110..6bacaf3a 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -34,7 +34,7 @@ pub use crate::locale::*; pub use crate::datetime::*; pub use crate::service; -pub use crate::service::{HttpRequest, HttpResponse}; +pub use crate::service::{HttpMessage, HttpRequest, HttpResponse}; pub use crate::core::{AnyCast, AnyInfo, TypeInfo}; diff --git a/src/service.rs b/src/service.rs index cc32d56e..6897a439 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,12 +1,13 @@ //! Gestión del servidor y servicios web (con [Actix Web](https://docs.rs/actix-web)). +pub use actix_session::Session; pub use actix_web::body::BoxBody; pub use actix_web::dev::Server; pub use actix_web::dev::ServiceFactory as Factory; pub use actix_web::dev::ServiceRequest as Request; pub use actix_web::dev::ServiceResponse as Response; -pub use actix_web::{http, rt, web}; -pub use actix_web::{App, Error, HttpRequest, HttpResponse, HttpServer}; +pub use actix_web::{cookie, http, rt, web}; +pub use actix_web::{App, Error, HttpMessage, HttpRequest, HttpResponse, HttpServer}; #[doc(hidden)] pub use actix_web::test; From a88fcff00f7cbc827168ac374977b8e78ea8a2a1 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 28 Jul 2025 18:26:30 +0200 Subject: [PATCH 097/244] =?UTF-8?q?=F0=9F=9A=A8=20(build):=20Aplica=20mejo?= =?UTF-8?q?ra=20propuesta=20por=20clippy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-build/src/lib.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index e125c591..b0a13f33 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -230,15 +230,9 @@ impl StaticFilesBundle { // Guarda el archivo CSS compilado en el directorio temporal. let css_path = temp_dir.join(target_name); File::create(&css_path) - .expect(&format!( - "Failed to create CSS file `{}`", - css_path.display() - )) + .unwrap_or_else(|_| panic!("Failed to create CSS file `{}`", css_path.display())) .write_all(css_content.as_bytes()) - .expect(&format!( - "Failed to write CSS content to `{}`", - css_path.display() - )); + .unwrap_or_else(|_| panic!("Failed to write CSS content to `{}`", css_path.display())); // Identifica el directorio temporal de recursos. StaticFilesBundle { From e1265a04b69f3a85ea032fd17dbd9588f810c7da Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 28 Jul 2025 18:33:50 +0200 Subject: [PATCH 098/244] =?UTF-8?q?=F0=9F=8D=B1=20A=C3=B1ade=20gesti=C3=B3?= =?UTF-8?q?n=20de=20recursos=20est=C3=A1ticos=20de=20PageTop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 3 ++- Cargo.toml | 9 +++++++-- build.rs | 7 +++++++ src/core/extension/all.rs | 8 ++++---- src/global.rs | 18 ++++++++++++++++-- src/service.rs | 3 +++ 6 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 build.rs diff --git a/Cargo.lock b/Cargo.lock index b3cb7b25..20087bf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1569,7 +1569,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.0.13" +version = "0.0.14" dependencies = [ "actix-files", "actix-session", @@ -1582,6 +1582,7 @@ dependencies = [ "figlet-rs", "fluent-templates", "itoa", + "pagetop-build", "pagetop-macros", "parking_lot", "pastey", diff --git a/Cargo.toml b/Cargo.toml index 87b7f697..476168dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.13" +version = "0.0.14" edition = "2021" description = """\ @@ -42,7 +42,7 @@ static-files.workspace = true serde = { version = "1.0", features = ["derive"] } -pagetop-macros = { version = "0.0", path = "helpers/pagetop-macros" } +pagetop-macros.workspace = true [features] default = [] @@ -51,6 +51,8 @@ testing = [] [dev-dependencies] tempfile = "3.20.0" +[build-dependencies] +pagetop-build.workspace = true [workspace] @@ -68,3 +70,6 @@ authors = ["Manuel Cillero <manuel@cillero.es>"] [workspace.dependencies] static-files = "0.2.5" + +pagetop-build = { version = "0.0", path = "helpers/pagetop-build" } +pagetop-macros = { version = "0.0", path = "helpers/pagetop-macros" } diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..85e02e02 --- /dev/null +++ b/build.rs @@ -0,0 +1,7 @@ +use pagetop_build::StaticFilesBundle; + +fn main() -> std::io::Result<()> { + StaticFilesBundle::from_dir("./static", None) + .with_name("assets") + .build() +} diff --git a/src/core/extension/all.rs b/src/core/extension/all.rs index d5c452af..f0610447 100644 --- a/src/core/extension/all.rs +++ b/src/core/extension/all.rs @@ -1,7 +1,7 @@ use crate::core::action::add_action; use crate::core::extension::ExtensionRef; use crate::core::theme::all::THEMES; -use crate::{/*global, include_files, include_files_service, */ service, trace}; +use crate::{global, include_files, include_files_service, service, trace}; use parking_lot::RwLock; @@ -125,13 +125,13 @@ pub fn initialize_extensions() { // CONFIGURA LOS SERVICIOS ************************************************************************* -//include_files!(assets); +include_files!(assets); pub fn configure_services(scfg: &mut service::web::ServiceConfig) { for extension in ENABLED_EXTENSIONS.read().iter() { extension.configure_service(scfg); } - /*include_files_service!( + include_files_service!( scfg, assets => "/", [&global::SETTINGS.dev.pagetop_project_dir, "static"] - );*/ + ); } diff --git a/src/global.rs b/src/global.rs index 3f78b504..faa9c2f8 100644 --- a/src/global.rs +++ b/src/global.rs @@ -12,6 +12,9 @@ include_config!(SETTINGS: Settings => [ "app.language" => "en-US", "app.startup_banner" => "Slant", + // [dev] + "dev.pagetop_project_dir" => "", + // [log] "log.enabled" => true, "log.tracing" => "Info", @@ -27,10 +30,11 @@ include_config!(SETTINGS: Settings => [ ]); #[derive(Debug, Deserialize)] -/// Ajustes para las secciones globales [`[app]`](App), [`[log]`](Log) y [`[server]`](Server) de -/// [`SETTINGS`]. +/// Ajustes para las secciones globales [`[app]`](App), [`[dev]`](Dev), [`[log]`](Log) y +/// [`[server]`](Server) de [`SETTINGS`]. pub struct Settings { pub app: App, + pub dev: Dev, pub log: Log, pub server: Server, } @@ -54,6 +58,16 @@ pub struct App { pub run_mode: String, } +#[derive(Debug, Deserialize)] +/// Sección `[Dev]` de la configuración. Forma parte de [`Settings`]. +pub struct Dev { + /// Los archivos estáticos requeridos por `PageTop` se integran por defecto en el binario + /// ejecutable. Sin embargo, durante el desarrollo puede resultar útil servirlos desde su propio + /// directorio para evitar recompilar cada vez que se modifican. En ese caso, este ajuste debe + /// indicar la ruta absoluta al directorio raíz del proyecto. + pub pagetop_project_dir: String, +} + #[derive(Debug, Deserialize)] /// Sección `[log]` de la configuración. Forma parte de [`Settings`]. pub struct Log { diff --git a/src/service.rs b/src/service.rs index 6897a439..68c8d5d1 100644 --- a/src/service.rs +++ b/src/service.rs @@ -9,6 +9,9 @@ pub use actix_web::dev::ServiceResponse as Response; pub use actix_web::{cookie, http, rt, web}; pub use actix_web::{App, Error, HttpMessage, HttpRequest, HttpResponse, HttpServer}; +pub use actix_web_files::Files as ActixFiles; +pub use actix_web_static_files::ResourceFiles; + #[doc(hidden)] pub use actix_web::test; From 2bbb37bb5df3e4c4d08975158f5a7becbe139f18 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 2 Aug 2025 11:20:39 +0200 Subject: [PATCH 099/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20p=C3=A1gina=20?= =?UTF-8?q?de=20bienvenida=20y=20de=20comprobaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Añade nueva hoja de estilos (normalize.css) al tema básico. - Activa la extensión de la página de bienvenida por defecto en el registro de extensiones. - Añade traducciones en inglés y español para el contenido de la página de bienvenida. - Incluye estilos CSS y recursos gráficos para el diseño y disposición de la página de bienvenida. --- src/base.rs | 4 +- src/base/extension.rs | 4 + src/base/extension/welcome.rs | 108 +++++++ src/base/theme/basic.rs | 10 +- src/core/extension/all.rs | 13 +- src/global.rs | 2 +- src/lib.rs | 2 +- src/locale.rs | 16 +- src/locale/en-US/theme.ftl | 1 + src/locale/en-US/welcome.ftl | 21 ++ src/locale/es-ES/theme.ftl | 1 + src/locale/es-ES/welcome.ftl | 21 ++ static/css/normalize.css | 349 +++++++++++++++++++++ static/css/welcome.css | 460 ++++++++++++++++++++++++++++ static/img/monster-pagetop_250.avif | Bin 0 -> 10834 bytes static/img/monster-pagetop_250.png | Bin 0 -> 32018 bytes static/img/monster-pagetop_250.webp | Bin 0 -> 12090 bytes static/img/monster-pagetop_500.avif | Bin 0 -> 20876 bytes static/img/monster-pagetop_500.png | Bin 0 -> 80504 bytes static/img/monster-pagetop_500.webp | Bin 0 -> 22974 bytes static/img/welcome-header-sm.avif | Bin 0 -> 16768 bytes static/img/welcome-header-sm.jpg | Bin 0 -> 63203 bytes static/img/welcome-header-sm.webp | Bin 0 -> 85210 bytes static/img/welcome-header.avif | Bin 0 -> 37239 bytes static/img/welcome-header.jpg | Bin 0 -> 184289 bytes static/img/welcome-header.webp | Bin 0 -> 187824 bytes tests/service.rs | 5 +- 27 files changed, 1000 insertions(+), 17 deletions(-) create mode 100644 src/base/extension.rs create mode 100644 src/base/extension/welcome.rs create mode 100644 src/locale/en-US/welcome.ftl create mode 100644 src/locale/es-ES/welcome.ftl create mode 100644 static/css/normalize.css create mode 100644 static/css/welcome.css create mode 100644 static/img/monster-pagetop_250.avif create mode 100644 static/img/monster-pagetop_250.png create mode 100644 static/img/monster-pagetop_250.webp create mode 100644 static/img/monster-pagetop_500.avif create mode 100644 static/img/monster-pagetop_500.png create mode 100644 static/img/monster-pagetop_500.webp create mode 100644 static/img/welcome-header-sm.avif create mode 100644 static/img/welcome-header-sm.jpg create mode 100644 static/img/welcome-header-sm.webp create mode 100644 static/img/welcome-header.avif create mode 100644 static/img/welcome-header.jpg create mode 100644 static/img/welcome-header.webp diff --git a/src/base.rs b/src/base.rs index 6f22dd72..d27a9ad5 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 00000000..49e408dd --- /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 00000000..f0664d2d --- /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<Markup, ErrorPage> { + 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 0fc533c5..4ea24604 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 f0610447..93b5c4bd 100644 --- a/src/core/extension/all.rs +++ b/src/core/extension/all.rs @@ -29,8 +29,8 @@ pub fn register_extensions(root_extension: Option<ExtensionRef>) { 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 faa9c2f8..f150ca6d 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 63ca6a55..598c55e6 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 298b3508..2a08ba6f 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 fd7f228d..9c71e6bd 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 00000000..7d98f447 --- /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 <strong>PageTop!</strong> + +welcome_text1 = If you can read this page, it means that the <strong>PageTop</strong> 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 <strong>contact your system administrator</strong> for assistance. + +welcome_about = About +welcome_pagetop = <strong>PageTop</strong> is a <a href="https://www.rust-lang.org" target="_blank">Rust</a>-based web development framework for building modular, extensible, and configurable web solutions. + +welcome_issues1 = To report issues related to the <strong>PageTop</strong> framework, please use <a href="https://git.cillero.es/manuelcillero/pagetop/issues" target="_blank">SoloGit</a>. Before opening a new issue, check existing reports to avoid duplicates. +welcome_issues2 = For issues related specifically to <strong>{ $app }</strong>, please refer to its official repository or support channel, rather than directly to <strong>PageTop</strong>. + +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 c2026c6f..f193c537 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 00000000..8a384253 --- /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 <strong>PageTop!</strong> + +welcome_text1 = Si puedes leer esta página, significa que el servidor de <strong>PageTop</strong> 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 <strong>contacta con el administrador del sistema</strong> para recibir asistencia técnica. + +welcome_about = Acerca de +welcome_pagetop = <strong>PageTop</strong> es un entorno de desarrollo web basado en <a href="https://www.rust-lang.org/es" target="_blank">Rust</a>, diseñado para crear soluciones web modulares, extensibles y configurables. + +welcome_issues1 = Para comunicar cualquier problema con <strong>PageTop</strong>, utiliza <a href="https://git.cillero.es/manuelcillero/pagetop/issues" target="_blank">SoloGit</a>. Antes de informar de una incidencia, revisa los informes ya existentes para evitar duplicados. +welcome_issues2 = Si se trata de fallos específicos de <strong>{ $app }</strong>, por favor acude a su repositorio oficial o canal de soporte, y no al de <strong>PageTop</strong> 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 00000000..192eb9ce --- /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 00000000..8f603485 --- /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 0000000000000000000000000000000000000000..df864b85c67c980d485216b1ef18737713114554 GIT binary patch literal 10834 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 literal 0 HcmV?d00001 diff --git a/static/img/monster-pagetop_250.png b/static/img/monster-pagetop_250.png new file mode 100644 index 0000000000000000000000000000000000000000..baa7d1f895f60e0966aa09e926922e653ef469f4 GIT binary patch literal 32018 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 literal 0 HcmV?d00001 diff --git a/static/img/monster-pagetop_250.webp b/static/img/monster-pagetop_250.webp new file mode 100644 index 0000000000000000000000000000000000000000..dcc5ef26308dd2f26d1e9c2c1c688f750d544984 GIT binary patch literal 12090 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 YceFZN(cAxq=dFKgq5Ge|ng6l>1Gp;yN&o-= literal 0 HcmV?d00001 diff --git a/static/img/monster-pagetop_500.avif b/static/img/monster-pagetop_500.avif new file mode 100644 index 0000000000000000000000000000000000000000..d07f359de0e7a7c5d1d9378c55a8819a257838ec GIT binary patch literal 20876 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 LA51~|H)nvri_}K9 literal 0 HcmV?d00001 diff --git a/static/img/monster-pagetop_500.png b/static/img/monster-pagetop_500.png new file mode 100644 index 0000000000000000000000000000000000000000..d0b9e0b1399bf5939bd0e0f784f3105d4c52d0b2 GIT binary patch literal 80504 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 literal 0 HcmV?d00001 diff --git a/static/img/monster-pagetop_500.webp b/static/img/monster-pagetop_500.webp new file mode 100644 index 0000000000000000000000000000000000000000..18896fe50ed014ffe5571b8d0a115b755d63823e GIT binary patch literal 22974 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 F006P8s)7Ij literal 0 HcmV?d00001 diff --git a/static/img/welcome-header-sm.avif b/static/img/welcome-header-sm.avif new file mode 100644 index 0000000000000000000000000000000000000000..ec31a6db0108021e24b121684cb2f5367539139d GIT binary patch literal 16768 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 E9|Dm@zW@LL literal 0 HcmV?d00001 diff --git a/static/img/welcome-header-sm.jpg b/static/img/welcome-header-sm.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f2c875fe4764fa14b07751b6b44755555eeedd74 GIT binary patch literal 63203 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 ae}(Ef;VTZ}642H--2eK?)9?3l?EeAr`UL&} literal 0 HcmV?d00001 diff --git a/static/img/welcome-header-sm.webp b/static/img/welcome-header-sm.webp new file mode 100644 index 0000000000000000000000000000000000000000..9f7aff8751fa594bf8df6bd02c47aadb64be52ec GIT binary patch literal 85210 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 a!1&co532|+!KdL*Yl<1mek`;DKmY(OcGGqM literal 0 HcmV?d00001 diff --git a/static/img/welcome-header.avif b/static/img/welcome-header.avif new file mode 100644 index 0000000000000000000000000000000000000000..8018555a463cdd2ca6eb5c9eff0383dca6b0a41e GIT binary patch literal 37239 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 FmD;HdKPmtK literal 0 HcmV?d00001 diff --git a/static/img/welcome-header.jpg b/static/img/welcome-header.jpg new file mode 100644 index 0000000000000000000000000000000000000000..69f1dbe087e1dbdbfc8098fe435b766820267164 GIT binary patch literal 184289 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 literal 0 HcmV?d00001 diff --git a/static/img/welcome-header.webp b/static/img/welcome-header.webp new file mode 100644 index 0000000000000000000000000000000000000000..7da174cfae43ee89b913ba3ab2f3096e011dd31d GIT binary patch literal 187824 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%0ApKZC2)I|u~Au`q9_ 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%0Di5trV|2o14V^&^Mq9&3I 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 literal 0 HcmV?d00001 diff --git a/tests/service.rs b/tests/service.rs index 51e74c74..5aec398e 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); } From 3a6dcc5c72035ca097c858017ec3186e2484dea9 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 2 Aug 2025 20:26:39 +0200 Subject: [PATCH 100/244] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Mej?= =?UTF-8?q?ora=20funcionalidad=20del=20componente=20Html?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Amplía la documentación del componente. - Aplica la nueva funcionalidad en la página de bienvenida usando el nuevo renderizado dinámico con contexto. - Añade pruebas unitarias para el componente. --- src/base/component/html.rs | 70 +++++++++++++++++++++++++----- src/base/extension/welcome.rs | 4 +- src/core/component/definition.rs | 7 ++- src/html/context.rs | 10 ++--- src/response/page.rs | 9 ++-- src/response/page/error.rs | 8 ++-- tests/component_html.rs | 74 ++++++++++++++++++++++++++++++++ 7 files changed, 155 insertions(+), 27 deletions(-) create mode 100644 tests/component_html.rs diff --git a/src/base/component/html.rs b/src/base/component/html.rs index 09376059..228bfe86 100644 --- a/src/base/component/html.rs +++ b/src/base/component/html.rs @@ -1,28 +1,76 @@ use crate::prelude::*; -/// Componente básico para renderizar directamente código HTML. -#[derive(AutoDefault)] -pub struct Html(Markup); +/// Componente básico para renderizar dinámicamente código HTML recibiendo el contexto. +/// +/// Este componente permite generar contenido HTML arbitrario, usando la macro `html!` y accediendo +/// opcionalmente al contexto de renderizado. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// let component = Html::with(|_| { +/// html! { +/// div class="example" { +/// p { "Hello from PageTop." } +/// } +/// } +/// }); +/// ``` +/// +/// Para renderizar contenido que dependa del contexto, se puede acceder a él dentro del *closure*: +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// let component = Html::with(|cx| { +/// let user = cx.get_param::<String>("username").unwrap_or(String::from("visitor")); +/// html! { +/// h1 { "Hello, " (user) } +/// } +/// }); +/// ``` +pub struct Html(Box<dyn Fn(&mut Context) -> Markup + Send + Sync>); +impl Default for Html { + fn default() -> Self { + Html::with(|_| html! {}) + } +} impl ComponentTrait for Html { fn new() -> Self { Html::default() } - fn prepare_component(&self, _cx: &mut Context) -> PrepareMarkup { - PrepareMarkup::With(html! { (self.0) }) + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + PrepareMarkup::With((self.0)(cx)) } } impl Html { - /// Crear una instancia con el código HTML del argumento. - pub fn with(html: Markup) -> Self { - Html(html) + /// Crea una instancia que generará el `Markup`, con acceso opcional al contexto. + /// + /// El método [`prepare_component`](crate::core::component::ComponentTrait::prepare_component) + /// delega el renderizado en la función proporcionada, que recibe una referencia mutable + /// al contexto de renderizado ([`Context`]). + pub fn with<F>(f: F) -> Self + where + F: Fn(&mut Context) -> Markup + Send + Sync + 'static, + { + Html(Box::new(f)) } - /// Modifica el código HTML de la instancia con el nuevo código del argumento. - pub fn alter_html(&mut self, html: Markup) -> &mut Self { - self.0 = html; + /// Sustituye la función que genera el `Markup`. + /// + /// Permite a otras extensiones modificar la función de renderizado que se ejecutará cuando + /// [`prepare_component`](crate::core::component::ComponentTrait::prepare_component) invoque + /// esta instancia. La nueva función también recibe una referencia al contexto ([`Context`]). + pub fn alter_html<F>(&mut self, f: F) -> &mut Self + where + F: Fn(&mut Context) -> Markup + Send + Sync + 'static, + { + self.0 = Box::new(f); self } } diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs index f0664d2d..d8b1259f 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -24,11 +24,11 @@ impl ExtensionTrait for Welcome { async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { let app = &global::SETTINGS.app.name; - Page::new(request) + Page::new(Some(request)) .with_title(L10n::l("welcome_page")) .with_theme("Basic") .with_assets(AssetsOp::AddStyleSheet(StyleSheet::from("/css/welcome.css"))) - .with_component(Html::with(html! { + .with_component(Html::with(move |_| html! { div id="main-header" { header { h1 id="header-title" aria-label=(L10n::l("welcome_aria").with_arg("app", app)) { diff --git a/src/core/component/definition.rs b/src/core/component/definition.rs index 63264b7a..a9a4f815 100644 --- a/src/core/component/definition.rs +++ b/src/core/component/definition.rs @@ -53,8 +53,11 @@ pub trait ComponentTrait: AnyInfo + ComponentRender + Send + Sync { /// Devuelve una representación estructurada del componente lista para renderizar. /// - /// Puede sobrescribirse para generar dinámicamente el contenido HTML. Por defecto, devuelve - /// [`PrepareMarkup::None`]. + /// 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 + /// dinámicamente el contenido HTML con acceso al contexto de renderizado. + /// + /// Por defecto, devuelve [`PrepareMarkup::None`]. #[allow(unused_variables)] fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { PrepareMarkup::None diff --git a/src/html/context.rs b/src/html/context.rs index a1df9879..456ca7ab 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -107,7 +107,7 @@ impl Error for ErrorParam {} /// ``` #[rustfmt::skip] pub struct Context { - request : HttpRequest, // Solicitud HTTP de origen. + request : Option<HttpRequest>, // Solicitud HTTP de origen. langid : &'static LanguageIdentifier, // Identificador de idioma. theme : ThemeRef, // Referencia al tema para renderizar. layout : &'static str, // Composición del documento para renderizar. @@ -124,7 +124,7 @@ impl Context { /// El contexto inicializa el idioma, tema y composición por defecto, sin favicon ni recursos /// cargados. #[rustfmt::skip] - pub fn new(request: HttpRequest) -> Self { + pub fn new(request: Option<HttpRequest>) -> Self { Context { request, langid : &DEFAULT_LANGID, @@ -197,9 +197,9 @@ impl Context { // Context GETTERS ***************************************************************************** - /// Devuelve la solicitud HTTP asociada al documento. - pub fn request(&self) -> &HttpRequest { - &self.request + /// Devuelve una referencia a la solicitud HTTP asociada, si existe. + pub fn request(&self) -> Option<&HttpRequest> { + self.request.as_ref() } /// Devuelve el identificador de idioma asociado al documento. diff --git a/src/response/page.rs b/src/response/page.rs index b2528487..0964509b 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -30,9 +30,12 @@ pub struct Page { } impl Page { - /// Crea una nueva instancia de página con contexto basado en la petición HTTP. + /// Crea una nueva instancia de página. + /// + /// Si se proporciona la solicitud HTTP, se guardará en el contexto de renderizado de la página + /// para poder ser recuperada por los componentes si es necesario. #[rustfmt::skip] - pub fn new(request: HttpRequest) -> Self { + pub fn new(request: Option<HttpRequest>) -> Self { Page { title : OptionTranslated::default(), description : OptionTranslated::default(), @@ -165,7 +168,7 @@ impl Page { } /// Devuelve la solicitud HTTP asociada. - pub fn request(&self) -> &HttpRequest { + pub fn request(&self) -> Option<&HttpRequest> { self.context.request() } diff --git a/src/response/page/error.rs b/src/response/page/error.rs index 3d952c62..3a2511cf 100644 --- a/src/response/page/error.rs +++ b/src/response/page/error.rs @@ -28,12 +28,12 @@ impl fmt::Display for ErrorPage { ErrorPage::BadRequest(_) => write!(f, "Bad Client Data"), // Error 403. ErrorPage::AccessDenied(request) => { - let mut error_page = Page::new(request.clone()); + let mut error_page = Page::new(Some(request.clone())); let error403 = error_page.theme().error403(&mut error_page); if let Ok(page) = error_page .with_title(L10n::n("Error FORBIDDEN")) .with_layout("error") - .with_component(Html::with(error403)) + .with_component(Html::with(move |_| error403.clone())) .render() { write!(f, "{}", page.into_string()) @@ -43,12 +43,12 @@ impl fmt::Display for ErrorPage { } // Error 404. ErrorPage::NotFound(request) => { - let mut error_page = Page::new(request.clone()); + let mut error_page = Page::new(Some(request.clone())); let error404 = error_page.theme().error404(&mut error_page); if let Ok(page) = error_page .with_title(L10n::n("Error RESOURCE NOT FOUND")) .with_layout("error") - .with_component(Html::with(error404)) + .with_component(Html::with(move |_| error404.clone())) .render() { write!(f, "{}", page.into_string()) diff --git a/tests/component_html.rs b/tests/component_html.rs new file mode 100644 index 00000000..978248f1 --- /dev/null +++ b/tests/component_html.rs @@ -0,0 +1,74 @@ +use pagetop::prelude::*; + +#[pagetop::test] +async fn component_html_renders_static_markup() { + let component = Html::with(|_| { + html! { + p { "Test" } + } + }); + + let markup = component + .prepare_component(&mut Context::new(None)) + .render(); + + assert_eq!(markup.0, "<p>Test</p>"); +} + +#[pagetop::test] +async fn component_html_renders_using_context_param() { + let mut cx = Context::new(None).with_param("username", String::from("Alice")); + + let component = Html::with(|cx| { + let name = cx.get_param::<String>("username").unwrap_or_default(); + html! { + span { (name) } + } + }); + + let markup = component.prepare_component(&mut cx).render(); + + assert_eq!(markup.0, "<span>Alice</span>"); +} + +#[pagetop::test] +async fn component_html_allows_replacing_render_function() { + let mut component = Html::with(|_| html! { div { "Original" } }); + + component.alter_html(|_| html! { div { "Modified" } }); + + let markup = component + .prepare_component(&mut Context::new(None)) + .render(); + + assert_eq!(markup.0, "<div>Modified</div>"); +} + +#[pagetop::test] +async fn component_html_default_renders_empty_markup() { + let component = Html::default(); + + let markup = component + .prepare_component(&mut Context::new(None)) + .render(); + + assert_eq!(markup.0, ""); +} + +#[pagetop::test] +async fn component_html_can_access_http_method() { + let req = service::test::TestRequest::with_uri("/").to_http_request(); + let mut cx = Context::new(Some(req)); + + let component = Html::with(|cx| { + let method = cx + .request() + .map(|r| r.method().to_string()) + .unwrap_or_default(); + html! { span { (method) } } + }); + + let markup = component.prepare_component(&mut cx).render(); + + assert_eq!(markup.0, "<span>GET</span>"); +} From 4d4b654cd86f359595ffe5bf1658d488ca18b6d5 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 3 Aug 2025 08:32:13 +0200 Subject: [PATCH 101/244] =?UTF-8?q?=F0=9F=93=9D=20Retoca=20documentaci?= =?UTF-8?q?=C3=B3n=20generada=20para=20los=20ajustes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index 5dc05a16..08067fe6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -240,7 +240,7 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( macro_rules! include_config { ( $SETTINGS_NAME:ident : $Settings_Type:ty => [ $( $k:literal => $v:expr ),* $(,)? ] ) => { #[doc = concat!( - "Referencia a los ajustes de configuración deserializados de [`", + "Referencia y valores por defecto de los ajustes de configuración para [`", stringify!($Settings_Type), "`]." )] From a0c5c20aa151c871bbe9eaf7e782e67c91196098 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 3 Aug 2025 11:57:01 +0200 Subject: [PATCH 102/244] =?UTF-8?q?=F0=9F=92=A1=20Corrige=20ejemplos=20de?= =?UTF-8?q?=20uso=20del=20componente=20Html?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/theme/regions.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index 5e0186ad..22ab6f25 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -74,12 +74,12 @@ impl InRegion { /// use pagetop::prelude::*; /// /// // Banner global, en la región por defecto de cualquier página. - /// InRegion::Content.add(Child::with(Html::with( + /// InRegion::Content.add(Child::with(Html::with(|_| /// html! { ("🎉 ¡Bienvenido!") } /// ))); /// /// // Texto en la región "sidebar". - /// InRegion::Named("sidebar").add(Child::with(Html::with( + /// InRegion::Named("sidebar").add(Child::with(Html::with(|_| /// html! { ("Publicidad") } /// ))); /// ``` From fd5b48811da7199c64890cd65f24c3219137f7f5 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 3 Aug 2025 11:58:47 +0200 Subject: [PATCH 103/244] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactoriza=20mane?= =?UTF-8?q?jo=20de=20idiomas=20para=20localizaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/extension/welcome.rs | 38 ++++--- src/global.rs | 11 +- src/html/context.rs | 51 +++++++-- src/html/opt_translated.rs | 20 ++-- src/locale.rs | 207 ++++++++++++++++++++-------------- src/response/page.rs | 16 +-- tests/locale.rs | 10 +- 7 files changed, 218 insertions(+), 135 deletions(-) diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs index d8b1259f..39edfd37 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -28,12 +28,15 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { .with_title(L10n::l("welcome_page")) .with_theme("Basic") .with_assets(AssetsOp::AddStyleSheet(StyleSheet::from("/css/welcome.css"))) - .with_component(Html::with(move |_| html! { + .with_component(Html::with(move |cx| 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)) + h1 + id="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 id="header-image" aria-hidden="true" { @@ -59,20 +62,25 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { 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" { + 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 id="poweredby-text" { (L10n::l("welcome_powered").to_markup(cx)) } } } div class="content-text" { - p { (L10n::l("welcome_text1")) } - p { (L10n::l("welcome_text2")) } + p { (L10n::l("welcome_text1").to_markup(cx)) } + p { (L10n::l("welcome_text2").to_markup(cx)) } 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)) } + h1 { 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)) } } } } @@ -85,7 +93,7 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { viewBox="0 0 1614 1614" xmlns="http://www.w3.org/2000/svg" role="img" - aria-label=(L10n::l("pagetop_logo")) + aria-label=[L10n::l("pagetop_logo").using(cx)] preserveAspectRatio="xMidYMid slice" focusable="false" { @@ -97,8 +105,8 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { 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")) } + 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)) } } } } diff --git a/src/global.rs b/src/global.rs index f150ca6d..25a17811 100644 --- a/src/global.rs +++ b/src/global.rs @@ -9,7 +9,7 @@ include_config!(SETTINGS: Settings => [ "app.name" => "PageTop App", "app.description" => "Developed with the amazing PageTop framework.", "app.theme" => "Basic", - "app.language" => "en-US", + "app.language" => "", "app.startup_banner" => "Slant", // [dev] @@ -48,7 +48,14 @@ pub struct App { pub description: String, /// Tema predeterminado. pub theme: String, - /// Idioma predeterminado (localización). + /// Idioma por defecto para la aplicación. + /// + /// Si no se especifica un valor válido, normalmente se usará el idioma devuelto por la + /// implementación de [`LangId`](crate::locale::LangId) para [`Context`](crate::html::Context), + /// en el siguiente orden: primero, el idioma establecido explícitamente con + /// [`Context::with_langid`](crate::html::Context::with_langid); si no se ha definido, se usará + /// el indicado en la cabecera `Accept-Language` del navegador; y, si ninguno aplica, se + /// empleará el idioma de respaldo ("en-US"). pub language: String, /// Banner ASCII mostrado al inicio: *"Off"* (desactivado), *"Slant"*, *"Small"*, *"Speed"* o /// *"Starwars"*. diff --git a/src/html/context.rs b/src/html/context.rs index 456ca7ab..8aaeb4af 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -3,7 +3,7 @@ use crate::core::theme::ThemeRef; use crate::core::TypeInfo; use crate::html::{html, Markup}; use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; -use crate::locale::{LanguageIdentifier, DEFAULT_LANGID}; +use crate::locale::{LangId, LangMatch, LanguageIdentifier, DEFAULT_LANGID, FALLBACK_LANGID}; use crate::service::HttpRequest; use crate::{builder_fn, join}; @@ -69,9 +69,9 @@ impl Error for ErrorParam {} /// use pagetop::prelude::*; /// /// fn new_context(request: HttpRequest) -> Context { -/// Context::new(request) +/// Context::new(Some(request)) /// // Establece el idioma del documento a español. -/// .with_langid(LangMatch::langid_or_default("es-ES")) +/// .with_langid(&LangMatch::resolve("es-ES")) /// // Selecciona un tema (por su nombre corto). /// .with_theme("aliner") /// // Asigna un favicon. @@ -125,9 +125,23 @@ impl Context { /// cargados. #[rustfmt::skip] pub fn new(request: Option<HttpRequest>) -> Self { + // Se intenta DEFAULT_LANGID. + let langid = DEFAULT_LANGID + // Si es None evalúa la cadena de extracción desde la cabecera HTTP. + .or_else(|| { + request + // Se usa `as_ref()` sobre `Option<HttpRequest>` para no mover el valor. + .as_ref() + .and_then(|req| req.headers().get("Accept-Language")) + .and_then(|value| value.to_str().ok()) + .and_then(|language| LangMatch::resolve(language).as_option()) + }) + // Si todo falla, se recurre a &FALLBACK_LANGID. + .unwrap_or(&FALLBACK_LANGID); + Context { request, - langid : &DEFAULT_LANGID, + langid, theme : *DEFAULT_THEME, layout : "default", favicon : None, @@ -140,10 +154,10 @@ impl Context { // Context BUILDER ***************************************************************************** - /// Modifica el identificador de idioma del documento. + /// Modifica la fuente de idioma del documento. #[builder_fn] - pub fn with_langid(mut self, langid: &'static LanguageIdentifier) -> Self { - self.langid = langid; + pub fn with_langid(mut self, language: &impl LangId) -> Self { + self.langid = language.langid(); self } @@ -202,11 +216,6 @@ impl Context { self.request.as_ref() } - /// Devuelve el identificador de idioma asociado al documento. - pub fn langid(&self) -> &LanguageIdentifier { - self.langid - } - /// Devuelve el tema que se usará para renderizar el documento. pub fn theme(&self) -> ThemeRef { self.theme @@ -281,3 +290,21 @@ impl Context { } } } + +/// Permite a [`Context`](crate::html::Context) actuar como proveedor de idioma. +/// +/// Devuelve un [`LanguageIdentifier`] siguiendo este orden de prioridad: +/// +/// 1. Un idioma válido establecido explícitamente con [`Context::with_langid`]. +/// 2. El idioma por defecto configurado para la aplicación. +/// 3. Un idioma válido extraído de la cabecera `Accept-Language` del navegador. +/// 4. Y si ninguna de las opciones anteriores aplica, se usa el idioma de respaldo (`"en-US"`). +/// +/// Resulta útil para usar un contexto ([`Context`]) como fuente de traducción en +/// [`L10n::using`](crate::locale::L10n::using) o +/// [`L10n::to_markup`](crate::locale::L10n::to_markup). +impl LangId for Context { + fn langid(&self) -> &'static LanguageIdentifier { + self.langid + } +} diff --git a/src/html/opt_translated.rs b/src/html/opt_translated.rs index ba60a0f8..b15ea18a 100644 --- a/src/html/opt_translated.rs +++ b/src/html/opt_translated.rs @@ -1,5 +1,5 @@ use crate::html::Markup; -use crate::locale::{L10n, LanguageIdentifier}; +use crate::locale::{L10n, LangId}; use crate::{builder_fn, AutoDefault}; /// Cadena para traducir al renderizar ([`locale`](crate::locale)). @@ -16,18 +16,18 @@ use crate::{builder_fn, AutoDefault}; /// /// // Español disponible. /// assert_eq!( -/// hello.using(LangMatch::langid_or_default("es-ES")), +/// hello.using(&LangMatch::resolve("es-ES")), /// Some(String::from("¡Hola mundo!")) /// ); /// /// // Japonés no disponible, traduce al idioma de respaldo ("en-US"). /// assert_eq!( -/// hello.using(LangMatch::langid_or_fallback("ja-JP")), +/// hello.using(&LangMatch::resolve("ja-JP")), /// Some(String::from("Hello world!")) /// ); /// /// // Para incrustar en HTML escapado: -/// let markup = hello.escaped(LangMatch::langid_or_default("es-ES")); +/// let markup = hello.to_markup(&LangMatch::resolve("es-ES")); /// assert_eq!(markup.into_string(), "¡Hola mundo!"); /// ``` #[derive(AutoDefault, Clone, Debug)] @@ -50,16 +50,16 @@ impl OptionTranslated { // OptionTranslated GETTERS ******************************************************************** - /// Devuelve la traducción para `langid`, si existe. - pub fn using(&self, langid: &LanguageIdentifier) -> Option<String> { - self.0.using(langid) + /// Devuelve la traducción para `language`, si existe. + pub fn using(&self, language: &impl LangId) -> Option<String> { + self.0.using(language) } - /// Devuelve la traducción *escapada* como [`Markup`] para `langid`, si existe. + /// Devuelve la traducción *escapada* como [`Markup`] para `language`, si existe. /// /// Útil para incrustar el texto directamente en plantillas HTML sin riesgo de inyección de /// contenido. - pub fn escaped(&self, langid: &LanguageIdentifier) -> Markup { - self.0.escaped(langid) + pub fn to_markup(&self, language: &impl LangId) -> Markup { + self.0.to_markup(language) } } diff --git a/src/locale.rs b/src/locale.rs index 2a08ba6f..d81243e6 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, Render}; +use crate::html::{Markup, PreEscaped}; use crate::{global, hm, AutoDefault}; pub use fluent_templates; @@ -112,10 +112,10 @@ use std::fmt; static LANGUAGES: LazyLock<HashMap<&str, (LanguageIdentifier, &str)>> = LazyLock::new(|| { hm![ "en" => ( langid!("en-US"), "english" ), - "en-GB" => ( langid!("en-GB"), "english_british" ), - "en-US" => ( langid!("en-US"), "english_united_states" ), + "en-gb" => ( langid!("en-GB"), "english_british" ), + "en-us" => ( langid!("en-US"), "english_united_states" ), "es" => ( langid!("es-ES"), "spanish" ), - "es-ES" => ( langid!("es-ES"), "spanish_spain" ), + "es-es" => ( langid!("es-ES"), "spanish_spain" ), ] }); @@ -123,14 +123,23 @@ static LANGUAGES: LazyLock<HashMap<&str, (LanguageIdentifier, &str)>> = LazyLock // // Se usa cuando el valor del identificador de idioma en las traducciones no corresponde con ningún // idioma soportado por la aplicación. -static FALLBACK_LANGID: LazyLock<LanguageIdentifier> = LazyLock::new(|| langid!("en-US")); +pub(crate) static FALLBACK_LANGID: LazyLock<LanguageIdentifier> = + LazyLock::new(|| langid!("en-US")); // Identificador de idioma **por defecto** para la aplicación. // // Se resuelve a partir de [`global::SETTINGS.app.language`](global::SETTINGS). Si el identificador // de idioma no es válido o no está disponible entonces resuelve como [`FALLBACK_LANGID`]. -pub(crate) static DEFAULT_LANGID: LazyLock<&LanguageIdentifier> = - LazyLock::new(|| LangMatch::langid_or_fallback(&global::SETTINGS.app.language)); +pub(crate) static DEFAULT_LANGID: LazyLock<Option<&LanguageIdentifier>> = + LazyLock::new(|| LangMatch::resolve(&global::SETTINGS.app.language).as_option()); + +/// Representa la fuente de idioma (`LanguageIdentifier`) asociada a un recurso. +/// +/// Este *trait* permite que distintas estructuras expongan su fuente de idioma de forma uniforme. +pub trait LangId { + /// Devuelve el identificador de idioma asociado al recurso. + fn langid(&self) -> &'static LanguageIdentifier; +} /// Operaciones con los idiomas soportados por `PageTop`. /// @@ -144,11 +153,11 @@ pub(crate) static DEFAULT_LANGID: LazyLock<&LanguageIdentifier> = /// /// // Coincidencia exacta. /// let lang = LangMatch::resolve("es-ES"); -/// assert_eq!(lang.as_langid().to_string(), "es-ES"); +/// assert_eq!(lang.langid().to_string(), "es-ES"); /// /// // Coincidencia parcial (con el idioma base). /// let lang = LangMatch::resolve("es-EC"); -/// assert_eq!(lang.as_langid().to_string(), "es-ES"); // Porque "es-EC" no está soportado. +/// assert_eq!(lang.langid().to_string(), "es-ES"); // Porque "es-EC" no está soportado. /// /// // Idioma no especificado. /// let lang = LangMatch::resolve(""); @@ -159,21 +168,16 @@ pub(crate) static DEFAULT_LANGID: LazyLock<&LanguageIdentifier> = /// assert_eq!(lang, LangMatch::Unsupported(String::from("ja-JP"))); /// ``` /// -/// Las siguientes líneas devuelven siempre un [`LanguageIdentifier`] válido, ya sea porque -/// resuelven un idioma soportado o porque aplican el idioma por defecto o de respaldo: +/// Con la siguiente instrucción siempre se obtiene un [`LanguageIdentifier`] válido, ya sea porque +/// resuelve un idioma soportado o porque se aplica el idioma por defecto o, en último caso, el de +/// respaldo ("en-US"): /// /// ```rust /// use pagetop::prelude::*; /// -/// // Idioma por defecto si no resuelve. +/// // Idioma por defecto o de respaldo si no resuelve. /// let lang = LangMatch::resolve("it-IT"); -/// let langid = lang.as_langid(); -/// -/// // Idioma por defecto si no se encuentra. -/// let langid = LangMatch::langid_or_default("es-MX"); -/// -/// // Idioma de respaldo ("en-US") si no se encuentra. -/// let langid = LangMatch::langid_or_fallback("es-MX"); +/// let langid = lang.langid(); /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub enum LangMatch { @@ -187,6 +191,13 @@ pub enum LangMatch { Unsupported(String), } +impl Default for LangMatch { + /// Resuelve al idioma por defecto y, si no está disponible, al idioma de respaldo ("en-US"). + fn default() -> Self { + LangMatch::Found(DEFAULT_LANGID.unwrap_or(&FALLBACK_LANGID)) + } +} + impl LangMatch { /// Resuelve `language` y devuelve la variante [`LangMatch`] apropiada. pub fn resolve(language: impl AsRef<str>) -> Self { @@ -198,12 +209,13 @@ impl LangMatch { } // Intenta aplicar coincidencia exacta con el código completo (p.ej. "es-MX"). - if let Some(langid) = LANGUAGES.get(language).map(|(langid, _)| langid) { + let lang = language.to_ascii_lowercase(); + if let Some(langid) = LANGUAGES.get(lang.as_str()).map(|(langid, _)| langid) { return Self::Found(langid); } // Si la variante regional no existe, retrocede al idioma base (p.ej. "es"). - if let Some((base_lang, _)) = language.split_once('-') { + if let Some((base_lang, _)) = lang.split_once('-') { if let Some(langid) = LANGUAGES.get(base_lang).map(|(langid, _)| langid) { return Self::Found(langid); } @@ -213,37 +225,47 @@ impl LangMatch { Self::Unsupported(String::from(language)) } - /// Devuelve el idioma de la variante de la instancia, o el idioma por defecto si no está - /// soportado. + /// Devuelve el [`LanguageIdentifier`] si el idioma fue reconocido. /// - /// Siempre devuelve un [`LanguageIdentifier`] válido. + /// Solo retorna `Some` si la variante es [`LangMatch::Found`]. En cualquier otro caso (por + /// ejemplo, si el identificador es vacío o no está soportado), devuelve `None`. + /// + /// Este método es útil cuando se desea acceder directamente al idioma reconocido sin aplicar el + /// idioma por defecto ni el de respaldo. + /// + /// # Ejemplo + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// let lang = LangMatch::resolve("es-ES").as_option(); + /// assert_eq!(lang.unwrap().to_string(), "es-ES"); + /// + /// let lang = LangMatch::resolve("jp-JP").as_option(); + /// assert!(lang.is_none()); + /// ``` #[inline] - pub fn as_langid(&self) -> &'static LanguageIdentifier { + pub fn as_option(&self) -> Option<&'static LanguageIdentifier> { + match self { + LangMatch::Found(l) => Some(l), + _ => None, + } + } +} + +/// Permite a [`LangMatch`] actuar como proveedor de idioma. +/// +/// Devuelve el [`LanguageIdentifier`] si la variante es [`LangMatch::Found`]; en caso contrario, +/// devuelve el idioma por defecto de la aplicación y, si tampoco está disponible, el idioma de +/// respaldo ("en-US"). +/// +/// Resulta útil para usar un valor de [`LangMatch`] como fuente de traducción en [`L10n::using`] o +/// [`L10n::to_markup`]. +impl LangId for LangMatch { + fn langid(&self) -> &'static LanguageIdentifier { match self { LangMatch::Found(l) => l, - _ => &DEFAULT_LANGID, - } - } - - /// Si `language` está vacío o no está soportado, devuelve el idioma por defecto. - /// - /// Siempre devuelve un [`LanguageIdentifier`] válido. - #[inline] - pub fn langid_or_default(language: impl AsRef<str>) -> &'static LanguageIdentifier { - match Self::resolve(language) { - Self::Found(l) => l, - _ => &DEFAULT_LANGID, - } - } - - /// Si `language` está vacío o no está soportado, devuelve el idioma de respaldo ("en-US"). - /// - /// Siempre devuelve un [`LanguageIdentifier`] válido. - #[inline] - pub fn langid_or_fallback(language: impl AsRef<str>) -> &'static LanguageIdentifier { - match Self::resolve(language) { - Self::Found(l) => l, - _ => &FALLBACK_LANGID, + _ => DEFAULT_LANGID.unwrap_or(&FALLBACK_LANGID), } } } @@ -297,7 +319,7 @@ enum L10nOp { /// Cada instancia puede representar: /// /// - Un texto puro (`n()`) que no requiere traducción. -/// - Una clave para traducir un texto de las traducciones por defecto de `PageTop` (`l()`). +/// - Una clave para traducir un texto de las traducciones predefinidas de `PageTop` (`l()`). /// - Una clave para traducir de un conjunto concreto de traducciones (`t()`). /// /// # Ejemplo @@ -319,8 +341,8 @@ enum L10nOp { /// También para traducciones a idiomas concretos. /// /// ```rust,ignore -/// // Traducción con clave, conjunto de traducciones e identificador de idioma a usar. -/// let bye = L10n::t("goodbye", &LOCALES_CUSTOM).using(LangMatch::langid_or_default("it")); +/// // Traducción con clave, conjunto de traducciones y fuente de idioma. +/// let bye = L10n::t("goodbye", &LOCALES_CUSTOM).using(&LangMatch::resolve("it")); /// ``` #[derive(AutoDefault, Clone)] pub struct L10n { @@ -339,8 +361,8 @@ impl L10n { } } - /// **l** = *“lookup”*. Crea una instancia para traducir usando una clave de la tabla de - /// traducciones por defecto. + /// **l** = *“lookup”*. Crea una instancia para traducir usando una clave del conjunto de + /// traducciones predefinidas. pub fn l(key: impl Into<String>) -> Self { L10n { op: L10nOp::Translate(key.into()), @@ -348,8 +370,8 @@ impl L10n { } } - /// **t** = *“translate”*. Crea una instancia para traducir usando una clave de una tabla de - /// traducciones específica. + /// **t** = *“translate”*. Crea una instancia para traducir usando una clave de un conjunto de + /// traducciones específico. pub fn t(key: impl Into<String>, locales: &'static Locales) -> Self { L10n { op: L10nOp::Translate(key.into()), @@ -377,20 +399,47 @@ impl L10n { self } - /// Resuelve la traducción usando el idioma por defecto de la aplicación. Devuelve `None` si no - /// aplica o no encuentra una traducción. + /// Resuelve la traducción usando el idioma por defecto o de respaldo de la aplicación. + /// + /// Devuelve `None` si no aplica o no encuentra una traducción válida. + /// + /// # Ejemplo + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// let text = L10n::l("greeting").with_arg("name", "Manuel").get(); + /// ``` pub fn get(&self) -> Option<String> { - self.using(&DEFAULT_LANGID) + self.using(&LangMatch::default()) } - /// Resuelve la traducción usando el [`LanguageIdentifier`] indicado. Devuelve `None` si no - /// aplica o no encuentra una traducción. - pub fn using(&self, langid: &LanguageIdentifier) -> Option<String> { + /// Resuelve la traducción usando la fuente de idioma proporcionada. + /// + /// Devuelve `None` si no aplica o no encuentra una traducción válida. + /// + /// # Ejemplo + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// struct ResourceLang; + /// + /// impl LangId for ResourceLang { + /// fn langid(&self) -> &'static LanguageIdentifier { + /// LangMatch::resolve("es-MX").langid() + /// } + /// } + /// + /// let r = ResourceLang; + /// let text = L10n::l("greeting").with_arg("name", "Usuario").using(&r); + /// ``` + pub fn using(&self, language: &impl LangId) -> Option<String> { match &self.op { L10nOp::None => None, L10nOp::Text(text) => Some(text.to_owned()), L10nOp::Translate(key) => self.locales.try_lookup_with_args( - langid, + language.langid(), key, &self.args.iter().fold(HashMap::new(), |mut arg, (k, v)| { arg.insert(Cow::Owned(k.clone()), v.to_owned().into()); @@ -400,16 +449,19 @@ impl L10n { } } - /// 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()) + /// Traduce el texto y lo devuelve como [`Markup`] usando la fuente de idioma proporcionada. + /// + /// Si no se encuentra una traducción válida, devuelve una cadena vacía. + /// + /// # Ejemplo + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// let html = L10n::l("welcome.message").to_markup(&LangMatch::resolve("es")); + /// ``` + pub fn to_markup(&self, language: &impl LangId) -> Markup { + PreEscaped(self.using(language).unwrap_or_default()) } } @@ -423,14 +475,3 @@ impl fmt::Debug for L10n { .finish() } } - -impl fmt::Display for L10n { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let content = match &self.op { - L10nOp::None => String::new(), - L10nOp::Text(text) => text.clone(), - L10nOp::Translate(key) => self.get().unwrap_or_else(|| format!("??<{}>", key)), - }; - write!(f, "{content}") - } -} diff --git a/src/response/page.rs b/src/response/page.rs index 0964509b..c1815d09 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -9,7 +9,7 @@ use crate::core::component::{Child, ChildOp, ComponentTrait}; use crate::core::theme::{ChildrenInRegions, ThemeRef, CONTENT_REGION_NAME}; use crate::html::{html, AssetsOp, Context, Markup, DOCTYPE}; use crate::html::{ClassesOp, OptionClasses, OptionId, OptionTranslated}; -use crate::locale::{CharacterDirection, L10n, LanguageIdentifier}; +use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier}; use crate::service::HttpRequest; /// Representa una página HTML completa lista para renderizar. @@ -78,10 +78,10 @@ impl Page { self } - /// Modifica el identificador de idioma de la página ([`Context::with_langid`]). + /// Modifica la fuente de idioma de la página ([`Context::with_langid`]). #[builder_fn] - pub fn with_langid(mut self, langid: &'static LanguageIdentifier) -> Self { - self.context.alter_langid(langid); + pub fn with_langid(mut self, language: &impl LangId) -> Self { + self.context.alter_langid(language); self } @@ -147,14 +147,14 @@ impl Page { // Page GETTERS ******************************************************************************** - /// Devuelve el título traducido para el idioma activo, si existe. + /// Devuelve el título traducido para el idioma de la página, si existe. pub fn title(&mut self) -> Option<String> { - self.title.using(self.context.langid()) + self.title.using(&self.context) } - /// Devuelve la descripción traducida para el idioma activo, si existe. + /// Devuelve la descripción traducida para el idioma de la página, si existe. pub fn description(&mut self) -> Option<String> { - self.description.using(self.context.langid()) + self.description.using(&self.context) } /// Devuelve la lista de metadatos `<meta name=...>`. diff --git a/tests/locale.rs b/tests/locale.rs index 420914d8..ef875d7d 100644 --- a/tests/locale.rs +++ b/tests/locale.rs @@ -13,7 +13,7 @@ async fn translation_without_args() { let _app = service::test::init_service(Application::new().test()).await; let l10n = L10n::l("test-hello-world"); - let translation = l10n.using(LangMatch::langid_or_default("es-ES")); + let translation = l10n.using(&LangMatch::resolve("es-ES")); assert_eq!(translation, Some("¡Hola mundo!".to_string())); } @@ -22,7 +22,7 @@ async fn translation_with_args() { let _app = service::test::init_service(Application::new().test()).await; let l10n = L10n::l("test-hello-user").with_arg("userName", "Manuel"); - let translation = l10n.using(LangMatch::langid_or_default("es-ES")); + let translation = l10n.using(&LangMatch::resolve("es-ES")); assert_eq!(translation, Some("¡Hola, Manuel!".to_string())); } @@ -35,7 +35,7 @@ async fn translation_with_plural_and_select() { ("photoCount", "3"), ("userGender", "male"), ]); - let translation = l10n.using(LangMatch::langid_or_default("es-ES")).unwrap(); + let translation = l10n.using(&LangMatch::resolve("es-ES")).unwrap(); assert!(translation.contains("añadido 3 nuevas fotos de él")); } @@ -44,7 +44,7 @@ async fn check_fallback_language() { let _app = service::test::init_service(Application::new().test()).await; let l10n = L10n::l("test-hello-world"); - let translation = l10n.using(LangMatch::langid_or_fallback("xx-YY")); // Retrocede a "en-US". + let translation = l10n.using(&LangMatch::resolve("xx-YY")); // Retrocede a "en-US". assert_eq!(translation, Some("Hello world!".to_string())); } @@ -53,6 +53,6 @@ async fn check_unknown_key() { let _app = service::test::init_service(Application::new().test()).await; let l10n = L10n::l("non-existent-key"); - let translation = l10n.using(LangMatch::langid_or_default("en-US")); + let translation = l10n.using(&LangMatch::resolve("en-US")); assert_eq!(translation, None); } From f03f42f6d5d090e91ee0e470aa579920c515b0d3 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 3 Aug 2025 13:15:08 +0200 Subject: [PATCH 104/244] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20Simplifica=20no?= =?UTF-8?q?mbres=20de=20traits=20esenciales?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Los traits `ExtensionTrait`, `ThemeTrait` y `ComponentTrait` pasan a ser `Extension`, `Theme`y `Component`, respectivamente, --- helpers/pagetop-build/src/lib.rs | 2 +- .../action/component/after_render_component.rs | 8 ++++---- .../component/before_render_component.rs | 8 ++++---- src/base/action/component/is_renderable.rs | 8 ++++---- src/base/action/page/after_render_body.rs | 2 +- src/base/action/page/before_render_body.rs | 2 +- .../action/theme/after_render_component.rs | 10 +++++----- .../action/theme/before_render_component.rs | 10 +++++----- src/base/action/theme/prepare_render.rs | 10 +++++----- src/base/component/html.rs | 2 +- src/base/extension/welcome.rs | 2 +- src/base/theme/basic.rs | 4 ++-- src/core/action.rs | 4 ++-- src/core/component.rs | 2 +- src/core/component/children.rs | 18 +++++++++--------- src/core/component/definition.rs | 4 ++-- src/core/extension.rs | 4 ++-- src/core/extension/definition.rs | 16 ++++++++-------- src/core/theme.rs | 9 ++++----- src/core/theme/definition.rs | 16 ++++++++-------- src/html/opt_component.rs | 8 ++++---- src/response/page.rs | 6 +++--- src/service.rs | 2 +- 23 files changed, 78 insertions(+), 79 deletions(-) diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index b0a13f33..b18cf52f 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -101,7 +101,7 @@ //! //! pub struct MyExtension; //! -//! impl ExtensionTrait for MyExtension { +//! impl Extension for MyExtension { //! // Servicio web que publica los recursos de `guides` en `/ruta/a/guides`. //! fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { //! include_files_service!(scfg, guides => "/ruta/a/guides"); diff --git a/src/base/action/component/after_render_component.rs b/src/base/action/component/after_render_component.rs index 48873f76..917f3225 100644 --- a/src/base/action/component/after_render_component.rs +++ b/src/base/action/component/after_render_component.rs @@ -3,7 +3,7 @@ use crate::prelude::*; use crate::base::action::FnActionWithComponent; /// Ejecuta [`FnActionWithComponent`] después de renderizar un componente. -pub struct AfterRender<C: ComponentTrait> { +pub struct AfterRender<C: Component> { f: FnActionWithComponent<C>, referer_type_id: Option<UniqueId>, referer_id: OptionId, @@ -11,7 +11,7 @@ pub struct AfterRender<C: ComponentTrait> { } /// Filtro para despachar [`FnActionWithComponent`] después de renderizar un componente `C`. -impl<C: ComponentTrait> ActionDispatcher for AfterRender<C> { +impl<C: Component> ActionDispatcher for AfterRender<C> { /// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`. fn referer_type_id(&self) -> Option<UniqueId> { self.referer_type_id @@ -28,8 +28,8 @@ impl<C: ComponentTrait> ActionDispatcher for AfterRender<C> { } } -impl<C: ComponentTrait> AfterRender<C> { - /// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnActionWithComponent`]. +impl<C: Component> AfterRender<C> { + /// Permite [registrar](Extension::actions) una nueva acción [`FnActionWithComponent`]. pub fn new(f: FnActionWithComponent<C>) -> Self { AfterRender { f, diff --git a/src/base/action/component/before_render_component.rs b/src/base/action/component/before_render_component.rs index 483b9160..8c2e38d7 100644 --- a/src/base/action/component/before_render_component.rs +++ b/src/base/action/component/before_render_component.rs @@ -3,7 +3,7 @@ use crate::prelude::*; use crate::base::action::FnActionWithComponent; /// Ejecuta [`FnActionWithComponent`] antes de renderizar el componente. -pub struct BeforeRender<C: ComponentTrait> { +pub struct BeforeRender<C: Component> { f: FnActionWithComponent<C>, referer_type_id: Option<UniqueId>, referer_id: OptionId, @@ -11,7 +11,7 @@ pub struct BeforeRender<C: ComponentTrait> { } /// Filtro para despachar [`FnActionWithComponent`] antes de renderizar un componente `C`. -impl<C: ComponentTrait> ActionDispatcher for BeforeRender<C> { +impl<C: Component> ActionDispatcher for BeforeRender<C> { /// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`. fn referer_type_id(&self) -> Option<UniqueId> { self.referer_type_id @@ -28,8 +28,8 @@ impl<C: ComponentTrait> ActionDispatcher for BeforeRender<C> { } } -impl<C: ComponentTrait> BeforeRender<C> { - /// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnActionWithComponent`]. +impl<C: Component> BeforeRender<C> { + /// Permite [registrar](Extension::actions) una nueva acción [`FnActionWithComponent`]. pub fn new(f: FnActionWithComponent<C>) -> Self { BeforeRender { f, diff --git a/src/base/action/component/is_renderable.rs b/src/base/action/component/is_renderable.rs index 3f0f1638..baa86f1d 100644 --- a/src/base/action/component/is_renderable.rs +++ b/src/base/action/component/is_renderable.rs @@ -8,7 +8,7 @@ use crate::prelude::*; pub type FnIsRenderable<C> = fn(component: &C, cx: &Context) -> bool; /// Con la función [`FnIsRenderable`] se puede decidir si se renderiza o no un componente. -pub struct IsRenderable<C: ComponentTrait> { +pub struct IsRenderable<C: Component> { f: FnIsRenderable<C>, referer_type_id: Option<UniqueId>, referer_id: OptionId, @@ -16,7 +16,7 @@ pub struct IsRenderable<C: ComponentTrait> { } /// Filtro para despachar [`FnIsRenderable`] para decidir si se renderiza o no un componente `C`. -impl<C: ComponentTrait> ActionDispatcher for IsRenderable<C> { +impl<C: Component> ActionDispatcher for IsRenderable<C> { /// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`. fn referer_type_id(&self) -> Option<UniqueId> { self.referer_type_id @@ -33,8 +33,8 @@ impl<C: ComponentTrait> ActionDispatcher for IsRenderable<C> { } } -impl<C: ComponentTrait> IsRenderable<C> { - /// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnIsRenderable`]. +impl<C: Component> IsRenderable<C> { + /// Permite [registrar](Extension::actions) una nueva acción [`FnIsRenderable`]. pub fn new(f: FnIsRenderable<C>) -> Self { IsRenderable { f, diff --git a/src/base/action/page/after_render_body.rs b/src/base/action/page/after_render_body.rs index 081b9aa4..0bbfeaba 100644 --- a/src/base/action/page/after_render_body.rs +++ b/src/base/action/page/after_render_body.rs @@ -22,7 +22,7 @@ impl ActionDispatcher for AfterRenderBody { } impl AfterRenderBody { - /// Permite [registrar](ExtensionTrait::actions) una nueva acción + /// Permite [registrar](Extension::actions) una nueva acción /// [`FnActionWithPage`](crate::base::action::page::FnActionWithPage). pub fn new(f: FnActionWithPage) -> Self { AfterRenderBody { f, weight: 0 } diff --git a/src/base/action/page/before_render_body.rs b/src/base/action/page/before_render_body.rs index a6e5c565..68f4af7d 100644 --- a/src/base/action/page/before_render_body.rs +++ b/src/base/action/page/before_render_body.rs @@ -22,7 +22,7 @@ impl ActionDispatcher for BeforeRenderBody { } impl BeforeRenderBody { - /// Permite [registrar](ExtensionTrait::actions) una nueva acción + /// Permite [registrar](Extension::actions) una nueva acción /// [`FnActionWithPage`](crate::base::action::page::FnActionWithPage). pub fn new(f: FnActionWithPage) -> Self { BeforeRenderBody { f, weight: 0 } diff --git a/src/base/action/theme/after_render_component.rs b/src/base/action/theme/after_render_component.rs index d33e0d2d..d0beeb45 100644 --- a/src/base/action/theme/after_render_component.rs +++ b/src/base/action/theme/after_render_component.rs @@ -3,7 +3,7 @@ use crate::prelude::*; use crate::base::action::FnActionWithComponent; /// Ejecuta [`FnActionWithComponent`] después de que un tema renderice el componente. -pub struct AfterRender<C: ComponentTrait> { +pub struct AfterRender<C: Component> { f: FnActionWithComponent<C>, theme_type_id: Option<UniqueId>, referer_type_id: Option<UniqueId>, @@ -11,7 +11,7 @@ pub struct AfterRender<C: ComponentTrait> { /// Filtro para despachar [`FnActionWithComponent`] después de que un tema renderice el componente /// `C`. -impl<C: ComponentTrait> ActionDispatcher for AfterRender<C> { +impl<C: Component> ActionDispatcher for AfterRender<C> { /// Devuelve el identificador de tipo ([`UniqueId`]) del tema. fn theme_type_id(&self) -> Option<UniqueId> { self.theme_type_id @@ -23,9 +23,9 @@ impl<C: ComponentTrait> ActionDispatcher for AfterRender<C> { } } -impl<C: ComponentTrait> AfterRender<C> { - /// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnActionWithComponent`] para - /// un tema dado. +impl<C: Component> AfterRender<C> { + /// Permite [registrar](Extension::actions) una nueva acción [`FnActionWithComponent`] para un + /// tema dado. pub fn new(theme: ThemeRef, f: FnActionWithComponent<C>) -> Self { AfterRender { f, diff --git a/src/base/action/theme/before_render_component.rs b/src/base/action/theme/before_render_component.rs index 76f6cd22..ac5ee6b2 100644 --- a/src/base/action/theme/before_render_component.rs +++ b/src/base/action/theme/before_render_component.rs @@ -3,7 +3,7 @@ use crate::prelude::*; use crate::base::action::FnActionWithComponent; /// Ejecuta [`FnActionWithComponent`] antes de que un tema renderice el componente. -pub struct BeforeRender<C: ComponentTrait> { +pub struct BeforeRender<C: Component> { f: FnActionWithComponent<C>, theme_type_id: Option<UniqueId>, referer_type_id: Option<UniqueId>, @@ -11,7 +11,7 @@ pub struct BeforeRender<C: ComponentTrait> { /// Filtro para despachar [`FnActionWithComponent`] antes de que un tema renderice el componente /// `C`. -impl<C: ComponentTrait> ActionDispatcher for BeforeRender<C> { +impl<C: Component> ActionDispatcher for BeforeRender<C> { /// Devuelve el identificador de tipo ([`UniqueId`]) del tema. fn theme_type_id(&self) -> Option<UniqueId> { self.theme_type_id @@ -23,9 +23,9 @@ impl<C: ComponentTrait> ActionDispatcher for BeforeRender<C> { } } -impl<C: ComponentTrait> BeforeRender<C> { - /// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnActionWithComponent`] para - /// un tema dado. +impl<C: Component> BeforeRender<C> { + /// Permite [registrar](Extension::actions) una nueva acción [`FnActionWithComponent`] para un + /// tema dado. pub fn new(theme: ThemeRef, f: FnActionWithComponent<C>) -> Self { BeforeRender { f, diff --git a/src/base/action/theme/prepare_render.rs b/src/base/action/theme/prepare_render.rs index 9d3e2612..4a1a2da6 100644 --- a/src/base/action/theme/prepare_render.rs +++ b/src/base/action/theme/prepare_render.rs @@ -11,14 +11,14 @@ pub type FnPrepareRender<C> = fn(component: &C, cx: &mut Context) -> PrepareMark /// Ejecuta [`FnPrepareRender`] para preparar el renderizado de un componente. /// /// Permite a un tema hacer una implementación nueva del renderizado de un componente. -pub struct PrepareRender<C: ComponentTrait> { +pub struct PrepareRender<C: Component> { f: FnPrepareRender<C>, theme_type_id: Option<UniqueId>, referer_type_id: Option<UniqueId>, } /// Filtro para despachar [`FnPrepareRender`] que modifica el renderizado de un componente `C`. -impl<C: ComponentTrait> ActionDispatcher for PrepareRender<C> { +impl<C: Component> ActionDispatcher for PrepareRender<C> { /// Devuelve el identificador de tipo ([`UniqueId`]) del tema. fn theme_type_id(&self) -> Option<UniqueId> { self.theme_type_id @@ -30,9 +30,9 @@ impl<C: ComponentTrait> ActionDispatcher for PrepareRender<C> { } } -impl<C: ComponentTrait> PrepareRender<C> { - /// Permite [registrar](ExtensionTrait::actions) una nueva acción [`FnPrepareRender`] para un - /// tema dado. +impl<C: Component> PrepareRender<C> { + /// Permite [registrar](Extension::actions) una nueva acción [`FnPrepareRender`] para un tema + /// dado. pub fn new(theme: ThemeRef, f: FnPrepareRender<C>) -> Self { PrepareRender { f, diff --git a/src/base/component/html.rs b/src/base/component/html.rs index 228bfe86..1f49b052 100644 --- a/src/base/component/html.rs +++ b/src/base/component/html.rs @@ -38,7 +38,7 @@ impl Default for Html { Html::with(|_| html! {}) } } -impl ComponentTrait for Html { +impl Component for Html { fn new() -> Self { Html::default() } diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs index 39edfd37..3dda43eb 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -7,7 +7,7 @@ use crate::prelude::*; /// funcionando correctamente. pub struct Welcome; -impl ExtensionTrait for Welcome { +impl Extension for Welcome { fn name(&self) -> L10n { L10n::l("welcome_extension_name") } diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index 4ea24604..b02abfb5 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -5,13 +5,13 @@ use crate::prelude::*; /// Tema básico por defecto. pub struct Basic; -impl ExtensionTrait for Basic { +impl Extension for Basic { fn theme(&self) -> Option<ThemeRef> { Some(&Self) } } -impl ThemeTrait for Basic { +impl Theme for Basic { fn after_render_page_body(&self, page: &mut Page) { page.alter_assets(AssetsOp::AddStyleSheet( StyleSheet::from("/css/normalize.css") diff --git a/src/core/action.rs b/src/core/action.rs index f5dc11c5..91847b0c 100644 --- a/src/core/action.rs +++ b/src/core/action.rs @@ -25,7 +25,7 @@ pub use all::dispatch_actions; /// ```rust,ignore /// use pagetop::prelude::*; /// -/// impl ExtensionTrait for MyTheme { +/// impl Extension for MyTheme { /// fn actions(&self) -> Vec<ActionBox> { /// actions_boxed![ /// action::theme::BeforeRender::<Button>::new(&Self, before_render_button), @@ -34,7 +34,7 @@ pub use all::dispatch_actions; /// } /// } /// -/// impl ThemeTrait for MyTheme {} +/// impl Theme for MyTheme {} /// /// fn before_render_button(c: &mut Button, cx: &mut Context) { todo!() } /// fn render_error404(c: &Error404, cx: &mut Context) -> PrepareMarkup { todo!() } diff --git a/src/core/component.rs b/src/core/component.rs index 36c789a8..17b9b735 100644 --- a/src/core/component.rs +++ b/src/core/component.rs @@ -1,7 +1,7 @@ //! API para construir nuevos componentes. mod definition; -pub use definition::{ComponentRender, ComponentTrait}; +pub use definition::{Component, ComponentRender}; mod children; pub use children::Children; diff --git a/src/core/component/children.rs b/src/core/component/children.rs index c5b65a26..fb85db7a 100644 --- a/src/core/component/children.rs +++ b/src/core/component/children.rs @@ -1,4 +1,4 @@ -use crate::core::component::ComponentTrait; +use crate::core::component::Component; use crate::html::{html, Context, Markup}; use crate::{builder_fn, UniqueId}; @@ -9,14 +9,14 @@ use std::vec::IntoIter; /// Representa un componente encapsulado de forma segura y compartida. /// -/// Esta estructura permite manipular y renderizar cualquier tipo que implemente [`ComponentTrait`], +/// Esta estructura permite manipular y renderizar cualquier tipo que implemente [`Component`], /// garantizando acceso concurrente a través de [`Arc<RwLock<_>>`]. #[derive(Clone)] -pub struct Child(Arc<RwLock<dyn ComponentTrait>>); +pub struct Child(Arc<RwLock<dyn Component>>); impl Child { /// Crea un nuevo [`Child`] a partir de un componente. - pub fn with(component: impl ComponentTrait) -> Self { + pub fn with(component: impl Component) -> Self { Child(Arc::new(RwLock::new(component))) } @@ -47,15 +47,15 @@ impl Child { /// Variante tipada de [`Child`] para evitar conversiones durante el uso. /// /// Facilita el acceso a componentes del mismo tipo sin necesidad de hacer `downcast`. -pub struct Typed<C: ComponentTrait>(Arc<RwLock<C>>); +pub struct Typed<C: Component>(Arc<RwLock<C>>); -impl<C: ComponentTrait> Clone for Typed<C> { +impl<C: Component> Clone for Typed<C> { fn clone(&self) -> Self { Self(self.0.clone()) } } -impl<C: ComponentTrait> Typed<C> { +impl<C: Component> Typed<C> { /// Crea un nuevo [`Typed`] a partir de un componente. pub fn with(component: C) -> Self { Typed(Arc::new(RwLock::new(component))) @@ -97,7 +97,7 @@ pub enum ChildOp { } /// Operaciones con un componente hijo tipado [`Typed<C>`] en una lista [`Children`]. -pub enum TypedOp<C: ComponentTrait> { +pub enum TypedOp<C: Component> { Add(Typed<C>), InsertAfterId(&'static str, Typed<C>), InsertBeforeId(&'static str, Typed<C>), @@ -153,7 +153,7 @@ impl Children { /// Ejecuta una operación con [`TypedOp`] en la lista. #[builder_fn] - pub fn with_typed<C: ComponentTrait + Default>(mut self, op: TypedOp<C>) -> Self { + pub fn with_typed<C: Component + Default>(mut self, op: TypedOp<C>) -> Self { match op { TypedOp::Add(typed) => self.add(typed.into_child()), TypedOp::InsertAfterId(id, typed) => self.insert_after_id(id, typed.into_child()), diff --git a/src/core/component/definition.rs b/src/core/component/definition.rs index a9a4f815..e64e6160 100644 --- a/src/core/component/definition.rs +++ b/src/core/component/definition.rs @@ -5,7 +5,7 @@ use crate::html::{html, Context, Markup, PrepareMarkup, Render}; /// Define la función de renderizado para todos los componentes. /// /// Este *trait* se implementa automáticamente en cualquier tipo (componente) que implemente -/// [`ComponentTrait`], por lo que no requiere ninguna codificación manual. +/// [`Component`], por lo que no requiere ninguna codificación manual. pub trait ComponentRender { /// Renderiza el componente usando el contexto proporcionado. fn render(&mut self, cx: &mut Context) -> Markup; @@ -86,7 +86,7 @@ pub trait ComponentTrait: AnyInfo + ComponentRender + Send + Sync { /// 7. Despacha [`action::component::AfterRender<C>`](crate::base::action::component::AfterRender) /// para que otras extensiones puedan hacer sus últimos ajustes. /// 8. Finalmente devuelve un [`Markup`] del renderizado preparado en el paso 5. -impl<C: ComponentTrait> ComponentRender for C { +impl<C: Component> ComponentRender for C { fn render(&mut self, cx: &mut Context) -> Markup { // Si no es renderizable, devuelve un bloque HTML vacío. if !action::component::IsRenderable::dispatch(self, cx) { diff --git a/src/core/extension.rs b/src/core/extension.rs index c493cf5c..cabae5cd 100644 --- a/src/core/extension.rs +++ b/src/core/extension.rs @@ -1,9 +1,9 @@ //! API para añadir nuevas funcionalidades usando extensiones. //! //! Cada funcionalidad adicional que quiera incorporarse a una aplicación `PageTop` se debe modelar -//! como una **extensión**. Todas comparten la misma interfaz declarada en [`ExtensionTrait`]. +//! como una **extensión**. Todas comparten la misma interfaz declarada en [`Extension`]. mod definition; -pub use definition::{ExtensionRef, ExtensionTrait}; +pub use definition::{Extension, ExtensionRef}; pub(crate) mod all; diff --git a/src/core/extension/definition.rs b/src/core/extension/definition.rs index 2d9f6dda..195e2e51 100644 --- a/src/core/extension/definition.rs +++ b/src/core/extension/definition.rs @@ -8,7 +8,7 @@ use crate::{actions_boxed, service}; /// /// Las extensiones se definen como instancias estáticas globales para poder acceder a ellas desde /// cualquier hilo de la ejecución sin necesidad de sincronización adicional. -pub type ExtensionRef = &'static dyn ExtensionTrait; +pub type ExtensionRef = &'static dyn Extension; /// Interfaz común que debe implementar cualquier extensión de `PageTop`. /// @@ -20,12 +20,12 @@ pub type ExtensionRef = &'static dyn ExtensionTrait; /// /// pub struct Blog; /// -/// impl ExtensionTrait for Blog { +/// impl Extension for Blog { /// fn name(&self) -> L10n { L10n::n("Blog") } /// fn description(&self) -> L10n { L10n::n("Sistema de blogs") } /// } /// ``` -pub trait ExtensionTrait: AnyInfo + Send + Sync { +pub trait Extension: AnyInfo + Send + Sync { /// Nombre legible para el usuario. /// /// Predeterminado por el [`short_name`](AnyInfo::short_name) del tipo asociado a la extensión. @@ -38,8 +38,8 @@ pub trait ExtensionTrait: AnyInfo + Send + Sync { L10n::default() } - /// Los temas son extensiones que implementan [`ExtensionTrait`] y también - /// [`ThemeTrait`](crate::core::theme::ThemeTrait). + /// Los temas son extensiones que implementan [`Extension`] y también + /// [`Theme`](crate::core::theme::Theme). /// /// Si la extensión no es un tema, este método devuelve `None` por defecto. /// @@ -51,13 +51,13 @@ pub trait ExtensionTrait: AnyInfo + Send + Sync { /// /// pub struct MyTheme; /// - /// impl ExtensionTrait for MyTheme { + /// impl Extension for MyTheme { /// fn theme(&self) -> Option<ThemeRef> { /// Some(&Self) /// } /// } /// - /// impl ThemeTrait for MyTheme {} + /// impl Theme for MyTheme {} /// ``` fn theme(&self) -> Option<ThemeRef> { None @@ -94,7 +94,7 @@ pub trait ExtensionTrait: AnyInfo + Send + Sync { /// /// pub struct ExtensionSample; /// - /// impl ExtensionTrait for ExtensionSample { + /// impl Extension for ExtensionSample { /// fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { /// scfg.route("/sample", web::get().to(route_sample)); /// } diff --git a/src/core/theme.rs b/src/core/theme.rs index 35d9887d..0a0f8199 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -9,13 +9,12 @@ //! tipografías, espaciados y cualquier otro detalle visual o de comportamiento (como animaciones, //! *scripts* de interfaz, etc.). //! -//! Es una extensión más (implementando [`ExtensionTrait`](crate::core::extension::ExtensionTrait)). -//! Se instala, activa y declara dependencias igual que el resto de extensiones; y se señala a sí -//! misma como tema (implementando [`theme()`](crate::core::extension::ExtensionTrait::theme) -//! y [`ThemeTrait`]). +//! Es una extensión más (implementando [`Extension`](crate::core::extension::Extension)). Se +//! instala, activa y declara dependencias igual que el resto de extensiones; y se señala a sí misma +//! como tema (implementando [`theme()`](crate::core::extension::Extension::theme) y [`Theme`]). mod definition; -pub use definition::{ThemeRef, ThemeTrait}; +pub use definition::{Theme, ThemeRef}; mod regions; pub(crate) use regions::ChildrenInRegions; diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 075ce204..8de88bdd 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -1,4 +1,4 @@ -use crate::core::extension::ExtensionTrait; +use crate::core::extension::Extension; use crate::core::theme::CONTENT_REGION_NAME; use crate::global; use crate::html::{html, Markup}; @@ -8,20 +8,20 @@ use crate::response::page::Page; /// Representa una referencia a un tema. /// /// Los temas son también extensiones. Por tanto se deben definir igual, es decir, como instancias -/// estáticas globales que implementan [`ThemeTrait`], pero también [`ExtensionTrait`]. -pub type ThemeRef = &'static dyn ThemeTrait; +/// estáticas globales que implementan [`Theme`], pero también [`Extension`]. +pub type ThemeRef = &'static dyn Theme; /// Interfaz común que debe implementar cualquier tema de `PageTop`. /// -/// Un tema implementará [`ThemeTrait`] y los métodos que sean necesarios de [`ExtensionTrait`], -/// aunque el único obligatorio es [`theme()`](ExtensionTrait::theme). +/// Un tema implementará [`Theme`] y los métodos que sean necesarios de [`Extension`], aunque el +/// único obligatorio es [`theme()`](Extension::theme). /// /// ```rust /// use pagetop::prelude::*; /// /// pub struct MyTheme; /// -/// impl ExtensionTrait for MyTheme { +/// impl Extension for MyTheme { /// fn name(&self) -> L10n { L10n::n("My theme") } /// fn description(&self) -> L10n { L10n::n("Un tema personal") } /// @@ -30,9 +30,9 @@ pub type ThemeRef = &'static dyn ThemeTrait; /// } /// } /// -/// impl ThemeTrait for MyTheme {} +/// impl Theme for MyTheme {} /// ``` -pub trait ThemeTrait: ExtensionTrait + Send + Sync { +pub trait Theme: Extension + Send + Sync { fn regions(&self) -> Vec<(&'static str, L10n)> { vec![(CONTENT_REGION_NAME, L10n::l("content"))] } diff --git a/src/html/opt_component.rs b/src/html/opt_component.rs index 9e116cd2..39106d99 100644 --- a/src/html/opt_component.rs +++ b/src/html/opt_component.rs @@ -1,5 +1,5 @@ use crate::builder_fn; -use crate::core::component::{ComponentTrait, Typed}; +use crate::core::component::{Component, Typed}; use crate::html::{html, Context, Markup}; /// Contenedor de componente para incluir en otros componentes. @@ -16,15 +16,15 @@ use crate::html::{html, Context, Markup}; /// let opt = OptionComponent::new(comp); /// assert!(opt.get().is_some()); /// ``` -pub struct OptionComponent<C: ComponentTrait>(Option<Typed<C>>); +pub struct OptionComponent<C: Component>(Option<Typed<C>>); -impl<C: ComponentTrait> Default for OptionComponent<C> { +impl<C: Component> Default for OptionComponent<C> { fn default() -> Self { OptionComponent(None) } } -impl<C: ComponentTrait> OptionComponent<C> { +impl<C: Component> OptionComponent<C> { /// Crea un nuevo [`OptionComponent`]. /// /// El componente se envuelve automáticamente en un [`Typed`] y se almacena. diff --git a/src/response/page.rs b/src/response/page.rs index c1815d09..1b1c0de1 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -5,7 +5,7 @@ pub use actix_web::Result as ResultPage; use crate::base::action; use crate::builder_fn; -use crate::core::component::{Child, ChildOp, ComponentTrait}; +use crate::core::component::{Child, ChildOp, Component}; use crate::core::theme::{ChildrenInRegions, ThemeRef, CONTENT_REGION_NAME}; use crate::html::{html, AssetsOp, Context, Markup, DOCTYPE}; use crate::html::{ClassesOp, OptionClasses, OptionId, OptionTranslated}; @@ -121,7 +121,7 @@ impl Page { } /// Añade un componente a la región de contenido por defecto. - pub fn with_component(mut self, component: impl ComponentTrait) -> Self { + pub fn with_component(mut self, component: impl Component) -> Self { self.regions .alter_child_in_region(CONTENT_REGION_NAME, ChildOp::Add(Child::with(component))); self @@ -131,7 +131,7 @@ impl Page { pub fn with_component_in( mut self, region_name: &'static str, - component: impl ComponentTrait, + component: impl Component, ) -> Self { self.regions .alter_child_in_region(region_name, ChildOp::Add(Child::with(component))); diff --git a/src/service.rs b/src/service.rs index 68c8d5d1..261955cb 100644 --- a/src/service.rs +++ b/src/service.rs @@ -88,7 +88,7 @@ macro_rules! include_files { /// /// pub struct MyExtension; /// -/// impl ExtensionTrait for MyExtension { +/// impl Extension for MyExtension { /// fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { /// include_files_service!(scfg, assets => "/public"); /// } From dfd100c842c1e246e781a93954fc76d257b7a586 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 3 Aug 2025 13:36:00 +0200 Subject: [PATCH 105/244] =?UTF-8?q?=F0=9F=92=A1=20Retoques=20menores=20en?= =?UTF-8?q?=20comentarios=20para=20documentar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-macros/src/lib.rs | 2 +- src/app.rs | 8 ++++---- src/base/component/html.rs | 10 +++++----- src/core/action.rs | 3 +-- src/core/component/definition.rs | 14 +++++++------- src/core/extension/definition.rs | 3 ++- src/core/theme/all.rs | 2 +- src/global.rs | 4 ++-- src/html/assets/favicon.rs | 4 ++-- src/html/assets/javascript.rs | 4 ++-- src/html/assets/stylesheet.rs | 4 ++-- src/html/context.rs | 6 +++--- src/locale.rs | 4 ++-- src/response/page.rs | 6 +++--- src/service.rs | 3 ++- 15 files changed, 39 insertions(+), 38 deletions(-) diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 301f4831..b9be0bea 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -175,7 +175,7 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { // Genera el método alter_...() con el código del método with_...(). let fn_alter_doc = format!( - "Igual que [`{0}()`](Self::{0}), pero sin usar el patrón *builder*.", + "Igual que [`Self::{0}()`](Self::{0}), pero sin usar el patrón *builder*.", fn_with_name_str, ); let fn_alter = quote! { diff --git a/src/app.rs b/src/app.rs index 6b11c0fd..c3576fc5 100644 --- a/src/app.rs +++ b/src/app.rs @@ -16,10 +16,10 @@ use std::sync::LazyLock; /// Punto de entrada de una aplicación `PageTop`. /// -/// No almacena datos, pero **encapsula** el ciclo completo de configuración y puesta en marcha. -/// Para instanciarla se puede usar [`new`](Application::new) o [`prepare`](Application::prepare). -/// Después sólo hay que llamar a [`run`](Application::run) (o a [`test`](Application::test) si se -/// está preparando un entorno de pruebas). +/// No almacena datos, **encapsula** el inicio completo de configuración y puesta en marcha. Para +/// instanciarla se puede usar [`new()`](Application::new) o [`prepare()`](Application::prepare). +/// Después sólo hay que llamar a [`run()`](Application::run) para ejecutar la aplicación (o a +/// [`test()`](Application::test) si se está preparando un entorno de pruebas). pub struct Application; impl Default for Application { diff --git a/src/base/component/html.rs b/src/base/component/html.rs index 1f49b052..8f273edb 100644 --- a/src/base/component/html.rs +++ b/src/base/component/html.rs @@ -51,9 +51,9 @@ impl Component for Html { impl Html { /// Crea una instancia que generará el `Markup`, con acceso opcional al contexto. /// - /// El método [`prepare_component`](crate::core::component::ComponentTrait::prepare_component) - /// delega el renderizado en la función proporcionada, que recibe una referencia mutable - /// al contexto de renderizado ([`Context`]). + /// El método [`prepare_component()`](crate::core::component::Component::prepare_component) + /// delega el renderizado en la función proporcionada, que recibe una referencia mutable al + /// contexto de renderizado ([`Context`]). pub fn with<F>(f: F) -> Self where F: Fn(&mut Context) -> Markup + Send + Sync + 'static, @@ -64,8 +64,8 @@ impl Html { /// Sustituye la función que genera el `Markup`. /// /// Permite a otras extensiones modificar la función de renderizado que se ejecutará cuando - /// [`prepare_component`](crate::core::component::ComponentTrait::prepare_component) invoque - /// esta instancia. La nueva función también recibe una referencia al contexto ([`Context`]). + /// [`prepare_component()`](crate::core::component::Component::prepare_component) invoque esta + /// instancia. La nueva función también recibe una referencia al contexto ([`Context`]). pub fn alter_html<F>(&mut self, f: F) -> &mut Self where F: Fn(&mut Context) -> Markup + Send + Sync + 'static, diff --git a/src/core/action.rs b/src/core/action.rs index 91847b0c..cbbe79c0 100644 --- a/src/core/action.rs +++ b/src/core/action.rs @@ -14,8 +14,7 @@ mod all; pub(crate) use all::add_action; pub use all::dispatch_actions; -/// Facilita la implementación del método -/// [`actions()`](crate::core::extension::ExtensionTrait::actions). +/// Facilita la implementación del método [`actions()`](crate::core::extension::Extension::actions). /// /// Evita escribir repetidamente `Box::new(...)` para cada acción de la lista, manteniendo el código /// más limpio. diff --git a/src/core/component/definition.rs b/src/core/component/definition.rs index e64e6160..2818570a 100644 --- a/src/core/component/definition.rs +++ b/src/core/component/definition.rs @@ -14,9 +14,9 @@ pub trait ComponentRender { /// Interfaz común que debe implementar un componente renderizable en `PageTop`. /// /// Se recomienda que los componentes deriven [`AutoDefault`](crate::AutoDefault). También deben -/// implementar explícitamente el método [`new`](Self::new) y pueden sobrescribir los otros métodos -/// para personalizar su comportamiento. -pub trait ComponentTrait: AnyInfo + ComponentRender + Send + Sync { +/// implementar explícitamente el método [`new()`](Self::new) y pueden sobrescribir los otros +/// métodos para personalizar su comportamiento. +pub trait Component: AnyInfo + ComponentRender + Send + Sync { /// Crea una nueva instancia del componente. fn new() -> Self where @@ -70,8 +70,8 @@ pub trait ComponentTrait: AnyInfo + ComponentRender + Send + Sync { /// /// 1. Despacha [`action::component::IsRenderable`](crate::base::action::component::IsRenderable) /// para ver si se puede renderizar. Si no es así, devuelve un [`Markup`] vacío. -/// 2. Ejecuta [`setup_before_prepare()`](ComponentTrait::setup_before_prepare) para que el -/// componente pueda ajustar su estructura interna o modificar el contexto. +/// 2. Ejecuta [`setup_before_prepare()`](Component::setup_before_prepare) para que el componente +/// pueda ajustar su estructura interna o modificar el contexto. /// 3. Despacha [`action::theme::BeforeRender<C>`](crate::base::action::theme::BeforeRender) para /// que el tema pueda hacer ajustes en el componente o el contexto. /// 4. Despacha [`action::component::BeforeRender<C>`](crate::base::action::component::BeforeRender) @@ -79,8 +79,8 @@ pub trait ComponentTrait: AnyInfo + ComponentRender + Send + Sync { /// 5. **Prepara el renderizado del componente**: /// - Despacha [`action::theme::PrepareRender<C>`](crate::base::action::theme::PrepareRender) /// para permitir al tema preparar un renderizado diferente al predefinido. -/// - Si no es así, ejecuta [`prepare_component()`](ComponentTrait::prepare_component) para -/// preparar el renderizado predefinido del componente. +/// - Si no es así, ejecuta [`prepare_component()`](Component::prepare_component) para preparar +/// el renderizado predefinido del componente. /// 6. Despacha [`action::theme::AfterRender<C>`](crate::base::action::theme::AfterRender) para /// que el tema pueda hacer sus últimos ajustes. /// 7. Despacha [`action::component::AfterRender<C>`](crate::base::action::component::AfterRender) diff --git a/src/core/extension/definition.rs b/src/core/extension/definition.rs index 195e2e51..ac292592 100644 --- a/src/core/extension/definition.rs +++ b/src/core/extension/definition.rs @@ -28,7 +28,8 @@ pub type ExtensionRef = &'static dyn Extension; pub trait Extension: AnyInfo + Send + Sync { /// Nombre legible para el usuario. /// - /// Predeterminado por el [`short_name`](AnyInfo::short_name) del tipo asociado a la extensión. + /// Predeterminado por el [`short_name()`](AnyInfo::short_name) del tipo asociado a la + /// extensión. fn name(&self) -> L10n { L10n::n(self.short_name()) } diff --git a/src/core/theme/all.rs b/src/core/theme/all.rs index 787e0c9d..ebb28481 100644 --- a/src/core/theme/all.rs +++ b/src/core/theme/all.rs @@ -19,7 +19,7 @@ pub static DEFAULT_THEME: LazyLock<ThemeRef> = // TEMA POR NOMBRE ********************************************************************************* -/// Devuelve el tema identificado por su [`short_name`](AnyInfo::short_name). +// Devuelve el tema identificado por su [`short_name()`](AnyInfo::short_name). pub fn theme_by_short_name(short_name: &'static str) -> Option<ThemeRef> { let short_name = short_name.to_lowercase(); match THEMES diff --git a/src/global.rs b/src/global.rs index 25a17811..ea659b8b 100644 --- a/src/global.rs +++ b/src/global.rs @@ -53,8 +53,8 @@ pub struct App { /// Si no se especifica un valor válido, normalmente se usará el idioma devuelto por la /// implementación de [`LangId`](crate::locale::LangId) para [`Context`](crate::html::Context), /// en el siguiente orden: primero, el idioma establecido explícitamente con - /// [`Context::with_langid`](crate::html::Context::with_langid); si no se ha definido, se usará - /// el indicado en la cabecera `Accept-Language` del navegador; y, si ninguno aplica, se + /// [`Context::with_langid()`](crate::html::Context::with_langid); si no se ha definido, se + /// usará el indicado en la cabecera `Accept-Language` del navegador; y, si ninguno aplica, se /// empleará el idioma de respaldo ("en-US"). pub language: String, /// Banner ASCII mostrado al inicio: *"Off"* (desactivado), *"Slant"*, *"Small"*, *"Speed"* o diff --git a/src/html/assets/favicon.rs b/src/html/assets/favicon.rs index d02794eb..2af01730 100644 --- a/src/html/assets/favicon.rs +++ b/src/html/assets/favicon.rs @@ -12,8 +12,8 @@ use crate::AutoDefault; /// /// > **Nota** /// > Los archivos de los iconos deben estar disponibles en el servidor web de la aplicación. Pueden -/// > incluirse en el proyecto utilizando [`include_files`](crate::include_files) y servirse con -/// > [`include_files_service`](crate::include_files_service). +/// > incluirse en el proyecto utilizando [`include_files!`](crate::include_files) y servirse con +/// > [`include_files_service!`](crate::include_files_service). /// /// # Ejemplo /// diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs index 882b3aff..604e85ae 100644 --- a/src/html/assets/javascript.rs +++ b/src/html/assets/javascript.rs @@ -30,8 +30,8 @@ enum Source { /// /// > **Nota** /// > Los archivos de los *scripts* deben estar disponibles en el servidor web de la aplicación. -/// > Pueden incluirse en el proyecto utilizando [`include_files`](crate::include_files) y servirse -/// > con [`include_files_service`](crate::include_files_service). +/// > Pueden incluirse en el proyecto utilizando [`include_files!`](crate::include_files) y servirse +/// > con [`include_files_service!`](crate::include_files_service). /// /// # Ejemplo /// diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index dca5d869..72a79a10 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -55,8 +55,8 @@ impl TargetMedia { /// /// > **Nota** /// > Las hojas de estilo CSS deben estar disponibles en el servidor web de la aplicación. Pueden -/// > incluirse en el proyecto utilizando [`include_files`](crate::include_files) y servirse con -/// > [`include_files_service`](crate::include_files_service). +/// > incluirse en el proyecto utilizando [`include_files!`](crate::include_files) y servirse con +/// > [`include_files_service!`](crate::include_files_service). /// /// # Ejemplo /// diff --git a/src/html/context.rs b/src/html/context.rs index 8aaeb4af..5fbb39b5 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -163,7 +163,7 @@ impl Context { /// Modifica el tema que se usará para renderizar el documento. /// - /// Localiza el tema por su [`short_name`](crate::core::AnyInfo::short_name), y si no aplica + /// Localiza el tema por su [`short_name()`](crate::core::AnyInfo::short_name), y si no aplica /// ninguno entonces usará el tema por defecto. #[builder_fn] pub fn with_theme(mut self, theme_name: &'static str) -> Self { @@ -301,8 +301,8 @@ impl Context { /// 4. Y si ninguna de las opciones anteriores aplica, se usa el idioma de respaldo (`"en-US"`). /// /// Resulta útil para usar un contexto ([`Context`]) como fuente de traducción en -/// [`L10n::using`](crate::locale::L10n::using) o -/// [`L10n::to_markup`](crate::locale::L10n::to_markup). +/// [`L10n::using()`](crate::locale::L10n::using) o +/// [`L10n::to_markup()`](crate::locale::L10n::to_markup). impl LangId for Context { fn langid(&self) -> &'static LanguageIdentifier { self.langid diff --git a/src/locale.rs b/src/locale.rs index d81243e6..f23f51ee 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -259,8 +259,8 @@ impl LangMatch { /// devuelve el idioma por defecto de la aplicación y, si tampoco está disponible, el idioma de /// respaldo ("en-US"). /// -/// Resulta útil para usar un valor de [`LangMatch`] como fuente de traducción en [`L10n::using`] o -/// [`L10n::to_markup`]. +/// Resulta útil para usar un valor de [`LangMatch`] como fuente de traducción en [`L10n::using()`] +/// o [`L10n::to_markup()`]. impl LangId for LangMatch { fn langid(&self) -> &'static LanguageIdentifier { match self { diff --git a/src/response/page.rs b/src/response/page.rs index 1b1c0de1..44cab725 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -78,21 +78,21 @@ impl Page { self } - /// Modifica la fuente de idioma de la página ([`Context::with_langid`]). + /// Modifica la fuente de idioma de la página ([`Context::with_langid()`]). #[builder_fn] pub fn with_langid(mut self, language: &impl LangId) -> Self { self.context.alter_langid(language); self } - /// Modifica el tema que se usará para renderizar la página ([`Context::with_theme`]). + /// Modifica el tema que se usará para renderizar la página ([`Context::with_theme()`]). #[builder_fn] pub fn with_theme(mut self, theme_name: &'static str) -> Self { self.context.alter_theme(theme_name); self } - /// Modifica la composición para renderizar la página ([`Context::with_layout`]). + /// Modifica la composición para renderizar la página ([`Context::with_layout()`]). #[builder_fn] pub fn with_layout(mut self, layout_name: &'static str) -> Self { self.context.alter_layout(layout_name); diff --git a/src/service.rs b/src/service.rs index 261955cb..89ba4966 100644 --- a/src/service.rs +++ b/src/service.rs @@ -77,7 +77,8 @@ macro_rules! include_files { /// * `$route` – Ruta URL de origen desde la que se servirán los archivos. /// * `[ $root, $relative ]` *(opcional)* – Directorio raíz y ruta relativa para construir la ruta /// absoluta donde buscar los archivos en el sistema de ficheros (ver -/// [`absolute_dir`](crate::util::absolute_dir)). Si no existe, se usarán los recursos embebidos. +/// [`absolute_dir()`](crate::util::absolute_dir)). Si no existe, se usarán los recursos +/// embebidos. /// /// # Ejemplos /// From 867b307fc61746f512a9418a53da09a9eb7c2b80 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 3 Aug 2025 14:17:22 +0200 Subject: [PATCH 106/244] =?UTF-8?q?=F0=9F=9A=A7=20(pagetop):=20Preparando?= =?UTF-8?q?=20liberaci=C3=B3n=20de=20la=20v0.1.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CREDITS.md | 34 ++++++++++++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 64 +++++++++++++++++++++++++++++++++++++++++ examples/hello-name.rs | 24 ++++++++++++++++ examples/hello-world.rs | 20 +++++++++++++ 6 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 CREDITS.md create mode 100644 examples/hello-name.rs create mode 100644 examples/hello-world.rs diff --git a/CREDITS.md b/CREDITS.md new file mode 100644 index 00000000..5e89b868 --- /dev/null +++ b/CREDITS.md @@ -0,0 +1,34 @@ +# 🔃 Dependencias + +`PageTop` está basado en [Rust](https://www.rust-lang.org/) y crece a hombros de gigantes +aprovechando algunas de las librerías más robustas y populares del [ecosistema Rust](https://lib.rs) +como son: + + * [Actix Web](https://actix.rs/) para los servicios web. + * [Config](https://docs.rs/config) para cargar y procesar las opciones de configuración. + * [Tracing](https://github.com/tokio-rs/tracing) para la gestión de trazas y registro de eventos + de la aplicación. + * [Fluent templates](https://github.com/XAMPPRocky/fluent-templates), que integra + [Fluent](https://projectfluent.org/) para internacionalizar las aplicaciones. + * Además de otros crates adicionales que se pueden explorar en los archivos `Cargo.toml` de + `PageTop` y sus extensiones. + + +# 🗚 FIGfonts + +`PageTop` usa el *crate* [figlet-rs](https://crates.io/crates/figlet-rs) desarrollado por +*yuanbohan* para mostrar un banner de presentación en el terminal con el nombre de la aplicación en +caracteres [FIGlet](http://www.figlet.org). Las fuentes incluidas en `pagetop/src/app` son: + + * [slant.flf](http://www.figlet.org/fontdb_example.cgi?font=slant.flf) de *Glenn Chappell* + * [small.flf](http://www.figlet.org/fontdb_example.cgi?font=small.flf) de *Glenn Chappell* + (predeterminada) + * [speed.flf](http://www.figlet.org/fontdb_example.cgi?font=speed.flf) de *Claude Martins* + * [starwars.flf](http://www.figlet.org/fontdb_example.cgi?font=starwars.flf) de *Ryan Youck* + + +# 🎨 Icono + +"La Criatura" sonriente es una simpática creación de [Webalys](https://www.iconfinder.com/webalys). +Forma parte de su colección [Nasty Icons](https://www.iconfinder.com/iconsets/nasty), disponible en +[ICONFINDER](https://www.iconfinder.com). diff --git a/Cargo.lock b/Cargo.lock index 20087bf9..906b338c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1569,7 +1569,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.0.14" +version = "0.0.61" dependencies = [ "actix-files", "actix-session", diff --git a/Cargo.toml b/Cargo.toml index 476168dc..6844b7b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.14" +version = "0.0.61" edition = "2021" description = """\ diff --git a/README.md b/README.md index 6b4aff0c..2619cb66 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,25 @@ <p>Un entorno para el desarrollo de soluciones web modulares, extensibles y configurables.</p> [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +[![Doc API](https://img.shields.io/docsrs/pagetop?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop) +[![Crates.io](https://img.shields.io/crates/v/pagetop.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop) +[![Descargas](https://img.shields.io/crates/d/pagetop.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop) </div> `PageTop` reivindica la esencia de la web clásica usando [Rust](https://www.rust-lang.org/es) para la creación de soluciones web SSR (*renderizadas en el servidor*) basadas en HTML, CSS y JavaScript. +Ofrece un conjunto de herramientas que los desarrolladores pueden implementar, extender o adaptar +según las necesidades de cada proyecto, incluyendo: + + * **Acciones** (*actions*): alteran la lógica interna de una funcionalidad interceptando su flujo + de ejecución. + * **Componentes** (*components*): encapsulan HTML, CSS y JavaScript en unidades funcionales, + configurables y reutilizables. + * **Extensiones** (*extensions*): añaden, extienden o personalizan funcionalidades usando las APIs + de `PageTop` o de terceros. + * **Temas** (*themes*): son extensiones que permiten modificar la apariencia de páginas y + componentes sin comprometer su funcionalidad. # ⚡️ Guía rápida @@ -27,6 +41,55 @@ async fn main() -> std::io::Result<()> { } ``` +Sólo con esto, este código sirve por defecto una página web de bienvenida accesible desde un +navegador en la dirección `http://localhost:8080` con la configuración predeterminada. + +Para personalizar el servicio, se puede crear una extensión de `PageTop` de la siguiente manera: + +```rust +use pagetop::prelude::*; + +struct HelloWorld; + +impl Extension for HelloWorld { + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + scfg.route("/", service::web::get().to(hello_world)); + } +} + +async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { + Page::new(Some(request)) + .with_component(Html::with(move |_| html! { h1 { "Hello World!" } })) + .render() +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&HelloWorld).run()?.await +} +``` + +Este programa implementa una extensión llamada `HelloWorld` que sirve una página web en la ruta raíz +(`/`) mostrando el texto "Hello world!" dentro de un elemento HTML `<h1>`. + + +# 📂 Repositorio + +El código se organiza en un *workspace* donde actualmente se incluyen los siguientes subproyectos: + + * **[pagetop](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/src)**, con el código + fuente de la librería principal. Reúne algunos de los *crates* más estables y populares del + ecosistema Rust para proporcionar APIs y recursos para la creación avanzada de soluciones web. + +## Auxiliares + + * **[pagetop-build](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-build)**, + permite incluir fácilmente archivos estáticos o archivos SCSS compilados directamente en el + binario de las aplicaciones `PageTop`. + + * **[pagetop-macros](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-macros)**, + proporciona una colección de macros que mejoran la experiencia de desarrollo con `PageTop`. + # 🧪 Pruebas @@ -37,6 +100,7 @@ Para simplificar el flujo de trabajo, el repositorio incluye varios **alias de C | ------- | ----------- | | `cargo ts` | Ejecuta los tests de `pagetop` (*unit + integration*) con la *feature* `testing`. | | `cargo ts --test util` | Lanza sólo las pruebas de integración del módulo `util`. | +| `cargo ts --doc locale` | Lanza las pruebas de la documentación del módulo `locale`. | | `cargo tw` | Ejecuta los tests de **todos los paquetes** del *workspace*. | > **Nota** diff --git a/examples/hello-name.rs b/examples/hello-name.rs new file mode 100644 index 00000000..7a6db545 --- /dev/null +++ b/examples/hello-name.rs @@ -0,0 +1,24 @@ +use pagetop::prelude::*; + +struct HelloName; + +impl Extension for HelloName { + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + scfg.route("/hello/{name}", service::web::get().to(hello_name)); + } +} + +async fn hello_name( + request: HttpRequest, + path: service::web::Path<String>, +) -> ResultPage<Markup, ErrorPage> { + let name = path.into_inner(); + Page::new(Some(request)) + .with_component(Html::with(move |_| html! { h1 { "Hello " (name) "!" } })) + .render() +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&HelloName).run()?.await +} diff --git a/examples/hello-world.rs b/examples/hello-world.rs new file mode 100644 index 00000000..ba268dcd --- /dev/null +++ b/examples/hello-world.rs @@ -0,0 +1,20 @@ +use pagetop::prelude::*; + +struct HelloWorld; + +impl Extension for HelloWorld { + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + scfg.route("/", service::web::get().to(hello_world)); + } +} + +async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { + Page::new(Some(request)) + .with_component(Html::with(move |_| html! { h1 { "Hello World!" } })) + .render() +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&HelloWorld).run()?.await +} From bc1328546af7e37b54386836738509392ff33258 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 3 Aug 2025 18:00:02 +0200 Subject: [PATCH 107/244] =?UTF-8?q?=F0=9F=9A=A7=20Normaliza=20versiones=20?= =?UTF-8?q?a=20las=20=C3=BAltimas=20publicaciones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revisa y completa la documentación general. --- Cargo.lock | 4 +-- Cargo.toml | 4 +-- README.md | 4 +-- helpers/pagetop-build/Cargo.toml | 8 ++--- helpers/pagetop-build/README.md | 3 ++ helpers/pagetop-build/src/lib.rs | 3 ++ helpers/pagetop-macros/Cargo.toml | 6 ++-- helpers/pagetop-macros/README.md | 3 ++ helpers/pagetop-macros/src/lib.rs | 3 ++ src/lib.rs | 56 ++++++++++++++++++++++++++++++- 10 files changed, 80 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 906b338c..7cba8b96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "pagetop-build" -version = "0.0.1" +version = "0.0.16" dependencies = [ "grass", "static-files", @@ -1608,7 +1608,7 @@ dependencies = [ [[package]] name = "pagetop-macros" -version = "0.0.5" +version = "0.0.18" dependencies = [ "proc-macro2", "proc-macro2-diagnostics", diff --git a/Cargo.toml b/Cargo.toml index 6844b7b7..a1a6bfc7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,8 @@ name = "pagetop" version = "0.0.61" edition = "2021" -description = """\ - Un entorno de desarrollo para crear soluciones web modulares, extensibles y configurables.\ +description = """ + Un entorno de desarrollo para crear soluciones web modulares, extensibles y configurables. """ categories = ["web-programming", "gui", "development-tools", "asynchronous"] keywords = ["pagetop", "web", "framework", "frontend", "ssr"] diff --git a/README.md b/README.md index 2619cb66..e671b50b 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,8 @@ async fn main() -> std::io::Result<()> { } ``` -Sólo con esto, este código sirve por defecto una página web de bienvenida accesible desde un -navegador en la dirección `http://localhost:8080` con la configuración predeterminada. +Este código arranca el servidor de `PageTop` que, con la configuración por defecto, muestra una +página de bienvenida accesible desde un navegador local en `http://localhost:8080`. Para personalizar el servicio, se puede crear una extensión de `PageTop` de la siguiente manera: diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index 4b947b3e..c6d9d519 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "pagetop-build" -version = "0.0.1" +version = "0.0.16" edition = "2021" -description = """\ - Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el \ - binario de un proyecto PageTop.\ +description = """ + Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el + binario de un proyecto PageTop. """ categories = ["development-tools::build-utils", "web-programming"] keywords = ["pagetop", "build", "assets", "resources", "static"] diff --git a/helpers/pagetop-build/README.md b/helpers/pagetop-build/README.md index 9f912e99..27c98147 100644 --- a/helpers/pagetop-build/README.md +++ b/helpers/pagetop-build/README.md @@ -5,6 +5,9 @@ <p>Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el binario de un proyecto <strong>PageTop</strong>.</p> [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +[![Doc API](https://img.shields.io/docsrs/pagetop-build?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-build) +[![Crates.io](https://img.shields.io/crates/v/pagetop-build.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-build) +[![Descargas](https://img.shields.io/crates/d/pagetop-build.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-build) </div> diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index b18cf52f..90898dd3 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -5,6 +5,9 @@ //! <p>Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el binario de un proyecto <strong>PageTop</strong>.</p> //! //! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +//! [![Doc API](https://img.shields.io/docsrs/pagetop-build?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-build) +//! [![Crates.io](https://img.shields.io/crates/v/pagetop-build.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-build) +//! [![Descargas](https://img.shields.io/crates/d/pagetop-build.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-build) //! //! </div> //! diff --git a/helpers/pagetop-macros/Cargo.toml b/helpers/pagetop-macros/Cargo.toml index 3a7fd950..27325b88 100644 --- a/helpers/pagetop-macros/Cargo.toml +++ b/helpers/pagetop-macros/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "pagetop-macros" -version = "0.0.5" +version = "0.0.18" edition = "2021" -description = """\ - Una colección de macros que mejoran la experiencia de desarrollo con PageTop.\ +description = """ + Una colección de macros que mejoran la experiencia de desarrollo con PageTop. """ categories = ["development-tools::procedural-macro-helpers", "web-programming"] keywords = ["pagetop", "macros", "proc-macros", "codegen"] diff --git a/helpers/pagetop-macros/README.md b/helpers/pagetop-macros/README.md index e41dd0ec..826698ad 100644 --- a/helpers/pagetop-macros/README.md +++ b/helpers/pagetop-macros/README.md @@ -5,6 +5,9 @@ <p>Una colección de macros que mejoran la experiencia de desarrollo con <strong>PageTop</strong>.</p> [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +[![Doc API](https://img.shields.io/docsrs/pagetop-macros?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-macros) +[![Crates.io](https://img.shields.io/crates/v/pagetop-macros.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-macros) +[![Descargas](https://img.shields.io/crates/d/pagetop-macros.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-macros) </div> diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index b9be0bea..8a6b98b7 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -5,6 +5,9 @@ //! <p>Una colección de macros que mejoran la experiencia de desarrollo con <strong>PageTop</strong>.</p> //! //! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +//! [![Doc API](https://img.shields.io/docsrs/pagetop-macros?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-macros) +//! [![Crates.io](https://img.shields.io/crates/v/pagetop-macros.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-macros) +//! [![Descargas](https://img.shields.io/crates/d/pagetop-macros.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-macros) //! //! </div> //! diff --git a/src/lib.rs b/src/lib.rs index 598c55e6..c0e28d45 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,13 +7,26 @@ //! <p>Un entorno de desarrollo para crear soluciones web modulares, extensibles y configurables.</p> //! //! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +//! [![Doc API](https://img.shields.io/docsrs/pagetop?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop) +//! [![Crates.io](https://img.shields.io/crates/v/pagetop.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop) +//! [![Descargas](https://img.shields.io/crates/d/pagetop.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop) //! //! <br> //! </div> //! //! `PageTop` reivindica la esencia de la web clásica usando [Rust](https://www.rust-lang.org/es) //! para la creación de soluciones web SSR (*renderizadas en el servidor*) basadas en HTML, CSS y -//! JavaScript. +//! JavaScript. Ofrece un conjunto de herramientas que los desarrolladores pueden implementar, +//! extender o adaptar según las necesidades de cada proyecto, incluyendo: +//! +//! * **Acciones** (*actions*): alteran la lógica interna de una funcionalidad interceptando su +//! flujo de ejecución. +//! * **Componentes** (*components*): encapsulan HTML, CSS y JavaScript en unidades funcionales, +//! configurables y reutilizables. +//! * **Extensiones** (*extensions*): añaden, extienden o personalizan funcionalidades usando las +//! APIs de `PageTop` o de terceros. +//! * **Temas** (*themes*): son extensiones que permiten modificar la apariencia de páginas y +//! componentes sin comprometer su funcionalidad. //! //! # ⚡️ Guía rápida //! @@ -27,6 +40,47 @@ //! Application::new().run()?.await //! } //! ``` +//! +//! Este código arranca el servidor de `PageTop` que, con la +//! [configuración por defecto](crate::global::SETTINGS), muestra una página de bienvenida accesible +//! desde un navegador local en `http://localhost:8080`. +//! +//! Para personalizar el servicio, se puede crear una extensión de `PageTop` de la siguiente manera: +//! +//! ```rust,no_run +//! use pagetop::prelude::*; +//! +//! struct HelloWorld; +//! +//! impl Extension for HelloWorld { +//! fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { +//! scfg.route("/", service::web::get().to(hello_world)); +//! } +//! } +//! +//! async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { +//! Page::new(Some(request)) +//! .with_component(Html::with(move |_| html! { h1 { "Hello world!" } })) +//! .render() +//! } +//! +//! #[pagetop::main] +//! async fn main() -> std::io::Result<()> { +//! Application::prepare(&HelloWorld).run()?.await +//! } +//! ``` +//! +//! Este programa implementa una extensión llamada `HelloWorld` que sirve una página web en la ruta +//! raíz (`/`) mostrando el texto "Hello world!" dentro de un elemento HTML `<h1>`. +//! +//! # 🧩 Gestión de Dependencias +//! +//! Los proyectos que utilizan `PageTop` gestionan las dependencias con `cargo`, como cualquier otro +//! proyecto en Rust. +//! +//! Sin embargo, es fundamental que cada extensión declare explícitamente sus +//! [dependencias](core::extension::Extension::dependencies), si las tiene, para que `PageTop` pueda +//! estructurar e inicializar la aplicación de forma modular. #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( From 11caad11afadd8f65ae35924ce2ecf38ea0bf4d6 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 5 Aug 2025 18:49:04 +0200 Subject: [PATCH 108/244] =?UTF-8?q?=F0=9F=93=9D=20Retoques=20menores=20en?= =?UTF-8?q?=20la=20documentaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CREDITS.md | 2 +- README.md | 4 ++-- src/lib.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index 5e89b868..f5c1b0fa 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -10,7 +10,7 @@ como son: de la aplicación. * [Fluent templates](https://github.com/XAMPPRocky/fluent-templates), que integra [Fluent](https://projectfluent.org/) para internacionalizar las aplicaciones. - * Además de otros crates adicionales que se pueden explorar en los archivos `Cargo.toml` de + * Además de otros *crates* adicionales que se pueden explorar en los archivos `Cargo.toml` de `PageTop` y sus extensiones. diff --git a/README.md b/README.md index e671b50b..87f8b8da 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,8 @@ async fn main() -> std::io::Result<()> { } ``` -Este código arranca el servidor de `PageTop` que, con la configuración por defecto, muestra una -página de bienvenida accesible desde un navegador local en `http://localhost:8080`. +Este código arranca el servidor de `PageTop`. Con la configuración por defecto, muestra una página +de bienvenida accesible desde un navegador local en la dirección `http://localhost:8080`. Para personalizar el servicio, se puede crear una extensión de `PageTop` de la siguiente manera: diff --git a/src/lib.rs b/src/lib.rs index c0e28d45..baa57a69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,9 +41,9 @@ //! } //! ``` //! -//! Este código arranca el servidor de `PageTop` que, con la +//! Este código arranca el servidor de `PageTop`. Con la //! [configuración por defecto](crate::global::SETTINGS), muestra una página de bienvenida accesible -//! desde un navegador local en `http://localhost:8080`. +//! desde un navegador local en la dirección `http://localhost:8080`. //! //! Para personalizar el servicio, se puede crear una extensión de `PageTop` de la siguiente manera: //! From 4ae919ccd78d8863e3fb29431a7ebf087ebc49be Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 5 Aug 2025 18:52:00 +0200 Subject: [PATCH 109/244] =?UTF-8?q?=F0=9F=9A=A8=20Aplica=20cambios=20por?= =?UTF-8?q?=20sugerencias=20de=20clippy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-macros/src/lib.rs | 7 +++---- helpers/pagetop-macros/src/maud/ast.rs | 3 +++ helpers/pagetop-macros/src/smart_default/body_impl.rs | 8 ++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 8a6b98b7..fedd682f 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -177,10 +177,9 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { let fn_with_attrs = &fn_with.attrs; // Genera el método alter_...() con el código del método with_...(). - let fn_alter_doc = format!( - "Igual que [`Self::{0}()`](Self::{0}), pero sin usar el patrón *builder*.", - fn_with_name_str, - ); + let fn_alter_doc = + format!("Igual que [`Self::{fn_with_name_str}()`], pero sin usar el patrón *builder*."); + let fn_alter = quote! { #[doc = #fn_alter_doc] pub fn #fn_alter_name #fn_generics(&mut self, #(#args),*) -> &mut Self #where_clause { diff --git a/helpers/pagetop-macros/src/maud/ast.rs b/helpers/pagetop-macros/src/maud/ast.rs index fd499ae2..ebd53318 100644 --- a/helpers/pagetop-macros/src/maud/ast.rs +++ b/helpers/pagetop-macros/src/maud/ast.rs @@ -44,6 +44,7 @@ impl<E: ToTokens> ToTokens for Markups<E> { } #[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] pub enum Markup<E> { Block(Block<E>), Lit(HtmlLit), @@ -429,6 +430,7 @@ impl ToTokens for Attribute { } #[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] pub enum HtmlNameOrMarkup { HtmlName(HtmlName), Markup(Markup<NoElement>), @@ -472,6 +474,7 @@ impl Display for HtmlNameOrMarkup { } #[derive(Debug, Clone)] +#[allow(clippy::large_enum_variant)] pub enum AttributeType { Normal { eq_token: Eq, diff --git a/helpers/pagetop-macros/src/smart_default/body_impl.rs b/helpers/pagetop-macros/src/smart_default/body_impl.rs index 6a76f904..f7d59bb5 100644 --- a/helpers/pagetop-macros/src/smart_default/body_impl.rs +++ b/helpers/pagetop-macros/src/smart_default/body_impl.rs @@ -19,7 +19,7 @@ pub fn impl_my_derive(input: &DeriveInput) -> Result<TokenStream, Error> { quote! { #name #body_assignment }, - format!("Returns a `{}` default.", name), + format!("Returns a `{name}` default."), ) } syn::Data::Enum(ref body) => { @@ -44,7 +44,7 @@ pub fn impl_my_derive(input: &DeriveInput) -> Result<TokenStream, Error> { quote! { #name :: #default_variant_name #body_assignment }, - format!("Returns a `{}::{}` default.", name, default_variant_name), + format!("Returns a `{name}::{default_variant_name}` default."), ) } syn::Data::Union(_) => { @@ -109,7 +109,7 @@ fn default_body_tt(body: &syn::Fields) -> Result<(TokenStream, String), Error> { .iter() .map(|field| { let (default_value, default_doc) = field_default_expr_and_doc(field)?; - write!(&mut doc, "{}, ", default_doc).unwrap(); + write!(&mut doc, "{default_doc}, ").unwrap(); Ok(default_value) }) .collect::<Result<Vec<TokenStream>, Error>>()?; @@ -145,7 +145,7 @@ fn field_default_expr_and_doc(field: &syn::Field) -> Result<(TokenStream, String ConversionStrategy::Into => quote!((#field_value).into()), }; - let field_doc = format!("{}", field_value); + let field_doc = format!("{field_value}"); Ok((field_value, field_doc)) } else { Ok(( From b01b12f47245aacbcc9da90b126e268f0976b86e Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 5 Aug 2025 18:53:01 +0200 Subject: [PATCH 110/244] =?UTF-8?q?=F0=9F=94=A8=20(devops):=20Scripts=20pa?= =?UTF-8?q?ra=20la=20publicaci=C3=B3n=20de=20crates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cargo/cliff.toml | 67 +++++++++++++++++++++++++++++ .cargo/release.toml | 45 ++++++++++++++++++++ tools/changelog.sh | 101 ++++++++++++++++++++++++++++++++++++++++++++ tools/release.sh | 48 +++++++++++++++++++++ 4 files changed, 261 insertions(+) create mode 100644 .cargo/cliff.toml create mode 100644 .cargo/release.toml create mode 100755 tools/changelog.sh create mode 100755 tools/release.sh diff --git a/.cargo/cliff.toml b/.cargo/cliff.toml new file mode 100644 index 00000000..ff362c46 --- /dev/null +++ b/.cargo/cliff.toml @@ -0,0 +1,67 @@ +# cliff.toml + +[changelog] +header = """ +# CHANGELOG + +Este archivo documenta los cambios más relevantes realizados en cada versión. El formato está basado +en [Keep a Changelog](https://keepachangelog.com/es-ES/1.0.0/), y las versiones se numeran siguiendo +las reglas del [Versionado Semántico](https://semver.org/lang/es/). + +Resume la evolución del proyecto para usuarios y colaboradores, destacando nuevas funcionalidades, +correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o +internos pueden omitirse si no afectan al uso del proyecto. +""" +trim = true +render_always = true + +body = """ +{% if version %} +## {{ version | trim_start_matches(pat="v") }} ({{ timestamp | date(format="%Y-%m-%d") }}) +{% else %} +## Pendiente de publicación +{% endif %}\ +{% set base = "https://git.cillero.es/manuelcillero/pagetop" %}\ +{% for group, commits in commits | group_by(attribute="group") %} +### {{ group | upper_first }} +{% for commit in commits %} +{%- set msg = commit.message + | split(pat="\n") + | first + | replace(from="✨ ", to="") + | replace(from="🐛 ", to="") + | replace(from="⬆️ ", to="") + | replace(from="🚧 ", to="") + | replace(from="♻️ ", to="") + | replace(from="✏️ ", to="") + | replace(from="🏷️ ", to="") + | replace(from="🧑‍💻 ", to="") + | replace(from="🍱 ", to="") + | replace(from="📝 ", to="") + | replace(from="💡 ", to="") +-%} +{% set sha7 = commit.id | truncate(length=7, end="") %} +- {{ msg | trim }} ([{{ sha7 }}]({{ base }}/commit/{{ commit.id }}){% if commit.author.name != "Manuel Cillero" %} - {{ commit.author.name }}{% endif %}) +{% endfor %}{% endfor %} +""" + +[git] +conventional_commits = false +filter_unconventional = false +topo_order_commits = true +sort_commits = "oldest" + +commit_parsers = [ + { message = "^✨", group = "Añadido" }, + { message = "^🐛", group = "Corregido" }, + { message = "^🚧", group = "Cambiado" }, + { message = "^♻️", group = "Cambiado" }, + { message = "^✏️", group = "Cambiado" }, + { message = "^🏷️", group = "Cambiado" }, + { message = "^🧑‍💻", group = "Cambiado" }, + { message = "^🍱", group = "Cambiado" }, + { message = "^⬆️", group = "Dependencias" }, + { message = "^📝", group = "Documentado" }, + { message = "^💡", group = "Documentado" }, + { message = "^.*", group = "Otros cambios" }, +] diff --git a/.cargo/release.toml b/.cargo/release.toml new file mode 100644 index 00000000..9c073794 --- /dev/null +++ b/.cargo/release.toml @@ -0,0 +1,45 @@ +# release.toml + +# Etiqueta por crate: `pagetop-macros-v0.2.0` +tag-prefix = "{{crate_name}}-v" + +# Confirmaciones firmadas (no requeridas) +sign-commit = false +sign-tag = false + +# Empuja etiquetas y commits +push = true + +# Publica en crates.io (puedes desactivarlo para pruebas) +publish = true + +# Actualiza todos los dependientes internos +update-dependencies = true + +# Solo permite publicar estos crates (los que forman parte del workspace) +allow-branch = ["main"] +consolidate-commits = false +consolidate-pushes = true + +# Mensaje personalizado para el commit de versión +pre-release-commit-message = "🔖 Prepara publicación de {{crate_name}} {{version}}" + +[workspace] +# Lista de crates que se pueden publicar dentro del workspace +# Puedes añadir extensiones más adelante +allow-publish = [ + "pagetop", + "pagetop-build", + "pagetop-macros" +] + +# Opcional: ordena la publicación de dependencias internas +publish-order = [ + "pagetop-build", + "pagetop-macros", + "pagetop" +] + +pre-release-hook = [ + "./tools/changelog.sh", "{{crate_name}}", "{{version}}", "--stage" +] diff --git a/tools/changelog.sh b/tools/changelog.sh new file mode 100755 index 00000000..19cbed9e --- /dev/null +++ b/tools/changelog.sh @@ -0,0 +1,101 @@ +#!/bin/bash +set -euo pipefail + +# ------------------------------------------------------------------------------ +# Script para generar el archivo de cambios del crate indicado. +# Uso: +# ./tools/changelog.sh <crate> <version> [--stage] +# Ejemplo: +# ./tools/changelog.sh pagetop-macros 0.1.0 # Sólo genera archivo +# ./tools/changelog.sh pagetop 0.1.0 --stage # Prepara archivo para commit +# ------------------------------------------------------------------------------ + +# Configuración +CRATE="${1:-}" +VERSION="${2:-}" +STAGE="${3:-}" +CLIFF_CONFIG=".cargo/cliff.toml" + +# Comprobaciones +if [[ -z "$CRATE" || -z "$VERSION" ]]; then + echo "Usage: $0 <crate> <version> [--stage]" >&2 + exit 1 +fi + +# Dependencias +command -v git-cliff >/dev/null || { + echo "Error: git-cliff is not installed. Use: cargo install git-cliff" + exit 1 +} + +# Cambia al directorio del espacio +cd "$(dirname "$0")/.." || exit 1 + +# ------------------------------------------------------------------------------ +# Determina ruta del archivo y ámbito de los archivos afectados para el crate +# ------------------------------------------------------------------------------ +case "$CRATE" in + pagetop) + CHANGELOG_FILE="CHANGELOG.md" + PATH_FLAGS=( + --exclude-path "helpers/pagetop-macros/**/*" + --exclude-path "helpers/pagetop-build/**/*" + ) + ;; + pagetop-macros) + CHANGELOG_FILE="helpers/pagetop-macros/CHANGELOG.md" + PATH_FLAGS=(--include-path "helpers/pagetop-macros/**/*") + ;; + pagetop-build) + CHANGELOG_FILE="helpers/pagetop-build/CHANGELOG.md" + PATH_FLAGS=(--include-path "helpers/pagetop-build/**/*") + ;; + *) + echo "Error: unsupported crate '$CRATE'" >&2 + exit 1 + ;; +esac + +# ------------------------------------------------------------------------------ +# Obtiene la última etiqueta del crate +# ------------------------------------------------------------------------------ +LAST_TAG="$(git tag --list "${CRATE}-v*" --sort=-v:refname | head -n 1)" + +if [[ -n "$LAST_TAG" ]]; then + echo "Generating CHANGELOG for '$CRATE' from last tag '$LAST_TAG'" + CLIFF_ARGS=(--unreleased --tag "$VERSION") +else + echo "Generating initial CHANGELOG for '$CRATE'" + CLIFF_ARGS=(--tag "$VERSION") +fi + +# ------------------------------------------------------------------------------ +# Genera el CHANGELOG para el crate correspondiente +# ------------------------------------------------------------------------------ +git-cliff --config "$CLIFF_CONFIG" "${PATH_FLAGS[@]}" "${CLIFF_ARGS[@]}" -o "$CHANGELOG_FILE" -u +echo "CHANGELOG generated at '$CHANGELOG_FILE'" + +# Pregunta por la revisión del archivo de cambios generado +read -p "Do you want to review the changelog before continuing? (y/n) " -n 1 -r || exit 1 +echo +if [[ "$REPLY" =~ ^[Yy]$ ]]; then + ${EDITOR:-nano} "$CHANGELOG_FILE" +fi +read -p "Do you want to proceed with the release of $CRATE? (y/n) " -n 1 -r || exit 1 +echo +if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then + echo "Aborting release process." >&2 + exit 1 +fi + +# Si hay cambios y procede, añade al stage (cargo-release hará el commit) +if ! git diff --quiet -- "$CHANGELOG_FILE"; then + if [[ "$STAGE" == "--stage" ]]; then + git add "$CHANGELOG_FILE" + echo "Staged $CHANGELOG_FILE for commit" + else + echo "Changes detected in '$CHANGELOG_FILE', but not staged (no --stage flag)" + fi +else + echo "No changes in '$CHANGELOG_FILE', skipping staging" +fi diff --git a/tools/release.sh b/tools/release.sh new file mode 100755 index 00000000..f62993aa --- /dev/null +++ b/tools/release.sh @@ -0,0 +1,48 @@ +#!/bin/bash +set -euo pipefail + +# ------------------------------------------------------------------------------ +# Script para publicar un crate individual del workspace con cargo-release. +# Uso: +# ./tools/release.sh <crate> [patch|minor|major] [--execute] +# Ejemplos: +# ./tools/release.sh pagetop-macros patch # Dry run (por defecto) +# ./tools/release.sh pagetop minor --execute # Publicación real +# ------------------------------------------------------------------------------ + +# Configuración +CRATE="${1:-}" +LEVEL="${2:-patch}" +EXECUTE="${3:-}" +CONFIG=".cargo/release.toml" + +# Comprobaciones +if [[ -z "$CRATE" ]]; then + echo "Usage: $0 <crate> [patch|minor|major] [--execute]" + exit 1 +fi +if [[ ! "$LEVEL" =~ ^(patch|minor|major)$ ]]; then + echo "Error: invalid level '$LEVEL'. Use: patch, minor, or major" + exit 1 +fi + +# Dependencias +command -v cargo-release >/dev/null || { + echo "Error: cargo-release is not installed. Use: cargo install cargo-release" + exit 1 +} + +# Cambia al directorio del espacio +cd "$(dirname "$0")/.." || exit 1 + +# ------------------------------------------------------------------------------ +# DRY-RUN (por defecto) o ejecución real con --execute +# ------------------------------------------------------------------------------ +if [[ "$EXECUTE" != "--execute" ]]; then + echo "Running dry-run (default mode). Add --execute to publish" + CARGO_RELEASE_CONFIG="$CONFIG" cargo release --package "$CRATE" "$LEVEL" --dry-run +else + echo "Releasing $CRATE ($LEVEL)…" + CARGO_RELEASE_CONFIG="$CONFIG" cargo release --package "$CRATE" "$LEVEL" --execute + echo "Release completed." +fi From 5c0c3090b136484ba9a1672c38013da2488335b9 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 5 Aug 2025 18:53:21 +0200 Subject: [PATCH 111/244] =?UTF-8?q?=F0=9F=93=84=20Cada=20crate=20con=20su?= =?UTF-8?q?=20licencia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-build/LICENSE-APACHE | 201 ++++++++++++++++++++++++++ helpers/pagetop-build/LICENSE-MIT | 21 +++ helpers/pagetop-macros/LICENSE-APACHE | 201 ++++++++++++++++++++++++++ helpers/pagetop-macros/LICENSE-MIT | 21 +++ 4 files changed, 444 insertions(+) create mode 100644 helpers/pagetop-build/LICENSE-APACHE create mode 100644 helpers/pagetop-build/LICENSE-MIT create mode 100644 helpers/pagetop-macros/LICENSE-APACHE create mode 100644 helpers/pagetop-macros/LICENSE-MIT diff --git a/helpers/pagetop-build/LICENSE-APACHE b/helpers/pagetop-build/LICENSE-APACHE new file mode 100644 index 00000000..263ddac1 --- /dev/null +++ b/helpers/pagetop-build/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 Manuel Cillero + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/helpers/pagetop-build/LICENSE-MIT b/helpers/pagetop-build/LICENSE-MIT new file mode 100644 index 00000000..cd8af3d6 --- /dev/null +++ b/helpers/pagetop-build/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Manuel Cillero + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/helpers/pagetop-macros/LICENSE-APACHE b/helpers/pagetop-macros/LICENSE-APACHE new file mode 100644 index 00000000..263ddac1 --- /dev/null +++ b/helpers/pagetop-macros/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 Manuel Cillero + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/helpers/pagetop-macros/LICENSE-MIT b/helpers/pagetop-macros/LICENSE-MIT new file mode 100644 index 00000000..cd8af3d6 --- /dev/null +++ b/helpers/pagetop-macros/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Manuel Cillero + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file From 4928b0f7a6a8bd1978dca03346deb39a2d1085c7 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 5 Aug 2025 19:02:33 +0200 Subject: [PATCH 112/244] =?UTF-8?q?=F0=9F=A9=B9=20El=20modo=20dry-run=20se?= =?UTF-8?q?=20ejecuta=20por=20defecto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release.sh b/tools/release.sh index f62993aa..082869f5 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -40,7 +40,7 @@ cd "$(dirname "$0")/.." || exit 1 # ------------------------------------------------------------------------------ if [[ "$EXECUTE" != "--execute" ]]; then echo "Running dry-run (default mode). Add --execute to publish" - CARGO_RELEASE_CONFIG="$CONFIG" cargo release --package "$CRATE" "$LEVEL" --dry-run + CARGO_RELEASE_CONFIG="$CONFIG" cargo release --package "$CRATE" "$LEVEL" else echo "Releasing $CRATE ($LEVEL)…" CARGO_RELEASE_CONFIG="$CONFIG" cargo release --package "$CRATE" "$LEVEL" --execute From b03cd746c0c4cf95b160c55158c2f4ff39404f51 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 5 Aug 2025 23:11:21 +0200 Subject: [PATCH 113/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-build=200.1.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- Cargo.toml | 2 +- helpers/pagetop-build/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7cba8b96..1d32d893 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "pagetop-build" -version = "0.0.16" +version = "0.1.0" dependencies = [ "grass", "static-files", diff --git a/Cargo.toml b/Cargo.toml index a1a6bfc7..dcf191d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,5 +71,5 @@ authors = ["Manuel Cillero <manuel@cillero.es>"] [workspace.dependencies] static-files = "0.2.5" -pagetop-build = { version = "0.0", path = "helpers/pagetop-build" } +pagetop-build = { version = "0.1", path = "helpers/pagetop-build" } pagetop-macros = { version = "0.0", path = "helpers/pagetop-macros" } diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index c6d9d519..7bf60489 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-build" -version = "0.0.16" +version = "0.1.0" edition = "2021" description = """ From c8976edca45ed97f4e5bc13dc171d55f639ebbd8 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 01:54:47 +0200 Subject: [PATCH 114/244] =?UTF-8?q?=F0=9F=90=9B=20Corrige=20edici=C3=B3n?= =?UTF-8?q?=20de=20CHANGELOG=20y=20nuevas=20versiones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cargo/release.toml | 22 +-------------------- tools/changelog.sh | 47 +++++++++++++++++++++++---------------------- tools/release.sh | 4 ++-- 3 files changed, 27 insertions(+), 46 deletions(-) diff --git a/.cargo/release.toml b/.cargo/release.toml index 9c073794..b0ab9389 100644 --- a/.cargo/release.toml +++ b/.cargo/release.toml @@ -13,33 +13,13 @@ push = true # Publica en crates.io (puedes desactivarlo para pruebas) publish = true -# Actualiza todos los dependientes internos -update-dependencies = true - # Solo permite publicar estos crates (los que forman parte del workspace) allow-branch = ["main"] consolidate-commits = false -consolidate-pushes = true # Mensaje personalizado para el commit de versión pre-release-commit-message = "🔖 Prepara publicación de {{crate_name}} {{version}}" -[workspace] -# Lista de crates que se pueden publicar dentro del workspace -# Puedes añadir extensiones más adelante -allow-publish = [ - "pagetop", - "pagetop-build", - "pagetop-macros" -] - -# Opcional: ordena la publicación de dependencias internas -publish-order = [ - "pagetop-build", - "pagetop-macros", - "pagetop" -] - pre-release-hook = [ - "./tools/changelog.sh", "{{crate_name}}", "{{version}}", "--stage" + "sh", "-c", "ROOT=$(git rev-parse --show-toplevel) && \"$ROOT/tools/changelog.sh\" {{crate_name}} {{version}} --stage" ] diff --git a/tools/changelog.sh b/tools/changelog.sh index 19cbed9e..59f04693 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -35,20 +35,20 @@ cd "$(dirname "$0")/.." || exit 1 # Determina ruta del archivo y ámbito de los archivos afectados para el crate # ------------------------------------------------------------------------------ case "$CRATE" in - pagetop) - CHANGELOG_FILE="CHANGELOG.md" - PATH_FLAGS=( - --exclude-path "helpers/pagetop-macros/**/*" - --exclude-path "helpers/pagetop-build/**/*" - ) + pagetop-build) + CHANGELOG_FILE="helpers/pagetop-build/CHANGELOG.md" + PATH_FLAGS=(--include-path "helpers/pagetop-build/**/*") ;; pagetop-macros) CHANGELOG_FILE="helpers/pagetop-macros/CHANGELOG.md" PATH_FLAGS=(--include-path "helpers/pagetop-macros/**/*") ;; - pagetop-build) - CHANGELOG_FILE="helpers/pagetop-build/CHANGELOG.md" - PATH_FLAGS=(--include-path "helpers/pagetop-build/**/*") + pagetop) + CHANGELOG_FILE="CHANGELOG.md" + PATH_FLAGS=( + --exclude-path "helpers/pagetop-build/**/*" + --exclude-path "helpers/pagetop-macros/**/*" + ) ;; *) echo "Error: unsupported crate '$CRATE'" >&2 @@ -56,23 +56,24 @@ case "$CRATE" in ;; esac -# ------------------------------------------------------------------------------ -# Obtiene la última etiqueta del crate -# ------------------------------------------------------------------------------ -LAST_TAG="$(git tag --list "${CRATE}-v*" --sort=-v:refname | head -n 1)" - -if [[ -n "$LAST_TAG" ]]; then - echo "Generating CHANGELOG for '$CRATE' from last tag '$LAST_TAG'" - CLIFF_ARGS=(--unreleased --tag "$VERSION") -else - echo "Generating initial CHANGELOG for '$CRATE'" - CLIFF_ARGS=(--tag "$VERSION") -fi - # ------------------------------------------------------------------------------ # Genera el CHANGELOG para el crate correspondiente # ------------------------------------------------------------------------------ -git-cliff --config "$CLIFF_CONFIG" "${PATH_FLAGS[@]}" "${CLIFF_ARGS[@]}" -o "$CHANGELOG_FILE" -u +COMMON_ARGS=( + --config "$CLIFF_CONFIG" + "${PATH_FLAGS[@]}" + --tag-pattern "^${CRATE}-v" + --tag "$VERSION" + -o "$CHANGELOG_FILE" +) +LAST_TAG="$(git tag --list "${CRATE}-v*" --sort=-v:refname | head -n 1)" +if [[ -n "$LAST_TAG" ]]; then + echo "Generating CHANGELOG for '$CRATE' from tag '$LAST_TAG'" + git-cliff --unreleased "${COMMON_ARGS[@]}" +else + echo "Generating initial CHANGELOG for '$CRATE'" + git-cliff "${COMMON_ARGS[@]}" +fi echo "CHANGELOG generated at '$CHANGELOG_FILE'" # Pregunta por la revisión del archivo de cambios generado diff --git a/tools/release.sh b/tools/release.sh index 082869f5..bb092416 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -40,9 +40,9 @@ cd "$(dirname "$0")/.." || exit 1 # ------------------------------------------------------------------------------ if [[ "$EXECUTE" != "--execute" ]]; then echo "Running dry-run (default mode). Add --execute to publish" - CARGO_RELEASE_CONFIG="$CONFIG" cargo release --package "$CRATE" "$LEVEL" + cargo release --config "$CONFIG" --package "$CRATE" "$LEVEL" else echo "Releasing $CRATE ($LEVEL)…" - CARGO_RELEASE_CONFIG="$CONFIG" cargo release --package "$CRATE" "$LEVEL" --execute + cargo release --config "$CONFIG" --package "$CRATE" "$LEVEL" --execute echo "Release completed." fi From 49f5de9498ae1bd758767638637ca7fb7c521d49 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 02:01:32 +0200 Subject: [PATCH 115/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-build=200.1.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- helpers/pagetop-build/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d32d893..6b894b5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "pagetop-build" -version = "0.1.0" +version = "0.1.1" dependencies = [ "grass", "static-files", diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index 7bf60489..4769631b 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-build" -version = "0.1.0" +version = "0.1.1" edition = "2021" description = """ From 9aa8e05ed0108fc0b203d23c0b336cf51c2522f6 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 02:07:01 +0200 Subject: [PATCH 116/244] =?UTF-8?q?=F0=9F=90=9B=20Corrige=20comprobaci?= =?UTF-8?q?=C3=B3n=20de=20cambios=20en=20CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/changelog.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/changelog.sh b/tools/changelog.sh index 59f04693..5c5ec325 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -90,7 +90,7 @@ if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then fi # Si hay cambios y procede, añade al stage (cargo-release hará el commit) -if ! git diff --quiet -- "$CHANGELOG_FILE"; then +if ! git diff --quiet HEAD -- "$CHANGELOG_FILE"; then if [[ "$STAGE" == "--stage" ]]; then git add "$CHANGELOG_FILE" echo "Staged $CHANGELOG_FILE for commit" From bab44422a2787efa0210443bc066c3feee01bf0f Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 02:09:50 +0200 Subject: [PATCH 117/244] =?UTF-8?q?=F0=9F=9A=A7=20Trabajando=20sobre=20la?= =?UTF-8?q?=20publicaci=C3=B3n=20de=20versiones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- helpers/pagetop-build/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b894b5d..1d32d893 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "pagetop-build" -version = "0.1.1" +version = "0.1.0" dependencies = [ "grass", "static-files", diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index 4769631b..7bf60489 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-build" -version = "0.1.1" +version = "0.1.0" edition = "2021" description = """ From 652f5adfef09c370d368abfbb9303e5f4eb97861 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 02:10:37 +0200 Subject: [PATCH 118/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-build=200.1.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- helpers/pagetop-build/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d32d893..6b894b5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "pagetop-build" -version = "0.1.0" +version = "0.1.1" dependencies = [ "grass", "static-files", diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index 7bf60489..4769631b 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-build" -version = "0.1.0" +version = "0.1.1" edition = "2021" description = """ From 9abd67f479790e4f8d0568119f269751cf788e20 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 02:15:29 +0200 Subject: [PATCH 119/244] =?UTF-8?q?=F0=9F=9A=A7=20Validando=20comparaci?= =?UTF-8?q?=C3=B3n=20de=20versiones=20de=20CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- helpers/pagetop-build/Cargo.toml | 2 +- tools/changelog.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b894b5d..1d32d893 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "pagetop-build" -version = "0.1.1" +version = "0.1.0" dependencies = [ "grass", "static-files", diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index 4769631b..7bf60489 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-build" -version = "0.1.1" +version = "0.1.0" edition = "2021" description = """ diff --git a/tools/changelog.sh b/tools/changelog.sh index 5c5ec325..eb4ab7e5 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -90,7 +90,7 @@ if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then fi # Si hay cambios y procede, añade al stage (cargo-release hará el commit) -if ! git diff --quiet HEAD -- "$CHANGELOG_FILE"; then +if git status --porcelain -- "$CHANGELOG_FILE" | grep -qE '^( M|A |??)'; then if [[ "$STAGE" == "--stage" ]]; then git add "$CHANGELOG_FILE" echo "Staged $CHANGELOG_FILE for commit" From 1a3649897ee97b53a22588f1a5f1837bef1403ff Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 02:16:00 +0200 Subject: [PATCH 120/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-build=200.1.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- helpers/pagetop-build/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d32d893..6b894b5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "pagetop-build" -version = "0.1.0" +version = "0.1.1" dependencies = [ "grass", "static-files", diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index 7bf60489..4769631b 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-build" -version = "0.1.0" +version = "0.1.1" edition = "2021" description = """ From 7a6bbf9065b795361439b426f1633620a08fab34 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 02:19:01 +0200 Subject: [PATCH 121/244] =?UTF-8?q?=F0=9F=9A=A7=20Validaci=C3=B3n=20en=20c?= =?UTF-8?q?urso?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- helpers/pagetop-build/Cargo.toml | 2 +- tools/changelog.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b894b5d..1d32d893 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "pagetop-build" -version = "0.1.1" +version = "0.1.0" dependencies = [ "grass", "static-files", diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index 4769631b..7bf60489 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-build" -version = "0.1.1" +version = "0.1.0" edition = "2021" description = """ diff --git a/tools/changelog.sh b/tools/changelog.sh index eb4ab7e5..09ffcb0b 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -90,7 +90,7 @@ if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then fi # Si hay cambios y procede, añade al stage (cargo-release hará el commit) -if git status --porcelain -- "$CHANGELOG_FILE" | grep -qE '^( M|A |??)'; then +if [[ -n $(git status --porcelain -- "$CHANGELOG_FILE") ]]; then if [[ "$STAGE" == "--stage" ]]; then git add "$CHANGELOG_FILE" echo "Staged $CHANGELOG_FILE for commit" From 806249ea1b4a761ab74d442321fd33b885c40339 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 02:19:25 +0200 Subject: [PATCH 122/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-build=200.1.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- helpers/pagetop-build/CHANGELOG.md | 17 +++++++++++++++++ helpers/pagetop-build/Cargo.toml | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 helpers/pagetop-build/CHANGELOG.md diff --git a/Cargo.lock b/Cargo.lock index 1d32d893..6b894b5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1600,7 +1600,7 @@ dependencies = [ [[package]] name = "pagetop-build" -version = "0.1.0" +version = "0.1.1" dependencies = [ "grass", "static-files", diff --git a/helpers/pagetop-build/CHANGELOG.md b/helpers/pagetop-build/CHANGELOG.md new file mode 100644 index 00000000..22429694 --- /dev/null +++ b/helpers/pagetop-build/CHANGELOG.md @@ -0,0 +1,17 @@ +# CHANGELOG + +Este archivo documenta los cambios más relevantes realizados en cada versión. El formato está basado +en [Keep a Changelog](https://keepachangelog.com/es-ES/1.0.0/), y las versiones se numeran siguiendo +las reglas del [Versionado Semántico](https://semver.org/lang/es/). + +Resume la evolución del proyecto para usuarios y colaboradores, destacando nuevas funcionalidades, +correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o +internos pueden omitirse si no afectan al uso del proyecto. + +## 0.1.1 (2025-08-05) + +- Depura la edición de CHANGELOGs y publicación de nuevas versiones + +## 0.1.0 (2025-08-05) + +- Versión inicial diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index 7bf60489..4769631b 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-build" -version = "0.1.0" +version = "0.1.1" edition = "2021" description = """ From 605473a68368976b9534bff065507b9171b2ce83 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 03:01:19 +0200 Subject: [PATCH 123/244] =?UTF-8?q?=F0=9F=9A=91=20Corrige=20generaci=C3=B3?= =?UTF-8?q?n=20de=20CHANGELOG=20existentes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cargo/cliff.toml | 2 ++ .cargo/release.toml | 2 +- tools/changelog.sh | 12 +++++++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.cargo/cliff.toml b/.cargo/cliff.toml index ff362c46..5e4cfb85 100644 --- a/.cargo/cliff.toml +++ b/.cargo/cliff.toml @@ -30,6 +30,7 @@ body = """ | first | replace(from="✨ ", to="") | replace(from="🐛 ", to="") + | replace(from="🚑 ", to="") | replace(from="⬆️ ", to="") | replace(from="🚧 ", to="") | replace(from="♻️ ", to="") @@ -54,6 +55,7 @@ sort_commits = "oldest" commit_parsers = [ { message = "^✨", group = "Añadido" }, { message = "^🐛", group = "Corregido" }, + { message = "^🚑", group = "Corregido" }, { message = "^🚧", group = "Cambiado" }, { message = "^♻️", group = "Cambiado" }, { message = "^✏️", group = "Cambiado" }, diff --git a/.cargo/release.toml b/.cargo/release.toml index b0ab9389..68f7a9cc 100644 --- a/.cargo/release.toml +++ b/.cargo/release.toml @@ -1,7 +1,7 @@ # release.toml # Etiqueta por crate: `pagetop-macros-v0.2.0` -tag-prefix = "{{crate_name}}-v" +tag-prefix = "{{crate_name}}-" # Confirmaciones firmadas (no requeridas) sign-commit = false diff --git a/tools/changelog.sh b/tools/changelog.sh index 09ffcb0b..13333d4a 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -59,21 +59,27 @@ esac # ------------------------------------------------------------------------------ # Genera el CHANGELOG para el crate correspondiente # ------------------------------------------------------------------------------ +if [[ -f "$CHANGELOG_FILE" ]]; then + # Archivo existe: inserta la nueva sección arriba + OUTPUT_FLAG=(--prepend "$CHANGELOG_FILE") +else + # Primera vez: crea el fichero desde cero + OUTPUT_FLAG=(-o "$CHANGELOG_FILE") +fi COMMON_ARGS=( --config "$CLIFF_CONFIG" "${PATH_FLAGS[@]}" --tag-pattern "^${CRATE}-v" --tag "$VERSION" - -o "$CHANGELOG_FILE" + "${OUTPUT_FLAG[@]}" ) LAST_TAG="$(git tag --list "${CRATE}-v*" --sort=-v:refname | head -n 1)" if [[ -n "$LAST_TAG" ]]; then echo "Generating CHANGELOG for '$CRATE' from tag '$LAST_TAG'" - git-cliff --unreleased "${COMMON_ARGS[@]}" else echo "Generating initial CHANGELOG for '$CRATE'" - git-cliff "${COMMON_ARGS[@]}" fi +git-cliff --unreleased "${COMMON_ARGS[@]}" echo "CHANGELOG generated at '$CHANGELOG_FILE'" # Pregunta por la revisión del archivo de cambios generado From a5f75cdf5bbef09a5ddd9ba0fc41fedadd02b754 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 03:14:25 +0200 Subject: [PATCH 124/244] =?UTF-8?q?=F0=9F=9A=A9=20Asegura=20compilaci?= =?UTF-8?q?=C3=B3n=20para=20publicar=20nueva=20versi=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-macros/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/pagetop-macros/Cargo.toml b/helpers/pagetop-macros/Cargo.toml index 27325b88..76db954d 100644 --- a/helpers/pagetop-macros/Cargo.toml +++ b/helpers/pagetop-macros/Cargo.toml @@ -21,4 +21,4 @@ proc-macro = true proc-macro2 = "1.0.95" proc-macro2-diagnostics = { version = "0.10.1", default-features = false } quote = "1.0.40" -syn = { version = "2.0.104", features = ["full"] } +syn = { version = "2.0.104", features = ["full", "extra-traits"] } From 1ee9339bca7f621fa9628de4393eb2d7e53661b0 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 03:15:15 +0200 Subject: [PATCH 125/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-macros=200.1.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- Cargo.toml | 2 +- helpers/pagetop-macros/CHANGELOG.md | 13 +++++++++++++ helpers/pagetop-macros/Cargo.toml | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 helpers/pagetop-macros/CHANGELOG.md diff --git a/Cargo.lock b/Cargo.lock index 6b894b5d..baba4a51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1608,7 +1608,7 @@ dependencies = [ [[package]] name = "pagetop-macros" -version = "0.0.18" +version = "0.1.0" dependencies = [ "proc-macro2", "proc-macro2-diagnostics", diff --git a/Cargo.toml b/Cargo.toml index dcf191d6..860d4ee5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,4 +72,4 @@ authors = ["Manuel Cillero <manuel@cillero.es>"] static-files = "0.2.5" pagetop-build = { version = "0.1", path = "helpers/pagetop-build" } -pagetop-macros = { version = "0.0", path = "helpers/pagetop-macros" } +pagetop-macros = { version = "0.1", path = "helpers/pagetop-macros" } diff --git a/helpers/pagetop-macros/CHANGELOG.md b/helpers/pagetop-macros/CHANGELOG.md new file mode 100644 index 00000000..b01b9883 --- /dev/null +++ b/helpers/pagetop-macros/CHANGELOG.md @@ -0,0 +1,13 @@ +# CHANGELOG + +Este archivo documenta los cambios más relevantes realizados en cada versión. El formato está basado +en [Keep a Changelog](https://keepachangelog.com/es-ES/1.0.0/), y las versiones se numeran siguiendo +las reglas del [Versionado Semántico](https://semver.org/lang/es/). + +Resume la evolución del proyecto para usuarios y colaboradores, destacando nuevas funcionalidades, +correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o +internos pueden omitirse si no afectan al uso del proyecto. + +## 0.1.0 (2025-08-06) + +- Versión inicial diff --git a/helpers/pagetop-macros/Cargo.toml b/helpers/pagetop-macros/Cargo.toml index 76db954d..45ba3283 100644 --- a/helpers/pagetop-macros/Cargo.toml +++ b/helpers/pagetop-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-macros" -version = "0.0.18" +version = "0.1.0" edition = "2021" description = """ From 96bc0776166d9c2f1495bacb7b479c8b86f766ec Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 03:22:20 +0200 Subject: [PATCH 126/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop=200.1.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 13 +++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..b01b9883 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +# CHANGELOG + +Este archivo documenta los cambios más relevantes realizados en cada versión. El formato está basado +en [Keep a Changelog](https://keepachangelog.com/es-ES/1.0.0/), y las versiones se numeran siguiendo +las reglas del [Versionado Semántico](https://semver.org/lang/es/). + +Resume la evolución del proyecto para usuarios y colaboradores, destacando nuevas funcionalidades, +correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o +internos pueden omitirse si no afectan al uso del proyecto. + +## 0.1.0 (2025-08-06) + +- Versión inicial diff --git a/Cargo.lock b/Cargo.lock index baba4a51..e9ba9fb8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1569,7 +1569,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.0.61" +version = "0.1.0" dependencies = [ "actix-files", "actix-session", diff --git a/Cargo.toml b/Cargo.toml index 860d4ee5..229c989c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.0.61" +version = "0.1.0" edition = "2021" description = """ From bbc0a596513a9ed90170c6c08d97bbc6917ac0d8 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 11:24:13 +0200 Subject: [PATCH 127/244] =?UTF-8?q?=F0=9F=A9=B9=20Corrige=20enlaces=20de?= =?UTF-8?q?=20licencia=20en=20la=20documentaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- helpers/pagetop-build/README.md | 2 +- helpers/pagetop-build/src/lib.rs | 2 +- helpers/pagetop-macros/README.md | 2 +- helpers/pagetop-macros/src/lib.rs | 2 +- src/lib.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 87f8b8da..fe85e665 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ <p>Un entorno para el desarrollo de soluciones web modulares, extensibles y configurables.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop) [![Crates.io](https://img.shields.io/crates/v/pagetop.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop) [![Descargas](https://img.shields.io/crates/d/pagetop.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop) diff --git a/helpers/pagetop-build/README.md b/helpers/pagetop-build/README.md index 27c98147..d9d52571 100644 --- a/helpers/pagetop-build/README.md +++ b/helpers/pagetop-build/README.md @@ -4,7 +4,7 @@ <p>Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el binario de un proyecto <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-build?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-build) [![Crates.io](https://img.shields.io/crates/v/pagetop-build.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-build) [![Descargas](https://img.shields.io/crates/d/pagetop-build.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-build) diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index 90898dd3..4dcd70c0 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -4,7 +4,7 @@ //! //! <p>Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el binario de un proyecto <strong>PageTop</strong>.</p> //! -//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) //! [![Doc API](https://img.shields.io/docsrs/pagetop-build?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-build) //! [![Crates.io](https://img.shields.io/crates/v/pagetop-build.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-build) //! [![Descargas](https://img.shields.io/crates/d/pagetop-build.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-build) diff --git a/helpers/pagetop-macros/README.md b/helpers/pagetop-macros/README.md index 826698ad..c5006a87 100644 --- a/helpers/pagetop-macros/README.md +++ b/helpers/pagetop-macros/README.md @@ -4,7 +4,7 @@ <p>Una colección de macros que mejoran la experiencia de desarrollo con <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-macros?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-macros) [![Crates.io](https://img.shields.io/crates/v/pagetop-macros.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-macros) [![Descargas](https://img.shields.io/crates/d/pagetop-macros.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-macros) diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index fedd682f..496ce82b 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -4,7 +4,7 @@ //! //! <p>Una colección de macros que mejoran la experiencia de desarrollo con <strong>PageTop</strong>.</p> //! -//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) //! [![Doc API](https://img.shields.io/docsrs/pagetop-macros?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-macros) //! [![Crates.io](https://img.shields.io/crates/v/pagetop-macros.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-macros) //! [![Descargas](https://img.shields.io/crates/d/pagetop-macros.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-macros) diff --git a/src/lib.rs b/src/lib.rs index baa57a69..e0da3617 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ //! //! <p>Un entorno de desarrollo para crear soluciones web modulares, extensibles y configurables.</p> //! -//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-license) +//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) //! [![Doc API](https://img.shields.io/docsrs/pagetop?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop) //! [![Crates.io](https://img.shields.io/crates/v/pagetop.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop) //! [![Descargas](https://img.shields.io/crates/d/pagetop.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop) From 53f42f9a778ecd4de9ef4f0937c7fb9a8126f965 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 6 Aug 2025 11:26:56 +0200 Subject: [PATCH 128/244] =?UTF-8?q?=F0=9F=9A=A9=20Afina=20Cargo.toml=20par?= =?UTF-8?q?a=20buscar=20la=20mejor=20categor=C3=ADa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 2 +- helpers/pagetop-build/Cargo.toml | 2 +- helpers/pagetop-macros/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 229c989c..3eee24d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" description = """ Un entorno de desarrollo para crear soluciones web modulares, extensibles y configurables. """ -categories = ["web-programming", "gui", "development-tools", "asynchronous"] +categories = ["web-programming::http-server"] keywords = ["pagetop", "web", "framework", "frontend", "ssr"] repository.workspace = true diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index 4769631b..ba911efc 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -7,7 +7,7 @@ description = """ Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el binario de un proyecto PageTop. """ -categories = ["development-tools::build-utils", "web-programming"] +categories = ["development-tools::build-utils"] keywords = ["pagetop", "build", "assets", "resources", "static"] repository.workspace = true diff --git a/helpers/pagetop-macros/Cargo.toml b/helpers/pagetop-macros/Cargo.toml index 45ba3283..64f1cf4c 100644 --- a/helpers/pagetop-macros/Cargo.toml +++ b/helpers/pagetop-macros/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" description = """ Una colección de macros que mejoran la experiencia de desarrollo con PageTop. """ -categories = ["development-tools::procedural-macro-helpers", "web-programming"] +categories = ["development-tools::procedural-macro-helpers"] keywords = ["pagetop", "macros", "proc-macros", "codegen"] repository.workspace = true From 0ed4b6188048955740a8687772aabfb87df49473 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 8 Aug 2025 23:58:07 +0200 Subject: [PATCH 129/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20librer=C3=ADa?= =?UTF-8?q?=20para=20gestionar=20recursos=20est=C3=A1ticos=20(#1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://git.cillero.es/manuelcillero/pagetop/pulls/1 Co-authored-by: Manuel Cillero <manuel@cillero.es> Co-committed-by: Manuel Cillero <manuel@cillero.es> --- Cargo.lock | 48 +-- Cargo.toml | 9 +- helpers/pagetop-build/Cargo.toml | 2 +- helpers/pagetop-build/src/lib.rs | 2 +- helpers/pagetop-statics/Cargo.toml | 33 ++ helpers/pagetop-statics/LICENSE-APACHE | 201 +++++++++ helpers/pagetop-statics/LICENSE-MIT | 21 + helpers/pagetop-statics/README.md | 50 +++ helpers/pagetop-statics/build.rs | 43 ++ helpers/pagetop-statics/src/lib.rs | 34 ++ helpers/pagetop-statics/src/resource.rs | 249 +++++++++++ helpers/pagetop-statics/src/resource_dir.rs | 118 ++++++ helpers/pagetop-statics/src/resource_files.rs | 396 ++++++++++++++++++ helpers/pagetop-statics/src/sets.rs | 184 ++++++++ helpers/pagetop-statics/tests/file1.txt | 0 helpers/pagetop-statics/tests/file2.txt | 0 helpers/pagetop-statics/tests/file3.info | 0 helpers/pagetop-statics/tests/index.html | 10 + src/lib.rs | 8 +- src/service.rs | 4 +- 20 files changed, 1371 insertions(+), 41 deletions(-) create mode 100644 helpers/pagetop-statics/Cargo.toml create mode 100644 helpers/pagetop-statics/LICENSE-APACHE create mode 100644 helpers/pagetop-statics/LICENSE-MIT create mode 100644 helpers/pagetop-statics/README.md create mode 100644 helpers/pagetop-statics/build.rs create mode 100644 helpers/pagetop-statics/src/lib.rs create mode 100644 helpers/pagetop-statics/src/resource.rs create mode 100644 helpers/pagetop-statics/src/resource_dir.rs create mode 100644 helpers/pagetop-statics/src/resource_files.rs create mode 100644 helpers/pagetop-statics/src/sets.rs create mode 100644 helpers/pagetop-statics/tests/file1.txt create mode 100644 helpers/pagetop-statics/tests/file2.txt create mode 100644 helpers/pagetop-statics/tests/file3.info create mode 100644 helpers/pagetop-statics/tests/index.html diff --git a/Cargo.lock b/Cargo.lock index e9ba9fb8..2f15a489 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,18 +225,6 @@ dependencies = [ "syn", ] -[[package]] -name = "actix-web-static-files" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adf6d1ef6d7a60e084f9e0595e2a5234abda14e76c105ecf8e2d0e8800c41a1f" -dependencies = [ - "actix-web", - "derive_more 0.99.20", - "futures-util", - "static-files", -] - [[package]] name = "addr2line" version = "0.24.2" @@ -658,9 +646,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -1076,9 +1064,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ "bytes", "fnv", @@ -1574,7 +1562,6 @@ dependencies = [ "actix-files", "actix-session", "actix-web", - "actix-web-static-files", "chrono", "colored", "concat-string", @@ -1584,10 +1571,10 @@ dependencies = [ "itoa", "pagetop-build", "pagetop-macros", + "pagetop-statics", "parking_lot", "pastey", "serde", - "static-files", "substring", "tempfile", "terminal_size", @@ -1603,7 +1590,7 @@ name = "pagetop-build" version = "0.1.1" dependencies = [ "grass", - "static-files", + "pagetop-statics", ] [[package]] @@ -1616,6 +1603,18 @@ dependencies = [ "syn", ] +[[package]] +name = "pagetop-statics" +version = "0.0.1" +dependencies = [ + "actix-web", + "change-detection", + "derive_more 0.99.20", + "futures-util", + "mime_guess", + "path-slash", +] + [[package]] name = "parking_lot" version = "0.12.4" @@ -2178,17 +2177,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "static-files" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9c425c07353535ef55b45420f5a8b0a397cd9bc3d7e5236497ca0d90604aa9b" -dependencies = [ - "change-detection", - "mime_guess", - "path-slash", -] - [[package]] name = "strsim" version = "0.11.1" diff --git a/Cargo.toml b/Cargo.toml index 3eee24d6..36007421 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,15 +34,14 @@ tracing-actix-web = "0.7.19" fluent-templates = "0.13.0" unic-langid = { version = "0.9.6", features = ["macros"] } -actix-web = "4.11.0" +actix-web = { workspace = true, default-features = true } actix-session = { version = "0.10.1", features = ["cookie-session"] } actix-web-files = { package = "actix-files", version = "0.6.6" } -actix-web-static-files = "4.0.1" -static-files.workspace = true serde = { version = "1.0", features = ["derive"] } pagetop-macros.workspace = true +pagetop-statics.workspace = true [features] default = [] @@ -60,6 +59,7 @@ resolver = "2" members = [ "helpers/pagetop-build", "helpers/pagetop-macros", + "helpers/pagetop-statics", ] [workspace.package] @@ -69,7 +69,8 @@ license = "MIT OR Apache-2.0" authors = ["Manuel Cillero <manuel@cillero.es>"] [workspace.dependencies] -static-files = "0.2.5" +actix-web = { version = "4.11.0", default-features = false } pagetop-build = { version = "0.1", path = "helpers/pagetop-build" } pagetop-macros = { version = "0.1", path = "helpers/pagetop-macros" } +pagetop-statics = { version = "0.0", path = "helpers/pagetop-statics" } diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index ba911efc..41e826e9 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -17,4 +17,4 @@ authors.workspace = true [dependencies] grass = "0.13.4" -static-files.workspace = true +pagetop-statics.workspace = true diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index 4dcd70c0..b360377f 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -123,7 +123,7 @@ )] use grass::{from_path, Options, OutputStyle}; -use static_files::{resource_dir, ResourceDir}; +use pagetop_statics::{resource_dir, ResourceDir}; use std::fs::{create_dir_all, remove_dir_all, File}; use std::io::Write; diff --git a/helpers/pagetop-statics/Cargo.toml b/helpers/pagetop-statics/Cargo.toml new file mode 100644 index 00000000..f41cec76 --- /dev/null +++ b/helpers/pagetop-statics/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "pagetop-statics" +version = "0.0.1" +edition = "2021" + +description = """ + Librería para automatizar la recopilación de recursos estáticos en PageTop. +""" +categories = ["development-tools::build-utils"] +keywords = ["pagetop", "build", "static", "resources", "file"] + +repository.workspace = true +homepage.workspace = true +license.workspace = true +authors.workspace = true + +[features] +default = ["change-detection"] +sort = [] + +[dependencies] +change-detection = { version = "1.2", optional = true } +mime_guess = "2.0" +path-slash = "0.1" + +actix-web.workspace = true +derive_more = "0.99.17" +futures-util = { version = "0.3", default-features = false, features = ["std"] } + +[build-dependencies] +change-detection = { version = "1.2", optional = true } +mime_guess = "2.0" +path-slash = "0.1" diff --git a/helpers/pagetop-statics/LICENSE-APACHE b/helpers/pagetop-statics/LICENSE-APACHE new file mode 100644 index 00000000..263ddac1 --- /dev/null +++ b/helpers/pagetop-statics/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 Manuel Cillero + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/helpers/pagetop-statics/LICENSE-MIT b/helpers/pagetop-statics/LICENSE-MIT new file mode 100644 index 00000000..cd8af3d6 --- /dev/null +++ b/helpers/pagetop-statics/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Manuel Cillero + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/helpers/pagetop-statics/README.md b/helpers/pagetop-statics/README.md new file mode 100644 index 00000000..c053e955 --- /dev/null +++ b/helpers/pagetop-statics/README.md @@ -0,0 +1,50 @@ +<div align="center"> + +<h1>PageTop Statics</h1> + +<p>Librería para automatizar la recopilación de recursos estáticos en <strong>PageTop</strong>.</p> + +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) + +</div> + +## Descripción general + +Permite a `PageTop` incluir archivos estáticos en el ejecutable de la aplicación para servirlos de +forma eficiente vía web, con detección de cambios que optimiza el tiempo de compilación. + +Para ello, reúne el código de los *crates* [static-files](https://crates.io/crates/static_files) +(versión [0.2.5](https://github.com/static-files-rs/static-files/tree/v0.2.5)) y +[actix-web-static-files](https://crates.io/crates/actix_web_static_files) (versión +[4.0.1](https://github.com/kilork/actix-web-static-files/tree/v4.0.1)), desarrollados ambos por +[Alexander Korolev](https://crates.io/users/kilork). + +Estas implementaciones se integran en `PageTop` para evitar que cada proyecto tenga que declarar +`static-files` manualmente como dependencia en su `Cargo.toml`. + +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + + +# 🚧 Advertencia + +`PageTop` es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su +ecosistema. Su API está sujeta a cambios frecuentes. No se recomienda su uso en producción, al menos +hasta que se libere la versión **1.0.0**. + + +# 📜 Licencia + +El código está disponible bajo una doble licencia: + + * **Licencia MIT** + ([LICENSE-MIT](LICENSE-MIT) o también https://opensource.org/licenses/MIT) + + * **Licencia Apache, Versión 2.0** + ([LICENSE-APACHE](LICENSE-APACHE) o también https://www.apache.org/licenses/LICENSE-2.0) + +Puedes elegir la licencia que prefieras. Este enfoque de doble licencia es el estándar de facto en +el ecosistema Rust. diff --git a/helpers/pagetop-statics/build.rs b/helpers/pagetop-statics/build.rs new file mode 100644 index 00000000..fcd009c9 --- /dev/null +++ b/helpers/pagetop-statics/build.rs @@ -0,0 +1,43 @@ +#![allow(dead_code)] +#![doc(html_no_source)] +#![allow(clippy::needless_doctest_main)] + +mod resource { + include!("src/resource.rs"); +} +use resource::generate_resources_mapping; +mod resource_dir { + include!("src/resource_dir.rs"); +} +use resource_dir::resource_dir; +mod sets { + include!("src/sets.rs"); +} +use sets::{generate_resources_sets, SplitByCount}; + +use std::{env, path::Path}; + +fn main() -> std::io::Result<()> { + resource_dir("./tests").build_test()?; + + let out_dir = env::var("OUT_DIR").unwrap(); + + generate_resources_mapping( + "./tests", + None, + Path::new(&out_dir).join("generated_mapping.rs"), + "pagetop_statics", + )?; + + generate_resources_sets( + "./tests", + None, + Path::new(&out_dir).join("generated_sets.rs"), + "sets", + "generate", + &mut SplitByCount::new(2), + "pagetop_statics", + )?; + + Ok(()) +} diff --git a/helpers/pagetop-statics/src/lib.rs b/helpers/pagetop-statics/src/lib.rs new file mode 100644 index 00000000..fffd1ae3 --- /dev/null +++ b/helpers/pagetop-statics/src/lib.rs @@ -0,0 +1,34 @@ +//! <div align="center"> +//! +//! <h1>PageTop Statics</h1> +//! +//! <p>Librería para automatizar la recopilación de recursos estáticos en <strong>PageTop</strong>.</p> +//! +//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) +//! +//! </div> +//! +//! ## Sobre PageTop +//! +//! [PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la +//! web clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles +//! y configurables, basadas en HTML, CSS y JavaScript. + +#![doc(test(no_crate_inject))] +#![doc( + html_favicon_url = "https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/favicon.ico" +)] +#![allow(clippy::needless_doctest_main)] + +/// Resource definition and single module based generation. +pub mod resource; +pub use resource::Resource as StaticResource; + +mod resource_dir; +pub use resource_dir::{resource_dir, ResourceDir}; + +mod resource_files; +pub use resource_files::{ResourceFiles, UriSegmentError}; + +/// Support for module based generations. Use it for large data sets (more than 128 Mb). +pub mod sets; diff --git a/helpers/pagetop-statics/src/resource.rs b/helpers/pagetop-statics/src/resource.rs new file mode 100644 index 00000000..0b81969e --- /dev/null +++ b/helpers/pagetop-statics/src/resource.rs @@ -0,0 +1,249 @@ +use path_slash::PathExt; +use std::{ + fs::{self, File, Metadata}, + io::{self, Write}, + path::{Path, PathBuf}, + time::SystemTime, +}; + +/// Static files resource. +pub struct Resource { + pub data: &'static [u8], + pub modified: u64, + pub mime_type: &'static str, +} + +/// Used internally in generated functions. +#[inline] +pub fn new_resource(data: &'static [u8], modified: u64, mime_type: &'static str) -> Resource { + Resource { + data, + modified, + mime_type, + } +} + +pub(crate) const DEFAULT_VARIABLE_NAME: &str = "r"; + +/// Generate resources for `project_dir` using `filter`. +/// Result saved in `generated_filename` and function named as `fn_name`. +/// +/// in `build.rs`: +/// ```rust +/// use std::{env, path::Path}; +/// use pagetop_statics::resource::generate_resources; +/// +/// fn main() { +/// let out_dir = env::var("OUT_DIR").unwrap(); +/// let generated_filename = Path::new(&out_dir).join("generated.rs"); +/// generate_resources("./tests", None, generated_filename, "generate", "pagetop_statics").unwrap(); +/// } +/// ``` +/// +/// in `main.rs`: +/// ```rust +/// include!(concat!(env!("OUT_DIR"), "/generated.rs")); +/// +/// fn main() { +/// let generated_file = generate(); +/// +/// assert_eq!(generated_file.len(), 4); +/// } +/// ``` +pub fn generate_resources<P: AsRef<Path>, G: AsRef<Path>>( + project_dir: P, + filter: Option<fn(p: &Path) -> bool>, + generated_filename: G, + fn_name: &str, + crate_name: &str, +) -> io::Result<()> { + let resources = collect_resources(&project_dir, filter)?; + + let mut f = File::create(&generated_filename)?; + + generate_function_header(&mut f, fn_name, crate_name)?; + generate_uses(&mut f, crate_name)?; + + generate_variable_header(&mut f, DEFAULT_VARIABLE_NAME)?; + generate_resource_inserts(&mut f, &project_dir, DEFAULT_VARIABLE_NAME, resources)?; + generate_variable_return(&mut f, DEFAULT_VARIABLE_NAME)?; + + generate_function_end(&mut f)?; + + Ok(()) +} + +/// Generate resource mapping for `project_dir` using `filter`. +/// Result saved in `generated_filename` as anonymous block which returns HashMap<&'static str, Resource>. +/// +/// in `build.rs`: +/// ```rust +/// +/// use std::{env, path::Path}; +/// use pagetop_statics::resource::generate_resources_mapping; +/// +/// fn main() { +/// let out_dir = env::var("OUT_DIR").unwrap(); +/// let generated_filename = Path::new(&out_dir).join("generated_mapping.rs"); +/// generate_resources_mapping("./tests", None, generated_filename, "pagetop_statics").unwrap(); +/// } +/// ``` +/// +/// in `main.rs`: +/// ```rust +/// use std::collections::HashMap; +/// +/// use pagetop_statics::StaticResource; +/// +/// fn generate_mapping() -> HashMap<&'static str, StaticResource> { +/// include!(concat!(env!("OUT_DIR"), "/generated_mapping.rs")) +/// } +/// +/// fn main() { +/// let generated_file = generate_mapping(); +/// +/// assert_eq!(generated_file.len(), 4); +/// +/// } +/// ``` +pub fn generate_resources_mapping<P: AsRef<Path>, G: AsRef<Path>>( + project_dir: P, + filter: Option<fn(p: &Path) -> bool>, + generated_filename: G, + crate_name: &str, +) -> io::Result<()> { + let resources = collect_resources(&project_dir, filter)?; + + let mut f = File::create(&generated_filename)?; + writeln!(f, "{{")?; + + generate_uses(&mut f, crate_name)?; + + generate_variable_header(&mut f, DEFAULT_VARIABLE_NAME)?; + + generate_resource_inserts(&mut f, &project_dir, DEFAULT_VARIABLE_NAME, resources)?; + + generate_variable_return(&mut f, DEFAULT_VARIABLE_NAME)?; + + writeln!(f, "}}")?; + Ok(()) +} + +#[cfg(not(feature = "sort"))] +pub(crate) fn collect_resources<P: AsRef<Path>>( + path: P, + filter: Option<fn(p: &Path) -> bool>, +) -> io::Result<Vec<(PathBuf, Metadata)>> { + collect_resources_nested(path, filter) +} + +#[cfg(feature = "sort")] +pub(crate) fn collect_resources<P: AsRef<Path>>( + path: P, + filter: Option<fn(p: &Path) -> bool>, +) -> io::Result<Vec<(PathBuf, Metadata)>> { + let mut resources = collect_resources_nested(path, filter)?; + resources.sort_by(|a, b| a.0.cmp(&b.0)); + Ok(resources) +} + +#[inline] +fn collect_resources_nested<P: AsRef<Path>>( + path: P, + filter: Option<fn(p: &Path) -> bool>, +) -> io::Result<Vec<(PathBuf, Metadata)>> { + let mut result = vec![]; + + for entry in fs::read_dir(&path)? { + let entry = entry?; + let path = entry.path(); + + if let Some(ref filter) = filter { + if !filter(path.as_ref()) { + continue; + } + } + + if path.is_dir() { + let nested = collect_resources(path, filter)?; + result.extend(nested); + } else { + result.push((path, entry.metadata()?)); + } + } + + Ok(result) +} + +pub(crate) fn generate_resource_inserts<P: AsRef<Path>, W: Write>( + f: &mut W, + project_dir: &P, + variable_name: &str, + resources: Vec<(PathBuf, Metadata)>, +) -> io::Result<()> { + for resource in &resources { + generate_resource_insert(f, project_dir, variable_name, resource)?; + } + Ok(()) +} + +#[allow(clippy::unnecessary_debug_formatting)] +pub(crate) fn generate_resource_insert<P: AsRef<Path>, W: Write>( + f: &mut W, + project_dir: &P, + variable_name: &str, + resource: &(PathBuf, Metadata), +) -> io::Result<()> { + let (path, metadata) = resource; + let abs_path = path.canonicalize()?; + let key_path = path.strip_prefix(project_dir).unwrap().to_slash().unwrap(); + + let modified = if let Ok(Ok(modified)) = metadata + .modified() + .map(|x| x.duration_since(SystemTime::UNIX_EPOCH)) + { + modified.as_secs() + } else { + 0 + }; + let mime_type = mime_guess::MimeGuess::from_path(path).first_or_octet_stream(); + writeln!( + f, + "{}.insert({:?},n(i!({:?}),{:?},{:?}));", + variable_name, &key_path, &abs_path, modified, &mime_type, + ) +} + +pub(crate) fn generate_function_header<F: Write>( + f: &mut F, + fn_name: &str, + crate_name: &str, +) -> io::Result<()> { + writeln!( + f, + "#[allow(clippy::unreadable_literal)] pub fn {fn_name}() -> ::std::collections::HashMap<&'static str, ::{crate_name}::StaticResource> {{", + ) +} + +pub(crate) fn generate_function_end<F: Write>(f: &mut F) -> io::Result<()> { + writeln!(f, "}}") +} + +pub(crate) fn generate_uses<F: Write>(f: &mut F, crate_name: &str) -> io::Result<()> { + writeln!( + f, + "use ::{crate_name}::resource::new_resource as n; +use ::std::include_bytes as i;", + ) +} + +pub(crate) fn generate_variable_header<F: Write>(f: &mut F, variable_name: &str) -> io::Result<()> { + writeln!( + f, + "let mut {variable_name} = ::std::collections::HashMap::new();", + ) +} + +pub(crate) fn generate_variable_return<F: Write>(f: &mut F, variable_name: &str) -> io::Result<()> { + writeln!(f, "{variable_name}") +} diff --git a/helpers/pagetop-statics/src/resource_dir.rs b/helpers/pagetop-statics/src/resource_dir.rs new file mode 100644 index 00000000..805e1ed4 --- /dev/null +++ b/helpers/pagetop-statics/src/resource_dir.rs @@ -0,0 +1,118 @@ +use super::sets::{generate_resources_sets, SplitByCount}; +use std::{ + env, io, + path::{Path, PathBuf}, +}; + +/// Generate resources for `resource_dir`. +/// +/// ```rust,no_run +/// // Generate resources for ./tests dir with file name generated.rs +/// // stored in path defined by OUT_DIR environment variable. +/// // Function name is 'generate' +/// use pagetop_statics::resource_dir; +/// +/// resource_dir("./tests").build().unwrap(); +/// ``` +pub fn resource_dir<P: AsRef<Path>>(resource_dir: P) -> ResourceDir { + ResourceDir { + resource_dir: resource_dir.as_ref().into(), + ..Default::default() + } +} + +/// Resource dir. +/// +/// A builder structure allows to change default settings for: +/// - file filter +/// - generated file name +/// - generated function name +#[derive(Default)] +pub struct ResourceDir { + pub(crate) resource_dir: PathBuf, + pub(crate) filter: Option<fn(p: &Path) -> bool>, + pub(crate) generated_filename: Option<PathBuf>, + pub(crate) generated_fn: Option<String>, + pub(crate) module_name: Option<String>, + pub(crate) count_per_module: Option<usize>, +} + +pub const DEFAULT_MODULE_NAME: &str = "sets"; +pub const DEFAULT_COUNT_PER_MODULE: usize = 256; + +impl ResourceDir { + /// Generates resources for current configuration. + pub fn build(self) -> io::Result<()> { + self.internal_build("pagetop") + } + + /// Generates resources for testing current configuration. + #[allow(dead_code)] + pub(crate) fn build_test(self) -> io::Result<()> { + self.internal_build("pagetop_statics") + } + + fn internal_build(self, crate_name: &str) -> io::Result<()> { + let generated_filename = self.generated_filename.unwrap_or_else(|| { + let out_dir = env::var("OUT_DIR").unwrap(); + + Path::new(&out_dir).join("generated.rs") + }); + let generated_fn = self.generated_fn.unwrap_or_else(|| "generate".into()); + + let module_name = self + .module_name + .unwrap_or_else(|| format!("{}_{}", &generated_fn, DEFAULT_MODULE_NAME)); + + let count_per_module = self.count_per_module.unwrap_or(DEFAULT_COUNT_PER_MODULE); + + generate_resources_sets( + &self.resource_dir, + self.filter, + &generated_filename, + module_name.as_str(), + &generated_fn, + &mut SplitByCount::new(count_per_module), + crate_name, + ) + } + + /// Sets the file filter. + pub fn with_filter(&mut self, filter: fn(p: &Path) -> bool) -> &mut Self { + self.filter = Some(filter); + self + } + + /// Sets the generated filename. + pub fn with_generated_filename<P: AsRef<Path>>(&mut self, generated_filename: P) -> &mut Self { + self.generated_filename = Some(generated_filename.as_ref().into()); + self + } + + /// Sets the generated function name. + pub fn with_generated_fn<S>(&mut self, generated_fn: S) -> &mut Self + where + S: Into<String>, + { + self.generated_fn = Some(generated_fn.into()); + self + } + + /// Sets the generated module name. + /// + /// Default value is based on generated function name and the suffix "sets". + /// Generated module would be overriden by each call. + pub fn with_module_name<S>(&mut self, module_name: S) -> &mut Self + where + S: Into<String>, + { + self.module_name = Some(module_name.into()); + self + } + + /// Sets maximal count of files per module. + pub fn with_count_per_module(&mut self, count_per_module: usize) -> &mut Self { + self.count_per_module = Some(count_per_module); + self + } +} diff --git a/helpers/pagetop-statics/src/resource_files.rs b/helpers/pagetop-statics/src/resource_files.rs new file mode 100644 index 00000000..b487bca9 --- /dev/null +++ b/helpers/pagetop-statics/src/resource_files.rs @@ -0,0 +1,396 @@ +use super::resource::Resource; +use actix_web::{ + dev::{ + always_ready, AppService, HttpServiceFactory, ResourceDef, Service, ServiceFactory, + ServiceRequest, ServiceResponse, + }, + error::Error, + guard::{Guard, GuardContext}, + http::{ + header::{self, ContentType}, + Method, StatusCode, + }, + HttpMessage, HttpRequest, HttpResponse, ResponseError, +}; +use derive_more::{Deref, Display, Error}; +use futures_util::future::{ok, FutureExt, LocalBoxFuture, Ready}; +use std::{collections::HashMap, ops::Deref, rc::Rc}; + +/// Static resource files handling +/// +/// `ResourceFiles` service must be registered with `App::service` method. +/// +/// ```rust +/// use std::collections::HashMap; +/// +/// use actix_web::App; +/// +/// fn main() { +/// // serve root directory with default options: +/// // - resolve index.html +/// let files: HashMap<&'static str, pagetop_statics::StaticResource> = HashMap::new(); +/// let app = App::new() +/// .service(pagetop_statics::ResourceFiles::new("/", files)); +/// // or subpath with additional option to not resolve index.html +/// let files: HashMap<&'static str, pagetop_statics::StaticResource> = HashMap::new(); +/// let app = App::new() +/// .service(pagetop_statics::ResourceFiles::new("/imgs", files) +/// .do_not_resolve_defaults()); +/// } +/// ``` +#[allow(clippy::needless_doctest_main)] +pub struct ResourceFiles { + not_resolve_defaults: bool, + use_guard: bool, + not_found_resolves_to: Option<String>, + inner: Rc<ResourceFilesInner>, +} + +pub struct ResourceFilesInner { + path: String, + files: HashMap<&'static str, Resource>, +} + +const INDEX_HTML: &str = "index.html"; + +impl ResourceFiles { + pub fn new(path: &str, files: HashMap<&'static str, Resource>) -> Self { + let inner = ResourceFilesInner { + path: path.into(), + files, + }; + Self { + inner: Rc::new(inner), + not_resolve_defaults: false, + not_found_resolves_to: None, + use_guard: false, + } + } + + /// By default trying to resolve '.../' to '.../index.html' if it exists. + /// Turn off this resolution by calling this function. + pub fn do_not_resolve_defaults(mut self) -> Self { + self.not_resolve_defaults = true; + self + } + + /// Resolves not found references to this path. + /// + /// This can be useful for angular-like applications. + pub fn resolve_not_found_to<S: ToString>(mut self, path: S) -> Self { + self.not_found_resolves_to = Some(path.to_string()); + self + } + + /// Resolves not found references to root path. + /// + /// This can be useful for angular-like applications. + pub fn resolve_not_found_to_root(self) -> Self { + self.resolve_not_found_to(INDEX_HTML) + } + + /// If this is called, we will use an [actix_web::guard::Guard] to check if this request should be handled. + /// If set to true, we skip using the handler for files that haven't been found, instead of sending 404s. + /// Would be ignored, if `resolve_not_found_to` or `resolve_not_found_to_root` is used. + /// + /// Can be useful if you want to share files on a (sub)path that's also used by a different route handler. + pub fn skip_handler_when_not_found(mut self) -> Self { + self.use_guard = true; + self + } + + fn select_guard(&self) -> Box<dyn Guard> { + if self.not_resolve_defaults { + Box::new(NotResolveDefaultsGuard::from(self)) + } else { + Box::new(ResolveDefaultsGuard::from(self)) + } + } +} + +impl Deref for ResourceFiles { + type Target = ResourceFilesInner; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +struct NotResolveDefaultsGuard { + inner: Rc<ResourceFilesInner>, +} + +impl Guard for NotResolveDefaultsGuard { + fn check(&self, ctx: &GuardContext<'_>) -> bool { + self.inner + .files + .contains_key(ctx.head().uri.path().trim_start_matches('/')) + } +} + +impl From<&ResourceFiles> for NotResolveDefaultsGuard { + fn from(files: &ResourceFiles) -> Self { + Self { + inner: files.inner.clone(), + } + } +} + +struct ResolveDefaultsGuard { + inner: Rc<ResourceFilesInner>, +} + +impl Guard for ResolveDefaultsGuard { + fn check(&self, ctx: &GuardContext<'_>) -> bool { + let path = ctx.head().uri.path().trim_start_matches('/'); + self.inner.files.contains_key(path) + || ((path.is_empty() || path.ends_with('/')) + && self + .inner + .files + .contains_key((path.to_string() + INDEX_HTML).as_str())) + } +} + +impl From<&ResourceFiles> for ResolveDefaultsGuard { + fn from(files: &ResourceFiles) -> Self { + Self { + inner: files.inner.clone(), + } + } +} + +impl HttpServiceFactory for ResourceFiles { + fn register(self, config: &mut AppService) { + let prefix = self.path.trim_start_matches('/'); + let rdef = if config.is_root() { + ResourceDef::root_prefix(prefix) + } else { + ResourceDef::prefix(prefix) + }; + let guards = if self.use_guard && self.not_found_resolves_to.is_none() { + Some(vec![self.select_guard()]) + } else { + None + }; + config.register_service(rdef, guards, self, None); + } +} + +impl ServiceFactory<ServiceRequest> for ResourceFiles { + type Config = (); + type Response = ServiceResponse; + type Error = Error; + type Service = ResourceFilesService; + type InitError = (); + type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>; + + fn new_service(&self, _: ()) -> Self::Future { + ok(ResourceFilesService { + resolve_defaults: !self.not_resolve_defaults, + not_found_resolves_to: self.not_found_resolves_to.clone(), + inner: self.inner.clone(), + }) + .boxed_local() + } +} + +#[derive(Deref)] +pub struct ResourceFilesService { + resolve_defaults: bool, + not_found_resolves_to: Option<String>, + #[deref] + inner: Rc<ResourceFilesInner>, +} + +impl Service<ServiceRequest> for ResourceFilesService { + type Response = ServiceResponse; + type Error = Error; + type Future = Ready<Result<Self::Response, Self::Error>>; + + always_ready!(); + + fn call(&self, req: ServiceRequest) -> Self::Future { + match *req.method() { + Method::HEAD | Method::GET => (), + _ => { + return ok(ServiceResponse::new( + req.into_parts().0, + HttpResponse::MethodNotAllowed() + .insert_header(ContentType::plaintext()) + .insert_header((header::ALLOW, "GET, HEAD")) + .body("This resource only supports GET and HEAD."), + )); + } + } + + let req_path = req.match_info().unprocessed(); + let mut item = self.files.get(req_path); + + if item.is_none() + && self.resolve_defaults + && (req_path.is_empty() || req_path.ends_with('/')) + { + let index_req_path = req_path.to_string() + INDEX_HTML; + item = self.files.get(index_req_path.trim_start_matches('/')); + } + + let (req, response) = if item.is_some() { + let (req, _) = req.into_parts(); + let response = respond_to(&req, item); + (req, response) + } else { + let real_path = match get_pathbuf(req_path) { + Ok(item) => item, + Err(e) => return ok(req.error_response(e)), + }; + + let (req, _) = req.into_parts(); + + let mut item = self.files.get(real_path.as_str()); + + if item.is_none() && self.not_found_resolves_to.is_some() { + let not_found_path = self.not_found_resolves_to.as_ref().unwrap(); + item = self.files.get(not_found_path.as_str()); + } + + let response = respond_to(&req, item); + (req, response) + }; + + ok(ServiceResponse::new(req, response)) + } +} + +fn respond_to(req: &HttpRequest, item: Option<&Resource>) -> HttpResponse { + if let Some(file) = item { + let etag = Some(header::EntityTag::new_strong(format!( + "{:x}:{:x}", + file.data.len(), + file.modified + ))); + + let precondition_failed = !any_match(etag.as_ref(), req); + + let not_modified = !none_match(etag.as_ref(), req); + + let mut resp = HttpResponse::build(StatusCode::OK); + resp.insert_header((header::CONTENT_TYPE, file.mime_type)); + + if let Some(etag) = etag { + resp.insert_header(header::ETag(etag)); + } + + if precondition_failed { + return resp.status(StatusCode::PRECONDITION_FAILED).finish(); + } else if not_modified { + return resp.status(StatusCode::NOT_MODIFIED).finish(); + } + + resp.body(file.data) + } else { + HttpResponse::NotFound().body("Not found") + } +} + +/// Returns true if `req` has no `If-Match` header or one which matches `etag`. +fn any_match(etag: Option<&header::EntityTag>, req: &HttpRequest) -> bool { + match req.get_header::<header::IfMatch>() { + None | Some(header::IfMatch::Any) => true, + Some(header::IfMatch::Items(ref items)) => { + if let Some(some_etag) = etag { + for item in items { + if item.strong_eq(some_etag) { + return true; + } + } + } + false + } + } +} + +/// Returns true if `req` doesn't have an `If-None-Match` header matching `req`. +fn none_match(etag: Option<&header::EntityTag>, req: &HttpRequest) -> bool { + match req.get_header::<header::IfNoneMatch>() { + Some(header::IfNoneMatch::Any) => false, + Some(header::IfNoneMatch::Items(ref items)) => { + if let Some(some_etag) = etag { + for item in items { + if item.weak_eq(some_etag) { + return false; + } + } + } + true + } + None => true, + } +} + +/// Error type representing invalid characters in a URI path segment. +/// +/// This enum is used to report specific formatting errors in individual segments of a URI path, +/// such as starting, ending, or containing disallowed characters. Each variant wraps the offending +/// character that caused the error. +#[derive(Debug, PartialEq, Display, Error)] +pub enum UriSegmentError { + /// The segment started with the wrapped invalid character. + #[display(fmt = "The segment started with the wrapped invalid character")] + BadStart(#[error(not(source))] char), + + /// The segment contained the wrapped invalid character. + #[display(fmt = "The segment contained the wrapped invalid character")] + BadChar(#[error(not(source))] char), + + /// The segment ended with the wrapped invalid character. + #[display(fmt = "The segment ended with the wrapped invalid character")] + BadEnd(#[error(not(source))] char), +} + +#[cfg(test)] +mod tests_error_impl { + use super::*; + + fn assert_send_and_sync<T: Send + Sync + 'static>() {} + + #[test] + fn test_error_impl() { + // ensure backwards compatibility when migrating away from failure + assert_send_and_sync::<UriSegmentError>(); + } +} + +/// Return `BadRequest` for `UriSegmentError` +impl ResponseError for UriSegmentError { + fn error_response(&self) -> HttpResponse { + HttpResponse::new(StatusCode::BAD_REQUEST) + } +} + +fn get_pathbuf(path: &str) -> Result<String, UriSegmentError> { + let mut buf = Vec::new(); + for segment in path.split('/') { + if segment == ".." { + buf.pop(); + } else if segment.starts_with('.') { + return Err(UriSegmentError::BadStart('.')); + } else if segment.starts_with('*') { + return Err(UriSegmentError::BadStart('*')); + } else if segment.ends_with(':') { + return Err(UriSegmentError::BadEnd(':')); + } else if segment.ends_with('>') { + return Err(UriSegmentError::BadEnd('>')); + } else if segment.ends_with('<') { + return Err(UriSegmentError::BadEnd('<')); + } else if segment.is_empty() { + continue; + } else if cfg!(windows) && segment.contains('\\') { + return Err(UriSegmentError::BadChar('\\')); + } else { + buf.push(segment) + } + } + + Ok(buf.join("/")) +} diff --git a/helpers/pagetop-statics/src/sets.rs b/helpers/pagetop-statics/src/sets.rs new file mode 100644 index 00000000..1d9299df --- /dev/null +++ b/helpers/pagetop-statics/src/sets.rs @@ -0,0 +1,184 @@ +use std::{ + fs::{self, File, Metadata}, + io::{self, Write}, + path::{Path, PathBuf}, +}; + +use super::resource::{ + collect_resources, generate_function_end, generate_function_header, generate_resource_insert, + generate_uses, generate_variable_header, generate_variable_return, DEFAULT_VARIABLE_NAME, +}; + +/// Defines the split strategie. +pub trait SetSplitStrategie { + /// Register next file from resources. + fn register(&mut self, path: &Path, metadata: &Metadata); + /// Determine, should we split modules now. + fn should_split(&self) -> bool; + /// Resets internal counters after split. + fn reset(&mut self); +} + +/// Split modules by files count. +pub struct SplitByCount { + current: usize, + max: usize, +} + +impl SplitByCount { + pub fn new(max: usize) -> Self { + Self { current: 0, max } + } +} + +impl SetSplitStrategie for SplitByCount { + fn register(&mut self, _path: &Path, _metadata: &Metadata) { + self.current += 1; + } + + fn should_split(&self) -> bool { + self.current >= self.max + } + + fn reset(&mut self) { + self.current = 0; + } +} + +/// Generate resources for `project_dir` using `filter` +/// breaking them into separate modules using `set_split_strategie` (recommended for large > 128 Mb setups). +/// +/// Result saved in module named `module_name`. It exports +/// only one function named `fn_name`. It is then exported from +/// `generated_filename`. `generated_filename` is also used to determine +/// the parent directory for the module. +/// +/// in `build.rs`: +/// ```rust +/// +/// use std::{env, path::Path}; +/// use pagetop_statics::sets::{generate_resources_sets, SplitByCount}; +/// +/// fn main() { +/// let out_dir = env::var("OUT_DIR").unwrap(); +/// let generated_filename = Path::new(&out_dir).join("generated_sets.rs"); +/// generate_resources_sets( +/// "./tests", +/// None, +/// generated_filename, +/// "sets", +/// "generate", +/// &mut SplitByCount::new(2), +/// "pagetop_statics", +/// ) +/// .unwrap(); +/// } +/// ``` +/// +/// in `main.rs`: +/// ```rust +/// include!(concat!(env!("OUT_DIR"), "/generated_sets.rs")); +/// +/// fn main() { +/// let generated_file = generate(); +/// +/// assert_eq!(generated_file.len(), 4); +/// +/// } +/// ``` +pub fn generate_resources_sets<P, G, S>( + project_dir: P, + filter: Option<fn(p: &Path) -> bool>, + generated_filename: G, + module_name: &str, + fn_name: &str, + set_split_strategie: &mut S, + crate_name: &str, +) -> io::Result<()> +where + P: AsRef<Path>, + G: AsRef<Path>, + S: SetSplitStrategie, +{ + let resources = collect_resources(&project_dir, filter)?; + + let mut generated_file = File::create(&generated_filename)?; + + let module_dir = generated_filename.as_ref().parent().map_or_else( + || PathBuf::from(module_name), + |parent| parent.join(module_name), + ); + fs::create_dir_all(&module_dir)?; + + let mut module_file = File::create(module_dir.join("mod.rs"))?; + + generate_uses(&mut module_file, crate_name)?; + writeln!( + module_file, + " +use ::{crate_name}::StaticResource; +use ::std::collections::HashMap;" + )?; + + let mut modules_count = 1; + + let mut set_file = create_set_module_file(&module_dir, modules_count)?; + let mut should_split = set_split_strategie.should_split(); + + for resource in &resources { + let (path, metadata) = &resource; + if should_split { + set_split_strategie.reset(); + modules_count += 1; + generate_function_end(&mut set_file)?; + set_file = create_set_module_file(&module_dir, modules_count)?; + } + set_split_strategie.register(path, metadata); + should_split = set_split_strategie.should_split(); + + generate_resource_insert(&mut set_file, &project_dir, DEFAULT_VARIABLE_NAME, resource)?; + } + + generate_function_end(&mut set_file)?; + + for module_index in 1..=modules_count { + writeln!(module_file, "mod set_{module_index};")?; + } + + generate_function_header(&mut module_file, fn_name, crate_name)?; + + generate_variable_header(&mut module_file, DEFAULT_VARIABLE_NAME)?; + + for module_index in 1..=modules_count { + writeln!( + module_file, + "set_{module_index}::generate(&mut {DEFAULT_VARIABLE_NAME});", + )?; + } + + generate_variable_return(&mut module_file, DEFAULT_VARIABLE_NAME)?; + + generate_function_end(&mut module_file)?; + + writeln!( + generated_file, + "mod {module_name}; +pub use {module_name}::{fn_name};", + )?; + + Ok(()) +} + +fn create_set_module_file(module_dir: &Path, module_index: usize) -> io::Result<File> { + let mut set_module = File::create(module_dir.join(format!("set_{module_index}.rs")))?; + + writeln!( + set_module, + "#[allow(clippy::wildcard_imports)] +use super::*; +#[allow(clippy::unreadable_literal)] +pub(crate) fn generate({DEFAULT_VARIABLE_NAME}: &mut HashMap<&'static str, StaticResource>) {{", + )?; + + Ok(set_module) +} diff --git a/helpers/pagetop-statics/tests/file1.txt b/helpers/pagetop-statics/tests/file1.txt new file mode 100644 index 00000000..e69de29b diff --git a/helpers/pagetop-statics/tests/file2.txt b/helpers/pagetop-statics/tests/file2.txt new file mode 100644 index 00000000..e69de29b diff --git a/helpers/pagetop-statics/tests/file3.info b/helpers/pagetop-statics/tests/file3.info new file mode 100644 index 00000000..e69de29b diff --git a/helpers/pagetop-statics/tests/index.html b/helpers/pagetop-statics/tests/index.html new file mode 100644 index 00000000..36f505f2 --- /dev/null +++ b/helpers/pagetop-statics/tests/index.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Document</title> +</head> +<body> +</body> +</html> diff --git a/src/lib.rs b/src/lib.rs index e0da3617..bbc45302 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,21 +98,23 @@ use std::ops::Deref; pub use pagetop_macros::{builder_fn, html, main, test, AutoDefault}; +pub use pagetop_statics::{resource, StaticResource}; + /// Conjunto de recursos asociados a `$STATIC` en [`include_files!`](crate::include_files). pub struct StaticResources { - bundle: HashMap<&'static str, static_files::Resource>, + bundle: HashMap<&'static str, StaticResource>, } impl StaticResources { /// Crea un contenedor para un conjunto de recursos generado por `build.rs` (consultar /// [`pagetop_build`](https://docs.rs/pagetop-build)). - pub fn new(bundle: HashMap<&'static str, static_files::Resource>) -> Self { + pub fn new(bundle: HashMap<&'static str, StaticResource>) -> Self { Self { bundle } } } impl Deref for StaticResources { - type Target = HashMap<&'static str, static_files::Resource>; + type Target = HashMap<&'static str, StaticResource>; fn deref(&self) -> &Self::Target { &self.bundle diff --git a/src/service.rs b/src/service.rs index 89ba4966..47f1420d 100644 --- a/src/service.rs +++ b/src/service.rs @@ -8,9 +8,9 @@ pub use actix_web::dev::ServiceRequest as Request; pub use actix_web::dev::ServiceResponse as Response; pub use actix_web::{cookie, http, rt, web}; pub use actix_web::{App, Error, HttpMessage, HttpRequest, HttpResponse, HttpServer}; - pub use actix_web_files::Files as ActixFiles; -pub use actix_web_static_files::ResourceFiles; + +pub use pagetop_statics::ResourceFiles; #[doc(hidden)] pub use actix_web::test; From db1ee4887557951240720899aafee3f232ad11ce Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 9 Aug 2025 10:17:14 +0200 Subject: [PATCH 130/244] =?UTF-8?q?=F0=9F=94=A8=20A=C3=B1ade=20soporte=20a?= =?UTF-8?q?=20changelog=20de=20`pagetop-statics`=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://git.cillero.es/manuelcillero/pagetop/pulls/2 Co-authored-by: Manuel Cillero <manuel@cillero.es> Co-committed-by: Manuel Cillero <manuel@cillero.es> --- .cargo/cliff.toml | 6 +++--- tools/changelog.sh | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.cargo/cliff.toml b/.cargo/cliff.toml index 5e4cfb85..cbbb57b6 100644 --- a/.cargo/cliff.toml +++ b/.cargo/cliff.toml @@ -21,9 +21,9 @@ body = """ {% else %} ## Pendiente de publicación {% endif %}\ -{% set base = "https://git.cillero.es/manuelcillero/pagetop" %}\ {% for group, commits in commits | group_by(attribute="group") %} ### {{ group | upper_first }} + {% for commit in commits %} {%- set msg = commit.message | split(pat="\n") @@ -41,8 +41,8 @@ body = """ | replace(from="📝 ", to="") | replace(from="💡 ", to="") -%} -{% set sha7 = commit.id | truncate(length=7, end="") %} -- {{ msg | trim }} ([{{ sha7 }}]({{ base }}/commit/{{ commit.id }}){% if commit.author.name != "Manuel Cillero" %} - {{ commit.author.name }}{% endif %}) + +- {{ msg | trim }} {% if commit.author.name != "Manuel Cillero" %} - {{ commit.author.name }}{% endif %} {% endfor %}{% endfor %} """ diff --git a/tools/changelog.sh b/tools/changelog.sh index 13333d4a..2668ec67 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -35,6 +35,10 @@ cd "$(dirname "$0")/.." || exit 1 # Determina ruta del archivo y ámbito de los archivos afectados para el crate # ------------------------------------------------------------------------------ case "$CRATE" in + pagetop-statics) + CHANGELOG_FILE="helpers/pagetop-statics/CHANGELOG.md" + PATH_FLAGS=(--include-path "helpers/pagetop-statics/**/*") + ;; pagetop-build) CHANGELOG_FILE="helpers/pagetop-build/CHANGELOG.md" PATH_FLAGS=(--include-path "helpers/pagetop-build/**/*") @@ -46,6 +50,7 @@ case "$CRATE" in pagetop) CHANGELOG_FILE="CHANGELOG.md" PATH_FLAGS=( + --exclude-path "helpers/pagetop-statics/**/*" --exclude-path "helpers/pagetop-build/**/*" --exclude-path "helpers/pagetop-macros/**/*" ) From cb1b6cbdac96baabeb3f3cadf5f3b7385b74ad7f Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 9 Aug 2025 10:27:39 +0200 Subject: [PATCH 131/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-statics=200.1.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- Cargo.toml | 2 +- helpers/pagetop-statics/CHANGELOG.md | 15 +++++++++++++++ helpers/pagetop-statics/Cargo.toml | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 helpers/pagetop-statics/CHANGELOG.md diff --git a/Cargo.lock b/Cargo.lock index 2f15a489..8427dd24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1605,7 +1605,7 @@ dependencies = [ [[package]] name = "pagetop-statics" -version = "0.0.1" +version = "0.1.0" dependencies = [ "actix-web", "change-detection", diff --git a/Cargo.toml b/Cargo.toml index 36007421..ff45ad3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,4 +73,4 @@ actix-web = { version = "4.11.0", default-features = false } pagetop-build = { version = "0.1", path = "helpers/pagetop-build" } pagetop-macros = { version = "0.1", path = "helpers/pagetop-macros" } -pagetop-statics = { version = "0.0", path = "helpers/pagetop-statics" } +pagetop-statics = { version = "0.1", path = "helpers/pagetop-statics" } diff --git a/helpers/pagetop-statics/CHANGELOG.md b/helpers/pagetop-statics/CHANGELOG.md new file mode 100644 index 00000000..62ad97e8 --- /dev/null +++ b/helpers/pagetop-statics/CHANGELOG.md @@ -0,0 +1,15 @@ +# CHANGELOG + +Este archivo documenta los cambios más relevantes realizados en cada versión. El formato está basado +en [Keep a Changelog](https://keepachangelog.com/es-ES/1.0.0/), y las versiones se numeran siguiendo +las reglas del [Versionado Semántico](https://semver.org/lang/es/). + +Resume la evolución del proyecto para usuarios y colaboradores, destacando nuevas funcionalidades, +correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o +internos pueden omitirse si no afectan al uso del proyecto. + +## 0.1.0 (2025-08-09) + +### Añadido + +- Versión inicial diff --git a/helpers/pagetop-statics/Cargo.toml b/helpers/pagetop-statics/Cargo.toml index f41cec76..e5c58d5e 100644 --- a/helpers/pagetop-statics/Cargo.toml +++ b/helpers/pagetop-statics/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-statics" -version = "0.0.1" +version = "0.1.0" edition = "2021" description = """ From f7c1b56981e407a14ff28338b699a50ce88b045e Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 9 Aug 2025 10:30:53 +0200 Subject: [PATCH 132/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-build=200.2.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- Cargo.toml | 2 +- helpers/pagetop-build/CHANGELOG.md | 11 +++++++++++ helpers/pagetop-build/Cargo.toml | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8427dd24..8f1450ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1587,7 +1587,7 @@ dependencies = [ [[package]] name = "pagetop-build" -version = "0.1.1" +version = "0.2.0" dependencies = [ "grass", "pagetop-statics", diff --git a/Cargo.toml b/Cargo.toml index ff45ad3b..b3da8ca9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,6 +71,6 @@ authors = ["Manuel Cillero <manuel@cillero.es>"] [workspace.dependencies] actix-web = { version = "4.11.0", default-features = false } -pagetop-build = { version = "0.1", path = "helpers/pagetop-build" } +pagetop-build = { version = "0.2", path = "helpers/pagetop-build" } pagetop-macros = { version = "0.1", path = "helpers/pagetop-macros" } pagetop-statics = { version = "0.1", path = "helpers/pagetop-statics" } diff --git a/helpers/pagetop-build/CHANGELOG.md b/helpers/pagetop-build/CHANGELOG.md index 22429694..4d087556 100644 --- a/helpers/pagetop-build/CHANGELOG.md +++ b/helpers/pagetop-build/CHANGELOG.md @@ -8,6 +8,17 @@ Resume la evolución del proyecto para usuarios y colaboradores, destacando nuev correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o internos pueden omitirse si no afectan al uso del proyecto. +## 0.2.0 (2025-08-09) + +### Añadido + +- Añade librería propia para gestionar recursos estáticos (#1) + +### Otros cambios + +- 🩹 Corrige enlace del botón de licencia en la documentación +- 🚩 Afina Cargo.toml para buscar la mejor categoría + ## 0.1.1 (2025-08-05) - Depura la edición de CHANGELOGs y publicación de nuevas versiones diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index 41e826e9..14e6000b 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-build" -version = "0.1.1" +version = "0.2.0" edition = "2021" description = """ From 3bb8b9c0515f09009eceb03b305af9741b061dc6 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 9 Aug 2025 10:34:38 +0200 Subject: [PATCH 133/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop=200.2.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 12 ++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b01b9883..2248658d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,18 @@ Resume la evolución del proyecto para usuarios y colaboradores, destacando nuev correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o internos pueden omitirse si no afectan al uso del proyecto. +## 0.2.0 (2025-08-09) + +### Añadido + +- Añade librería para gestionar recursos estáticos (#1) +- Añade soporte a changelog de `pagetop-statics` (#2) + +### Otros cambios + +- 🩹 Corrige enlace del botón de licencia en la documentación +- 🚩 Afina Cargo.toml para buscar la mejor categoría + ## 0.1.0 (2025-08-06) - Versión inicial diff --git a/Cargo.lock b/Cargo.lock index 8f1450ae..22cf3086 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1557,7 +1557,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.1.0" +version = "0.2.0" dependencies = [ "actix-files", "actix-session", diff --git a/Cargo.toml b/Cargo.toml index b3da8ca9..cdeae782 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = """ From b77e47d6e4073f3c9c46a4b66919a241d7597bcb Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 10 Aug 2025 00:48:39 +0200 Subject: [PATCH 134/244] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Mej?= =?UTF-8?q?ora=20funci=C3=B3n=20`from=5Fdir`=20por=20compatibilidad=20(#3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://git.cillero.es/manuelcillero/pagetop/pulls/3 Co-authored-by: Manuel Cillero <manuel@cillero.es> Co-committed-by: Manuel Cillero <manuel@cillero.es> --- helpers/pagetop-build/src/lib.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index b360377f..bb326063 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -129,8 +129,7 @@ use std::fs::{create_dir_all, remove_dir_all, File}; use std::io::Write; use std::path::Path; -/// Prepara un conjunto de recursos para ser incluidos en el binario del proyecto utilizando -/// [static_files](https://docs.rs/static-files/). +/// Prepara un conjunto de recursos para ser incluidos en el binario del proyecto. pub struct StaticFilesBundle { resource_dir: ResourceDir, } @@ -163,8 +162,19 @@ impl StaticFilesBundle { /// .build() /// } /// ``` - pub fn from_dir(dir: impl AsRef<str>, filter: Option<fn(p: &Path) -> bool>) -> Self { - let mut resource_dir = resource_dir(dir.as_ref()); + pub fn from_dir<P>(dir: P, filter: Option<fn(&Path) -> bool>) -> Self + where + P: AsRef<Path>, + { + let dir_path = dir.as_ref(); + let dir_str = dir_path.to_str().unwrap_or_else(|| { + panic!( + "Resource directory path is not valid UTF-8: {}", + dir_path.display() + ); + }); + + let mut resource_dir = resource_dir(dir_str); // Aplica el filtro si está definido. if let Some(f) = filter { From 168d5dc648784d334f197c6aaba801ea1e6b7c74 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 10 Aug 2025 01:10:05 +0200 Subject: [PATCH 135/244] =?UTF-8?q?=F0=9F=93=9D=20Cambia=20el=20formato=20?= =?UTF-8?q?para=20la=20documentaci=C3=B3n=20(#4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://git.cillero.es/manuelcillero/pagetop/pulls/4 Co-authored-by: Manuel Cillero <manuel@cillero.es> Co-committed-by: Manuel Cillero <manuel@cillero.es> --- README.md | 14 +- helpers/pagetop-build/README.md | 101 ++++++++++++ helpers/pagetop-build/src/lib.rs | 240 +++++++++++++++-------------- helpers/pagetop-macros/README.md | 17 +- helpers/pagetop-macros/src/lib.rs | 49 +++--- helpers/pagetop-statics/README.md | 21 +-- helpers/pagetop-statics/src/lib.rs | 49 ++++-- src/lib.rs | 169 ++++++++++---------- 8 files changed, 404 insertions(+), 256 deletions(-) diff --git a/README.md b/README.md index fe85e665..e7fab94b 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ [![Crates.io](https://img.shields.io/crates/v/pagetop.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop) [![Descargas](https://img.shields.io/crates/d/pagetop.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop) +<br> </div> `PageTop` reivindica la esencia de la web clásica usando [Rust](https://www.rust-lang.org/es) para @@ -32,7 +33,7 @@ según las necesidades de cada proyecto, incluyendo: La aplicación más sencilla de `PageTop` se ve así: -```rust +```rust,no_run use pagetop::prelude::*; #[pagetop::main] @@ -46,7 +47,7 @@ de bienvenida accesible desde un navegador local en la dirección `http://localh Para personalizar el servicio, se puede crear una extensión de `PageTop` de la siguiente manera: -```rust +```rust,no_run use pagetop::prelude::*; struct HelloWorld; @@ -83,9 +84,14 @@ El código se organiza en un *workspace* donde actualmente se incluyen los sigui ## Auxiliares + * **[pagetop-statics](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-statics)**, + es la librería que permite incluir archivos estáticos en el ejecutable de las aplicaciones + `PageTop` para servirlos de forma eficiente, con detección de cambios que optimizan el tiempo + de compilación. + * **[pagetop-build](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-build)**, - permite incluir fácilmente archivos estáticos o archivos SCSS compilados directamente en el - binario de las aplicaciones `PageTop`. + prepara los archivos estáticos o archivos SCSS compilados para incluirlos en el binario de las + aplicaciones `PageTop` durante la compilación de los ejecutables. * **[pagetop-macros](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-macros)**, proporciona una colección de macros que mejoran la experiencia de desarrollo con `PageTop`. diff --git a/helpers/pagetop-build/README.md b/helpers/pagetop-build/README.md index d9d52571..5af492b1 100644 --- a/helpers/pagetop-build/README.md +++ b/helpers/pagetop-build/README.md @@ -18,6 +18,107 @@ clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares configurables, basadas en HTML, CSS y JavaScript. +# ⚡️ Guía rápida + +Añadir en el archivo `Cargo.toml` del proyecto: + +```toml +[build-dependencies] +pagetop-build = { ... } +``` + +Y crear un archivo `build.rs` a la altura de `Cargo.toml` para indicar cómo se van a incluir los +archivos estáticos o cómo se van a compilar los archivos SCSS para el proyecto. Casos de uso: + +## Incluir archivos estáticos desde un directorio + +Hay que preparar una carpeta en el proyecto con todos los archivos que se quieren incluir, por +ejemplo `static`, y añadir el siguiente código en `build.rs` para crear el conjunto de recursos: + +```rust,no_run +use pagetop_build::StaticFilesBundle; + +fn main() -> std::io::Result<()> { + StaticFilesBundle::from_dir("./static", None) + .with_name("guides") + .build() +} +``` + +Si es necesario, se puede añadir un filtro para seleccionar archivos específicos de la carpeta, por +ejemplo: + +```rust,no_run +use pagetop_build::StaticFilesBundle; +use std::path::Path; + +fn main() -> std::io::Result<()> { + fn only_pdf_files(path: &Path) -> bool { + // Selecciona únicamente los archivos con extensión `.pdf`. + path.extension().map_or(false, |ext| ext == "pdf") + } + + StaticFilesBundle::from_dir("./static", Some(only_pdf_files)) + .with_name("guides") + .build() +} +``` + +## Compilar archivos SCSS a CSS + +Se puede compilar un archivo SCSS, que podría importar otros a su vez, para preparar un recurso con +el archivo CSS minificado obtenido. Por ejemplo: + +```rust,no_run +use pagetop_build::StaticFilesBundle; + +fn main() -> std::io::Result<()> { + StaticFilesBundle::from_scss("./styles/main.scss", "styles.min.css") + .with_name("main_styles") + .build() +} +``` + +Este código compila el archivo `main.scss` de la carpeta `static` del proyecto, y prepara un recurso +llamado `main_styles` que contiene el archivo `styles.min.css` obtenido. + + +# 📦 Módulos generados + +Cada conjunto de recursos [`StaticFilesBundle`] genera un archivo en el directorio estándar +[OUT_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) +donde se incluyen los recursos necesarios para compilar el proyecto. Por ejemplo, para +`with_name("guides")` se crea un archivo llamado `guides.rs`. + +No hay ningún problema en generar más de un conjunto de recursos para cada proyecto. + +Normalmente no habrá que acceder a estos módulos; bastará con incluirlos en el proyecto con +[`include_files!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files.html), y luego con +[`include_files_service!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files_service.html) +configurar un servicio web para servir los recursos desde la ruta indicada: + +```rust,ignore +use pagetop::prelude::*; + +include_files!(guides); + +pub struct MyExtension; + +impl Extension for MyExtension { + // Servicio web que publica los recursos de `guides` en `/ruta/a/guides`. + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + include_files_service!(scfg, guides => "/ruta/a/guides"); + } +} +``` + +También se puede asignar el conjunto de recursos a una variable global; p.ej. `GUIDES`: + +```rust,ignore +include_files!(GUIDES => guides); +``` + + # 🚧 Advertencia `PageTop` es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index bb326063..09dec428 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -1,122 +1,124 @@ -//! <div align="center"> -//! -//! <h1>PageTop Build</h1> -//! -//! <p>Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el binario de un proyecto <strong>PageTop</strong>.</p> -//! -//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) -//! [![Doc API](https://img.shields.io/docsrs/pagetop-build?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-build) -//! [![Crates.io](https://img.shields.io/crates/v/pagetop-build.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-build) -//! [![Descargas](https://img.shields.io/crates/d/pagetop-build.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-build) -//! -//! </div> -//! -//! ## Sobre PageTop -//! -//! [PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la -//! web clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles -//! y configurables, basadas en HTML, CSS y JavaScript. -//! -//! -//! # ⚡️ Guía rápida -//! -//! Añadir en el archivo `Cargo.toml` del proyecto: -//! -//! ```toml -//! [build-dependencies] -//! pagetop-build = { ... } -//! ``` -//! -//! Y crear un archivo `build.rs` a la altura de `Cargo.toml` para indicar cómo se van a incluir los -//! archivos estáticos o cómo se van a compilar los archivos SCSS para el proyecto. Casos de uso: -//! -//! ## Incluir archivos estáticos desde un directorio -//! -//! Hay que preparar una carpeta en el proyecto con todos los archivos que se quieren incluir, por -//! ejemplo `static`, y añadir el siguiente código en `build.rs` para crear el conjunto de recursos: -//! -//! ```rust,no_run -//! use pagetop_build::StaticFilesBundle; -//! -//! fn main() -> std::io::Result<()> { -//! StaticFilesBundle::from_dir("./static", None) -//! .with_name("guides") -//! .build() -//! } -//! ``` -//! -//! Si es necesario, se puede añadir un filtro para seleccionar archivos específicos de la carpeta, -//! por ejemplo: -//! -//! ```rust,no_run -//! use pagetop_build::StaticFilesBundle; -//! use std::path::Path; -//! -//! fn main() -> std::io::Result<()> { -//! fn only_pdf_files(path: &Path) -> bool { -//! // Selecciona únicamente los archivos con extensión `.pdf`. -//! path.extension().map_or(false, |ext| ext == "pdf") -//! } -//! -//! StaticFilesBundle::from_dir("./static", Some(only_pdf_files)) -//! .with_name("guides") -//! .build() -//! } -//! ``` -//! -//! ## Compilar archivos SCSS a CSS -//! -//! Se puede compilar un archivo SCSS, que podría importar otros a su vez, para preparar un recurso -//! con el archivo CSS minificado obtenido. Por ejemplo: -//! -//! ```rust,no_run -//! use pagetop_build::StaticFilesBundle; -//! -//! fn main() -> std::io::Result<()> { -//! StaticFilesBundle::from_scss("./styles/main.scss", "styles.min.css") -//! .with_name("main_styles") -//! .build() -//! } -//! ``` -//! -//! Este código compila el archivo `main.scss` de la carpeta `static` del proyecto, y prepara un -//! recurso llamado `main_styles` que contiene el archivo `styles.min.css` obtenido. -//! -//! -//! # 📦 Módulos generados -//! -//! Cada conjunto de recursos [`StaticFilesBundle`] genera un archivo en el directorio estándar -//! [OUT_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) -//! donde se incluyen los recursos necesarios para compilar el proyecto. Por ejemplo, para -//! `with_name("guides")` se crea un archivo llamado `guides.rs`. -//! -//! No hay ningún problema en generar más de un conjunto de recursos para cada proyecto. -//! -//! Normalmente no habrá que acceder a estos módulos; bastará con incluirlos en el proyecto con -//! [`include_files!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files.html), y luego con -//! [`include_files_service!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files_service.html) -//! configurar un servicio web para servir los recursos desde la ruta indicada: -//! -//! ```rust,ignore -//! use pagetop::prelude::*; -//! -//! include_files!(guides); -//! -//! pub struct MyExtension; -//! -//! impl Extension for MyExtension { -//! // Servicio web que publica los recursos de `guides` en `/ruta/a/guides`. -//! fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { -//! include_files_service!(scfg, guides => "/ruta/a/guides"); -//! } -//! } -//! ``` -//! -//! También se puede asignar el conjunto de recursos a una variable global; p.ej. `GUIDES`: -//! -//! ```rust,ignore -//! include_files!(GUIDES => guides); -//! ``` +/*! +<div align="center"> + +<h1>PageTop Build</h1> + +<p>Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el binario de un proyecto <strong>PageTop</strong>.</p> + +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) +[![Doc API](https://img.shields.io/docsrs/pagetop-build?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-build) +[![Crates.io](https://img.shields.io/crates/v/pagetop-build.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-build) +[![Descargas](https://img.shields.io/crates/d/pagetop-build.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-build) + +</div> + +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + + +# ⚡️ Guía rápida + +Añadir en el archivo `Cargo.toml` del proyecto: + +```toml +[build-dependencies] +pagetop-build = { ... } +``` + +Y crear un archivo `build.rs` a la altura de `Cargo.toml` para indicar cómo se van a incluir los +archivos estáticos o cómo se van a compilar los archivos SCSS para el proyecto. Casos de uso: + +## Incluir archivos estáticos desde un directorio + +Hay que preparar una carpeta en el proyecto con todos los archivos que se quieren incluir, por +ejemplo `static`, y añadir el siguiente código en `build.rs` para crear el conjunto de recursos: + +```rust,no_run +use pagetop_build::StaticFilesBundle; + +fn main() -> std::io::Result<()> { + StaticFilesBundle::from_dir("./static", None) + .with_name("guides") + .build() +} +``` + +Si es necesario, se puede añadir un filtro para seleccionar archivos específicos de la carpeta, por +ejemplo: + +```rust,no_run +use pagetop_build::StaticFilesBundle; +use std::path::Path; + +fn main() -> std::io::Result<()> { + fn only_pdf_files(path: &Path) -> bool { + // Selecciona únicamente los archivos con extensión `.pdf`. + path.extension().map_or(false, |ext| ext == "pdf") + } + + StaticFilesBundle::from_dir("./static", Some(only_pdf_files)) + .with_name("guides") + .build() +} +``` + +## Compilar archivos SCSS a CSS + +Se puede compilar un archivo SCSS, que podría importar otros a su vez, para preparar un recurso con +el archivo CSS minificado obtenido. Por ejemplo: + +```rust,no_run +use pagetop_build::StaticFilesBundle; + +fn main() -> std::io::Result<()> { + StaticFilesBundle::from_scss("./styles/main.scss", "styles.min.css") + .with_name("main_styles") + .build() +} +``` + +Este código compila el archivo `main.scss` de la carpeta `static` del proyecto, y prepara un recurso +llamado `main_styles` que contiene el archivo `styles.min.css` obtenido. + + +# 📦 Módulos generados + +Cada conjunto de recursos [`StaticFilesBundle`] genera un archivo en el directorio estándar +[OUT_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) +donde se incluyen los recursos necesarios para compilar el proyecto. Por ejemplo, para +`with_name("guides")` se crea un archivo llamado `guides.rs`. + +No hay ningún problema en generar más de un conjunto de recursos para cada proyecto. + +Normalmente no habrá que acceder a estos módulos; bastará con incluirlos en el proyecto con +[`include_files!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files.html), y luego con +[`include_files_service!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files_service.html) +configurar un servicio web para servir los recursos desde la ruta indicada: + +```rust,ignore +use pagetop::prelude::*; + +include_files!(guides); + +pub struct MyExtension; + +impl Extension for MyExtension { + // Servicio web que publica los recursos de `guides` en `/ruta/a/guides`. + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + include_files_service!(scfg, guides => "/ruta/a/guides"); + } +} +``` + +También se puede asignar el conjunto de recursos a una variable global; p.ej. `GUIDES`: + +```rust,ignore +include_files!(GUIDES => guides); +``` +*/ #![doc( html_favicon_url = "https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/favicon.ico" diff --git a/helpers/pagetop-macros/README.md b/helpers/pagetop-macros/README.md index c5006a87..e58d24c7 100644 --- a/helpers/pagetop-macros/README.md +++ b/helpers/pagetop-macros/README.md @@ -11,9 +11,16 @@ </div> -## Descripción general +## Sobre PageTop -Entre sus macros se incluye una adaptación de [maud-macros](https://crates.io/crates/maud_macros) +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + +## Créditos + +Esta librería incluye entre sus macros una adaptación de +[maud-macros](https://crates.io/crates/maud_macros) ([0.27.0](https://github.com/lambda-fairy/maud/tree/v0.27.0/maud_macros)) de [Chris Wong](https://crates.io/users/lambda-fairy) y una versión renombrada de [SmartDefault](https://crates.io/crates/smart_default) (0.7.1) de @@ -21,12 +28,6 @@ Entre sus macros se incluye una adaptación de [maud-macros](https://crates.io/c necesidad de referenciar `maud` o `smart_default` en las dependencias del archivo `Cargo.toml` de cada proyecto `PageTop`. -## Sobre PageTop - -[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web -clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y -configurables, basadas en HTML, CSS y JavaScript. - # 🚧 Advertencia diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 496ce82b..6421ca6e 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -1,21 +1,34 @@ -//! <div align="center"> -//! -//! <h1>PageTop Macros</h1> -//! -//! <p>Una colección de macros que mejoran la experiencia de desarrollo con <strong>PageTop</strong>.</p> -//! -//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) -//! [![Doc API](https://img.shields.io/docsrs/pagetop-macros?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-macros) -//! [![Crates.io](https://img.shields.io/crates/v/pagetop-macros.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-macros) -//! [![Descargas](https://img.shields.io/crates/d/pagetop-macros.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-macros) -//! -//! </div> -//! -//! ## Sobre PageTop -//! -//! [PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la -//! web clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles -//! y configurables, basadas en HTML, CSS y JavaScript. +/*! +<div align="center"> + +<h1>PageTop Macros</h1> + +<p>Una colección de macros que mejoran la experiencia de desarrollo con <strong>PageTop</strong>.</p> + +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) +[![Doc API](https://img.shields.io/docsrs/pagetop-macros?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-macros) +[![Crates.io](https://img.shields.io/crates/v/pagetop-macros.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-macros) +[![Descargas](https://img.shields.io/crates/d/pagetop-macros.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-macros) + +</div> + +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + +## Créditos + +Esta librería incluye entre sus macros una adaptación de +[maud-macros](https://crates.io/crates/maud_macros) +([0.27.0](https://github.com/lambda-fairy/maud/tree/v0.27.0/maud_macros)) de +[Chris Wong](https://crates.io/users/lambda-fairy) y una versión renombrada de +[SmartDefault](https://crates.io/crates/smart_default) (0.7.1) de +[Jane Doe](https://crates.io/users/jane-doe), llamada `AutoDefault`. Estas macros eliminan la +necesidad de referenciar `maud` o `smart_default` en las dependencias del archivo `Cargo.toml` de +cada proyecto `PageTop`. +*/ #![doc( html_favicon_url = "https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/favicon.ico" diff --git a/helpers/pagetop-statics/README.md b/helpers/pagetop-statics/README.md index c053e955..92999c04 100644 --- a/helpers/pagetop-statics/README.md +++ b/helpers/pagetop-statics/README.md @@ -8,12 +8,21 @@ </div> +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + ## Descripción general -Permite a `PageTop` incluir archivos estáticos en el ejecutable de la aplicación para servirlos de -forma eficiente vía web, con detección de cambios que optimiza el tiempo de compilación. +Esta librería permite incluir archivos estáticos en el ejecutable de las aplicaciones `PageTop` para +servirlos de forma eficiente vía web, con detección de cambios que optimizan el tiempo de +compilación. -Para ello, reúne el código de los *crates* [static-files](https://crates.io/crates/static_files) +## Créditos + +Para ello, adapta el código de los *crates* [static-files](https://crates.io/crates/static_files) (versión [0.2.5](https://github.com/static-files-rs/static-files/tree/v0.2.5)) y [actix-web-static-files](https://crates.io/crates/actix_web_static_files) (versión [4.0.1](https://github.com/kilork/actix-web-static-files/tree/v4.0.1)), desarrollados ambos por @@ -22,12 +31,6 @@ Para ello, reúne el código de los *crates* [static-files](https://crates.io/cr Estas implementaciones se integran en `PageTop` para evitar que cada proyecto tenga que declarar `static-files` manualmente como dependencia en su `Cargo.toml`. -## Sobre PageTop - -[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web -clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y -configurables, basadas en HTML, CSS y JavaScript. - # 🚧 Advertencia diff --git a/helpers/pagetop-statics/src/lib.rs b/helpers/pagetop-statics/src/lib.rs index fffd1ae3..dab50d9e 100644 --- a/helpers/pagetop-statics/src/lib.rs +++ b/helpers/pagetop-statics/src/lib.rs @@ -1,18 +1,37 @@ -//! <div align="center"> -//! -//! <h1>PageTop Statics</h1> -//! -//! <p>Librería para automatizar la recopilación de recursos estáticos en <strong>PageTop</strong>.</p> -//! -//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) -//! -//! </div> -//! -//! ## Sobre PageTop -//! -//! [PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la -//! web clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles -//! y configurables, basadas en HTML, CSS y JavaScript. +/*! +<div align="center"> + +<h1>PageTop Statics</h1> + +<p>Librería para automatizar la recopilación de recursos estáticos en <strong>PageTop</strong>.</p> + +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) + +</div> + +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + +## Descripción general + +Esta librería permite incluir archivos estáticos en el ejecutable de las aplicaciones `PageTop` para +servirlos de forma eficiente vía web, con detección de cambios que optimizan el tiempo de +compilación. + +## Créditos + +Para ello, adapta el código de los *crates* [static-files](https://crates.io/crates/static_files) +(versión [0.2.5](https://github.com/static-files-rs/static-files/tree/v0.2.5)) y +[actix-web-static-files](https://crates.io/crates/actix_web_static_files) (versión +[4.0.1](https://github.com/kilork/actix-web-static-files/tree/v4.0.1)), desarrollados ambos por +[Alexander Korolev](https://crates.io/users/kilork). + +Estas implementaciones se integran en `PageTop` para evitar que cada proyecto tenga que declarar +`static-files` manualmente como dependencia en su `Cargo.toml`. +*/ #![doc(test(no_crate_inject))] #![doc( diff --git a/src/lib.rs b/src/lib.rs index bbc45302..d50a4489 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,86 +1,89 @@ -//! <div align="center"> -//! -//! <img src="https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/banner.png" /> -//! -//! <h1>PageTop</h1> -//! -//! <p>Un entorno de desarrollo para crear soluciones web modulares, extensibles y configurables.</p> -//! -//! [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) -//! [![Doc API](https://img.shields.io/docsrs/pagetop?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop) -//! [![Crates.io](https://img.shields.io/crates/v/pagetop.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop) -//! [![Descargas](https://img.shields.io/crates/d/pagetop.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop) -//! -//! <br> -//! </div> -//! -//! `PageTop` reivindica la esencia de la web clásica usando [Rust](https://www.rust-lang.org/es) -//! para la creación de soluciones web SSR (*renderizadas en el servidor*) basadas en HTML, CSS y -//! JavaScript. Ofrece un conjunto de herramientas que los desarrolladores pueden implementar, -//! extender o adaptar según las necesidades de cada proyecto, incluyendo: -//! -//! * **Acciones** (*actions*): alteran la lógica interna de una funcionalidad interceptando su -//! flujo de ejecución. -//! * **Componentes** (*components*): encapsulan HTML, CSS y JavaScript en unidades funcionales, -//! configurables y reutilizables. -//! * **Extensiones** (*extensions*): añaden, extienden o personalizan funcionalidades usando las -//! APIs de `PageTop` o de terceros. -//! * **Temas** (*themes*): son extensiones que permiten modificar la apariencia de páginas y -//! componentes sin comprometer su funcionalidad. -//! -//! # ⚡️ Guía rápida -//! -//! La aplicación más sencilla de `PageTop` se ve así: -//! -//! ```rust,no_run -//! use pagetop::prelude::*; -//! -//! #[pagetop::main] -//! async fn main() -> std::io::Result<()> { -//! Application::new().run()?.await -//! } -//! ``` -//! -//! Este código arranca el servidor de `PageTop`. Con la -//! [configuración por defecto](crate::global::SETTINGS), muestra una página de bienvenida accesible -//! desde un navegador local en la dirección `http://localhost:8080`. -//! -//! Para personalizar el servicio, se puede crear una extensión de `PageTop` de la siguiente manera: -//! -//! ```rust,no_run -//! use pagetop::prelude::*; -//! -//! struct HelloWorld; -//! -//! impl Extension for HelloWorld { -//! fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { -//! scfg.route("/", service::web::get().to(hello_world)); -//! } -//! } -//! -//! async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { -//! Page::new(Some(request)) -//! .with_component(Html::with(move |_| html! { h1 { "Hello world!" } })) -//! .render() -//! } -//! -//! #[pagetop::main] -//! async fn main() -> std::io::Result<()> { -//! Application::prepare(&HelloWorld).run()?.await -//! } -//! ``` -//! -//! Este programa implementa una extensión llamada `HelloWorld` que sirve una página web en la ruta -//! raíz (`/`) mostrando el texto "Hello world!" dentro de un elemento HTML `<h1>`. -//! -//! # 🧩 Gestión de Dependencias -//! -//! Los proyectos que utilizan `PageTop` gestionan las dependencias con `cargo`, como cualquier otro -//! proyecto en Rust. -//! -//! Sin embargo, es fundamental que cada extensión declare explícitamente sus -//! [dependencias](core::extension::Extension::dependencies), si las tiene, para que `PageTop` pueda -//! estructurar e inicializar la aplicación de forma modular. +/*! +<div align="center"> + +<img src="https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/banner.png" /> + +<h1>PageTop</h1> + +<p>Un entorno para el desarrollo de soluciones web modulares, extensibles y configurables.</p> + +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) +[![Doc API](https://img.shields.io/docsrs/pagetop?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop) +[![Crates.io](https://img.shields.io/crates/v/pagetop.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop) +[![Descargas](https://img.shields.io/crates/d/pagetop.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop) + +<br> +</div> + +`PageTop` reivindica la esencia de la web clásica usando [Rust](https://www.rust-lang.org/es) para +la creación de soluciones web SSR (*renderizadas en el servidor*) basadas en HTML, CSS y JavaScript. +Ofrece un conjunto de herramientas que los desarrolladores pueden implementar, extender o adaptar +según las necesidades de cada proyecto, incluyendo: + + * **Acciones** (*actions*): alteran la lógica interna de una funcionalidad interceptando su flujo + de ejecución. + * **Componentes** (*components*): encapsulan HTML, CSS y JavaScript en unidades funcionales, + configurables y reutilizables. + * **Extensiones** (*extensions*): añaden, extienden o personalizan funcionalidades usando las APIs + de `PageTop` o de terceros. + * **Temas** (*themes*): son extensiones que permiten modificar la apariencia de páginas y + componentes sin comprometer su funcionalidad. + + +# ⚡️ Guía rápida + +La aplicación más sencilla de `PageTop` se ve así: + +```rust,no_run +use pagetop::prelude::*; + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::new().run()?.await +} +``` + +Este código arranca el servidor de `PageTop`. Con la configuración por defecto, muestra una página +de bienvenida accesible desde un navegador local en la dirección `http://localhost:8080`. + +Para personalizar el servicio, se puede crear una extensión de `PageTop` de la siguiente manera: + +```rust,no_run +use pagetop::prelude::*; + +struct HelloWorld; + +impl Extension for HelloWorld { + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + scfg.route("/", service::web::get().to(hello_world)); + } +} + +async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { + Page::new(Some(request)) + .with_component(Html::with(move |_| html! { h1 { "Hello World!" } })) + .render() +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&HelloWorld).run()?.await +} +``` + +Este programa implementa una extensión llamada `HelloWorld` que sirve una página web en la ruta raíz +(`/`) mostrando el texto "Hello world!" dentro de un elemento HTML `<h1>`. + + +# 🧩 Gestión de Dependencias + +Los proyectos que utilizan `PageTop` gestionan las dependencias con `cargo`, como cualquier otro +proyecto en Rust. + +Sin embargo, es fundamental que cada extensión declare explícitamente sus +[dependencias](core::extension::Extension::dependencies), si las tiene, para que `PageTop` pueda +estructurar e inicializar la aplicación de forma modular. +*/ #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( From 801642faabbbe9b29d397790ae40eaaf6d29ca03 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 16 Aug 2025 11:54:48 +0200 Subject: [PATCH 136/244] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Red?= =?UTF-8?q?efine=20funci=C3=B3n=20para=20directorios=20absolutos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config.rs | 27 +++++++---------------- src/util.rs | 53 ++++++++++++++++++++++++++++++--------------- tests/util.rs | 60 +++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 95 insertions(+), 45 deletions(-) diff --git a/src/config.rs b/src/config.rs index 08067fe6..27cf630e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -110,11 +110,13 @@ //! } //! ``` +use crate::util; + use config::builder::DefaultState; use config::{Config, ConfigBuilder, File}; use std::env; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::sync::LazyLock; // Nombre del directorio de configuración por defecto. @@ -125,25 +127,12 @@ const DEFAULT_RUN_MODE: &str = "default"; /// Valores originales cargados desde los archivos de configuración como pares `clave = valor`. pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new(|| { - // Determina el directorio de configuración: - // - Usa CONFIG_DIR si está definido en el entorno (p.ej.: CONFIG_DIR=/etc/myapp ./myapp). - // - Si no, intenta DEFAULT_CONFIG_DIR dentro del proyecto (en CARGO_MANIFEST_DIR). - // - Si nada de esto aplica, entonces usa DEFAULT_CONFIG_DIR relativo al ejecutable. - let config_dir: PathBuf = if let Ok(env_dir) = env::var("CONFIG_DIR") { - env_dir.into() - } else if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") { - let manifest_config = Path::new(&manifest_dir).join(DEFAULT_CONFIG_DIR); - if manifest_config.exists() { - manifest_config - } else { - DEFAULT_CONFIG_DIR.into() - } - } else { - DEFAULT_CONFIG_DIR.into() - }; + // CONFIG_DIR (si existe) o DEFAULT_CONFIG_DIR. Si no se puede resolver, se usa tal cual. + let dir = env::var_os("CONFIG_DIR").unwrap_or_else(|| DEFAULT_CONFIG_DIR.into()); + let config_dir = util::resolve_absolute_dir(&dir).unwrap_or_else(|_| PathBuf::from(&dir)); - // Determina el modo de ejecución según la variable de entorno PAGETOP_RUN_MODE. Por defecto usa - // DEFAULT_RUN_MODE si no está definida (p.ej.: PAGETOP_RUN_MODE=production ./myapp). + // Modo de ejecución según la variable de entorno PAGETOP_RUN_MODE. Si no está definida, se usa + // por defecto, DEFAULT_RUN_MODE (p.ej.: PAGETOP_RUN_MODE=production). let rm = env::var("PAGETOP_RUN_MODE").unwrap_or_else(|_| DEFAULT_RUN_MODE.into()); Config::builder() diff --git a/src/util.rs b/src/util.rs index b605125f..21537c5d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2,35 +2,44 @@ use crate::trace; +use std::env; use std::io; use std::path::{Path, PathBuf}; // FUNCIONES ÚTILES ******************************************************************************** -/// Devuelve la ruta absoluta a un directorio existente. +/// Resuelve y valida la ruta de un directorio existente, devolviendo una ruta absoluta. /// -/// * Si `relative_path` es una ruta absoluta, entonces se ignora `root_path`. -/// * Si la ruta final es relativa, se convierte en absoluta respecto al directorio actual. -/// * Devuelve error si la ruta no existe o no es un directorio. +/// - Si la ruta es relativa, se resuelve respecto al directorio del proyecto según la variable de +/// entorno `CARGO_MANIFEST_DIR` (si existe) o, en su defecto, respecto al directorio actual de +/// trabajo. +/// - Normaliza y valida la ruta final (resuelve `.`/`..` y enlaces simbólicos). +/// - Devuelve error si la ruta no existe o no es un directorio. /// -/// # Ejemplo +/// # Ejemplos /// /// ```rust,no_run /// use pagetop::prelude::*; /// -/// let root = "/home/user"; -/// let rel = "documents"; -/// println!("{:#?}", util::absolute_dir(root, rel)); +/// // Ruta relativa, se resuelve respecto a CARGO_MANIFEST_DIR o al directorio actual (`cwd`). +/// println!("{:#?}", util::resolve_absolute_dir("documents")); +/// +/// // Ruta absoluta, se normaliza y valida tal cual. +/// println!("{:#?}", util::resolve_absolute_dir("/var/www")); /// ``` -pub fn absolute_dir<P, Q>(root_path: P, relative_path: Q) -> io::Result<PathBuf> -where - P: AsRef<Path>, - Q: AsRef<Path>, -{ - // Une ambas rutas: - // - Si `relative_path` es absoluta, el `join` la devuelve tal cual, descartando `root_path`. - // - Si el resultado es aún relativo, lo será respecto al directorio actual. - let candidate = root_path.as_ref().join(relative_path.as_ref()); +pub fn resolve_absolute_dir<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { + let path = path.as_ref(); + + let candidate = if path.is_absolute() { + path.to_path_buf() + } else { + // Directorio base CARGO_MANIFEST_DIR si está disponible; o current_dir() en su defecto. + env::var_os("CARGO_MANIFEST_DIR") + .map(PathBuf::from) + .or_else(|| env::current_dir().ok()) + .unwrap_or_else(|| PathBuf::from(".")) + .join(path) + }; // Resuelve `.`/`..`, enlaces simbólicos y obtiene la ruta absoluta en un único paso. let absolute_dir = candidate.canonicalize()?; @@ -47,6 +56,16 @@ where } } +/// Devuelve la ruta absoluta a un directorio existente. +#[deprecated(since = "0.3.0", note = "Use [`resolve_absolute_dir`] instead")] +pub fn absolute_dir<P, Q>(root_path: P, relative_path: Q) -> io::Result<PathBuf> +where + P: AsRef<Path>, + Q: AsRef<Path>, +{ + resolve_absolute_dir(root_path.as_ref().join(relative_path.as_ref())) +} + // MACROS ÚTILES *********************************************************************************** #[doc(hidden)] diff --git a/tests/util.rs b/tests/util.rs index 6e0896ff..70699a74 100644 --- a/tests/util.rs +++ b/tests/util.rs @@ -1,6 +1,6 @@ use pagetop::prelude::*; -use std::{fs, io}; +use std::{env, fs, io}; use tempfile::TempDir; #[cfg(unix)] @@ -13,15 +13,36 @@ mod unix { // /tmp/<rand>/sub let td = TempDir::new()?; - let root = td.path(); - let sub = root.join("sub"); + let sub = td.path().join("sub"); fs::create_dir(&sub)?; - let abs = util::absolute_dir(root, "sub")?; + let abs = util::resolve_absolute_dir(&sub)?; assert_eq!(abs, std::fs::canonicalize(&sub)?); Ok(()) } + #[pagetop::test] + async fn ok_relative_dir_with_manifest() -> io::Result<()> { + let _app = service::test::init_service(Application::new().test()).await; + + let td = TempDir::new()?; + let sub = td.path().join("sub"); + fs::create_dir(&sub)?; + + // Fija CARGO_MANIFEST_DIR para que "sub" se resuelva contra td.path() + let prev_manifest_dir = env::var_os("CARGO_MANIFEST_DIR"); + env::set_var("CARGO_MANIFEST_DIR", td.path()); + let res = util::resolve_absolute_dir("sub"); + // Restaura entorno. + match prev_manifest_dir { + Some(v) => env::set_var("CARGO_MANIFEST_DIR", v), + None => env::remove_var("CARGO_MANIFEST_DIR"), + } + + assert_eq!(res?, std::fs::canonicalize(&sub)?); + Ok(()) + } + #[pagetop::test] async fn error_not_a_directory() -> io::Result<()> { let _app = service::test::init_service(Application::new().test()).await; @@ -30,7 +51,7 @@ mod unix { let file = td.path().join("foo.txt"); fs::write(&file, b"data")?; - let err = util::absolute_dir(td.path(), "foo.txt").unwrap_err(); + let err = util::resolve_absolute_dir(&file).unwrap_err(); assert_eq!(err.kind(), io::ErrorKind::InvalidInput); Ok(()) } @@ -46,15 +67,36 @@ mod windows { // C:\Users\...\Temp\... let td = TempDir::new()?; - let root = td.path(); - let sub = root.join("sub"); + let sub = td.path().join("sub"); fs::create_dir(&sub)?; - let abs = util::absolute_dir(root, sub.as_path())?; + let abs = util::resolve_absolute_dir(&sub)?; assert_eq!(abs, std::fs::canonicalize(&sub)?); Ok(()) } + #[pagetop::test] + async fn ok_relative_dir_with_manifest() -> io::Result<()> { + let _app = service::test::init_service(Application::new().test()).await; + + let td = TempDir::new()?; + let sub = td.path().join("sub"); + fs::create_dir(&sub)?; + + // Fija CARGO_MANIFEST_DIR para que "sub" se resuelva contra td.path() + let prev_manifest_dir = env::var_os("CARGO_MANIFEST_DIR"); + env::set_var("CARGO_MANIFEST_DIR", td.path()); + let res = util::resolve_absolute_dir("sub"); + // Restaura entorno. + match prev_manifest_dir { + Some(v) => env::set_var("CARGO_MANIFEST_DIR", v), + None => env::remove_var("CARGO_MANIFEST_DIR"), + } + + assert_eq!(res?, std::fs::canonicalize(&sub)?); + Ok(()) + } + #[pagetop::test] async fn error_not_a_directory() -> io::Result<()> { let _app = service::test::init_service(Application::new().test()).await; @@ -63,7 +105,7 @@ mod windows { let file = td.path().join("foo.txt"); fs::write(&file, b"data")?; - let err = util::absolute_dir(td.path(), "foo.txt").unwrap_err(); + let err = util::resolve_absolute_dir(&file).unwrap_err(); assert_eq!(err.kind(), io::ErrorKind::InvalidInput); Ok(()) } From 69fac6d9ea949b664c80bc281d947614ffa8c304 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 16 Aug 2025 12:15:16 +0200 Subject: [PATCH 137/244] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Mej?= =?UTF-8?q?ora=20la=20integraci=C3=B3n=20de=20archivos=20est=C3=A1ticos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Elimina el uso de `include_files!` y sustituye `include_files_service!` por alternativas más completas ofreciadas por `static_files_service!`. --- helpers/pagetop-build/README.md | 26 +++---- helpers/pagetop-build/src/lib.rs | 26 +++---- src/core/extension/all.rs | 8 +-- src/global.rs | 16 +++-- src/html/assets/favicon.rs | 3 +- src/html/assets/javascript.rs | 3 +- src/html/assets/stylesheet.rs | 3 +- src/lib.rs | 3 +- src/prelude.rs | 3 +- src/service.rs | 119 +++++++++++++++++++++++++++++++ 10 files changed, 156 insertions(+), 54 deletions(-) diff --git a/helpers/pagetop-build/README.md b/helpers/pagetop-build/README.md index 5af492b1..80d6bba2 100644 --- a/helpers/pagetop-build/README.md +++ b/helpers/pagetop-build/README.md @@ -83,41 +83,33 @@ Este código compila el archivo `main.scss` de la carpeta `static` del proyecto, llamado `main_styles` que contiene el archivo `styles.min.css` obtenido. -# 📦 Módulos generados +# 📦 Archivos generados Cada conjunto de recursos [`StaticFilesBundle`] genera un archivo en el directorio estándar [OUT_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) -donde se incluyen los recursos necesarios para compilar el proyecto. Por ejemplo, para -`with_name("guides")` se crea un archivo llamado `guides.rs`. +donde se incluye el código necesario para compilar el proyecto. Por ejemplo, para +`with_name("guides")` se genera un archivo llamado `guides.rs`. -No hay ningún problema en generar más de un conjunto de recursos para cada proyecto. +No hay ningún problema en generar más de un conjunto de recursos para cada proyecto siempre que se +usen nombres diferentes. -Normalmente no habrá que acceder a estos módulos; bastará con incluirlos en el proyecto con -[`include_files!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files.html), y luego con -[`include_files_service!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files_service.html) -configurar un servicio web para servir los recursos desde la ruta indicada: +Normalmente no habrá que acceder a estos módulos; sólo declarar el nombre del conjunto de recursos +en [`static_files_service!`](https://docs.rs/pagetop/latest/pagetop/macro.static_files_service.html) +para configurar un servicio web que sirva los archivos desde la ruta indicada. Por ejemplo: ```rust,ignore use pagetop::prelude::*; -include_files!(guides); - pub struct MyExtension; impl Extension for MyExtension { // Servicio web que publica los recursos de `guides` en `/ruta/a/guides`. fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { - include_files_service!(scfg, guides => "/ruta/a/guides"); + static_files_service!(scfg, guides => "/ruta/a/guides"); } } ``` -También se puede asignar el conjunto de recursos a una variable global; p.ej. `GUIDES`: - -```rust,ignore -include_files!(GUIDES => guides); -``` - # 🚧 Advertencia diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index 09dec428..c6e72367 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -84,40 +84,32 @@ Este código compila el archivo `main.scss` de la carpeta `static` del proyecto, llamado `main_styles` que contiene el archivo `styles.min.css` obtenido. -# 📦 Módulos generados +# 📦 Archivos generados Cada conjunto de recursos [`StaticFilesBundle`] genera un archivo en el directorio estándar [OUT_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) -donde se incluyen los recursos necesarios para compilar el proyecto. Por ejemplo, para -`with_name("guides")` se crea un archivo llamado `guides.rs`. +donde se incluye el código necesario para compilar el proyecto. Por ejemplo, para +`with_name("guides")` se genera un archivo llamado `guides.rs`. -No hay ningún problema en generar más de un conjunto de recursos para cada proyecto. +No hay ningún problema en generar más de un conjunto de recursos para cada proyecto siempre que se +usen nombres diferentes. -Normalmente no habrá que acceder a estos módulos; bastará con incluirlos en el proyecto con -[`include_files!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files.html), y luego con -[`include_files_service!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files_service.html) -configurar un servicio web para servir los recursos desde la ruta indicada: +Normalmente no habrá que acceder a estos módulos; sólo declarar el nombre del conjunto de recursos +en [`static_files_service!`](https://docs.rs/pagetop/latest/pagetop/macro.static_files_service.html) +para configurar un servicio web que sirva los archivos desde la ruta indicada. Por ejemplo: ```rust,ignore use pagetop::prelude::*; -include_files!(guides); - pub struct MyExtension; impl Extension for MyExtension { // Servicio web que publica los recursos de `guides` en `/ruta/a/guides`. fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { - include_files_service!(scfg, guides => "/ruta/a/guides"); + static_files_service!(scfg, guides => "/ruta/a/guides"); } } ``` - -También se puede asignar el conjunto de recursos a una variable global; p.ej. `GUIDES`: - -```rust,ignore -include_files!(GUIDES => guides); -``` */ #![doc( diff --git a/src/core/extension/all.rs b/src/core/extension/all.rs index 93b5c4bd..a243778c 100644 --- a/src/core/extension/all.rs +++ b/src/core/extension/all.rs @@ -1,7 +1,7 @@ use crate::core::action::add_action; use crate::core::extension::ExtensionRef; use crate::core::theme::all::THEMES; -use crate::{global, include_files, include_files_service, service, trace}; +use crate::{global, service, static_files_service, trace}; use parking_lot::RwLock; @@ -125,8 +125,6 @@ pub fn initialize_extensions() { // CONFIGURA LOS SERVICIOS ************************************************************************* -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)] @@ -140,7 +138,5 @@ pub fn configure_services(scfg: &mut service::web::ServiceConfig) { extension.configure_service(scfg); } - include_files_service!( - scfg, assets => "/", [&global::SETTINGS.dev.pagetop_project_dir, "static"] - ); + static_files_service!(scfg, [&global::SETTINGS.dev.pagetop_static_dir, assets] => "/"); } diff --git a/src/global.rs b/src/global.rs index ea659b8b..8a03589c 100644 --- a/src/global.rs +++ b/src/global.rs @@ -13,7 +13,7 @@ include_config!(SETTINGS: Settings => [ "app.startup_banner" => "Slant", // [dev] - "dev.pagetop_project_dir" => "", + "dev.pagetop_static_dir" => "", // [log] "log.enabled" => true, @@ -68,11 +68,15 @@ pub struct App { #[derive(Debug, Deserialize)] /// Sección `[Dev]` de la configuración. Forma parte de [`Settings`]. pub struct Dev { - /// Los archivos estáticos requeridos por `PageTop` se integran por defecto en el binario - /// ejecutable. Sin embargo, durante el desarrollo puede resultar útil servirlos desde su propio - /// directorio para evitar recompilar cada vez que se modifican. En ese caso, este ajuste debe - /// indicar la ruta absoluta al directorio raíz del proyecto. - pub pagetop_project_dir: String, + /// Directorio desde el que servir los archivos estáticos de `PageTop`. + /// + /// Por defecto, los archivos se integran en el binario de la aplicación. Si aquí se indica una + /// ruta válida, ya sea absoluta o relativa al directorio del proyecto o del binario en + /// ejecución, se servirán desde el sistema de ficheros en su lugar. Esto es especialmente útil + /// en desarrollo, ya que evita recompilar el proyecto por cambios en estos archivos. + /// + /// Si la cadena está vacía, se ignora este ajuste. + pub pagetop_static_dir: String, } #[derive(Debug, Deserialize)] diff --git a/src/html/assets/favicon.rs b/src/html/assets/favicon.rs index 2af01730..1a8b29e7 100644 --- a/src/html/assets/favicon.rs +++ b/src/html/assets/favicon.rs @@ -12,8 +12,7 @@ use crate::AutoDefault; /// /// > **Nota** /// > Los archivos de los iconos deben estar disponibles en el servidor web de la aplicación. Pueden -/// > incluirse en el proyecto utilizando [`include_files!`](crate::include_files) y servirse con -/// > [`include_files_service!`](crate::include_files_service). +/// > servirse usando [`static_files_service!`](crate::static_files_service). /// /// # Ejemplo /// diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs index 604e85ae..db5754e9 100644 --- a/src/html/assets/javascript.rs +++ b/src/html/assets/javascript.rs @@ -30,8 +30,7 @@ enum Source { /// /// > **Nota** /// > Los archivos de los *scripts* deben estar disponibles en el servidor web de la aplicación. -/// > Pueden incluirse en el proyecto utilizando [`include_files!`](crate::include_files) y servirse -/// > con [`include_files_service!`](crate::include_files_service). +/// > Pueden servirse usando [`static_files_service!`](crate::static_files_service). /// /// # Ejemplo /// diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index 72a79a10..bb60b01c 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -55,8 +55,7 @@ impl TargetMedia { /// /// > **Nota** /// > Las hojas de estilo CSS deben estar disponibles en el servidor web de la aplicación. Pueden -/// > incluirse en el proyecto utilizando [`include_files!`](crate::include_files) y servirse con -/// > [`include_files_service!`](crate::include_files_service). +/// > servirse usando [`static_files_service!`](crate::static_files_service). /// /// # Ejemplo /// diff --git a/src/lib.rs b/src/lib.rs index d50a4489..90ea4625 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -103,7 +103,8 @@ pub use pagetop_macros::{builder_fn, html, main, test, AutoDefault}; pub use pagetop_statics::{resource, StaticResource}; -/// Conjunto de recursos asociados a `$STATIC` en [`include_files!`](crate::include_files). +/// Contenedor para un conjunto de recursos embebidos. +#[derive(AutoDefault)] pub struct StaticResources { bundle: HashMap<&'static str, StaticResource>, } diff --git a/src/prelude.rs b/src/prelude.rs index 6bacaf3a..9072dec9 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -15,7 +15,8 @@ pub use crate::include_config; // crate::locale pub use crate::include_locales; // crate::service -pub use crate::{include_files, include_files_service}; +#[allow(deprecated)] +pub use crate::{include_files, include_files_service, static_files_service}; // crate::core::action pub use crate::actions_boxed; diff --git a/src/service.rs b/src/service.rs index 47f1420d..288e1eb5 100644 --- a/src/service.rs +++ b/src/service.rs @@ -15,6 +15,9 @@ pub use pagetop_statics::ResourceFiles; #[doc(hidden)] pub use actix_web::test; +/// **Obsoleto desde la versión 0.3.0**: usar [`static_files_service!`](crate::static_files_service) +/// en su lugar. +/// /// Incluye en código un conjunto de recursos previamente preparado con `build.rs`. /// /// # Formas de uso @@ -39,6 +42,7 @@ pub use actix_web::test; /// /// include_files!(STATIC_ASSETS => assets); /// ``` +#[deprecated(since = "0.3.0", note = "Use `static_files_service!` instead")] #[macro_export] macro_rules! include_files { // Forma 1: incluye un conjunto de recursos por nombre. @@ -63,6 +67,9 @@ macro_rules! include_files { }; } +/// **Obsoleto desde la versión 0.3.0**: usar [`static_files_service!`](crate::static_files_service) +/// en su lugar. +/// /// Configura un servicio web para publicar los recursos embebidos con [`include_files!`]. /// /// El código expandido de la macro decide durante el arranque de la aplicación si debe servir los @@ -104,6 +111,7 @@ macro_rules! include_files { /// // También desde el directorio actual de ejecución. /// include_files_service!(cfg, assets => "/public", ["", "static"]); /// ``` +#[deprecated(since = "0.3.0", note = "Use `static_files_service!` instead")] #[macro_export] macro_rules! include_files_service { ( $scfg:ident, $bundle:ident => $route:expr $(, [$root:expr, $relative:expr])? ) => {{ @@ -137,3 +145,114 @@ macro_rules! include_files_service { } }}; } + +/// Configura un servicio web para publicar archivos estáticos. +/// +/// La macro ofrece tres modos para configurar el servicio: +/// +/// - **Sistema de ficheros o embebido** (`[$path, $bundle]`): trata de servir los archivos desde +/// `$path`; y si es una cadena vacía, no existe o no es un directorio, entonces usará el conjunto +/// de recursos `$bundle` integrado en el binario. +/// - **Sólo embebido** (`[$bundle]`): sirve siempre desde el conjunto de recursos `$bundle` +/// integrado en el binario. +/// - **Sólo sistema de ficheros** (`$path`): sin usar corchetes, sirve únicamente desde el sistema +/// de ficheros si existe; en otro caso no registra el servicio. +/// +/// # Argumentos +/// +/// * `$scfg` – Instancia de [`ServiceConfig`](crate::service::web::ServiceConfig) donde aplicar la +/// configuración. +/// * `$path` – Ruta al directorio local con los archivos estáticos. +/// * `$bundle` – Nombre del conjunto de recursos que esta macro integra en el binario. +/// * `$route` – Ruta URL base desde la que se servirán los archivos. +/// +/// # Ejemplos +/// +/// ```rust,ignore +/// use pagetop::prelude::*; +/// +/// pub struct MyExtension; +/// +/// impl Extension for MyExtension { +/// fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { +/// // Forma 1) Sistema de ficheros o embebido. +/// static_files_service!(scfg, ["/var/www/static", assets] => "/public"); +/// +/// // Forma 2) Siempre embebido. +/// static_files_service!(scfg, [assets] => "/public"); +/// +/// // Forma 3) Sólo sistema de ficheros (no requiere `assets`). +/// static_files_service!(scfg, "/var/www/static" => "/public"); +/// } +/// } +/// ``` +#[macro_export] +macro_rules! static_files_service { + // Forma 1: primero intenta servir desde el sistema de ficheros; si falla, sirve embebido. + ( $scfg:ident, [$path:expr, $bundle:ident] => $route:expr $(,)? ) => {{ + let span = $crate::trace::debug_span!( + "Configuring static files (file system or embedded)", + mode = "fs_or_embedded", + route = $route, + ); + let _ = span.in_scope(|| { + let mut serve_embedded: bool = true; + if !::std::path::Path::new(&$path).as_os_str().is_empty() { + if let Ok(absolute) = $crate::util::resolve_absolute_dir($path) { + $scfg.service($crate::service::ActixFiles::new($route, absolute)); + serve_embedded = false; + } + } + if serve_embedded { + $crate::util::paste! { + mod [<static_files_ $bundle>] { + include!(concat!(env!("OUT_DIR"), "/", stringify!($bundle), ".rs")); + } + $scfg.service($crate::service::ResourceFiles::new( + $route, + [<static_files_ $bundle>]::$bundle(), + )); + } + } + }); + }}; + // Forma 2: sirve siempre embebido. + ( $scfg:ident, [$bundle:ident] => $route:expr $(,)? ) => {{ + let span = $crate::trace::debug_span!( + "Configuring static files (using embedded only)", + mode = "embedded", + route = $route, + ); + let _ = span.in_scope(|| { + $crate::util::paste! { + mod [<static_files_ $bundle>] { + include!(concat!(env!("OUT_DIR"), "/", stringify!($bundle), ".rs")); + } + $scfg.service($crate::service::ResourceFiles::new( + $route, + [<static_files_ $bundle>]::$bundle(), + )); + } + }); + }}; + // Forma 3: intenta servir desde el sistema de ficheros. + ( $scfg:ident, $path:expr => $route:expr $(,)? ) => {{ + let span = $crate::trace::debug_span!( + "Configuring static files (file system only)", + mode = "fs", + route = $route, + ); + let _ = span.in_scope(|| match $crate::util::resolve_absolute_dir($path) { + Ok(absolute) => { + $scfg.service($crate::service::ActixFiles::new($route, absolute)); + } + Err(e) => { + $crate::trace::warn!( + "Static dir not found or invalid for route `{}`: {:?} ({e})", + $route, + $path, + ); + } + }); + }}; +} From 662b269423938503d320d1ea85c8830e294fd1f7 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 16 Aug 2025 12:39:51 +0200 Subject: [PATCH 138/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-statics=200.1.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- helpers/pagetop-statics/CHANGELOG.md | 6 ++++++ helpers/pagetop-statics/Cargo.toml | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 22cf3086..48adecf2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1605,7 +1605,7 @@ dependencies = [ [[package]] name = "pagetop-statics" -version = "0.1.0" +version = "0.1.1" dependencies = [ "actix-web", "change-detection", diff --git a/helpers/pagetop-statics/CHANGELOG.md b/helpers/pagetop-statics/CHANGELOG.md index 62ad97e8..811a77f4 100644 --- a/helpers/pagetop-statics/CHANGELOG.md +++ b/helpers/pagetop-statics/CHANGELOG.md @@ -8,6 +8,12 @@ Resume la evolución del proyecto para usuarios y colaboradores, destacando nuev correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o internos pueden omitirse si no afectan al uso del proyecto. +## 0.1.1 (2025-08-16) + +### Documentado + +- Cambia el formato para la documentación (#4) + ## 0.1.0 (2025-08-09) ### Añadido diff --git a/helpers/pagetop-statics/Cargo.toml b/helpers/pagetop-statics/Cargo.toml index e5c58d5e..2afe3739 100644 --- a/helpers/pagetop-statics/Cargo.toml +++ b/helpers/pagetop-statics/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-statics" -version = "0.1.0" +version = "0.1.1" edition = "2021" description = """ From 85497bf45256b530bd7cd84a5b47f5438240801f Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 16 Aug 2025 12:47:02 +0200 Subject: [PATCH 139/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-build=200.3.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- Cargo.toml | 2 +- helpers/pagetop-build/CHANGELOG.md | 11 +++++++++++ helpers/pagetop-build/Cargo.toml | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48adecf2..8e9795f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1587,7 +1587,7 @@ dependencies = [ [[package]] name = "pagetop-build" -version = "0.2.0" +version = "0.3.0" dependencies = [ "grass", "pagetop-statics", diff --git a/Cargo.toml b/Cargo.toml index cdeae782..bb31197f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,6 +71,6 @@ authors = ["Manuel Cillero <manuel@cillero.es>"] [workspace.dependencies] actix-web = { version = "4.11.0", default-features = false } -pagetop-build = { version = "0.2", path = "helpers/pagetop-build" } +pagetop-build = { version = "0.3", path = "helpers/pagetop-build" } pagetop-macros = { version = "0.1", path = "helpers/pagetop-macros" } pagetop-statics = { version = "0.1", path = "helpers/pagetop-statics" } diff --git a/helpers/pagetop-build/CHANGELOG.md b/helpers/pagetop-build/CHANGELOG.md index 4d087556..3e3801e8 100644 --- a/helpers/pagetop-build/CHANGELOG.md +++ b/helpers/pagetop-build/CHANGELOG.md @@ -8,6 +8,17 @@ Resume la evolución del proyecto para usuarios y colaboradores, destacando nuev correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o internos pueden omitirse si no afectan al uso del proyecto. +## 0.3.0 (2025-08-16) + +### Cambiado + +- Mejora función `from_dir` por compatibilidad (#3) +- Mejora la integración de archivos estáticos + +### Documentado + +- Cambia el formato para la documentación (#4) + ## 0.2.0 (2025-08-09) ### Añadido diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index 14e6000b..e0f5ef76 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-build" -version = "0.2.0" +version = "0.3.0" edition = "2021" description = """ From b11b5d97c67b5a6dfdc9392e24e5d5620d15b231 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 16 Aug 2025 12:51:11 +0200 Subject: [PATCH 140/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-macros=200.1.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- helpers/pagetop-macros/CHANGELOG.md | 11 +++++++++++ helpers/pagetop-macros/Cargo.toml | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e9795f1..64f77eeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1595,7 +1595,7 @@ dependencies = [ [[package]] name = "pagetop-macros" -version = "0.1.0" +version = "0.1.1" dependencies = [ "proc-macro2", "proc-macro2-diagnostics", diff --git a/helpers/pagetop-macros/CHANGELOG.md b/helpers/pagetop-macros/CHANGELOG.md index b01b9883..b61471a1 100644 --- a/helpers/pagetop-macros/CHANGELOG.md +++ b/helpers/pagetop-macros/CHANGELOG.md @@ -8,6 +8,17 @@ Resume la evolución del proyecto para usuarios y colaboradores, destacando nuev correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o internos pueden omitirse si no afectan al uso del proyecto. +## 0.1.1 (2025-08-16) + +### Documentado + +- Cambia el formato para la documentación (#4) +- Corrige enlaces de licencia en la documentación + +### Otros cambios + +- Afina Cargo.toml para buscar la mejor categoría + ## 0.1.0 (2025-08-06) - Versión inicial diff --git a/helpers/pagetop-macros/Cargo.toml b/helpers/pagetop-macros/Cargo.toml index 64f1cf4c..d5ceb1b6 100644 --- a/helpers/pagetop-macros/Cargo.toml +++ b/helpers/pagetop-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-macros" -version = "0.1.0" +version = "0.1.1" edition = "2021" description = """ From 2cf5ce2a7086d35407cc7dbd9d98bc1ce2eb5559 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 16 Aug 2025 12:57:00 +0200 Subject: [PATCH 141/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop=200.3.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 18 ++++++++++++++++-- Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2248658d..9e187143 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,17 @@ Resume la evolución del proyecto para usuarios y colaboradores, destacando nuev correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o internos pueden omitirse si no afectan al uso del proyecto. +## 0.3.0 (2025-08-16) + +### Cambiado + +- Redefine función para directorios absolutos +- Mejora la integración de archivos estáticos + +### Documentado + +- Cambia el formato para la documentación (#4) + ## 0.2.0 (2025-08-09) ### Añadido @@ -15,10 +26,13 @@ internos pueden omitirse si no afectan al uso del proyecto. - Añade librería para gestionar recursos estáticos (#1) - Añade soporte a changelog de `pagetop-statics` (#2) +### Documentado + +- Corrige enlace del botón de licencia en la documentación + ### Otros cambios -- 🩹 Corrige enlace del botón de licencia en la documentación -- 🚩 Afina Cargo.toml para buscar la mejor categoría +- Afina Cargo.toml para buscar la mejor categoría ## 0.1.0 (2025-08-06) diff --git a/Cargo.lock b/Cargo.lock index 64f77eeb..944027d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1557,7 +1557,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.2.0" +version = "0.3.0" dependencies = [ "actix-files", "actix-session", diff --git a/Cargo.toml b/Cargo.toml index bb31197f..8ccd69ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.2.0" +version = "0.3.0" edition = "2021" description = """ From 313ce391d5a80e94b78aa3ad4cf7f6bdeae53c0a Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 21 Aug 2025 09:12:22 +0200 Subject: [PATCH 142/244] =?UTF-8?q?=F0=9F=93=9D=20Retoques=20menores=20en?= =?UTF-8?q?=20la=20documentaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/theme.rs | 7 ++++--- src/core/theme/definition.rs | 11 ++++++++--- src/util.rs | 4 +++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/core/theme.rs b/src/core/theme.rs index 0a0f8199..2cd5bb1f 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -9,9 +9,10 @@ //! tipografías, espaciados y cualquier otro detalle visual o de comportamiento (como animaciones, //! *scripts* de interfaz, etc.). //! -//! Es una extensión más (implementando [`Extension`](crate::core::extension::Extension)). Se -//! instala, activa y declara dependencias igual que el resto de extensiones; y se señala a sí misma -//! como tema (implementando [`theme()`](crate::core::extension::Extension::theme) y [`Theme`]). +//! Los temas son extensiones que implementan [`Extension`](crate::core::extension::Extension); por +//! lo que se instancian, declaran sus dependencias y se inician igual que el resto de extensiones; +//! pero serán temas si además implementan [`theme()`](crate::core::extension::Extension::theme) y +//! [`Theme`]. mod definition; pub use definition::{Theme, ThemeRef}; diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 8de88bdd..e9cfbba9 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -14,7 +14,7 @@ pub type ThemeRef = &'static dyn Theme; /// Interfaz común que debe implementar cualquier tema de `PageTop`. /// /// Un tema implementará [`Theme`] y los métodos que sean necesarios de [`Extension`], aunque el -/// único obligatorio es [`theme()`](Extension::theme). +/// único obligatorio será [`theme()`](Extension::theme). /// /// ```rust /// use pagetop::prelude::*; @@ -22,8 +22,13 @@ pub type ThemeRef = &'static dyn Theme; /// pub struct MyTheme; /// /// impl Extension for MyTheme { -/// fn name(&self) -> L10n { L10n::n("My theme") } -/// fn description(&self) -> L10n { L10n::n("Un tema personal") } +/// fn name(&self) -> L10n { +/// L10n::n("My theme") +/// } +/// +/// fn description(&self) -> L10n { +/// L10n::n("A personal theme") +/// } /// /// fn theme(&self) -> Option<ThemeRef> { /// Some(&Self) diff --git a/src/util.rs b/src/util.rs index 21537c5d..e70b0998 100644 --- a/src/util.rs +++ b/src/util.rs @@ -56,8 +56,10 @@ pub fn resolve_absolute_dir<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { } } +/// **Obsoleto desde la versión 0.3.0**: usar [`resolve_absolute_dir()`] en su lugar. +/// /// Devuelve la ruta absoluta a un directorio existente. -#[deprecated(since = "0.3.0", note = "Use [`resolve_absolute_dir`] instead")] +#[deprecated(since = "0.3.0", note = "Use `resolve_absolute_dir()` instead")] pub fn absolute_dir<P, Q>(root_path: P, relative_path: Q) -> io::Result<PathBuf> where P: AsRef<Path>, From 3b5c5dd4e7f7e9ee48da7fe35b1925b1ceac7594 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 21 Aug 2025 09:31:20 +0200 Subject: [PATCH 143/244] =?UTF-8?q?=F0=9F=A6=BA=20Modifica=20tipos=20para?= =?UTF-8?q?=20atributos=20HTML=20a=20min=C3=BAsculas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html/opt_classes.rs | 7 ++++--- src/html/opt_id.rs | 5 +++-- src/html/opt_name.rs | 5 +++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/html/opt_classes.rs b/src/html/opt_classes.rs index abb3ba48..a9857625 100644 --- a/src/html/opt_classes.rs +++ b/src/html/opt_classes.rs @@ -25,6 +25,7 @@ pub enum ClassesOp { /// /// - El [orden de las clases no es relevante](https://stackoverflow.com/a/1321712) en CSS. /// - No se permiten clases duplicadas. +/// - Las clases se convierten a minúsculas. /// - Las clases vacías se ignoran. /// /// # Ejemplo @@ -32,8 +33,8 @@ pub enum ClassesOp { /// ```rust /// use pagetop::prelude::*; /// -/// let classes = OptionClasses::new("btn btn-primary") -/// .with_value(ClassesOp::Add, "active") +/// let classes = OptionClasses::new("Btn btn-primary") +/// .with_value(ClassesOp::Add, "Active") /// .with_value(ClassesOp::Remove, "btn-primary"); /// /// assert_eq!(classes.get(), Some(String::from("btn active"))); @@ -51,7 +52,7 @@ impl OptionClasses { #[builder_fn] pub fn with_value(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { - let classes: &str = classes.as_ref(); + let classes = classes.as_ref().to_ascii_lowercase(); let classes: Vec<&str> = classes.split_ascii_whitespace().collect(); if classes.is_empty() { diff --git a/src/html/opt_id.rs b/src/html/opt_id.rs index 893ac6d3..139fdcd6 100644 --- a/src/html/opt_id.rs +++ b/src/html/opt_id.rs @@ -7,6 +7,7 @@ use crate::{builder_fn, AutoDefault}; /// # Normalización /// /// - Se eliminan los espacios al principio y al final. +/// - Se convierte a minúsculas. /// - Se sustituyen los espacios intermedios por guiones bajos (`_`). /// - Si el resultado es una cadena vacía, se guarda `None`. /// @@ -15,7 +16,7 @@ use crate::{builder_fn, AutoDefault}; /// ```rust /// use pagetop::prelude::*; /// -/// let id = OptionId::new("main section"); +/// let id = OptionId::new(" main Section "); /// assert_eq!(id.get(), Some(String::from("main_section"))); /// /// let empty = OptionId::default(); @@ -39,7 +40,7 @@ impl OptionId { /// El valor se normaliza automáticamente. #[builder_fn] pub fn with_value(mut self, value: impl AsRef<str>) -> Self { - let value = value.as_ref().trim().replace(' ', "_"); + let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_"); self.0 = (!value.is_empty()).then_some(value); self } diff --git a/src/html/opt_name.rs b/src/html/opt_name.rs index aa74e3b9..ffb0b989 100644 --- a/src/html/opt_name.rs +++ b/src/html/opt_name.rs @@ -7,6 +7,7 @@ use crate::{builder_fn, AutoDefault}; /// # Normalización /// /// - Se eliminan los espacios al principio y al final. +/// - Se convierte a minúsculas. /// - Se sustituyen los espacios intermedios por guiones bajos (`_`). /// - Si el resultado es una cadena vacía, se guarda `None`. /// @@ -15,7 +16,7 @@ use crate::{builder_fn, AutoDefault}; /// ```rust /// use pagetop::prelude::*; /// -/// let name = OptionName::new(" display name "); +/// let name = OptionName::new(" DISplay name "); /// assert_eq!(name.get(), Some(String::from("display_name"))); /// /// let empty = OptionName::default(); @@ -39,7 +40,7 @@ impl OptionName { /// El valor se normaliza automáticamente. #[builder_fn] pub fn with_value(mut self, value: impl AsRef<str>) -> Self { - let value = value.as_ref().trim().replace(' ', "_"); + let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_"); self.0 = (!value.is_empty()).then_some(value); self } From 2cb963350341997fea9b10030278fb930dc242a1 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 21 Aug 2025 09:36:25 +0200 Subject: [PATCH 144/244] =?UTF-8?q?=F0=9F=8E=A8=20Retoques=20al=20importar?= =?UTF-8?q?=20`fmt`=20para=20usar=20`Display`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html/context.rs | 5 ++--- src/response/page/error.rs | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/html/context.rs b/src/html/context.rs index 5fbb39b5..72c0ff29 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -9,10 +9,9 @@ use crate::{builder_fn, join}; use std::collections::HashMap; use std::error::Error; +use std::fmt::{self, Display}; use std::str::FromStr; -use std::fmt; - /// Operaciones para modificar el contexto ([`Context`]) del documento. pub enum AssetsOp { // Favicon. @@ -43,7 +42,7 @@ pub enum ErrorParam { ParseError(String), } -impl fmt::Display for ErrorParam { +impl Display for ErrorParam { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ErrorParam::NotFound => write!(f, "Parameter not found"), diff --git a/src/response/page/error.rs b/src/response/page/error.rs index 3a2511cf..99ba62bf 100644 --- a/src/response/page/error.rs +++ b/src/response/page/error.rs @@ -6,7 +6,7 @@ use crate::service::{HttpRequest, HttpResponse}; use super::Page; -use std::fmt; +use std::fmt::{self, Display}; #[derive(Debug)] pub enum ErrorPage { @@ -19,7 +19,7 @@ pub enum ErrorPage { Timeout(HttpRequest), } -impl fmt::Display for ErrorPage { +impl Display for ErrorPage { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { // Error 304. From 40c4cabe45d7663b74d17a0a90913bd0d146edcb Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 21 Aug 2025 09:40:10 +0200 Subject: [PATCH 145/244] =?UTF-8?q?=F0=9F=90=9B=20(welcome):=20Corrige=20g?= =?UTF-8?q?iro=20bot=C3=B3n=20con=20ancho=20estrecho?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/css/welcome.css | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/static/css/welcome.css b/static/css/welcome.css index 8f603485..76b042b9 100644 --- a/static/css/welcome.css +++ b/static/css/welcome.css @@ -295,11 +295,6 @@ a:hover:visited { 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; } @@ -323,6 +318,11 @@ a:hover:visited { max-width: 29.375rem; margin-bottom: 0; } + #poweredby-link:hover { + transition: all .5s; + transform: rotate(-3deg) scale(1.1); + box-shadow: 0px 3px 5px rgba(0,0,0,.4); + } } .content-text { From ba71f8a83fab01fb95d51c1464068c8ba76eb9e6 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 22 Aug 2025 07:46:36 +0200 Subject: [PATCH 146/244] =?UTF-8?q?=E2=9C=A8=20(app):=20A=C3=B1ade=20manej?= =?UTF-8?q?o=20de=20rutas=20no=20encontradas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/app.rs b/src/app.rs index c3576fc5..400b0cd3 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3,6 +3,9 @@ mod figfont; use crate::core::{extension, extension::ExtensionRef}; +use crate::html::Markup; +use crate::response::page::{ErrorPage, ResultPage}; +use crate::service::HttpRequest; use crate::{global, locale, service, trace}; use actix_session::config::{BrowserSession, PersistentSession, SessionLifecycle}; @@ -170,6 +173,12 @@ impl Application { InitError = (), >, > { - service::App::new().configure(extension::all::configure_services) + service::App::new() + .configure(extension::all::configure_services) + .default_service(service::web::route().to(service_not_found)) } } + +async fn service_not_found(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { + Err(ErrorPage::NotFound(request)) +} From e08c412a36e205bdeddd1bda2eb4d216c5406d3f Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 22 Aug 2025 08:29:11 +0200 Subject: [PATCH 147/244] =?UTF-8?q?=F0=9F=8E=A8=20(theme):=20Mejora=20gest?= =?UTF-8?q?i=C3=B3n=20de=20regiones=20en=20p=C3=A1ginas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/extension/definition.rs | 19 +++---- src/core/theme.rs | 5 +- src/core/theme/definition.rs | 81 ++++++++++++++++++++++++++---- src/core/theme/regions.rs | 85 ++++++++++++++++++++++++++------ src/locale/en-US/theme.ftl | 9 +++- src/locale/es-ES/theme.ftl | 9 +++- src/response/page.rs | 15 +++--- 7 files changed, 174 insertions(+), 49 deletions(-) diff --git a/src/core/extension/definition.rs b/src/core/extension/definition.rs index ac292592..6df70427 100644 --- a/src/core/extension/definition.rs +++ b/src/core/extension/definition.rs @@ -26,7 +26,7 @@ pub type ExtensionRef = &'static dyn Extension; /// } /// ``` pub trait Extension: AnyInfo + Send + Sync { - /// Nombre legible para el usuario. + /// Nombre localizado de la extensión legible para el usuario. /// /// Predeterminado por el [`short_name()`](AnyInfo::short_name) del tipo asociado a la /// extensión. @@ -34,18 +34,15 @@ pub trait Extension: AnyInfo + Send + Sync { L10n::n(self.short_name()) } - /// Descripción corta para paneles, listados, etc. + /// Descripción corta localizada de la extensión para paneles, listados, etc. fn description(&self) -> L10n { L10n::default() } - /// Los temas son extensiones que implementan [`Extension`] y también - /// [`Theme`](crate::core::theme::Theme). + /// Devuelve una referencia a esta misma extensión cuando se trata de un tema. /// - /// Si la extensión no es un tema, este método devuelve `None` por defecto. - /// - /// En caso contrario, este método debe implementarse para devolver una referencia de sí mismo - /// como tema. Por ejemplo: + /// Para ello, debe implementar [`Extension`] y también [`Theme`](crate::core::theme::Theme). Si + /// la extensión no es un tema, este método devuelve `None` por defecto. /// /// ```rust /// use pagetop::prelude::*; @@ -81,7 +78,7 @@ pub trait Extension: AnyInfo + Send + Sync { actions_boxed![] } - /// Inicializa la extensión durante la lógica de arranque de la aplicación. + /// Inicializa la extensión durante la fase de arranque de la aplicación. /// /// Se llama una sola vez, después de que todas las dependencias se han inicializado y antes de /// aceptar cualquier petición HTTP. @@ -104,8 +101,8 @@ pub trait Extension: AnyInfo + Send + Sync { #[allow(unused_variables)] fn configure_service(&self, scfg: &mut service::web::ServiceConfig) {} - /// Permite crear extensiones para deshabilitar y desinstalar los recursos de otras extensiones - /// utilizadas en versiones anteriores de la aplicación. + /// Permite crear extensiones para deshabilitar y desinstalar recursos de otras de versiones + /// anteriores de la aplicación. /// /// Actualmente no se usa, pero se deja como *placeholder* para futuras implementaciones. fn drop_extensions(&self) -> Vec<ExtensionRef> { diff --git a/src/core/theme.rs b/src/core/theme.rs index 2cd5bb1f..aa526f16 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -19,9 +19,6 @@ pub use definition::{Theme, ThemeRef}; mod regions; pub(crate) use regions::ChildrenInRegions; -pub use regions::InRegion; +pub use regions::{InRegion, Region, REGION_CONTENT}; pub(crate) mod all; - -/// Nombre de la región por defecto: `content`. -pub const CONTENT_REGION_NAME: &str = "content"; diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index e9cfbba9..8d1b632f 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -1,10 +1,12 @@ use crate::core::extension::Extension; -use crate::core::theme::CONTENT_REGION_NAME; +use crate::core::theme::Region; use crate::global; use crate::html::{html, Markup}; use crate::locale::L10n; use crate::response::page::Page; +use std::sync::LazyLock; + /// Representa una referencia a un tema. /// /// Los temas son también extensiones. Por tanto se deben definir igual, es decir, como instancias @@ -38,21 +40,67 @@ pub type ThemeRef = &'static dyn Theme; /// 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_REGION_NAME, L10n::l("content"))] + 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")), + ] + }); + &REGIONS[..] + } + + /// 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. + /// + /// 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 { html! { body id=[page.body_id().get()] class=[page.body_classes().get()] { - @for (region_name, _) in self.regions() { - @let output = page.render_region(region_name); + @for (region, region_label) in self.declared_regions() { + @let output = page.render_region(region.key()); @if !output.is_empty() { - div id=(region_name) class={ "region-container region-" (region_name) } { - (output) + @let region_name = region.name(); + div + id=(region_name) + class="region" + role="region" + aria-label=[region_label.using(page)] + { + div class={ "region__" (region_name) } { + (output) + } } } } @@ -60,9 +108,16 @@ 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 { let viewport = "width=device-width, initial-scale=1, shrink-to-fit=no"; html! { @@ -94,11 +149,17 @@ pub trait Theme: Extension + Send + Sync { } } - fn error403(&self, _page: &mut Page) -> Markup { - html! { div { h1 { ("FORBIDDEN ACCESS") } } } + /// Página de error "*403 – Forbidden*" predeterminada. + /// + /// 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)) } } } } - fn error404(&self, _page: &mut Page) -> Markup { - html! { div { h1 { ("RESOURCE NOT FOUND") } } } + /// Página de error "*404 – Not Found*" predeterminada. + /// + /// 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)) } } } } } diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index 22ab6f25..c8a05554 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -1,5 +1,5 @@ use crate::core::component::{Child, ChildOp, Children}; -use crate::core::theme::{ThemeRef, CONTENT_REGION_NAME}; +use crate::core::theme::ThemeRef; use crate::{builder_fn, AutoDefault, UniqueId}; use parking_lot::RwLock; @@ -7,15 +7,71 @@ use parking_lot::RwLock; use std::collections::HashMap; use std::sync::LazyLock; -// Regiones globales con componentes para un tema dado. +// Conjunto de regiones globales asociadas a un tema específico. static THEME_REGIONS: LazyLock<RwLock<HashMap<UniqueId, ChildrenInRegions>>> = LazyLock::new(|| RwLock::new(HashMap::new())); -// Regiones globales con componentes para cualquier tema. +// Conjunto de regiones globales comunes a todos los temas. static COMMON_REGIONS: LazyLock<RwLock<ChildrenInRegions>> = LazyLock::new(|| RwLock::new(ChildrenInRegions::default())); -// Estructura interna para mantener los componentes de una región. +/// Nombre de la región de contenido por defecto (`"content"`). +pub const REGION_CONTENT: &str = "content"; + +/// Identificador de una región de página. +/// +/// Incluye una **clave estática** ([`key()`](Self::key)) que identifica la región en el tema, y un +/// **nombre normalizado** ([`name()`](Self::name)) en minúsculas para su uso en atributos HTML +/// (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)). +pub struct Region { + key: &'static str, + name: String, +} + +impl Default for Region { + #[inline] + fn default() -> Self { + Self { + key: REGION_CONTENT, + name: String::from(REGION_CONTENT), + } + } +} + +impl Region { + /// Declara una región a partir de su clave estática. + /// + /// Genera además un nombre normalizado de la clave, eliminando espacios iniciales y finales, + /// convirtiendo a minúsculas y sustituyendo los espacios intermedios por guiones (`-`). + /// + /// Esta clave se usará para añadir componentes a la región; por ello se recomiendan nombres + /// sencillos, limitando los caracteres a `[a-z0-9-]` (p.ej., `"sidebar"` o `"main-menu"`), cuyo + /// nombre normalizado coincidirá con la clave. + #[inline] + pub fn declare(key: &'static str) -> Self { + Self { + key, + name: key.trim().to_ascii_lowercase().replace(' ', "-"), + } + } + + /// Devuelve la clave estática asignada a la región. + #[inline] + pub fn key(&self) -> &'static str { + self.key + } + + /// Devuelve el nombre normalizado de la región (para atributos y búsquedas). + #[inline] + pub fn name(&self) -> &str { + &self.name + } +} + +// Contenedor interno de componentes agrupados por región. #[derive(AutoDefault)] pub struct ChildrenInRegions(HashMap<&'static str, Children>); @@ -48,25 +104,24 @@ impl ChildrenInRegions { } } -/// Permite añadir componentes a regiones globales o regiones de temas concretos. +/// Punto de acceso para añadir componentes a regiones globales o específicas de un tema. /// -/// Dada una región, según la variante seleccionada, se le podrán añadir ([`add()`](Self::add)) -/// componentes que se mantendrán durante la ejecución de la aplicación. +/// Según la variante, se pueden añadir componentes ([`add()`](Self::add)) que permanecerán +/// disponibles durante toda la ejecución. /// -/// Estas estructuras de componentes se renderizarán automáticamente al procesar los documentos HTML -/// que las usan, como las páginas de contenido ([`Page`](crate::response::page::Page)), por -/// ejemplo. +/// Estos componentes se renderizarán automáticamente al procesar los documentos HTML que incluyen +/// estas regiones, como las páginas de contenido ([`Page`](crate::response::page::Page)). pub enum InRegion { - /// Representa la región por defecto en la que se pueden añadir componentes. + /// Región de contenido por defecto. Content, - /// Representa la región con el nombre del argumento. + /// Región identificada por el nombre proporcionado. Named(&'static str), - /// Representa la región con el nombre y del tema especificado en los argumentos. + /// Región identificada por un nombre y asociada a un tema concreto. OfTheme(&'static str, ThemeRef), } impl InRegion { - /// Permite añadir un componente en la región de la variante seleccionada. + /// Añade un componente a la región indicada por la variante. /// /// # Ejemplo /// @@ -88,7 +143,7 @@ impl InRegion { InRegion::Content => { COMMON_REGIONS .write() - .alter_child_in_region(CONTENT_REGION_NAME, ChildOp::Add(child)); + .alter_child_in_region(REGION_CONTENT, ChildOp::Add(child)); } InRegion::Named(name) => { COMMON_REGIONS diff --git a/src/locale/en-US/theme.ftl b/src/locale/en-US/theme.ftl index 9c71e6bd..f766766d 100644 --- a/src/locale/en-US/theme.ftl +++ b/src/locale/en-US/theme.ftl @@ -1,2 +1,9 @@ -content = Content +# Regions. +region_header = Header +region_content = Content +region_footer = Footer + +error403_notice = FORBIDDEN ACCESS +error404_notice = RESOURCE NOT FOUND + pagetop_logo = PageTop Logo diff --git a/src/locale/es-ES/theme.ftl b/src/locale/es-ES/theme.ftl index f193c537..b8b91449 100644 --- a/src/locale/es-ES/theme.ftl +++ b/src/locale/es-ES/theme.ftl @@ -1,2 +1,9 @@ -content = Contenido +# Regions. +region_header = Cabecera +region_content = Contenido +region_footer = Pie de página + +error403_notice = ACCESO NO PERMITIDO +error404_notice = RECURSO NO ENCONTRADO + pagetop_logo = Logotipo de PageTop diff --git a/src/response/page.rs b/src/response/page.rs index 44cab725..f30e299e 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -6,7 +6,7 @@ pub use actix_web::Result as ResultPage; use crate::base::action; use crate::builder_fn; use crate::core::component::{Child, ChildOp, Component}; -use crate::core::theme::{ChildrenInRegions, ThemeRef, CONTENT_REGION_NAME}; +use crate::core::theme::{ChildrenInRegions, ThemeRef, REGION_CONTENT}; use crate::html::{html, AssetsOp, Context, Markup, DOCTYPE}; use crate::html::{ClassesOp, OptionClasses, OptionId, OptionTranslated}; use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier}; @@ -123,7 +123,7 @@ impl Page { /// Añade un componente a la región de contenido por defecto. pub fn with_component(mut self, component: impl Component) -> Self { self.regions - .alter_child_in_region(CONTENT_REGION_NAME, ChildOp::Add(Child::with(component))); + .alter_child_in_region(REGION_CONTENT, ChildOp::Add(Child::with(component))); self } @@ -172,11 +172,6 @@ impl Page { self.context.request() } - /// Devuelve el identificador de idioma asociado. - pub fn langid(&self) -> &LanguageIdentifier { - self.context.langid() - } - /// Devuelve el tema que se usará para renderizar la página. pub fn theme(&self) -> ThemeRef { self.context.theme() @@ -250,3 +245,9 @@ impl Page { }) } } + +impl LangId for Page { + fn langid(&self) -> &'static LanguageIdentifier { + self.context.langid() + } +} From 5ef85154b561e7bd3794ae30cacfbf5b2c2f8afd Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 23 Aug 2025 18:52:45 +0200 Subject: [PATCH 148/244] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(html):=20Cambia?= =?UTF-8?q?=20tipos=20`Option...`=20por=20`Attr...`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renombra los tipos para atributos HTML `Id`, `Name`, `Value` (`String`), `L10n` (`Translate`) y `Classes`. Y mueve `OptionComponent` al *core* de componentes como `TypedSlot`. --- .../component/after_render_component.rs | 4 +- .../component/before_render_component.rs | 4 +- src/base/action/component/is_renderable.rs | 4 +- src/core/component.rs | 3 + src/core/component/children.rs | 17 ++-- src/core/component/slot.rs | 64 +++++++++++++ src/html.rs | 90 +++++++++++++------ src/html/{opt_classes.rs => attr_classes.rs} | 14 +-- src/html/attr_id.rs | 63 +++++++++++++ src/html/{opt_translated.rs => attr_l10n.rs} | 16 ++-- src/html/attr_name.rs | 63 +++++++++++++ src/html/attr_value.rs | 65 ++++++++++++++ src/html/opt_component.rs | 68 -------------- src/html/opt_id.rs | 59 ------------ src/html/opt_name.rs | 59 ------------ src/html/opt_string.rs | 57 ------------ src/response/page.rs | 28 +++--- 17 files changed, 367 insertions(+), 311 deletions(-) create mode 100644 src/core/component/slot.rs rename src/html/{opt_classes.rs => attr_classes.rs} (90%) create mode 100644 src/html/attr_id.rs rename src/html/{opt_translated.rs => attr_l10n.rs} (79%) create mode 100644 src/html/attr_name.rs create mode 100644 src/html/attr_value.rs delete mode 100644 src/html/opt_component.rs delete mode 100644 src/html/opt_id.rs delete mode 100644 src/html/opt_name.rs delete mode 100644 src/html/opt_string.rs diff --git a/src/base/action/component/after_render_component.rs b/src/base/action/component/after_render_component.rs index 917f3225..0cb03347 100644 --- a/src/base/action/component/after_render_component.rs +++ b/src/base/action/component/after_render_component.rs @@ -6,7 +6,7 @@ use crate::base::action::FnActionWithComponent; pub struct AfterRender<C: Component> { f: FnActionWithComponent<C>, referer_type_id: Option<UniqueId>, - referer_id: OptionId, + referer_id: AttrId, weight: Weight, } @@ -34,7 +34,7 @@ impl<C: Component> AfterRender<C> { AfterRender { f, referer_type_id: Some(UniqueId::of::<C>()), - referer_id: OptionId::default(), + referer_id: AttrId::default(), weight: 0, } } diff --git a/src/base/action/component/before_render_component.rs b/src/base/action/component/before_render_component.rs index 8c2e38d7..46ff9aae 100644 --- a/src/base/action/component/before_render_component.rs +++ b/src/base/action/component/before_render_component.rs @@ -6,7 +6,7 @@ use crate::base::action::FnActionWithComponent; pub struct BeforeRender<C: Component> { f: FnActionWithComponent<C>, referer_type_id: Option<UniqueId>, - referer_id: OptionId, + referer_id: AttrId, weight: Weight, } @@ -34,7 +34,7 @@ impl<C: Component> BeforeRender<C> { BeforeRender { f, referer_type_id: Some(UniqueId::of::<C>()), - referer_id: OptionId::default(), + referer_id: AttrId::default(), weight: 0, } } diff --git a/src/base/action/component/is_renderable.rs b/src/base/action/component/is_renderable.rs index baa86f1d..5a0e244e 100644 --- a/src/base/action/component/is_renderable.rs +++ b/src/base/action/component/is_renderable.rs @@ -11,7 +11,7 @@ pub type FnIsRenderable<C> = fn(component: &C, cx: &Context) -> bool; pub struct IsRenderable<C: Component> { f: FnIsRenderable<C>, referer_type_id: Option<UniqueId>, - referer_id: OptionId, + referer_id: AttrId, weight: Weight, } @@ -39,7 +39,7 @@ impl<C: Component> IsRenderable<C> { IsRenderable { f, referer_type_id: Some(UniqueId::of::<C>()), - referer_id: OptionId::default(), + referer_id: AttrId::default(), weight: 0, } } diff --git a/src/core/component.rs b/src/core/component.rs index 17b9b735..36914722 100644 --- a/src/core/component.rs +++ b/src/core/component.rs @@ -7,3 +7,6 @@ mod children; pub use children::Children; pub use children::{Child, ChildOp}; pub use children::{Typed, TypedOp}; + +mod slot; +pub use slot::TypedSlot; diff --git a/src/core/component/children.rs b/src/core/component/children.rs index fb85db7a..cb112e16 100644 --- a/src/core/component/children.rs +++ b/src/core/component/children.rs @@ -9,13 +9,13 @@ use std::vec::IntoIter; /// Representa un componente encapsulado de forma segura y compartida. /// -/// Esta estructura permite manipular y renderizar cualquier tipo que implemente [`Component`], -/// garantizando acceso concurrente a través de [`Arc<RwLock<_>>`]. +/// Esta estructura permite manipular y renderizar un componente que implemente [`Component`], y +/// habilita acceso concurrente mediante [`Arc<RwLock<_>>`]. #[derive(Clone)] pub struct Child(Arc<RwLock<dyn Component>>); impl Child { - /// Crea un nuevo [`Child`] a partir de un componente. + /// Crea un nuevo `Child` a partir de un componente. pub fn with(component: impl Component) -> Self { Child(Arc::new(RwLock::new(component))) } @@ -46,7 +46,8 @@ impl Child { /// Variante tipada de [`Child`] para evitar conversiones durante el uso. /// -/// Facilita el acceso a componentes del mismo tipo sin necesidad de hacer `downcast`. +/// Esta estructura permite manipular y renderizar un componente concreto que implemente +/// [`Component`], y habilita acceso concurrente mediante [`Arc<RwLock<_>>`]. pub struct Typed<C: Component>(Arc<RwLock<C>>); impl<C: Component> Clone for Typed<C> { @@ -56,7 +57,7 @@ impl<C: Component> Clone for Typed<C> { } impl<C: Component> Typed<C> { - /// Crea un nuevo [`Typed`] a partir de un componente. + /// Crea un nuevo `Typed` a partir de un componente. pub fn with(component: C) -> Self { Typed(Arc::new(RwLock::new(component))) } @@ -284,7 +285,7 @@ impl IntoIterator for Children { /// /// # Ejemplo de uso: /// - /// ```rust#ignore + /// ```rust,ignore /// let children = Children::new().with(child1).with(child2); /// for child in children { /// println!("{:?}", child.id()); @@ -303,7 +304,7 @@ impl<'a> IntoIterator for &'a Children { /// /// # Ejemplo de uso: /// - /// ```rust#ignore + /// ```rust,ignore /// let children = Children::new().with(child1).with(child2); /// for child in &children { /// println!("{:?}", child.id()); @@ -322,7 +323,7 @@ impl<'a> IntoIterator for &'a mut Children { /// /// # Ejemplo de uso: /// - /// ```rust#ignore + /// ```rust,ignore /// let mut children = Children::new().with(child1).with(child2); /// for child in &mut children { /// child.render(&mut context); diff --git a/src/core/component/slot.rs b/src/core/component/slot.rs new file mode 100644 index 00000000..19ed72ac --- /dev/null +++ b/src/core/component/slot.rs @@ -0,0 +1,64 @@ +use crate::builder_fn; +use crate::core::component::{Component, Typed}; +use crate::html::{html, Context, Markup}; + +/// Contenedor para un componente [`Typed`] opcional. +/// +/// Un `TypedSlot` actúa como un contenedor dentro de otro componente para incluir o no un +/// subcomponente. Internamente encapsula `Option<Typed<C>>`, pero proporciona una API más sencilla +/// para construir estructuras jerárquicas. +/// +/// # Ejemplo +/// +/// ```rust,ignore +/// use pagetop::prelude::*; +/// +/// let comp = MyComponent::new(); +/// let opt = TypedSlot::new(comp); +/// assert!(opt.get().is_some()); +/// ``` +pub struct TypedSlot<C: Component>(Option<Typed<C>>); + +impl<C: Component> Default for TypedSlot<C> { + fn default() -> Self { + TypedSlot(None) + } +} + +impl<C: Component> TypedSlot<C> { + /// Crea un nuevo [`TypedSlot`]. + /// + /// El componente se envuelve automáticamente en un [`Typed`] y se almacena. + pub fn new(component: C) -> Self { + TypedSlot(Some(Typed::with(component))) + } + + // TypedSlot BUILDER ********************************************************************* + + /// Establece un componente nuevo, o lo vacía. + /// + /// Si se proporciona `Some(component)`, se guarda en [`Typed`]; y si es `None`, se limpia. + #[builder_fn] + pub fn with_value(mut self, component: Option<C>) -> Self { + self.0 = component.map(Typed::with); + self + } + + // TypedSlot GETTERS ********************************************************************* + + /// Devuelve un clon (incrementa el contador `Arc`) de [`Typed<C>`], si existe. + pub fn get(&self) -> Option<Typed<C>> { + self.0.clone() + } + + // TypedSlot RENDER ************************************************************************ + + /// Renderiza el componente, si existe. + pub fn render(&self, cx: &mut Context) -> Markup { + if let Some(component) = &self.0 { + component.render(cx) + } else { + html! {} + } + } +} diff --git a/src/html.rs b/src/html.rs index 82fa906b..784457ed 100644 --- a/src/html.rs +++ b/src/html.rs @@ -3,52 +3,82 @@ mod maud; pub use maud::{display, html, html_private, Escaper, Markup, PreEscaped, Render, DOCTYPE}; +// HTML DOCUMENT ASSETS **************************************************************************** + mod assets; pub use assets::favicon::Favicon; pub use assets::javascript::JavaScript; pub use assets::stylesheet::{StyleSheet, TargetMedia}; pub(crate) use assets::Assets; +// HTML DOCUMENT CONTEXT *************************************************************************** + mod context; pub use context::{AssetsOp, Context, ErrorParam}; -mod opt_id; -pub use opt_id::OptionId; +// HTML ATTRIBUTES ********************************************************************************* -mod opt_name; -pub use opt_name::OptionName; +mod attr_id; +pub use attr_id::AttrId; +/// **Obsoleto desde la versión 0.4.0**: usar [`AttrId`] en su lugar. +#[deprecated(since = "0.4.0", note = "Use `AttrId` instead")] +pub type OptionId = AttrId; -mod opt_string; -pub use opt_string::OptionString; +mod attr_name; +pub use attr_name::AttrName; +/// **Obsoleto desde la versión 0.4.0**: usar [`AttrName`] en su lugar. +#[deprecated(since = "0.4.0", note = "Use `AttrName` instead")] +pub type OptionName = AttrName; -mod opt_translated; -pub use opt_translated::OptionTranslated; +mod attr_value; +pub use attr_value::AttrValue; +/// **Obsoleto desde la versión 0.4.0**: usar [`AttrValue`] en su lugar. +#[deprecated(since = "0.4.0", note = "Use `AttrValue` instead")] +pub type OptionString = AttrValue; -mod opt_classes; -pub use opt_classes::{ClassesOp, OptionClasses}; +mod attr_l10n; +pub use attr_l10n::AttrL10n; +/// **Obsoleto desde la versión 0.4.0**: usar [`AttrL10n`] en su lugar. +#[deprecated(since = "0.4.0", note = "Use `AttrL10n` instead")] +pub type OptionTranslated = AttrL10n; -mod opt_component; -pub use opt_component::OptionComponent; +mod attr_classes; +pub use attr_classes::{AttrClasses, ClassesOp}; +/// **Obsoleto desde la versión 0.4.0**: usar [`AttrClasses`] en su lugar. +#[deprecated(since = "0.4.0", note = "Use `AttrClasses` instead")] +pub type OptionClasses = AttrClasses; -use crate::AutoDefault; +use crate::{core, AutoDefault}; + +/// **Obsoleto desde la versión 0.4.0**: usar [`TypedSlot`](crate::core::component::TypedSlot) en su +/// lugar. +#[deprecated( + since = "0.4.0", + note = "Use `pagetop::core::component::TypedSlot` instead" +)] +#[allow(type_alias_bounds)] +pub type OptionComponent<C: core::component::Component> = core::component::TypedSlot<C>; /// Prepara contenido HTML para su conversión a [`Markup`]. /// -/// Este tipo encapsula distintos orígenes de contenido HTML (texto plano, HTML escapado o marcado -/// ya procesado) para renderizar de forma homogénea en plantillas sin interferir con el uso -/// estándar de [`Markup`]. +/// Este tipo encapsula distintos orígenes de contenido HTML (texto plano, HTML sin escapar o +/// fragmentos ya procesados) para renderizarlos de forma homogénea en plantillas, sin interferir +/// con el uso estándar de [`Markup`]. /// /// # Ejemplo /// /// ```rust /// use pagetop::prelude::*; /// -/// let fragment = PrepareMarkup::Text(String::from("Hola <b>mundo</b>")); +/// // Texto normal, se escapa automáticamente para evitar inyección de HTML. +/// let fragment = PrepareMarkup::Escaped(String::from("Hola <b>mundo</b>")); /// assert_eq!(fragment.render().into_string(), "Hola &lt;b&gt;mundo&lt;/b&gt;"); /// -/// let raw_html = PrepareMarkup::Escaped(String::from("<b>negrita</b>")); +/// // HTML literal, se inserta directamente, sin escapado adicional. +/// let raw_html = PrepareMarkup::Raw(String::from("<b>negrita</b>")); /// assert_eq!(raw_html.render().into_string(), "<b>negrita</b>"); /// +/// // Fragmento ya preparado con la macro `html!`. /// let prepared = PrepareMarkup::With(html! { /// h2 { "Título de ejemplo" } /// p { "Este es un párrafo con contenido dinámico." } @@ -60,14 +90,22 @@ use crate::AutoDefault; /// ``` #[derive(AutoDefault)] pub enum PrepareMarkup { - /// No se genera contenido HTML (devuelve `html! {}`). + /// No se genera contenido HTML (equivale a `html! {}`). #[default] None, - /// Texto estático que se escapará automáticamente para no ser interpretado como HTML. - Text(String), - /// Contenido sin escapado adicional, útil para HTML generado externamente. + /// Texto plano que se **escapará automáticamente** para que no sea interpretado como HTML. + /// + /// Úsalo con textos que provengan de usuarios u otras fuentes externas para garantizar la + /// seguridad contra inyección de código. Escaped(String), + /// HTML literal que se inserta **sin escapado adicional**. + /// + /// Úsalo únicamente para contenido generado de forma confiable o controlada, ya que cualquier + /// etiqueta o script incluido será renderizado directamente en el documento. + Raw(String), /// Fragmento HTML ya preparado como [`Markup`], listo para insertarse directamente. + /// + /// Normalmente proviene de expresiones `html! { ... }`. With(Markup), } @@ -76,8 +114,8 @@ impl PrepareMarkup { pub fn is_empty(&self) -> bool { match self { PrepareMarkup::None => true, - PrepareMarkup::Text(text) => text.is_empty(), - PrepareMarkup::Escaped(string) => string.is_empty(), + PrepareMarkup::Escaped(text) => text.is_empty(), + PrepareMarkup::Raw(string) => string.is_empty(), PrepareMarkup::With(markup) => markup.is_empty(), } } @@ -88,8 +126,8 @@ impl Render for PrepareMarkup { fn render(&self) -> Markup { match self { PrepareMarkup::None => html! {}, - PrepareMarkup::Text(text) => html! { (text) }, - PrepareMarkup::Escaped(string) => html! { (PreEscaped(string)) }, + PrepareMarkup::Escaped(text) => html! { (text) }, + PrepareMarkup::Raw(string) => html! { (PreEscaped(string)) }, PrepareMarkup::With(markup) => html! { (markup) }, } } diff --git a/src/html/opt_classes.rs b/src/html/attr_classes.rs similarity index 90% rename from src/html/opt_classes.rs rename to src/html/attr_classes.rs index a9857625..92851aa3 100644 --- a/src/html/opt_classes.rs +++ b/src/html/attr_classes.rs @@ -1,6 +1,6 @@ use crate::{builder_fn, AutoDefault}; -/// Operaciones disponibles sobre la lista de clases en [`OptionClasses`]. +/// Operaciones disponibles sobre la lista de clases en [`AttrClasses`]. pub enum ClassesOp { /// Añade al final (si no existe). Add, @@ -33,7 +33,7 @@ pub enum ClassesOp { /// ```rust /// use pagetop::prelude::*; /// -/// let classes = OptionClasses::new("Btn btn-primary") +/// let classes = AttrClasses::new("Btn btn-primary") /// .with_value(ClassesOp::Add, "Active") /// .with_value(ClassesOp::Remove, "btn-primary"); /// @@ -41,14 +41,14 @@ pub enum ClassesOp { /// assert!(classes.contains("active")); /// ``` #[derive(AutoDefault, Clone, Debug)] -pub struct OptionClasses(Vec<String>); +pub struct AttrClasses(Vec<String>); -impl OptionClasses { +impl AttrClasses { pub fn new(classes: impl AsRef<str>) -> Self { - OptionClasses::default().with_value(ClassesOp::Prepend, classes) + AttrClasses::default().with_value(ClassesOp::Prepend, classes) } - // OptionClasses BUILDER *********************************************************************** + // AttrClasses BUILDER ************************************************************************* #[builder_fn] pub fn with_value(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { @@ -114,7 +114,7 @@ impl OptionClasses { } } - // OptionClasses GETTERS *********************************************************************** + // AttrClasses GETTERS ************************************************************************* /// Devuele la cadena de clases, si existe. pub fn get(&self) -> Option<String> { diff --git a/src/html/attr_id.rs b/src/html/attr_id.rs new file mode 100644 index 00000000..8bb1d33b --- /dev/null +++ b/src/html/attr_id.rs @@ -0,0 +1,63 @@ +use crate::{builder_fn, AutoDefault}; + +/// Identificador normalizado para el atributo `id` o similar de HTML. +/// +/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso: +/// +/// - Se eliminan los espacios al principio y al final. +/// - Se convierte a minúsculas. +/// - Se sustituyen los espacios intermedios por guiones bajos (`_`). +/// - Si el resultado es una cadena vacía, se guarda `None`. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// let id = AttrId::new(" main Section "); +/// assert_eq!(id.as_str(), Some("main_section")); +/// +/// let empty = AttrId::default(); +/// assert_eq!(empty.get(), None); +/// ``` +#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)] +pub struct AttrId(Option<String>); + +impl AttrId { + /// Crea un nuevo `AttrId` normalizando el valor. + pub fn new(value: impl AsRef<str>) -> Self { + AttrId::default().with_value(value) + } + + // AttrId BUILDER ****************************************************************************** + + /// Establece un identificador nuevo normalizando el valor. + #[builder_fn] + pub fn with_value(mut self, value: impl AsRef<str>) -> Self { + let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_"); + self.0 = if value.is_empty() { None } else { Some(value) }; + self + } + + // AttrId GETTERS ****************************************************************************** + + /// Devuelve el identificador normalizado, si existe. + pub fn get(&self) -> Option<String> { + self.0.as_ref().cloned() + } + + /// Devuelve el identificador normalizado (sin clonar), si existe. + pub fn as_str(&self) -> Option<&str> { + self.0.as_deref() + } + + /// Devuelve el identificador normalizado (propiedad), si existe. + pub fn into_inner(self) -> Option<String> { + self.0 + } + + /// `true` si no hay valor. + pub fn is_empty(&self) -> bool { + self.0.is_none() + } +} diff --git a/src/html/opt_translated.rs b/src/html/attr_l10n.rs similarity index 79% rename from src/html/opt_translated.rs rename to src/html/attr_l10n.rs index b15ea18a..cd5b389d 100644 --- a/src/html/opt_translated.rs +++ b/src/html/attr_l10n.rs @@ -2,7 +2,7 @@ use crate::html::Markup; use crate::locale::{L10n, LangId}; use crate::{builder_fn, AutoDefault}; -/// Cadena para traducir al renderizar ([`locale`](crate::locale)). +/// Texto para [traducir](crate::locale) en atributos HTML. /// /// Encapsula un tipo [`L10n`] para manejar traducciones de forma segura. /// @@ -12,7 +12,7 @@ use crate::{builder_fn, AutoDefault}; /// use pagetop::prelude::*; /// /// // Traducción por clave en las locales por defecto de PageTop. -/// let hello = OptionTranslated::new(L10n::l("test-hello-world")); +/// let hello = AttrL10n::new(L10n::l("test-hello-world")); /// /// // Español disponible. /// assert_eq!( @@ -31,15 +31,15 @@ use crate::{builder_fn, AutoDefault}; /// assert_eq!(markup.into_string(), "¡Hola mundo!"); /// ``` #[derive(AutoDefault, Clone, Debug)] -pub struct OptionTranslated(L10n); +pub struct AttrL10n(L10n); -impl OptionTranslated { - /// Crea una nueva instancia [`OptionTranslated`]. +impl AttrL10n { + /// Crea una nueva instancia `AttrL10n`. pub fn new(value: L10n) -> Self { - OptionTranslated(value) + AttrL10n(value) } - // OptionTranslated BUILDER ******************************************************************** + // AttrL10n BUILDER **************************************************************************** /// Establece una traducción nueva. #[builder_fn] @@ -48,7 +48,7 @@ impl OptionTranslated { self } - // OptionTranslated GETTERS ******************************************************************** + // AttrL10n GETTERS **************************************************************************** /// Devuelve la traducción para `language`, si existe. pub fn using(&self, language: &impl LangId) -> Option<String> { diff --git a/src/html/attr_name.rs b/src/html/attr_name.rs new file mode 100644 index 00000000..928f841f --- /dev/null +++ b/src/html/attr_name.rs @@ -0,0 +1,63 @@ +use crate::{builder_fn, AutoDefault}; + +/// Nombre normalizado para el atributo `name` o similar de HTML. +/// +/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso: +/// +/// - Se eliminan los espacios al principio y al final. +/// - Se convierte a minúsculas. +/// - Se sustituyen los espacios intermedios por guiones bajos (`_`). +/// - Si el resultado es una cadena vacía, se guarda `None`. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// let name = AttrName::new(" DISplay name "); +/// assert_eq!(name.as_str(), Some("display_name")); +/// +/// let empty = AttrName::default(); +/// assert_eq!(empty.get(), None); +/// ``` +#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)] +pub struct AttrName(Option<String>); + +impl AttrName { + /// Crea un nuevo `AttrName` normalizando el valor. + pub fn new(value: impl AsRef<str>) -> Self { + AttrName::default().with_value(value) + } + + // AttrName BUILDER **************************************************************************** + + /// Establece un nombre nuevo normalizando el valor. + #[builder_fn] + pub fn with_value(mut self, value: impl AsRef<str>) -> Self { + let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_"); + self.0 = if value.is_empty() { None } else { Some(value) }; + self + } + + // AttrName GETTERS **************************************************************************** + + /// Devuelve el nombre normalizado, si existe. + pub fn get(&self) -> Option<String> { + self.0.as_ref().cloned() + } + + /// Devuelve el nombre normalizado (sin clonar), si existe. + pub fn as_str(&self) -> Option<&str> { + self.0.as_deref() + } + + /// Devuelve el nombre normalizado (propiedad), si existe. + pub fn into_inner(self) -> Option<String> { + self.0 + } + + /// `true` si no hay valor. + pub fn is_empty(&self) -> bool { + self.0.is_none() + } +} diff --git a/src/html/attr_value.rs b/src/html/attr_value.rs new file mode 100644 index 00000000..c70229f9 --- /dev/null +++ b/src/html/attr_value.rs @@ -0,0 +1,65 @@ +use crate::{builder_fn, AutoDefault}; + +/// Cadena normalizada para renderizar en atributos HTML. +/// +/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso: +/// +/// - Se eliminan los espacios al principio y al final. +/// - Si el resultado es una cadena vacía, se guarda `None`. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// let s = AttrValue::new(" a new string "); +/// assert_eq!(s.as_str(), Some("a new string")); +/// +/// let empty = AttrValue::default(); +/// assert_eq!(empty.get(), None); +/// ``` +#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)] +pub struct AttrValue(Option<String>); + +impl AttrValue { + /// Crea un nuevo `AttrValue` normalizando el valor. + pub fn new(value: impl AsRef<str>) -> Self { + AttrValue::default().with_value(value) + } + + // AttrValue BUILDER *************************************************************************** + + /// Establece una cadena nueva normalizando el valor. + #[builder_fn] + pub fn with_value(mut self, value: impl AsRef<str>) -> Self { + let value = value.as_ref().trim(); + self.0 = if value.is_empty() { + None + } else { + Some(value.to_owned()) + }; + self + } + + // AttrValue GETTERS *************************************************************************** + + /// Devuelve la cadena normalizada, si existe. + pub fn get(&self) -> Option<String> { + self.0.as_ref().cloned() + } + + /// Devuelve la cadena normalizada (sin clonar), si existe. + pub fn as_str(&self) -> Option<&str> { + self.0.as_deref() + } + + /// Devuelve la cadena normalizada (propiedad), si existe. + pub fn into_inner(self) -> Option<String> { + self.0 + } + + /// `true` si no hay valor. + pub fn is_empty(&self) -> bool { + self.0.is_none() + } +} diff --git a/src/html/opt_component.rs b/src/html/opt_component.rs deleted file mode 100644 index 39106d99..00000000 --- a/src/html/opt_component.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::builder_fn; -use crate::core::component::{Component, Typed}; -use crate::html::{html, Context, Markup}; - -/// Contenedor de componente para incluir en otros componentes. -/// -/// Este tipo encapsula `Option<Typed<C>>` para incluir un componente de manera segura en otros -/// componentes, útil para representar estructuras complejas. -/// -/// # Ejemplo -/// -/// ```rust,ignore -/// use pagetop::prelude::*; -/// -/// let comp = MyComponent::new(); -/// let opt = OptionComponent::new(comp); -/// assert!(opt.get().is_some()); -/// ``` -pub struct OptionComponent<C: Component>(Option<Typed<C>>); - -impl<C: Component> Default for OptionComponent<C> { - fn default() -> Self { - OptionComponent(None) - } -} - -impl<C: Component> OptionComponent<C> { - /// Crea un nuevo [`OptionComponent`]. - /// - /// El componente se envuelve automáticamente en un [`Typed`] y se almacena. - pub fn new(component: C) -> Self { - OptionComponent::default().with_value(Some(component)) - } - - // OptionComponent BUILDER ********************************************************************* - - /// Establece un componente nuevo, o lo vacía. - /// - /// Si se proporciona `Some(component)`, se guarda en [`Typed`]; y si es `None`, se limpia. - #[builder_fn] - pub fn with_value(mut self, component: Option<C>) -> Self { - if let Some(component) = component { - self.0 = Some(Typed::with(component)); - } else { - self.0 = None; - } - self - } - - // OptionComponent GETTERS ********************************************************************* - - /// Devuelve el componente, si existe. - pub fn get(&self) -> Option<Typed<C>> { - if let Some(value) = &self.0 { - return Some(value.clone()); - } - None - } - - /// Renderiza el componente, si existe. - pub fn render(&self, cx: &mut Context) -> Markup { - if let Some(component) = &self.0 { - component.render(cx) - } else { - html! {} - } - } -} diff --git a/src/html/opt_id.rs b/src/html/opt_id.rs deleted file mode 100644 index 139fdcd6..00000000 --- a/src/html/opt_id.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::{builder_fn, AutoDefault}; - -/// Identificador normalizado para el atributo `id` o similar de HTML. -/// -/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso. -/// -/// # Normalización -/// -/// - Se eliminan los espacios al principio y al final. -/// - Se convierte a minúsculas. -/// - Se sustituyen los espacios intermedios por guiones bajos (`_`). -/// - Si el resultado es una cadena vacía, se guarda `None`. -/// -/// # Ejemplo -/// -/// ```rust -/// use pagetop::prelude::*; -/// -/// let id = OptionId::new(" main Section "); -/// assert_eq!(id.get(), Some(String::from("main_section"))); -/// -/// let empty = OptionId::default(); -/// assert_eq!(empty.get(), None); -/// ``` -#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)] -pub struct OptionId(Option<String>); - -impl OptionId { - /// Crea un nuevo [`OptionId`]. - /// - /// El valor se normaliza automáticamente. - pub fn new(value: impl AsRef<str>) -> Self { - OptionId::default().with_value(value) - } - - // OptionId BUILDER **************************************************************************** - - /// Establece un identificador nuevo. - /// - /// El valor se normaliza automáticamente. - #[builder_fn] - pub fn with_value(mut self, value: impl AsRef<str>) -> Self { - let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_"); - self.0 = (!value.is_empty()).then_some(value); - self - } - - // OptionId GETTERS **************************************************************************** - - /// Devuelve el identificador, si existe. - pub fn get(&self) -> Option<String> { - if let Some(value) = &self.0 { - if !value.is_empty() { - return Some(value.to_owned()); - } - } - None - } -} diff --git a/src/html/opt_name.rs b/src/html/opt_name.rs deleted file mode 100644 index ffb0b989..00000000 --- a/src/html/opt_name.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::{builder_fn, AutoDefault}; - -/// Nombre normalizado para el atributo `name` o similar de HTML. -/// -/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso. -/// -/// # Normalización -/// -/// - Se eliminan los espacios al principio y al final. -/// - Se convierte a minúsculas. -/// - Se sustituyen los espacios intermedios por guiones bajos (`_`). -/// - Si el resultado es una cadena vacía, se guarda `None`. -/// -/// # Ejemplo -/// -/// ```rust -/// use pagetop::prelude::*; -/// -/// let name = OptionName::new(" DISplay name "); -/// assert_eq!(name.get(), Some(String::from("display_name"))); -/// -/// let empty = OptionName::default(); -/// assert_eq!(empty.get(), None); -/// ``` -#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)] -pub struct OptionName(Option<String>); - -impl OptionName { - /// Crea un nuevo [`OptionName`]. - /// - /// El valor se normaliza automáticamente. - pub fn new(value: impl AsRef<str>) -> Self { - OptionName::default().with_value(value) - } - - // OptionName BUILDER ************************************************************************** - - /// Establece un nombre nuevo. - /// - /// El valor se normaliza automáticamente. - #[builder_fn] - pub fn with_value(mut self, value: impl AsRef<str>) -> Self { - let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_"); - self.0 = (!value.is_empty()).then_some(value); - self - } - - // OptionName GETTERS ************************************************************************** - - /// Devuelve el nombre, si existe. - pub fn get(&self) -> Option<String> { - if let Some(value) = &self.0 { - if !value.is_empty() { - return Some(value.to_owned()); - } - } - None - } -} diff --git a/src/html/opt_string.rs b/src/html/opt_string.rs deleted file mode 100644 index 5bfd9c71..00000000 --- a/src/html/opt_string.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::{builder_fn, AutoDefault}; - -/// Cadena normalizada para renderizar en atributos HTML. -/// -/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso. -/// -/// # Normalización -/// -/// - Se eliminan los espacios al principio y al final. -/// - Si el resultado es una cadena vacía, se guarda `None`. -/// -/// # Ejemplo -/// -/// ```rust -/// use pagetop::prelude::*; -/// -/// let s = OptionString::new(" a new string "); -/// assert_eq!(s.get(), Some(String::from("a new string"))); -/// -/// let empty = OptionString::default(); -/// assert_eq!(empty.get(), None); -/// ``` -#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)] -pub struct OptionString(Option<String>); - -impl OptionString { - /// Crea un nuevo [`OptionString`]. - /// - /// El valor se normaliza automáticamente. - pub fn new(value: impl AsRef<str>) -> Self { - OptionString::default().with_value(value) - } - - // OptionString BUILDER ************************************************************************ - - /// Establece una cadena nueva. - /// - /// El valor se normaliza automáticamente. - #[builder_fn] - pub fn with_value(mut self, value: impl AsRef<str>) -> Self { - let value = value.as_ref().trim().to_owned(); - self.0 = (!value.is_empty()).then_some(value); - self - } - - // OptionString GETTERS ************************************************************************ - - /// Devuelve la cadena, si existe. - pub fn get(&self) -> Option<String> { - if let Some(value) = &self.0 { - if !value.is_empty() { - return Some(value.to_owned()); - } - } - None - } -} diff --git a/src/response/page.rs b/src/response/page.rs index f30e299e..ea88e846 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -7,8 +7,10 @@ use crate::base::action; use crate::builder_fn; use crate::core::component::{Child, ChildOp, Component}; use crate::core::theme::{ChildrenInRegions, ThemeRef, REGION_CONTENT}; -use crate::html::{html, AssetsOp, Context, Markup, DOCTYPE}; -use crate::html::{ClassesOp, OptionClasses, OptionId, OptionTranslated}; +use crate::html::{html, Markup, DOCTYPE}; +use crate::html::{AssetsOp, Context}; +use crate::html::{AttrClasses, ClassesOp}; +use crate::html::{AttrId, AttrL10n}; use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier}; use crate::service::HttpRequest; @@ -19,13 +21,13 @@ use crate::service::HttpRequest; /// renderizado. #[rustfmt::skip] pub struct Page { - title : OptionTranslated, - description : OptionTranslated, + title : AttrL10n, + description : AttrL10n, metadata : Vec<(&'static str, &'static str)>, properties : Vec<(&'static str, &'static str)>, context : Context, - body_id : OptionId, - body_classes: OptionClasses, + body_id : AttrId, + body_classes: AttrClasses, regions : ChildrenInRegions, } @@ -37,13 +39,13 @@ impl Page { #[rustfmt::skip] pub fn new(request: Option<HttpRequest>) -> Self { Page { - title : OptionTranslated::default(), - description : OptionTranslated::default(), + title : AttrL10n::default(), + description : AttrL10n::default(), metadata : Vec::default(), properties : Vec::default(), context : Context::new(request), - body_id : OptionId::default(), - body_classes: OptionClasses::default(), + body_id : AttrId::default(), + body_classes: AttrClasses::default(), regions : ChildrenInRegions::default(), } } @@ -113,7 +115,7 @@ impl Page { self } - /// Modifica las clases CSS del elemento `<body>` con una operación sobre [`OptionClasses`]. + /// Modifica las clases CSS del elemento `<body>` con una operación sobre [`AttrClasses`]. #[builder_fn] pub fn with_body_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { self.body_classes.alter_value(op, classes); @@ -183,12 +185,12 @@ impl Page { } /// Devuelve el identificador del elemento `<body>`. - pub fn body_id(&self) -> &OptionId { + pub fn body_id(&self) -> &AttrId { &self.body_id } /// Devuelve las clases CSS del elemento `<body>`. - pub fn body_classes(&self) -> &OptionClasses { + pub fn body_classes(&self) -> &AttrClasses { &self.body_classes } From fbdce1035c13bc0bb386b0e19001c82650c1a232 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 23 Aug 2025 19:34:26 +0200 Subject: [PATCH 149/244] =?UTF-8?q?=E2=9C=85=20(tests):=20Ampl=C3=ADa=20pr?= =?UTF-8?q?uebas=20para=20`PrepareMarkup'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/html.rs | 105 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 99 insertions(+), 6 deletions(-) diff --git a/tests/html.rs b/tests/html.rs index 315f74ad..1499c709 100644 --- a/tests/html.rs +++ b/tests/html.rs @@ -1,17 +1,110 @@ use pagetop::prelude::*; #[pagetop::test] -async fn prepare_markup_is_empty() { - let _app = service::test::init_service(Application::new().test()).await; +async fn prepare_markup_render_none_is_empty_string() { + assert_eq!(render(&PrepareMarkup::None), ""); +} +#[pagetop::test] +async fn prepare_markup_render_escaped_escapes_html_and_ampersands() { + let pm = PrepareMarkup::Escaped(String::from("<b>& \" ' </b>")); + assert_eq!(render(&pm), "&lt;b&gt;&amp; &quot; ' &lt;/b&gt;"); +} + +#[pagetop::test] +async fn prepare_markup_render_raw_is_inserted_verbatim() { + let pm = PrepareMarkup::Raw(String::from("<b>bold</b><script>1<2</script>")); + assert_eq!(render(&pm), "<b>bold</b><script>1<2</script>"); +} + +#[pagetop::test] +async fn prepare_markup_render_with_keeps_structure() { + let pm = PrepareMarkup::With(html! { + h2 { "Sample title" } + p { "This is a paragraph." } + }); + assert_eq!( + render(&pm), + "<h2>Sample title</h2><p>This is a paragraph.</p>" + ); +} + +#[pagetop::test] +async fn prepare_markup_does_not_double_escape_when_wrapped_in_html_macro() { + // Escaped: dentro de `html!` no debe volver a escaparse. + let escaped = PrepareMarkup::Escaped("<i>x</i>".into()); + let wrapped_escaped = html! { div { (escaped) } }; + assert_eq!( + wrapped_escaped.into_string(), + "<div>&lt;i&gt;x&lt;/i&gt;</div>" + ); + + // Raw: tampoco debe escaparse al integrarlo. + let raw = PrepareMarkup::Raw("<i>x</i>".into()); + let wrapped_raw = html! { div { (raw) } }; + assert_eq!(wrapped_raw.into_string(), "<div><i>x</i></div>"); + + // With: debe incrustar el Markup tal cual. + let with = PrepareMarkup::With(html! { span.title { "ok" } }); + let wrapped_with = html! { div { (with) } }; + assert_eq!( + wrapped_with.into_string(), + "<div><span class=\"title\">ok</span></div>" + ); +} + +#[pagetop::test] +async fn prepare_markup_unicode_is_preserved() { + // Texto con acentos y emojis debe conservarse (salvo el escape HTML de signos). + let esc = PrepareMarkup::Escaped("Hello, tomorrow coffee ☕ & donuts!".into()); + assert_eq!(render(&esc), "Hello, tomorrow coffee ☕ &amp; donuts!"); + + // Raw debe pasar íntegro. + let raw = PrepareMarkup::Raw("Title — section © 2025".into()); + assert_eq!(render(&raw), "Title — section © 2025"); +} + +#[pagetop::test] +async fn prepare_markup_is_empty_semantics() { assert!(PrepareMarkup::None.is_empty()); - assert!(PrepareMarkup::Text(String::from("")).is_empty()); - assert!(!PrepareMarkup::Text(String::from("x")).is_empty()); - assert!(PrepareMarkup::Escaped(String::new()).is_empty()); - assert!(!PrepareMarkup::Escaped("a".into()).is_empty()); + assert!(PrepareMarkup::Escaped(String::from("")).is_empty()); + assert!(!PrepareMarkup::Escaped(String::from("x")).is_empty()); + + assert!(PrepareMarkup::Raw(String::new()).is_empty()); + assert!(PrepareMarkup::Raw(String::from("")).is_empty()); + assert!(!PrepareMarkup::Raw("a".into()).is_empty()); assert!(PrepareMarkup::With(html! {}).is_empty()); assert!(!PrepareMarkup::With(html! { span { "!" } }).is_empty()); + + // Ojo: espacios NO deberían considerarse vacíos (comportamiento actual). + assert!(!PrepareMarkup::Escaped(" ".into()).is_empty()); + assert!(!PrepareMarkup::Raw(" ".into()).is_empty()); +} + +#[pagetop::test] +async fn prepare_markup_equivalence_between_render_and_inline_in_html_macro() { + let cases = [ + PrepareMarkup::None, + PrepareMarkup::Escaped("<b>x</b>".into()), + PrepareMarkup::Raw("<b>x</b>".into()), + PrepareMarkup::With(html! { b { "x" } }), + ]; + + for pm in cases { + let rendered = render(&pm); + let in_macro = html! { (pm) }.into_string(); + assert_eq!( + rendered, in_macro, + "The output of Render and (pm) inside html! must match" + ); + } +} + +// HELPERS ***************************************************************************************** + +fn render(x: &impl Render) -> String { + x.render().into_string() } From fdf7c40da715162c4fc1217e2b841ca493b16fca Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 24 Aug 2025 10:04:51 +0200 Subject: [PATCH 150/244] =?UTF-8?q?=F0=9F=93=9D=20(component):=20Ampl?= =?UTF-8?q?=C3=ADa=20documentaci=C3=B3n=20de=20preparaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Añade un párrafo explicando la mejor manera de que `prepare_component()` pueda ser útil a los programadores que sobrescriban su comportamiento. --- src/core/component/definition.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/component/definition.rs b/src/core/component/definition.rs index 2818570a..e9a792d7 100644 --- a/src/core/component/definition.rs +++ b/src/core/component/definition.rs @@ -51,12 +51,17 @@ 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 lista para renderizar. + /// Devuelve una representación estructurada del componente preparada para el renderizado. /// /// 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 /// dinámicamente el contenido HTML con acceso al contexto de renderizado. /// + /// Este método debe ser capaz de preparar el renderizado del componente con los métodos del + /// propio componente y el contexto proporcionado, no debería hacerlo accediendo directamente a + /// los campos de la estructura del componente. Es una forma de garantizar que los programadores + /// podrán sobrescribir este método sin preocuparse por los detalles internos del componente. + /// /// Por defecto, devuelve [`PrepareMarkup::None`]. #[allow(unused_variables)] fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { From c63c4e828914e3a13fd8312e11aedb64f8290999 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 24 Aug 2025 10:05:46 +0200 Subject: [PATCH 151/244] =?UTF-8?q?=F0=9F=92=A1=20Correcci=C3=B3n=20menor?= =?UTF-8?q?=20en=20comentario?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html/attr_classes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/html/attr_classes.rs b/src/html/attr_classes.rs index 92851aa3..91ccfaf0 100644 --- a/src/html/attr_classes.rs +++ b/src/html/attr_classes.rs @@ -116,7 +116,7 @@ impl AttrClasses { // AttrClasses GETTERS ************************************************************************* - /// Devuele la cadena de clases, si existe. + /// Devuelve la cadena de clases, si existe. pub fn get(&self) -> Option<String> { if self.0.is_empty() { None From c8e232d3890069acd2608611aad4216b5998d0e4 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 24 Aug 2025 10:09:22 +0200 Subject: [PATCH 152/244] =?UTF-8?q?=F0=9F=9A=A7=20(html):=20Implementa=20`?= =?UTF-8?q?Default`=20en=20`Context`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html/context.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/html/context.rs b/src/html/context.rs index 72c0ff29..96787863 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -117,6 +117,12 @@ pub struct Context { id_counter : usize, // Contador para generar identificadores únicos. } +impl Default for Context { + fn default() -> Self { + Context::new(None) + } +} + impl Context { /// Crea un nuevo contexto asociado a una solicitud HTTP. /// From 551e85b23937d6716bc03860415c7d30ffd68e7a Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 24 Aug 2025 10:16:02 +0200 Subject: [PATCH 153/244] =?UTF-8?q?=F0=9F=9A=A7=20Aplica=20recomendaciones?= =?UTF-8?q?=20en=20componente=20Html?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component/html.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/base/component/html.rs b/src/base/component/html.rs index 8f273edb..cac39eaf 100644 --- a/src/base/component/html.rs +++ b/src/base/component/html.rs @@ -44,11 +44,13 @@ impl Component for Html { } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - PrepareMarkup::With((self.0)(cx)) + PrepareMarkup::With(self.html(cx)) } } impl Html { + // Html BUILDER ******************************************************************************** + /// Crea una instancia que generará el `Markup`, con acceso opcional al contexto. /// /// El método [`prepare_component()`](crate::core::component::Component::prepare_component) @@ -66,11 +68,24 @@ impl Html { /// Permite a otras extensiones modificar la función de renderizado que se ejecutará cuando /// [`prepare_component()`](crate::core::component::Component::prepare_component) invoque esta /// instancia. La nueva función también recibe una referencia al contexto ([`Context`]). - pub fn alter_html<F>(&mut self, f: F) -> &mut Self + #[builder_fn] + pub fn with_fn<F>(mut self, f: F) -> Self where F: Fn(&mut Context) -> Markup + Send + Sync + 'static, { self.0 = Box::new(f); self } + + // Html GETTERS ******************************************************************************** + + /// Aplica la función interna de renderizado con el [`Context`] proporcionado. + /// + /// Normalmente no se invoca manualmente, ya que el proceso de renderizado de los componentes lo + /// invoca automáticamente durante la construcción de la página. Puede usarse, no obstante, para + /// sobrescribir [`prepare_component()`](crate::core::component::Component::prepare_component) + /// y alterar el comportamiento del componente. + pub fn html(&self, cx: &mut Context) -> Markup { + (self.0)(cx) + } } From bb759e9a3824509886a8312b96638f07d31e2057 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 24 Aug 2025 10:19:17 +0200 Subject: [PATCH 154/244] =?UTF-8?q?=F0=9F=92=84=20A=C3=B1ade=20componente?= =?UTF-8?q?=20`PoweredBy`=20para=20copyright?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapta la página de bienvenida al tratamiento revisado de regiones y añade en el pie el componente `PoweredBy` para la nota de copyright. --- src/base/component.rs | 3 + src/base/component/poweredby.rs | 69 ++++++++++++++++++++++ src/base/extension/welcome.rs | 49 ++++++++-------- src/base/theme/basic.rs | 5 ++ src/core/theme/definition.rs | 6 +- src/locale/en-US/base.ftl | 2 + src/locale/es-ES/base.ftl | 2 + static/css/basic.css | 11 ++++ static/css/welcome.css | 54 ++++++++++------- tests/component_poweredby.rs | 100 ++++++++++++++++++++++++++++++++ 10 files changed, 251 insertions(+), 50 deletions(-) create mode 100644 src/base/component/poweredby.rs create mode 100644 src/locale/en-US/base.ftl create mode 100644 src/locale/es-ES/base.ftl create mode 100644 static/css/basic.css create mode 100644 tests/component_poweredby.rs diff --git a/src/base/component.rs b/src/base/component.rs index 27f0f739..1bb160b2 100644 --- a/src/base/component.rs +++ b/src/base/component.rs @@ -2,3 +2,6 @@ mod html; pub use html::Html; + +mod poweredby; +pub use poweredby::PoweredBy; diff --git a/src/base/component/poweredby.rs b/src/base/component/poweredby.rs new file mode 100644 index 00000000..5a374645 --- /dev/null +++ b/src/base/component/poweredby.rs @@ -0,0 +1,69 @@ +use crate::prelude::*; + +/// Muestra un texto con información de copyright, típica en un pie de página. +/// +/// Por defecto, usando [`default()`](Self::default) sólo se muestra un +/// reconocimiento a PageTop. Sin embargo, se puede usar [`new()`](Self::new) +/// para crear una instancia con un texto de copyright predeterminado. +#[derive(AutoDefault)] +pub struct PoweredBy { + copyright: Option<String>, +} + +impl Component for PoweredBy { + /// Crea una nueva instancia de `PoweredBy`. + /// + /// El copyright se genera automáticamente con el año actual y el nombre de + /// la aplicación configurada en [`global::SETTINGS`]. + fn new() -> Self { + let year = Utc::now().format("%Y").to_string(); + let c = join!(year, " © ", global::SETTINGS.app.name); + PoweredBy { copyright: Some(c) } + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let poweredby_pagetop = L10n::l("poweredby_pagetop") + .with_arg( + "pagetop_link", + "<a href=\"https://crates.io/crates/pagetop\">PageTop</a>", + ) + .to_markup(cx); + + PrepareMarkup::With(html! { + div id=[self.id()] class="poweredby" { + @if let Some(c) = self.copyright() { + span class="poweredby__copyright" { (c) "." } " " + } + span class="poweredby__pagetop" { (poweredby_pagetop) } + } + }) + } +} + +impl PoweredBy { + // PoweredBy BUILDER *************************************************************************** + + /// Establece el texto de copyright que mostrará el componente. + /// + /// Al pasar `Some(valor)` se sobrescribe el texto de copyright por defecto. Al pasar `None` se + /// eliminará, pero en este caso es necesario especificar el tipo explícitamente: + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// let p1 = PoweredBy::default().with_copyright(Some("2001 © Foo Inc.")); + /// let p2 = PoweredBy::new().with_copyright(None::<String>); + /// ``` + #[builder_fn] + pub fn with_copyright(mut self, copyright: Option<impl Into<String>>) -> Self { + self.copyright = copyright.map(Into::into); + self + } + + // PoweredBy GETTERS *************************************************************************** + + /// Devuelve el texto de copyright actual, si existe. + pub fn copyright(&self) -> Option<&str> { + self.copyright.as_deref() + } +} diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs index 3dda43eb..5f413d3c 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -28,6 +28,7 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { .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(Html::with(move |cx| html! { div id="main-header" { header { @@ -58,7 +59,8 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { } } } - + })) + .with_component(Html::with(move |cx| html! { main id="main-content" { section class="content-body" { div id="poweredby-button" { @@ -85,32 +87,31 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { } } } - - 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").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="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", 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() } diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index b02abfb5..bc380ac3 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -17,6 +17,11 @@ impl Theme for Basic { StyleSheet::from("/css/normalize.css") .with_version("8.0.1") .with_weight(-99), + )) + .alter_assets(AssetsOp::AddStyleSheet( + StyleSheet::from("/css/basic.css") + .with_version(env!("CARGO_PKG_VERSION")) + .with_weight(-99), )); } } diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 8d1b632f..3b26a573 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -94,13 +94,11 @@ pub trait Theme: Extension + Send + Sync { @let region_name = region.name(); div id=(region_name) - class="region" + class={ "region region--" (region_name) } role="region" aria-label=[region_label.using(page)] { - div class={ "region__" (region_name) } { - (output) - } + (output) } } } diff --git a/src/locale/en-US/base.ftl b/src/locale/en-US/base.ftl new file mode 100644 index 00000000..b2c92564 --- /dev/null +++ b/src/locale/en-US/base.ftl @@ -0,0 +1,2 @@ +# PoweredBy component. +poweredby_pagetop = Powered by { $pagetop_link } diff --git a/src/locale/es-ES/base.ftl b/src/locale/es-ES/base.ftl new file mode 100644 index 00000000..74eb62e8 --- /dev/null +++ b/src/locale/es-ES/base.ftl @@ -0,0 +1,2 @@ +# PoweredBy component. +poweredby_pagetop = Funciona con { $pagetop_link } \ No newline at end of file diff --git a/static/css/basic.css b/static/css/basic.css new file mode 100644 index 00000000..312ddf09 --- /dev/null +++ b/static/css/basic.css @@ -0,0 +1,11 @@ +/* Page layout */ + +.region--footer { + padding-bottom: 2rem; +} + +/* PoweredBy component */ + +.poweredby { + text-align: center; +} diff --git a/static/css/welcome.css b/static/css/welcome.css index 76b042b9..7630f3e2 100644 --- a/static/css/welcome.css +++ b/static/css/welcome.css @@ -410,51 +410,61 @@ a:hover:visited { transform: rotate(2deg); } -#footer { - width: 100%; +/* + * Region footer + */ + +.region--footer { background-color: black; color: var(--color-gray); +} + +.welcome-footer { font-size: 1.15rem; font-weight: 300; line-height: 100%; - display: flex; justify-content: center; + display: flex; + flex-direction: column; + max-width: 80rem; + padding: 0 10.625rem 2rem; +/* z-index: 10; +*/ } -#footer a:visited { +.welcome-footer a:visited { color: var(--color-gray); } -.footer-logo { - max-height: 12.625rem; -} -.footer-logo svg { - width: 100%; -} -.footer-logo, -.footer-links, -.footer-inner { +.welcome-footer__logo, +.welcome-footer__links { display: flex; justify-content: center; width: 100%; } -.footer-links { +.welcome-footer__logo { + max-height: 12.625rem; +} +.welcome-footer__logo svg { + width: 100%; +} +.welcome-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 { + .welcome-footer__logo { display: none; } } @media (max-width: 64rem) { - .footer-inner { + .welcome-footer { padding: 0 1rem 2rem; } } + +/* PoweredBy component */ + +.poweredby a:visited { + color: var(--color-gray); +} diff --git a/tests/component_poweredby.rs b/tests/component_poweredby.rs new file mode 100644 index 00000000..b2e4418b --- /dev/null +++ b/tests/component_poweredby.rs @@ -0,0 +1,100 @@ +use pagetop::prelude::*; + +#[pagetop::test] +async fn poweredby_default_shows_only_pagetop_recognition() { + let _app = service::test::init_service(Application::new().test()).await; + + let p = PoweredBy::default(); + let html = render_component(&p); + + // Debe mostrar el bloque de reconocimiento a PageTop. + assert!(html.contains("poweredby__pagetop")); + + // Y NO debe mostrar el bloque de copyright. + assert!(!html.contains("poweredby__copyright")); +} + +#[pagetop::test] +async fn poweredby_new_includes_current_year_and_app_name() { + let _app = service::test::init_service(Application::new().test()).await; + + let p = PoweredBy::new(); + let html = render_component(&p); + + let year = Utc::now().format("%Y").to_string(); + assert!(html.contains(&year), "HTML should include the current year"); + + // El nombre de la app proviene de `global::SETTINGS.app.name`. + let app_name = &global::SETTINGS.app.name; + assert!( + html.contains(app_name), + "HTML should include the application name" + ); + + // Debe existir el span de copyright. + assert!(html.contains("poweredby__copyright")); +} + +#[pagetop::test] +async fn poweredby_with_copyright_overrides_text() { + let _app = service::test::init_service(Application::new().test()).await; + + let custom = "2001 © FooBar Inc."; + let p = PoweredBy::default().with_copyright(Some(custom)); + let html = render_component(&p); + + assert!(html.contains(custom)); + assert!(html.contains("poweredby__copyright")); +} + +#[pagetop::test] +async fn poweredby_with_copyright_none_hides_text() { + let _app = service::test::init_service(Application::new().test()).await; + + let p = PoweredBy::new().with_copyright(None::<String>); + let html = render_component(&p); + + assert!(!html.contains("poweredby__copyright")); + // El reconocimiento a PageTop siempre debe aparecer. + assert!(html.contains("poweredby__pagetop")); +} + +#[pagetop::test] +async fn poweredby_link_points_to_crates_io() { + let _app = service::test::init_service(Application::new().test()).await; + + let p = PoweredBy::default(); + let html = render_component(&p); + + assert!( + html.contains("https://crates.io/crates/pagetop"), + "Link should point to crates.io/pagetop" + ); +} + +#[pagetop::test] +async fn poweredby_getter_reflects_internal_state() { + let _app = service::test::init_service(Application::new().test()).await; + + // Por defecto no hay copyright. + let p0 = PoweredBy::default(); + assert_eq!(p0.copyright(), None); + + // Y `new()` lo inicializa con año + nombre de app. + let p1 = PoweredBy::new(); + let c1 = p1.copyright().expect("Expected copyright to exis"); + assert!(c1.contains(&Utc::now().format("%Y").to_string())); + assert!(c1.contains(&global::SETTINGS.app.name)); +} + +// HELPERS ***************************************************************************************** + +fn render(x: &impl Render) -> String { + x.render().into_string() +} + +fn render_component<C: Component>(c: &C) -> String { + let mut cx = Context::default(); + let pm = c.prepare_component(&mut cx); + render(&pm) +} From a38f983f09d73f49ad123c23f03b49fe7a9064a0 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 25 Aug 2025 07:12:30 +0200 Subject: [PATCH 155/244] =?UTF-8?q?=F0=9F=90=9B=20(welcome):=20Corrige=20c?= =?UTF-8?q?entrado=20del=20pie=20de=20p=C3=A1gina?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/css/welcome.css | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/static/css/welcome.css b/static/css/welcome.css index 7630f3e2..906c05d5 100644 --- a/static/css/welcome.css +++ b/static/css/welcome.css @@ -420,17 +420,15 @@ a:hover:visited { } .welcome-footer { + display: flex; + justify-content: center; + flex-direction: column; + margin: 0 auto; + padding: 0 10.625rem 2rem; + max-width: 80rem; font-size: 1.15rem; font-weight: 300; line-height: 100%; - justify-content: center; - display: flex; - flex-direction: column; - max-width: 80rem; - padding: 0 10.625rem 2rem; -/* - z-index: 10; -*/ } .welcome-footer a:visited { color: var(--color-gray); From 779c16010a2a7a1507590cf917c91f5b7bdde320 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 25 Aug 2025 23:25:39 +0200 Subject: [PATCH 156/244] =?UTF-8?q?=F0=9F=90=9B=20Corrige=20nombre=20de=20?= =?UTF-8?q?funci=C3=B3n=20en=20prueba=20de=20`Html`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/component_html.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/component_html.rs b/tests/component_html.rs index 978248f1..b9b8e5ec 100644 --- a/tests/component_html.rs +++ b/tests/component_html.rs @@ -35,7 +35,7 @@ async fn component_html_renders_using_context_param() { async fn component_html_allows_replacing_render_function() { let mut component = Html::with(|_| html! { div { "Original" } }); - component.alter_html(|_| html! { div { "Modified" } }); + component.alter_fn(|_| html! { div { "Modified" } }); let markup = component .prepare_component(&mut Context::new(None)) From ce5a6c07bda0f3a5ba2dd7d13c0d82427d0969c7 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 25 Aug 2025 23:30:53 +0200 Subject: [PATCH 157/244] =?UTF-8?q?=F0=9F=92=84=20Aplica=20BEM=20a=20estil?= =?UTF-8?q?os=20de=20bienvenida=20y=20componente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component/poweredby.rs | 26 ++++---- src/base/extension/welcome.rs | 30 +++++---- static/css/welcome.css | 111 +++++++++++++++++--------------- 3 files changed, 88 insertions(+), 79 deletions(-) diff --git a/src/base/component/poweredby.rs b/src/base/component/poweredby.rs index 5a374645..afa8db72 100644 --- a/src/base/component/poweredby.rs +++ b/src/base/component/poweredby.rs @@ -1,10 +1,13 @@ use crate::prelude::*; -/// Muestra un texto con información de copyright, típica en un pie de página. +// Enlace a la página oficial de PageTop. +const LINK: &str = "<a href=\"https://pagetop.cillero.es\" rel=\"noreferrer\">PageTop</a>"; + +/// Componente que renderiza la sección 'Powered by' (*Funciona con*) típica del pie de página. /// -/// Por defecto, usando [`default()`](Self::default) sólo se muestra un -/// reconocimiento a PageTop. Sin embargo, se puede usar [`new()`](Self::new) -/// para crear una instancia con un texto de copyright predeterminado. +/// Por defecto, usando [`default()`](Self::default) sólo se muestra un reconocimiento a PageTop. +/// Sin embargo, se puede usar [`new()`](Self::new) para crear una instancia con un texto de +/// copyright predeterminado. #[derive(AutoDefault)] pub struct PoweredBy { copyright: Option<String>, @@ -13,8 +16,8 @@ pub struct PoweredBy { impl Component for PoweredBy { /// Crea una nueva instancia de `PoweredBy`. /// - /// El copyright se genera automáticamente con el año actual y el nombre de - /// la aplicación configurada en [`global::SETTINGS`]. + /// El copyright se genera automáticamente con el año actual y el nombre de la aplicación + /// configurada en [`global::SETTINGS`]. fn new() -> Self { let year = Utc::now().format("%Y").to_string(); let c = join!(year, " © ", global::SETTINGS.app.name); @@ -22,19 +25,14 @@ impl Component for PoweredBy { } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let poweredby_pagetop = L10n::l("poweredby_pagetop") - .with_arg( - "pagetop_link", - "<a href=\"https://crates.io/crates/pagetop\">PageTop</a>", - ) - .to_markup(cx); - PrepareMarkup::With(html! { div id=[self.id()] class="poweredby" { @if let Some(c) = self.copyright() { span class="poweredby__copyright" { (c) "." } " " } - span class="poweredby__pagetop" { (poweredby_pagetop) } + span class="poweredby__pagetop" { + (L10n::l("poweredby_pagetop").with_arg("pagetop_link", LINK).to_markup(cx)) + } } }) } diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs index 5f413d3c..f7682104 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -29,19 +29,19 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { .with_theme("Basic") .with_assets(AssetsOp::AddStyleSheet(StyleSheet::from("/css/welcome.css"))) .with_body_classes(ClassesOp::Add, "welcome") - .with_component(Html::with(move |cx| html! { - div id="main-header" { - header { + .with_component_in("header", Html::with(move |cx| html! { + div class="welcome-header" { + header class="welcome-header__body" { h1 - id="header-title" + 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 id="header-image" aria-hidden="true" { - div id="monster" { + aside class="welcome-header__image" aria-hidden="true" { + div class="welcome-header__monster" { picture { source type="image/avif" @@ -61,25 +61,27 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { } })) .with_component(Html::with(move |cx| html! { - main id="main-content" { - section class="content-body" { - div id="poweredby-button" { + main class="welcome-content" { + section class="welcome-content__body" { + div class="welcome-poweredby" { a - id="poweredby-link" + class="welcome-poweredby__link" href="https://pagetop.cillero.es" target="_blank" rel="noreferrer" { span {} span {} span {} - div id="poweredby-text" { (L10n::l("welcome_powered").to_markup(cx)) } + div class="welcome-poweredby__text" { + (L10n::l("welcome_powered").to_markup(cx)) + } } } - div class="content-text" { + div class="welcome-text" { p { (L10n::l("welcome_text1").to_markup(cx)) } p { (L10n::l("welcome_text2").to_markup(cx)) } - div class="subcontent" { - h1 { span { (L10n::l("welcome_about").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)) } diff --git a/static/css/welcome.css b/static/css/welcome.css index 906c05d5..4ce8046b 100644 --- a/static/css/welcome.css +++ b/static/css/welcome.css @@ -58,12 +58,17 @@ a:hover:visited { align-items: center; } -#main-header { +/* + * Region header + */ + +.welcome-header { display: flex; flex-direction: column-reverse; - padding-bottom: 9rem; - max-width: 80rem; width: 100%; + max-width: 80rem; + margin: 0 auto; + padding-bottom: 9rem; background-image: var(--bg-img-sm); background-image: var(--bg-img-sm-set); background-position: top center; @@ -71,11 +76,11 @@ a:hover:visited { background-size: contain; background-repeat: no-repeat; } -#main-header header { +.welcome-header__body { padding: 0; background: none; } -#header-title { +.welcome-header__title { margin: 0 0 0 1.5rem; text-align: left; display: flex; @@ -89,7 +94,7 @@ a:hover:visited { line-height: 110%; text-shadow: 0 0.125rem 0.1875rem rgba(0, 0, 0, 0.3); } -#header-title > span { +.welcome-header__title > span { background: linear-gradient(180deg, #ddff95 30%, #ffb84b 100%); background-clip: text; -webkit-background-clip: text; @@ -100,40 +105,44 @@ a:hover:visited { line-height: 110%; text-shadow: none; } -#header-image { - width: 100%; - text-align: right; +.welcome-header__image { display: flex; justify-content: flex-start; + text-align: right; + width: 100%; } -#header-image #monster { +.welcome-header__monster { margin-right: 12rem; margin-top: 1rem; flex-shrink: 1; } @media (min-width: 64rem) { - #main-header { + .welcome-header { background-image: var(--bg-img); background-image: var(--bg-img-set); } - #header-title { + .welcome-header__title { padding: 1.2rem 2rem 2.6rem 2rem; } - #header-image { + .welcome-header__image { justify-content: flex-end; } } -#main-content { +/* + * Region content + */ + +.welcome-content { height: auto; margin-top: 1.6rem; } -.content-body { +.welcome-content__body { box-sizing: border-box; max-width: 80rem; } -.content-body:before, -.content-body:after { +.welcome-content__body:before, +.welcome-content__body:after { content: ''; position: absolute; left: 0; @@ -143,38 +152,38 @@ a:hover:visited { filter: blur(2.75rem); opacity: 0.8; inset: 11.75rem; - z-index: 0; + /*z-index: 0;*/ } -.content-body:before { +.welcome-content__body:before { top: -1rem; } -.content-body:after { +.welcome-content__body:after { bottom: -1rem; } @media (max-width: 48rem) { - .content-body { + .welcome-content__body { margin-top: -9.8rem; } - .content-body:before, - .content-body:after { + .welcome-content__body:before, + .welcome-content__body:after { inset: unset; } } @media (min-width: 64rem) { - #main-content { + .welcome-content { margin-top: 0; } - .content-body { + .welcome-content__body { margin-top: -5.7rem; } } -#poweredby-button { +.welcome-poweredby { width: 100%; margin: 0 auto 3rem; z-index: 10; } -#poweredby-link { +.welcome-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; @@ -187,7 +196,7 @@ a:hover:visited { font-size: 1.5rem; line-height: 1.3; text-decoration: none; - text-shadow: var(--shadow); + /*text-shadow: var(--shadow);*/ transition: transform 0.3s ease-in-out; position: relative; overflow: hidden; @@ -195,7 +204,7 @@ a:hover:visited { min-height: 7.6875rem; outline: none; } -#poweredby-link::before { +.welcome-poweredby__link::before { content: ''; position: absolute; top: -13.125rem; @@ -207,7 +216,7 @@ a:hover:visited { transition: transform 0.3s ease-in-out; z-index: 5; } -#poweredby-text { +.welcome-poweredby__text { display: flex; flex-direction: column; flex: 1; @@ -217,25 +226,25 @@ 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); + /*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 { +.welcome-poweredby__text strong { font-size: 2.625rem; font-weight: 600; line-height: 130.023%; letter-spacing: 0.013125rem; } -#poweredby-link span { +.welcome-poweredby__link span { position: absolute; display: block; pointer-events: none; } -#poweredby-link span:nth-child(1) { +.welcome-poweredby__link span:nth-child(1) { height: 8px; width: 100%; top: 0; @@ -255,7 +264,7 @@ a:hover:visited { transform: translateX(100%); } } -#poweredby-link span:nth-child(2) { +.welcome-poweredby__link span:nth-child(2) { width: 8px; height: 100%; top: 0; @@ -275,7 +284,7 @@ a:hover:visited { transform: translateY(100%); } } -#poweredby-link span:nth-child(3) { +.welcome-poweredby__link span:nth-child(3) { height: 8px; width: 100%; bottom: 0; @@ -295,22 +304,22 @@ a:hover:visited { transform: translateX(-100%); } } -#poweredby-link:hover span { +.welcome-poweredby__link:hover span { animation-play-state: paused; } @media (max-width: 48rem) { - #poweredby-link { + .welcome-poweredby__link { height: 6.25rem; min-width: auto; border-radius: 0; } - #poweredby-text { + .welcome-poweredby__text { display: inline; padding-top: .5rem; } } @media (min-width: 48rem) { - #poweredby-button { + .welcome-poweredby { position: absolute; top: 0; left: 50%; @@ -318,14 +327,14 @@ a:hover:visited { max-width: 29.375rem; margin-bottom: 0; } - #poweredby-link:hover { + .welcome-poweredby__link:hover { transition: all .5s; transform: rotate(-3deg) scale(1.1); - box-shadow: 0px 3px 5px rgba(0,0,0,.4); + /*box-shadow: 0px 3px 5px rgba(0,0,0,.4);*/ } } -.content-text { +.welcome-text { z-index: 1; width: 100%; display: flex; @@ -343,7 +352,7 @@ a:hover:visited { padding: 6rem 1.063rem 0.75rem; overflow: hidden; } -.content-text p { +.welcome-text p { width: 100%; line-height: 150%; font-weight: 400; @@ -351,14 +360,14 @@ a:hover:visited { margin: 0 0 1.5rem; } @media (min-width: 48rem) { - .content-text { + .welcome-text { font-size: 1.375rem; line-height: 2rem; padding-top: 7rem; } } @media (min-width: 64rem) { - .content-text { + .welcome-text { border-radius: 0.75rem; box-shadow: var(--shadow); max-width: 60rem; @@ -368,13 +377,13 @@ a:hover:visited { } } -.subcontent { +.welcome-text__block { position: relative; } -.subcontent h1 { +.welcome-text__block h2 { margin: 1em 0 .8em; } -.subcontent h1 span { +.welcome-text__block h2 span { display: inline-block; padding: 10px 30px 14px; margin: 0 0 0 20px; @@ -385,7 +394,7 @@ a:hover:visited { border-color: orangered; transform: rotate(-3deg) translateY(-25%); } -.subcontent h1:before { +.welcome-text__block h2:before { content: ""; height: 5px; position: absolute; @@ -398,7 +407,7 @@ a:hover:visited { transform: rotate(2deg) translateY(-50%); transform-origin: top left; } -.subcontent h1:after { +.welcome-text__block h2:after { content: ""; height: 70rem; position: absolute; From b315e6d08e825176c8e2927d5151ac460046212b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 3 Sep 2025 21:05:35 +0200 Subject: [PATCH 158/244] =?UTF-8?q?=F0=9F=93=9D=20(doc):=20Normaliza=20ref?= =?UTF-8?q?erencias=20al=20nombre=20PageTop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CREDITS.md | 13 ++++++------- README.md | 24 ++++++++++++------------ helpers/pagetop-build/README.md | 2 +- helpers/pagetop-macros/README.md | 4 ++-- helpers/pagetop-macros/src/lib.rs | 6 +++--- helpers/pagetop-statics/README.md | 6 +++--- helpers/pagetop-statics/src/lib.rs | 4 ++-- src/app.rs | 4 ++-- src/base/action.rs | 2 +- src/base/component.rs | 2 +- src/base/extension.rs | 2 +- src/base/extension/welcome.rs | 2 +- src/base/theme.rs | 2 +- src/base/theme/basic.rs | 2 +- src/config.rs | 6 +++--- src/core.rs | 2 +- src/core/component/definition.rs | 2 +- src/core/extension.rs | 2 +- src/core/extension/definition.rs | 4 ++-- src/core/theme.rs | 2 +- src/global.rs | 2 +- src/lib.rs | 18 +++++++++--------- src/locale.rs | 14 +++++++------- src/prelude.rs | 2 +- src/trace.rs | 4 ++-- 25 files changed, 66 insertions(+), 67 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index f5c1b0fa..c5a7bd2e 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -1,8 +1,7 @@ # 🔃 Dependencias -`PageTop` está basado en [Rust](https://www.rust-lang.org/) y crece a hombros de gigantes -aprovechando algunas de las librerías más robustas y populares del [ecosistema Rust](https://lib.rs) -como son: +PageTop está basado en [Rust](https://www.rust-lang.org/) y crece a hombros de gigantes aprovechando +algunas de las librerías más robustas y populares del [ecosistema Rust](https://lib.rs) como son: * [Actix Web](https://actix.rs/) para los servicios web. * [Config](https://docs.rs/config) para cargar y procesar las opciones de configuración. @@ -11,14 +10,14 @@ como son: * [Fluent templates](https://github.com/XAMPPRocky/fluent-templates), que integra [Fluent](https://projectfluent.org/) para internacionalizar las aplicaciones. * Además de otros *crates* adicionales que se pueden explorar en los archivos `Cargo.toml` de - `PageTop` y sus extensiones. + PageTop y sus extensiones. # 🗚 FIGfonts -`PageTop` usa el *crate* [figlet-rs](https://crates.io/crates/figlet-rs) desarrollado por -*yuanbohan* para mostrar un banner de presentación en el terminal con el nombre de la aplicación en -caracteres [FIGlet](http://www.figlet.org). Las fuentes incluidas en `pagetop/src/app` son: +PageTop usa el *crate* [figlet-rs](https://crates.io/crates/figlet-rs) desarrollado por *yuanbohan* +para mostrar un banner de presentación en el terminal con el nombre de la aplicación en caracteres +[FIGlet](http://www.figlet.org). Las fuentes incluidas en `pagetop/src/app` son: * [slant.flf](http://www.figlet.org/fontdb_example.cgi?font=slant.flf) de *Glenn Chappell* * [small.flf](http://www.figlet.org/fontdb_example.cgi?font=small.flf) de *Glenn Chappell* diff --git a/README.md b/README.md index e7fab94b..9d5efc88 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ <br> </div> -`PageTop` reivindica la esencia de la web clásica usando [Rust](https://www.rust-lang.org/es) para -la creación de soluciones web SSR (*renderizadas en el servidor*) basadas en HTML, CSS y JavaScript. +PageTop reivindica la esencia de la web clásica usando [Rust](https://www.rust-lang.org/es) para la +creación de soluciones web SSR (*renderizadas en el servidor*) basadas en HTML, CSS y JavaScript. Ofrece un conjunto de herramientas que los desarrolladores pueden implementar, extender o adaptar según las necesidades de cada proyecto, incluyendo: @@ -24,14 +24,14 @@ según las necesidades de cada proyecto, incluyendo: * **Componentes** (*components*): encapsulan HTML, CSS y JavaScript en unidades funcionales, configurables y reutilizables. * **Extensiones** (*extensions*): añaden, extienden o personalizan funcionalidades usando las APIs - de `PageTop` o de terceros. + de PageTop o de terceros. * **Temas** (*themes*): son extensiones que permiten modificar la apariencia de páginas y componentes sin comprometer su funcionalidad. # ⚡️ Guía rápida -La aplicación más sencilla de `PageTop` se ve así: +La aplicación más sencilla de PageTop se ve así: ```rust,no_run use pagetop::prelude::*; @@ -42,10 +42,10 @@ async fn main() -> std::io::Result<()> { } ``` -Este código arranca el servidor de `PageTop`. Con la configuración por defecto, muestra una página -de bienvenida accesible desde un navegador local en la dirección `http://localhost:8080`. +Este código arranca el servidor de PageTop. Con la configuración por defecto, muestra una página de +bienvenida accesible desde un navegador local en la dirección `http://localhost:8080`. -Para personalizar el servicio, se puede crear una extensión de `PageTop` de la siguiente manera: +Para personalizar el servicio, se puede crear una extensión de PageTop de la siguiente manera: ```rust,no_run use pagetop::prelude::*; @@ -86,15 +86,15 @@ El código se organiza en un *workspace* donde actualmente se incluyen los sigui * **[pagetop-statics](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-statics)**, es la librería que permite incluir archivos estáticos en el ejecutable de las aplicaciones - `PageTop` para servirlos de forma eficiente, con detección de cambios que optimizan el tiempo - de compilación. + PageTop para servirlos de forma eficiente, con detección de cambios que optimizan el tiempo de + compilación. * **[pagetop-build](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-build)**, prepara los archivos estáticos o archivos SCSS compilados para incluirlos en el binario de las - aplicaciones `PageTop` durante la compilación de los ejecutables. + aplicaciones PageTop durante la compilación de los ejecutables. * **[pagetop-macros](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-macros)**, - proporciona una colección de macros que mejoran la experiencia de desarrollo con `PageTop`. + proporciona una colección de macros que mejoran la experiencia de desarrollo con PageTop. # 🧪 Pruebas @@ -116,7 +116,7 @@ Para simplificar el flujo de trabajo, el repositorio incluye varios **alias de C # 🚧 Advertencia -`PageTop` es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su +**PageTop** es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su ecosistema. Su API está sujeta a cambios frecuentes. No se recomienda su uso en producción, al menos hasta que se libere la versión **1.0.0**. diff --git a/helpers/pagetop-build/README.md b/helpers/pagetop-build/README.md index 80d6bba2..57273e83 100644 --- a/helpers/pagetop-build/README.md +++ b/helpers/pagetop-build/README.md @@ -113,7 +113,7 @@ impl Extension for MyExtension { # 🚧 Advertencia -`PageTop` es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su +**PageTop** es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su ecosistema. Su API está sujeta a cambios frecuentes. No se recomienda su uso en producción, al menos hasta que se libere la versión **1.0.0**. diff --git a/helpers/pagetop-macros/README.md b/helpers/pagetop-macros/README.md index e58d24c7..7c9c2e86 100644 --- a/helpers/pagetop-macros/README.md +++ b/helpers/pagetop-macros/README.md @@ -26,12 +26,12 @@ Esta librería incluye entre sus macros una adaptación de [SmartDefault](https://crates.io/crates/smart_default) (0.7.1) de [Jane Doe](https://crates.io/users/jane-doe), llamada `AutoDefault`. Estas macros eliminan la necesidad de referenciar `maud` o `smart_default` en las dependencias del archivo `Cargo.toml` de -cada proyecto `PageTop`. +cada proyecto PageTop. # 🚧 Advertencia -`PageTop` es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su +**PageTop** es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su ecosistema. Su API está sujeta a cambios frecuentes. No se recomienda su uso en producción, al menos hasta que se libere la versión **1.0.0**. diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 6421ca6e..b462ea13 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -27,7 +27,7 @@ Esta librería incluye entre sus macros una adaptación de [SmartDefault](https://crates.io/crates/smart_default) (0.7.1) de [Jane Doe](https://crates.io/users/jane-doe), llamada `AutoDefault`. Estas macros eliminan la necesidad de referenciar `maud` o `smart_default` en las dependencias del archivo `Cargo.toml` de -cada proyecto `PageTop`. +cada proyecto PageTop. */ #![doc( @@ -219,7 +219,7 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { expanded.into() } -/// Define una función `main` asíncrona como punto de entrada de `PageTop`. +/// Define una función `main` asíncrona como punto de entrada de PageTop. /// /// # Ejemplo /// @@ -240,7 +240,7 @@ pub fn main(_: TokenStream, item: TokenStream) -> TokenStream { output } -/// Define funciones de prueba asíncronas para usar con `PageTop`. +/// Define funciones de prueba asíncronas para usar con PageTop. /// /// # Ejemplo /// diff --git a/helpers/pagetop-statics/README.md b/helpers/pagetop-statics/README.md index 92999c04..4168cd4a 100644 --- a/helpers/pagetop-statics/README.md +++ b/helpers/pagetop-statics/README.md @@ -16,7 +16,7 @@ configurables, basadas en HTML, CSS y JavaScript. ## Descripción general -Esta librería permite incluir archivos estáticos en el ejecutable de las aplicaciones `PageTop` para +Esta librería permite incluir archivos estáticos en el ejecutable de las aplicaciones PageTop para servirlos de forma eficiente vía web, con detección de cambios que optimizan el tiempo de compilación. @@ -28,13 +28,13 @@ Para ello, adapta el código de los *crates* [static-files](https://crates.io/cr [4.0.1](https://github.com/kilork/actix-web-static-files/tree/v4.0.1)), desarrollados ambos por [Alexander Korolev](https://crates.io/users/kilork). -Estas implementaciones se integran en `PageTop` para evitar que cada proyecto tenga que declarar +Estas implementaciones se integran en PageTop para evitar que cada proyecto tenga que declarar `static-files` manualmente como dependencia en su `Cargo.toml`. # 🚧 Advertencia -`PageTop` es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su +**PageTop** es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su ecosistema. Su API está sujeta a cambios frecuentes. No se recomienda su uso en producción, al menos hasta que se libere la versión **1.0.0**. diff --git a/helpers/pagetop-statics/src/lib.rs b/helpers/pagetop-statics/src/lib.rs index dab50d9e..201d90ef 100644 --- a/helpers/pagetop-statics/src/lib.rs +++ b/helpers/pagetop-statics/src/lib.rs @@ -17,7 +17,7 @@ configurables, basadas en HTML, CSS y JavaScript. ## Descripción general -Esta librería permite incluir archivos estáticos en el ejecutable de las aplicaciones `PageTop` para +Esta librería permite incluir archivos estáticos en el ejecutable de las aplicaciones PageTop para servirlos de forma eficiente vía web, con detección de cambios que optimizan el tiempo de compilación. @@ -29,7 +29,7 @@ Para ello, adapta el código de los *crates* [static-files](https://crates.io/cr [4.0.1](https://github.com/kilork/actix-web-static-files/tree/v4.0.1)), desarrollados ambos por [Alexander Korolev](https://crates.io/users/kilork). -Estas implementaciones se integran en `PageTop` para evitar que cada proyecto tenga que declarar +Estas implementaciones se integran en PageTop para evitar que cada proyecto tenga que declarar `static-files` manualmente como dependencia en su `Cargo.toml`. */ diff --git a/src/app.rs b/src/app.rs index 400b0cd3..94d901f1 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,4 +1,4 @@ -//! Prepara y ejecuta una aplicación creada con `Pagetop`. +//! Prepara y ejecuta una aplicación creada con PageTop. mod figfont; @@ -17,7 +17,7 @@ use substring::Substring; use std::io::Error; use std::sync::LazyLock; -/// Punto de entrada de una aplicación `PageTop`. +/// Punto de entrada de una aplicación PageTop. /// /// No almacena datos, **encapsula** el inicio completo de configuración y puesta en marcha. Para /// instanciarla se puede usar [`new()`](Application::new) o [`prepare()`](Application::prepare). diff --git a/src/base/action.rs b/src/base/action.rs index be35e922..977ae9e2 100644 --- a/src/base/action.rs +++ b/src/base/action.rs @@ -1,4 +1,4 @@ -//! Acciones predefinidas para alterar el funcionamiento interno de `PageTop`. +//! Acciones predefinidas para alterar el funcionamiento interno de PageTop. use crate::prelude::*; diff --git a/src/base/component.rs b/src/base/component.rs index 1bb160b2..30cb6866 100644 --- a/src/base/component.rs +++ b/src/base/component.rs @@ -1,4 +1,4 @@ -//! Componentes nativos proporcionados por `PageTop`. +//! Componentes nativos proporcionados por PageTop. mod html; pub use html::Html; diff --git a/src/base/extension.rs b/src/base/extension.rs index 49e408dd..1f94fe23 100644 --- a/src/base/extension.rs +++ b/src/base/extension.rs @@ -1,4 +1,4 @@ -//! Extensiones para funcionalidades avanzadas de `PageTop`. +//! 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 index f7682104..0252cff3 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -1,6 +1,6 @@ use crate::prelude::*; -/// Página de bienvenida predeterminada de `PageTop`. +/// 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á diff --git a/src/base/theme.rs b/src/base/theme.rs index ea9eeb66..40129bfa 100644 --- a/src/base/theme.rs +++ b/src/base/theme.rs @@ -1,4 +1,4 @@ -//! Temas básicos soportados por `PageTop`. +//! Temas básicos soportados por PageTop. mod basic; pub use basic::Basic; diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index bc380ac3..961864be 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -1,4 +1,4 @@ -//! Es el tema básico que incluye `PageTop` por defecto. +//! Es el tema básico que incluye PageTop por defecto. use crate::prelude::*; diff --git a/src/config.rs b/src/config.rs index 27cf630e..f2fb9f7f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,7 +3,7 @@ //! Estos ajustes se obtienen de archivos [TOML](https://toml.io) como pares `clave = valor` que se //! mapean a estructuras **fuertemente tipadas** y valores predefinidos. //! -//! Siguiendo la metodología [Twelve-Factor App](https://12factor.net/config), `PageTop` separa el +//! Siguiendo la metodología [Twelve-Factor App](https://12factor.net/config), PageTop separa el //! **código** de la **configuración**, lo que permite tener configuraciones diferentes para cada //! despliegue, como *dev*, *staging* o *production*, sin modificar el código fuente. //! @@ -13,14 +13,14 @@ //! Si tu aplicación necesita archivos de configuración, crea un directorio `config` en la raíz del //! proyecto, al mismo nivel que el archivo *Cargo.toml* o que el binario de la aplicación. //! -//! `PageTop` carga en este orden, y siempre de forma opcional, los siguientes archivos TOML: +//! PageTop carga en este orden, y siempre de forma opcional, los siguientes archivos TOML: //! //! 1. **config/common.toml**, para ajustes comunes a todos los entornos. Este enfoque simplifica el //! mantenimiento al centralizar los valores de configuración comunes. //! //! 2. **config/{rm}.toml**, donde `{rm}` es el valor de la variable de entorno `PAGETOP_RUN_MODE`: //! -//! * Si `PAGETOP_RUN_MODE` no está definida, se asume el valor `default`, y `PageTop` intentará +//! * Si `PAGETOP_RUN_MODE` no está definida, se asume el valor `default`, y PageTop intentará //! cargar *config/default.toml* si el archivo existe. //! //! * Útil para definir configuraciones específicas por entorno, garantizando que cada uno (p.ej. diff --git a/src/core.rs b/src/core.rs index 0c8aa21f..79d92074 100644 --- a/src/core.rs +++ b/src/core.rs @@ -117,7 +117,7 @@ impl TypeInfo { /// /// Este *trait* se implementa automáticamente para **todos** los tipos que implementen [`Any`], de /// modo que basta con traer [`AnyInfo`] al ámbito (`use crate::AnyInfo;`) para disponer de estos -/// métodos adicionales, o usar el [`prelude`](crate::prelude) de `PageTop`. +/// métodos adicionales, o usar el [`prelude`](crate::prelude) de PageTop. /// /// # Ejemplo /// diff --git a/src/core/component/definition.rs b/src/core/component/definition.rs index e9a792d7..c43dfb0f 100644 --- a/src/core/component/definition.rs +++ b/src/core/component/definition.rs @@ -11,7 +11,7 @@ pub trait ComponentRender { fn render(&mut self, cx: &mut Context) -> Markup; } -/// Interfaz común que debe implementar un componente renderizable en `PageTop`. +/// Interfaz común que debe implementar un componente renderizable en PageTop. /// /// Se recomienda que los componentes deriven [`AutoDefault`](crate::AutoDefault). También deben /// implementar explícitamente el método [`new()`](Self::new) y pueden sobrescribir los otros diff --git a/src/core/extension.rs b/src/core/extension.rs index cabae5cd..6ae6d333 100644 --- a/src/core/extension.rs +++ b/src/core/extension.rs @@ -1,6 +1,6 @@ //! API para añadir nuevas funcionalidades usando extensiones. //! -//! Cada funcionalidad adicional que quiera incorporarse a una aplicación `PageTop` se debe modelar +//! Cada funcionalidad adicional que quiera incorporarse a una aplicación PageTop se debe modelar //! como una **extensión**. Todas comparten la misma interfaz declarada en [`Extension`]. mod definition; diff --git a/src/core/extension/definition.rs b/src/core/extension/definition.rs index 6df70427..90bdbad2 100644 --- a/src/core/extension/definition.rs +++ b/src/core/extension/definition.rs @@ -10,7 +10,7 @@ use crate::{actions_boxed, service}; /// cualquier hilo de la ejecución sin necesidad de sincronización adicional. pub type ExtensionRef = &'static dyn Extension; -/// Interfaz común que debe implementar cualquier extensión de `PageTop`. +/// Interfaz común que debe implementar cualquier extensión de PageTop. /// /// Este *trait* es fácil de implementar, basta con declarar una estructura de tamaño cero para la /// extensión y sobreescribir los métodos que sea necesario. @@ -63,7 +63,7 @@ pub trait Extension: AnyInfo + Send + Sync { /// Otras extensiones que deben habilitarse **antes** de esta. /// - /// `PageTop` las resolverá automáticamente respetando el orden durante el arranque de la + /// PageTop las resolverá automáticamente respetando el orden durante el arranque de la /// aplicación. fn dependencies(&self) -> Vec<ExtensionRef> { vec![] diff --git a/src/core/theme.rs b/src/core/theme.rs index aa526f16..e0c3008e 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -1,6 +1,6 @@ //! API para añadir y gestionar nuevos temas. //! -//! En `PageTop` un tema es la *piel* de la aplicación, decide cómo se muestra cada documento HTML, +//! En PageTop un tema es la *piel* de la aplicación, decide cómo se muestra cada documento HTML, //! especialmente las páginas de contenido ([`Page`](crate::response::page::Page)), sin alterar la //! lógica interna de sus componentes. //! diff --git a/src/global.rs b/src/global.rs index 8a03589c..6be0774d 100644 --- a/src/global.rs +++ b/src/global.rs @@ -68,7 +68,7 @@ pub struct App { #[derive(Debug, Deserialize)] /// Sección `[Dev]` de la configuración. Forma parte de [`Settings`]. pub struct Dev { - /// Directorio desde el que servir los archivos estáticos de `PageTop`. + /// Directorio desde el que servir los archivos estáticos de PageTop. /// /// Por defecto, los archivos se integran en el binario de la aplicación. Si aquí se indica una /// ruta válida, ya sea absoluta o relativa al directorio del proyecto o del binario en diff --git a/src/lib.rs b/src/lib.rs index 90ea4625..e43da2f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,8 +15,8 @@ <br> </div> -`PageTop` reivindica la esencia de la web clásica usando [Rust](https://www.rust-lang.org/es) para -la creación de soluciones web SSR (*renderizadas en el servidor*) basadas en HTML, CSS y JavaScript. +PageTop reivindica la esencia de la web clásica usando [Rust](https://www.rust-lang.org/es) para la +creación de soluciones web SSR (*renderizadas en el servidor*) basadas en HTML, CSS y JavaScript. Ofrece un conjunto de herramientas que los desarrolladores pueden implementar, extender o adaptar según las necesidades de cada proyecto, incluyendo: @@ -25,14 +25,14 @@ según las necesidades de cada proyecto, incluyendo: * **Componentes** (*components*): encapsulan HTML, CSS y JavaScript en unidades funcionales, configurables y reutilizables. * **Extensiones** (*extensions*): añaden, extienden o personalizan funcionalidades usando las APIs - de `PageTop` o de terceros. + de PageTop o de terceros. * **Temas** (*themes*): son extensiones que permiten modificar la apariencia de páginas y componentes sin comprometer su funcionalidad. # ⚡️ Guía rápida -La aplicación más sencilla de `PageTop` se ve así: +La aplicación más sencilla de PageTop se ve así: ```rust,no_run use pagetop::prelude::*; @@ -43,10 +43,10 @@ async fn main() -> std::io::Result<()> { } ``` -Este código arranca el servidor de `PageTop`. Con la configuración por defecto, muestra una página -de bienvenida accesible desde un navegador local en la dirección `http://localhost:8080`. +Este código arranca el servidor de PageTop. Con la configuración por defecto, muestra una página de +bienvenida accesible desde un navegador local en la dirección `http://localhost:8080`. -Para personalizar el servicio, se puede crear una extensión de `PageTop` de la siguiente manera: +Para personalizar el servicio, se puede crear una extensión de PageTop de la siguiente manera: ```rust,no_run use pagetop::prelude::*; @@ -77,11 +77,11 @@ Este programa implementa una extensión llamada `HelloWorld` que sirve una pági # 🧩 Gestión de Dependencias -Los proyectos que utilizan `PageTop` gestionan las dependencias con `cargo`, como cualquier otro +Los proyectos que utilizan PageTop gestionan las dependencias con `cargo`, como cualquier otro proyecto en Rust. Sin embargo, es fundamental que cada extensión declare explícitamente sus -[dependencias](core::extension::Extension::dependencies), si las tiene, para que `PageTop` pueda +[dependencias](core::extension::Extension::dependencies), si las tiene, para que PageTop pueda estructurar e inicializar la aplicación de forma modular. */ diff --git a/src/locale.rs b/src/locale.rs index f23f51ee..43612bd5 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -1,6 +1,6 @@ //! Localización (L10n). //! -//! `PageTop` utiliza las especificaciones de [Fluent](https://www.projectfluent.org/) para la +//! PageTop utiliza las especificaciones de [Fluent](https://www.projectfluent.org/) para la //! localización de aplicaciones, y aprovecha [fluent-templates](https://docs.rs/fluent-templates/) //! para integrar los recursos de traducción directamente en el binario de la aplicación. //! @@ -87,7 +87,7 @@ //! include_locales!(LOCALES_SAMPLE from "ruta/a/las/traducciones"); //! ``` //! -//! Y *voilà*, sólo queda operar con los idiomas soportados por `PageTop` usando [`LangMatch`] y +//! Y *voilà*, sólo queda operar con los idiomas soportados por PageTop usando [`LangMatch`] y //! traducir textos con [`L10n`]. use crate::html::{Markup, PreEscaped}; @@ -141,10 +141,10 @@ pub trait LangId { fn langid(&self) -> &'static LanguageIdentifier; } -/// Operaciones con los idiomas soportados por `PageTop`. +/// Operaciones con los idiomas soportados por PageTop. /// /// Utiliza [`LangMatch`] para transformar un identificador de idioma en un [`LanguageIdentifier`] -/// soportado por `PageTop`. +/// soportado por PageTop. /// /// # Ejemplos /// @@ -183,11 +183,11 @@ pub trait LangId { pub enum LangMatch { /// Cuando el identificador de idioma es una cadena vacía. Unspecified, - /// Si encuentra un [`LanguageIdentifier`] en la lista de idiomas soportados por `PageTop` que + /// Si encuentra un [`LanguageIdentifier`] en la lista de idiomas soportados por PageTop que /// coincide exactamente con el identificador de idioma (p.ej. "es-ES"), o con el identificador /// del idioma base (p.ej. "es"). Found(&'static LanguageIdentifier), - /// Si el identificador de idioma no está entre los soportados por `PageTop`. + /// Si el identificador de idioma no está entre los soportados por PageTop. Unsupported(String), } @@ -319,7 +319,7 @@ enum L10nOp { /// Cada instancia puede representar: /// /// - Un texto puro (`n()`) que no requiere traducción. -/// - Una clave para traducir un texto de las traducciones predefinidas de `PageTop` (`l()`). +/// - Una clave para traducir un texto de las traducciones predefinidas de PageTop (`l()`). /// - Una clave para traducir de un conjunto concreto de traducciones (`t()`). /// /// # Ejemplo diff --git a/src/prelude.rs b/src/prelude.rs index 9072dec9..484e53c1 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,4 +1,4 @@ -//! *Prelude* de `PageTop`. +//! *Prelude* de PageTop. // RE-EXPORTED. diff --git a/src/trace.rs b/src/trace.rs index c57c6a3c..12e428a8 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -1,13 +1,13 @@ //! Gestión de trazas y registro de eventos de la aplicación. //! -//! `PageTop` recopila información de diagnóstico de la aplicación de forma estructurada y basada en +//! PageTop recopila información de diagnóstico de la aplicación de forma estructurada y basada en //! eventos. //! //! En los sistemas asíncronos, interpretar los mensajes de log tradicionales suele volverse //! complicado. Las tareas individuales se multiplexan en el mismo hilo y los eventos y registros //! asociados se entremezclan, lo que dificulta seguir la secuencia lógica. //! -//! `PageTop` usa [`tracing`](https://docs.rs/tracing) para registrar eventos estructurados y con +//! PageTop usa [`tracing`](https://docs.rs/tracing) para registrar eventos estructurados y con //! información adicional sobre la *temporalidad* y la *causalidad*. A diferencia de un mensaje de //! log, un *span* (intervalo) tiene un momento de inicio y de fin, puede entrar y salir del flujo //! de ejecución y puede existir dentro de un árbol anidado de *spans* similares. Además, estos From fec3c32b8e7b5c1be942423425f97b28d32dd045 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 3 Sep 2025 21:12:19 +0200 Subject: [PATCH 159/244] =?UTF-8?q?=F0=9F=93=9D=20(doc):=20Simplifica=20do?= =?UTF-8?q?cumentaci=C3=B3n=20de=20obsoletos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/service.rs | 67 -------------------------------------------------- src/util.rs | 2 -- 2 files changed, 69 deletions(-) diff --git a/src/service.rs b/src/service.rs index 288e1eb5..09dc6183 100644 --- a/src/service.rs +++ b/src/service.rs @@ -17,31 +17,6 @@ pub use actix_web::test; /// **Obsoleto desde la versión 0.3.0**: usar [`static_files_service!`](crate::static_files_service) /// en su lugar. -/// -/// Incluye en código un conjunto de recursos previamente preparado con `build.rs`. -/// -/// # Formas de uso -/// -/// * `include_files!(media)` - Para incluir un conjunto de recursos llamado `media`. Normalmente se -/// usará esta forma. -/// -/// * `include_files!(BLOG => media)` - También se puede asignar el conjunto de recursos a una -/// variable global; p.ej. `BLOG`. -/// -/// # Argumentos -/// -/// * `$bundle` – Nombre del conjunto de recursos generado por `build.rs` (consultar -/// [`pagetop_build`](https://docs.rs/pagetop-build)). -/// * `$STATIC` – Asigna el conjunto de recursos a una variable global de tipo -/// [`StaticResources`](crate::StaticResources). -/// -/// # Ejemplos -/// -/// ```rust,ignore -/// include_files!(assets); // Uso habitual. -/// -/// include_files!(STATIC_ASSETS => assets); -/// ``` #[deprecated(since = "0.3.0", note = "Use `static_files_service!` instead")] #[macro_export] macro_rules! include_files { @@ -69,48 +44,6 @@ macro_rules! include_files { /// **Obsoleto desde la versión 0.3.0**: usar [`static_files_service!`](crate::static_files_service) /// en su lugar. -/// -/// Configura un servicio web para publicar los recursos embebidos con [`include_files!`]. -/// -/// El código expandido de la macro decide durante el arranque de la aplicación si debe servir los -/// archivos de los recursos embebidos o directamente desde el sistema de ficheros, si se ha -/// indicado una ruta válida a un directorio de recursos. -/// -/// # Argumentos -/// -/// * `$scfg` – Instancia de [`ServiceConfig`](crate::service::web::ServiceConfig) donde aplicar la -/// configuración del servicio web. -/// * `$bundle` – Nombre del conjunto de recursos incluido con [`include_files!`]. -/// * `$route` – Ruta URL de origen desde la que se servirán los archivos. -/// * `[ $root, $relative ]` *(opcional)* – Directorio raíz y ruta relativa para construir la ruta -/// absoluta donde buscar los archivos en el sistema de ficheros (ver -/// [`absolute_dir()`](crate::util::absolute_dir)). Si no existe, se usarán los recursos -/// embebidos. -/// -/// # Ejemplos -/// -/// ```rust,ignore -/// use pagetop::prelude::*; -/// -/// include_files!(assets); -/// -/// pub struct MyExtension; -/// -/// impl Extension for MyExtension { -/// fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { -/// include_files_service!(scfg, assets => "/public"); -/// } -/// } -/// ``` -/// -/// Y para buscar los recursos en el sistema de ficheros (si existe la ruta absoluta): -/// -/// ```rust,ignore -/// include_files_service!(cfg, assets => "/public", ["/var/www", "assets"]); -/// -/// // También desde el directorio actual de ejecución. -/// include_files_service!(cfg, assets => "/public", ["", "static"]); -/// ``` #[deprecated(since = "0.3.0", note = "Use `static_files_service!` instead")] #[macro_export] macro_rules! include_files_service { diff --git a/src/util.rs b/src/util.rs index e70b0998..808014b2 100644 --- a/src/util.rs +++ b/src/util.rs @@ -57,8 +57,6 @@ pub fn resolve_absolute_dir<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { } /// **Obsoleto desde la versión 0.3.0**: usar [`resolve_absolute_dir()`] en su lugar. -/// -/// Devuelve la ruta absoluta a un directorio existente. #[deprecated(since = "0.3.0", note = "Use `resolve_absolute_dir()` instead")] pub fn absolute_dir<P, Q>(root_path: P, relative_path: Q) -> io::Result<PathBuf> where From fdb8132c37e757abc02de6f63f51db87a37ea5a0 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 4 Sep 2025 00:27:25 +0200 Subject: [PATCH 160/244] =?UTF-8?q?=F0=9F=8E=A8=20(locale):=20Mejora=20el?= =?UTF-8?q?=20uso=20de=20`lookup`=20/=20`using`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component/poweredby.rs | 2 +- src/html/attr_l10n.rs | 29 ++++++----- src/html/context.rs | 3 +- src/locale.rs | 86 +++++++++++++++++++-------------- src/response/page.rs | 4 +- tests/locale.rs | 10 ++-- 6 files changed, 75 insertions(+), 59 deletions(-) diff --git a/src/base/component/poweredby.rs b/src/base/component/poweredby.rs index afa8db72..bfe38351 100644 --- a/src/base/component/poweredby.rs +++ b/src/base/component/poweredby.rs @@ -31,7 +31,7 @@ impl Component for PoweredBy { span class="poweredby__copyright" { (c) "." } " " } span class="poweredby__pagetop" { - (L10n::l("poweredby_pagetop").with_arg("pagetop_link", LINK).to_markup(cx)) + (L10n::l("poweredby_pagetop").with_arg("pagetop_link", LINK).using(cx)) } } }) diff --git a/src/html/attr_l10n.rs b/src/html/attr_l10n.rs index cd5b389d..3e8a4e4b 100644 --- a/src/html/attr_l10n.rs +++ b/src/html/attr_l10n.rs @@ -4,7 +4,7 @@ use crate::{builder_fn, AutoDefault}; /// Texto para [traducir](crate::locale) en atributos HTML. /// -/// Encapsula un tipo [`L10n`] para manejar traducciones de forma segura. +/// Encapsula un [`L10n`] para manejar traducciones de forma segura en atributos. /// /// # Ejemplo /// @@ -16,19 +16,19 @@ use crate::{builder_fn, AutoDefault}; /// /// // Español disponible. /// assert_eq!( -/// hello.using(&LangMatch::resolve("es-ES")), +/// hello.lookup(&LangMatch::resolve("es-ES")), /// Some(String::from("¡Hola mundo!")) /// ); /// /// // Japonés no disponible, traduce al idioma de respaldo ("en-US"). /// assert_eq!( -/// hello.using(&LangMatch::resolve("ja-JP")), +/// hello.lookup(&LangMatch::resolve("ja-JP")), /// Some(String::from("Hello world!")) /// ); /// -/// // Para incrustar en HTML escapado: -/// let markup = hello.to_markup(&LangMatch::resolve("es-ES")); -/// assert_eq!(markup.into_string(), "¡Hola mundo!"); +/// // Uso típico en un atributo: +/// let title = hello.value(&LangMatch::resolve("es-ES")); +/// // Ejemplo: html! { a title=(title) { "Link" } } /// ``` #[derive(AutoDefault, Clone, Debug)] pub struct AttrL10n(L10n); @@ -51,15 +51,18 @@ impl AttrL10n { // AttrL10n GETTERS **************************************************************************** /// Devuelve la traducción para `language`, si existe. - pub fn using(&self, language: &impl LangId) -> Option<String> { - self.0.using(language) + pub fn lookup(&self, language: &impl LangId) -> Option<String> { + self.0.lookup(language) } - /// Devuelve la traducción *escapada* como [`Markup`] para `language`, si existe. - /// - /// Útil para incrustar el texto directamente en plantillas HTML sin riesgo de inyección de - /// contenido. + /// Devuelve la traducción para `language` o una cadena vacía si no existe. + pub fn value(&self, language: &impl LangId) -> String { + self.0.lookup(language).unwrap_or_default() + } + + /// **Obsoleto desde la versión 0.4.0**: no recomendado para atributos HTML. + #[deprecated(since = "0.4.0", note = "For attributes use `lookup()` or `value()`")] pub fn to_markup(&self, language: &impl LangId) -> Markup { - self.0.to_markup(language) + self.0.using(language) } } diff --git a/src/html/context.rs b/src/html/context.rs index 96787863..8b7afba3 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -306,8 +306,7 @@ impl Context { /// 4. Y si ninguna de las opciones anteriores aplica, se usa el idioma de respaldo (`"en-US"`). /// /// Resulta útil para usar un contexto ([`Context`]) como fuente de traducción en -/// [`L10n::using()`](crate::locale::L10n::using) o -/// [`L10n::to_markup()`](crate::locale::L10n::to_markup). +/// [`L10n::lookup()`](crate::locale::L10n::lookup) o [`L10n::using()`](crate::locale::L10n::using). impl LangId for Context { fn langid(&self) -> &'static LanguageIdentifier { self.langid diff --git a/src/locale.rs b/src/locale.rs index 43612bd5..cf44dd82 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -13,7 +13,7 @@ //! //! # Recursos Fluent //! -//! Por defecto las traducciones están en el directorio `src/locale`, con subdirectorios para cada +//! Por defecto, las traducciones están en el directorio `src/locale`, con subdirectorios para cada //! [Identificador de Idioma Unicode](https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier) //! válido. Podríamos tener una estructura como esta: //! @@ -34,7 +34,7 @@ //! └── main.ftl //! ``` //! -//! Ejemplo de un archivo en `src/locale/en-US/main.ftl` +//! Ejemplo de un archivo en `src/locale/en-US/main.ftl`: //! //! ```text //! hello-world = Hello world! @@ -53,7 +53,7 @@ //! Y su archivo equivalente para español en `src/locale/es-ES/main.ftl`: //! //! ```text -//! hello-world = Hola mundo! +//! hello-world = ¡Hola, mundo! //! hello-user = ¡Hola, {$userName}! //! shared-photos = //! {$userName} {$photoCount -> @@ -81,7 +81,7 @@ //! include_locales!(LOCALES_SAMPLE); //! ``` //! -//! Si están ubicados en otro directorio se puede usar la forma: +//! Si están ubicados en otro directorio, se puede usar la forma: //! //! ```rust,ignore //! include_locales!(LOCALES_SAMPLE from "ruta/a/las/traducciones"); @@ -129,7 +129,7 @@ pub(crate) static FALLBACK_LANGID: LazyLock<LanguageIdentifier> = // Identificador de idioma **por defecto** para la aplicación. // // Se resuelve a partir de [`global::SETTINGS.app.language`](global::SETTINGS). Si el identificador -// de idioma no es válido o no está disponible entonces resuelve como [`FALLBACK_LANGID`]. +// de idioma no es válido o no está disponible, se usa [`FALLBACK_LANGID`]. pub(crate) static DEFAULT_LANGID: LazyLock<Option<&LanguageIdentifier>> = LazyLock::new(|| LangMatch::resolve(&global::SETTINGS.app.language).as_option()); @@ -155,7 +155,7 @@ pub trait LangId { /// let lang = LangMatch::resolve("es-ES"); /// assert_eq!(lang.langid().to_string(), "es-ES"); /// -/// // Coincidencia parcial (con el idioma base). +/// // Coincidencia parcial (retrocede al idioma base si no hay variante regional). /// let lang = LangMatch::resolve("es-EC"); /// assert_eq!(lang.langid().to_string(), "es-ES"); // Porque "es-EC" no está soportado. /// @@ -221,7 +221,7 @@ impl LangMatch { } } - // En otro caso indica que el idioma no está soportado. + // En caso contrario, indica que el idioma no está soportado. Self::Unsupported(String::from(language)) } @@ -241,7 +241,7 @@ impl LangMatch { /// let lang = LangMatch::resolve("es-ES").as_option(); /// assert_eq!(lang.unwrap().to_string(), "es-ES"); /// - /// let lang = LangMatch::resolve("jp-JP").as_option(); + /// let lang = LangMatch::resolve("ja-JP").as_option(); /// assert!(lang.is_none()); /// ``` #[inline] @@ -259,8 +259,8 @@ impl LangMatch { /// devuelve el idioma por defecto de la aplicación y, si tampoco está disponible, el idioma de /// respaldo ("en-US"). /// -/// Resulta útil para usar un valor de [`LangMatch`] como fuente de traducción en [`L10n::using()`] -/// o [`L10n::to_markup()`]. +/// Resulta útil para usar un valor de [`LangMatch`] como fuente de traducción en [`L10n::lookup()`] +/// o [`L10n::using()`]. impl LangId for LangMatch { fn langid(&self) -> &'static LanguageIdentifier { match self { @@ -271,10 +271,10 @@ impl LangId for LangMatch { } #[macro_export] -/// Define un conjunto de elementos de localización y textos de traducción local. +/// Incluye un conjunto de recursos **Fluent** y textos de traducción propios. macro_rules! include_locales { - // Se eliminan las marcas de aislamiento Unicode en los argumentos para mejorar la legibilidad y - // la compatibilidad en ciertos contextos de renderizado. + // Se desactiva la inserción de marcas de aislamiento Unicode (FSI/PDI) en los argumentos para + // mejorar la legibilidad y la compatibilidad en ciertos contextos de renderizado. ( $LOCALES:ident $(, $core_locales:literal)? ) => { $crate::locale::fluent_templates::static_loader! { static $LOCALES = { @@ -310,8 +310,8 @@ include_locales!(LOCALES_PAGETOP); enum L10nOp { #[default] None, - Text(String), - Translate(String), + Text(Cow<'static, str>), + Translate(Cow<'static, str>), } /// Crea instancias para traducir textos localizados. @@ -324,7 +324,7 @@ enum L10nOp { /// /// # Ejemplo /// -/// Los argumentos dinámicos se añaden usando `with_arg()` o `with_args()`. +/// Los argumentos dinámicos se añaden con `with_arg()` o `with_args()`. /// /// ```rust /// use pagetop::prelude::*; @@ -338,11 +338,11 @@ enum L10nOp { /// .get(); /// ``` /// -/// También para traducciones a idiomas concretos. +/// También sirve para traducciones contra un conjunto de recursos concreto. /// /// ```rust,ignore /// // Traducción con clave, conjunto de traducciones y fuente de idioma. -/// let bye = L10n::t("goodbye", &LOCALES_CUSTOM).using(&LangMatch::resolve("it")); +/// let bye = L10n::t("goodbye", &LOCALES_CUSTOM).lookup(&LangMatch::resolve("it")); /// ``` #[derive(AutoDefault, Clone)] pub struct L10n { @@ -354,7 +354,7 @@ pub struct L10n { impl L10n { /// **n** = *“native”*. Crea una instancia con una cadena literal sin traducción. - pub fn n(text: impl Into<String>) -> Self { + pub fn n(text: impl Into<Cow<'static, str>>) -> Self { L10n { op: L10nOp::Text(text.into()), ..Default::default() @@ -363,7 +363,7 @@ impl L10n { /// **l** = *“lookup”*. Crea una instancia para traducir usando una clave del conjunto de /// traducciones predefinidas. - pub fn l(key: impl Into<String>) -> Self { + pub fn l(key: impl Into<Cow<'static, str>>) -> Self { L10n { op: L10nOp::Translate(key.into()), ..Default::default() @@ -372,7 +372,7 @@ impl L10n { /// **t** = *“translate”*. Crea una instancia para traducir usando una clave de un conjunto de /// traducciones específico. - pub fn t(key: impl Into<String>, locales: &'static Locales) -> Self { + pub fn t(key: impl Into<Cow<'static, str>>, locales: &'static Locales) -> Self { L10n { op: L10nOp::Translate(key.into()), locales, @@ -399,7 +399,8 @@ impl L10n { self } - /// Resuelve la traducción usando el idioma por defecto o de respaldo de la aplicación. + /// Resuelve la traducción usando el idioma por defecto o, si no procede, el de respaldo de la + /// aplicación. /// /// Devuelve `None` si no aplica o no encuentra una traducción válida. /// @@ -411,7 +412,7 @@ impl L10n { /// let text = L10n::l("greeting").with_arg("name", "Manuel").get(); /// ``` pub fn get(&self) -> Option<String> { - self.using(&LangMatch::default()) + self.lookup(&LangMatch::default()) } /// Resuelve la traducción usando la fuente de idioma proporcionada. @@ -432,20 +433,27 @@ impl L10n { /// } /// /// let r = ResourceLang; - /// let text = L10n::l("greeting").with_arg("name", "Usuario").using(&r); + /// let text = L10n::l("greeting").with_arg("name", "Usuario").lookup(&r); /// ``` - pub fn using(&self, language: &impl LangId) -> Option<String> { + pub fn lookup(&self, language: &impl LangId) -> Option<String> { match &self.op { L10nOp::None => None, - L10nOp::Text(text) => Some(text.to_owned()), - L10nOp::Translate(key) => self.locales.try_lookup_with_args( - language.langid(), - key, - &self.args.iter().fold(HashMap::new(), |mut arg, (k, v)| { - arg.insert(Cow::Owned(k.clone()), v.to_owned().into()); - arg - }), - ), + L10nOp::Text(text) => Some(text.clone().into_owned()), + L10nOp::Translate(key) => { + if self.args.is_empty() { + self.locales.try_lookup(language.langid(), key.as_ref()) + } else { + self.locales.try_lookup_with_args( + language.langid(), + key.as_ref(), + &self + .args + .iter() + .map(|(k, v)| (Cow::Owned(k.clone()), v.clone().into())) + .collect::<HashMap<_, _>>(), + ) + } + } } } @@ -458,10 +466,16 @@ impl L10n { /// ```rust /// use pagetop::prelude::*; /// - /// let html = L10n::l("welcome.message").to_markup(&LangMatch::resolve("es")); + /// let html = L10n::l("welcome.message").using(&LangMatch::resolve("es")); /// ``` + pub fn using(&self, language: &impl LangId) -> Markup { + PreEscaped(self.lookup(language).unwrap_or_default()) + } + + /// **Obsoleto desde la versión 0.4.0**: usar [`using()`](Self::using) en su lugar. + #[deprecated(since = "0.4.0", note = "Use `using()` instead")] pub fn to_markup(&self, language: &impl LangId) -> Markup { - PreEscaped(self.using(language).unwrap_or_default()) + self.using(language) } } diff --git a/src/response/page.rs b/src/response/page.rs index ea88e846..7ef52703 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -151,12 +151,12 @@ impl Page { /// Devuelve el título traducido para el idioma de la página, si existe. pub fn title(&mut self) -> Option<String> { - self.title.using(&self.context) + self.title.lookup(&self.context) } /// Devuelve la descripción traducida para el idioma de la página, si existe. pub fn description(&mut self) -> Option<String> { - self.description.using(&self.context) + self.description.lookup(&self.context) } /// Devuelve la lista de metadatos `<meta name=...>`. diff --git a/tests/locale.rs b/tests/locale.rs index ef875d7d..ee7ac27c 100644 --- a/tests/locale.rs +++ b/tests/locale.rs @@ -13,7 +13,7 @@ async fn translation_without_args() { let _app = service::test::init_service(Application::new().test()).await; let l10n = L10n::l("test-hello-world"); - let translation = l10n.using(&LangMatch::resolve("es-ES")); + let translation = l10n.lookup(&LangMatch::resolve("es-ES")); assert_eq!(translation, Some("¡Hola mundo!".to_string())); } @@ -22,7 +22,7 @@ async fn translation_with_args() { let _app = service::test::init_service(Application::new().test()).await; let l10n = L10n::l("test-hello-user").with_arg("userName", "Manuel"); - let translation = l10n.using(&LangMatch::resolve("es-ES")); + let translation = l10n.lookup(&LangMatch::resolve("es-ES")); assert_eq!(translation, Some("¡Hola, Manuel!".to_string())); } @@ -35,7 +35,7 @@ async fn translation_with_plural_and_select() { ("photoCount", "3"), ("userGender", "male"), ]); - let translation = l10n.using(&LangMatch::resolve("es-ES")).unwrap(); + let translation = l10n.lookup(&LangMatch::resolve("es-ES")).unwrap(); assert!(translation.contains("añadido 3 nuevas fotos de él")); } @@ -44,7 +44,7 @@ async fn check_fallback_language() { let _app = service::test::init_service(Application::new().test()).await; let l10n = L10n::l("test-hello-world"); - let translation = l10n.using(&LangMatch::resolve("xx-YY")); // Retrocede a "en-US". + let translation = l10n.lookup(&LangMatch::resolve("xx-YY")); // Retrocede a "en-US". assert_eq!(translation, Some("Hello world!".to_string())); } @@ -53,6 +53,6 @@ async fn check_unknown_key() { let _app = service::test::init_service(Application::new().test()).await; let l10n = L10n::l("non-existent-key"); - let translation = l10n.using(&LangMatch::resolve("en-US")); + let translation = l10n.lookup(&LangMatch::resolve("en-US")); assert_eq!(translation, None); } From 543f2de333adf8b7635b2556dd98796ddfb0e99b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 4 Sep 2025 01:11:03 +0200 Subject: [PATCH 161/244] =?UTF-8?q?=F0=9F=9A=9A=20Renombra=20`with=5Fcompo?= =?UTF-8?q?nent`=20por=20`add=5Fcomponent`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/hello-name.rs | 2 +- examples/hello-world.rs | 2 +- src/core/theme/regions.rs | 12 +++++------ src/response/page.rs | 42 ++++++++++++++++++++++++++++++++------ src/response/page/error.rs | 4 ++-- 5 files changed, 46 insertions(+), 16 deletions(-) diff --git a/examples/hello-name.rs b/examples/hello-name.rs index 7a6db545..3a491a68 100644 --- a/examples/hello-name.rs +++ b/examples/hello-name.rs @@ -14,7 +14,7 @@ async fn hello_name( ) -> ResultPage<Markup, ErrorPage> { let name = path.into_inner(); Page::new(Some(request)) - .with_component(Html::with(move |_| html! { h1 { "Hello " (name) "!" } })) + .add_component(Html::with(move |_| html! { h1 { "Hello " (name) "!" } })) .render() } diff --git a/examples/hello-world.rs b/examples/hello-world.rs index ba268dcd..5550514b 100644 --- a/examples/hello-world.rs +++ b/examples/hello-world.rs @@ -10,7 +10,7 @@ impl Extension for HelloWorld { async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(Some(request)) - .with_component(Html::with(move |_| html! { h1 { "Hello World!" } })) + .add_component(Html::with(move |_| html! { h1 { "Hello World!" } })) .render() } diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index c8a05554..4fcd7dfa 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -77,11 +77,11 @@ pub struct ChildrenInRegions(HashMap<&'static str, Children>); impl ChildrenInRegions { pub fn with(region_name: &'static str, child: Child) -> Self { - ChildrenInRegions::default().with_child_in_region(region_name, ChildOp::Add(child)) + ChildrenInRegions::default().with_child_in(region_name, ChildOp::Add(child)) } #[builder_fn] - pub fn with_child_in_region(mut self, region_name: &'static str, op: ChildOp) -> Self { + pub fn with_child_in(mut self, region_name: &'static str, op: ChildOp) -> Self { if let Some(region) = self.0.get_mut(region_name) { region.alter_child(op); } else { @@ -143,17 +143,17 @@ impl InRegion { InRegion::Content => { COMMON_REGIONS .write() - .alter_child_in_region(REGION_CONTENT, ChildOp::Add(child)); + .alter_child_in(REGION_CONTENT, ChildOp::Add(child)); } - InRegion::Named(name) => { + InRegion::Named(region_name) => { COMMON_REGIONS .write() - .alter_child_in_region(name, ChildOp::Add(child)); + .alter_child_in(region_name, ChildOp::Add(child)); } InRegion::OfTheme(region_name, theme_ref) => { let mut regions = THEME_REGIONS.write(); if let Some(r) = regions.get_mut(&theme_ref.type_id()) { - r.alter_child_in_region(region_name, ChildOp::Add(child)); + r.alter_child_in(region_name, ChildOp::Add(child)); } else { regions.insert( theme_ref.type_id(), diff --git a/src/response/page.rs b/src/response/page.rs index 7ef52703..5ac3720c 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -122,28 +122,58 @@ impl Page { self } + /// **Obsoleto desde la versión 0.4.0**: usar [`add_component()`](Self::add_component) en su + /// lugar. + #[deprecated(since = "0.4.0", note = "Use `add_component()` instead")] + pub fn with_component(self, component: impl Component) -> Self { + self.add_component(component) + } + + /// **Obsoleto desde la versión 0.4.0**: usar [`add_component_in()`](Self::add_component_in) en + /// su lugar. + #[deprecated(since = "0.4.0", note = "Use `add_component_in()` instead")] + pub fn with_component_in(self, region_name: &'static str, component: impl Component) -> Self { + self.add_component_in(region_name, component) + } + /// Añade un componente a la región de contenido por defecto. - pub fn with_component(mut self, component: impl Component) -> Self { + pub fn add_component(mut self, component: impl Component) -> Self { self.regions - .alter_child_in_region(REGION_CONTENT, ChildOp::Add(Child::with(component))); + .alter_child_in(REGION_CONTENT, ChildOp::Add(Child::with(component))); self } /// Añade un componente en una región (`region_name`) de la página. - pub fn with_component_in( + pub fn add_component_in( mut self, region_name: &'static str, component: impl Component, ) -> Self { self.regions - .alter_child_in_region(region_name, ChildOp::Add(Child::with(component))); + .alter_child_in(region_name, ChildOp::Add(Child::with(component))); + self + } + + /// **Obsoleto desde la versión 0.4.0**: usar [`with_child_in()`](Self::with_child_in) en su + /// lugar. + #[deprecated(since = "0.4.0", note = "Use `with_child_in()` instead")] + pub fn with_child_in_region(mut self, region_name: &'static str, op: ChildOp) -> Self { + self.alter_child_in(region_name, op); + self + } + + /// **Obsoleto desde la versión 0.4.0**: usar [`alter_child_in()`](Self::alter_child_in) en su + /// lugar. + #[deprecated(since = "0.4.0", note = "Use `alter_child_in()` instead")] + pub fn alter_child_in_region(&mut self, region_name: &'static str, op: ChildOp) -> &mut Self { + self.alter_child_in(region_name, op); self } /// Opera con [`ChildOp`] en una región (`region_name`) de la página. #[builder_fn] - pub fn with_child_in_region(mut self, region_name: &'static str, op: ChildOp) -> Self { - self.regions.alter_child_in_region(region_name, op); + pub fn with_child_in(mut self, region_name: &'static str, op: ChildOp) -> Self { + self.regions.alter_child_in(region_name, op); self } diff --git a/src/response/page/error.rs b/src/response/page/error.rs index 99ba62bf..ab56338f 100644 --- a/src/response/page/error.rs +++ b/src/response/page/error.rs @@ -33,7 +33,7 @@ impl Display for ErrorPage { if let Ok(page) = error_page .with_title(L10n::n("Error FORBIDDEN")) .with_layout("error") - .with_component(Html::with(move |_| error403.clone())) + .add_component(Html::with(move |_| error403.clone())) .render() { write!(f, "{}", page.into_string()) @@ -48,7 +48,7 @@ impl Display for ErrorPage { if let Ok(page) = error_page .with_title(L10n::n("Error RESOURCE NOT FOUND")) .with_layout("error") - .with_component(Html::with(move |_| error404.clone())) + .add_component(Html::with(move |_| error404.clone())) .render() { write!(f, "{}", page.into_string()) From 970442a45aaeea242073845d4cfbfd5109d00653 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 4 Sep 2025 01:12:59 +0200 Subject: [PATCH 162/244] =?UTF-8?q?=F0=9F=9A=A7=20Retoques=20en=20el=20c?= =?UTF-8?q?=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-macros/src/lib.rs | 2 +- tests/component_poweredby.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index b462ea13..0a60d532 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -191,7 +191,7 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { // Genera el método alter_...() con el código del método with_...(). let fn_alter_doc = - format!("Igual que [`Self::{fn_with_name_str}()`], pero sin usar el patrón *builder*."); + format!("Equivalente a [`Self::{fn_with_name_str}()`], pero sin usar el patrón *builder*."); let fn_alter = quote! { #[doc = #fn_alter_doc] diff --git a/tests/component_poweredby.rs b/tests/component_poweredby.rs index b2e4418b..9f8e8222 100644 --- a/tests/component_poweredby.rs +++ b/tests/component_poweredby.rs @@ -67,8 +67,8 @@ async fn poweredby_link_points_to_crates_io() { let html = render_component(&p); assert!( - html.contains("https://crates.io/crates/pagetop"), - "Link should point to crates.io/pagetop" + html.contains("https://pagetop.cillero.es"), + "Link should point to pagetop.cillero.es" ); } From c43c8458cce0453d8c7fd34579ae51f92a27a7ed Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 4 Sep 2025 01:53:51 +0200 Subject: [PATCH 163/244] =?UTF-8?q?=F0=9F=9A=A7=20(welcome):=20Crea=20p?= =?UTF-8?q?=C3=A1gina=20de=20bienvenida=20desde=20intro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Implementa un nuevo *layout* en el tema `Basic` para crear una plantilla de páginas de introducción. - Añade nuevo fichero CSS `intro.css` para los estilos globales de la página de introducción. - Incorpora nuevos recursos gráficos para la cabecera de la página de introducción en varios formatos (AVIF, WebP, JPEG). - Revisa los ficheros de localización. --- src/base/component.rs | 3 + src/base/component/block.rs | 103 +++++++++ src/base/extension/welcome.rs | 105 ++------- src/base/theme/basic.rs | 91 +++++++- src/core/component/definition.rs | 6 +- src/core/theme.rs | 6 +- src/core/theme/definition.rs | 210 +++++++++++------- src/core/theme/regions.rs | 2 +- src/locale/en-US/welcome.ftl | 1 - src/locale/es-ES/welcome.ftl | 1 - static/css/{welcome.css => intro.css} | 150 ++++++------- ...me-header-sm.avif => intro-header-sm.avif} | Bin ...come-header-sm.jpg => intro-header-sm.jpg} | Bin ...me-header-sm.webp => intro-header-sm.webp} | Bin ...{welcome-header.avif => intro-header.avif} | Bin .../{welcome-header.jpg => intro-header.jpg} | Bin ...{welcome-header.webp => intro-header.webp} | Bin 17 files changed, 420 insertions(+), 258 deletions(-) create mode 100644 src/base/component/block.rs rename static/css/{welcome.css => intro.css} (78%) rename static/img/{welcome-header-sm.avif => intro-header-sm.avif} (100%) rename static/img/{welcome-header-sm.jpg => intro-header-sm.jpg} (100%) rename static/img/{welcome-header-sm.webp => intro-header-sm.webp} (100%) rename static/img/{welcome-header.avif => intro-header.avif} (100%) rename static/img/{welcome-header.jpg => intro-header.jpg} (100%) rename static/img/{welcome-header.webp => intro-header.webp} (100%) diff --git a/src/base/component.rs b/src/base/component.rs index 30cb6866..4df64ff1 100644 --- a/src/base/component.rs +++ b/src/base/component.rs @@ -3,5 +3,8 @@ mod html; pub use html::Html; +mod block; +pub use block::Block; + mod poweredby; pub use poweredby::PoweredBy; diff --git a/src/base/component/block.rs b/src/base/component/block.rs new file mode 100644 index 00000000..c96f2baf --- /dev/null +++ b/src/base/component/block.rs @@ -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 + } +} diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs index 0252cff3..3c0de3db 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -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() } diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index 961864be..dc16f2ac 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -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)) } + } + } + } + } + } +} diff --git a/src/core/component/definition.rs b/src/core/component/definition.rs index c43dfb0f..d547c4b3 100644 --- a/src/core/component/definition.rs +++ b/src/core/component/definition.rs @@ -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 diff --git a/src/core/theme.rs b/src/core/theme.rs index e0c3008e..5889dcf7 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -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; diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 3b26a573..a4faf0b8 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -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")), - ] - }); - &REGIONS[..] - } - - /// 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")), + ] + }); + &REGIONS[..] + } + + /// 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 {} diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index 4fcd7dfa..1a2e0fbb 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -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, diff --git a/src/locale/en-US/welcome.ftl b/src/locale/en-US/welcome.ftl index 7d98f447..7b7d74d8 100644 --- a/src/locale/en-US/welcome.ftl +++ b/src/locale/en-US/welcome.ftl @@ -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> diff --git a/src/locale/es-ES/welcome.ftl b/src/locale/es-ES/welcome.ftl index 8a384253..78238322 100644 --- a/src/locale/es-ES/welcome.ftl +++ b/src/locale/es-ES/welcome.ftl @@ -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> diff --git a/static/css/welcome.css b/static/css/intro.css similarity index 78% rename from static/css/welcome.css rename to static/css/intro.css index 4ce8046b..5a5461e4 100644 --- a/static/css/welcome.css +++ b/static/css/intro.css @@ -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; } } diff --git a/static/img/welcome-header-sm.avif b/static/img/intro-header-sm.avif similarity index 100% rename from static/img/welcome-header-sm.avif rename to static/img/intro-header-sm.avif diff --git a/static/img/welcome-header-sm.jpg b/static/img/intro-header-sm.jpg similarity index 100% rename from static/img/welcome-header-sm.jpg rename to static/img/intro-header-sm.jpg diff --git a/static/img/welcome-header-sm.webp b/static/img/intro-header-sm.webp similarity index 100% rename from static/img/welcome-header-sm.webp rename to static/img/intro-header-sm.webp diff --git a/static/img/welcome-header.avif b/static/img/intro-header.avif similarity index 100% rename from static/img/welcome-header.avif rename to static/img/intro-header.avif diff --git a/static/img/welcome-header.jpg b/static/img/intro-header.jpg similarity index 100% rename from static/img/welcome-header.jpg rename to static/img/intro-header.jpg diff --git a/static/img/welcome-header.webp b/static/img/intro-header.webp similarity index 100% rename from static/img/welcome-header.webp rename to static/img/intro-header.webp From da1390c2fe7eb1ba2df5db199049482bf7b770df Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 6 Sep 2025 09:41:01 +0200 Subject: [PATCH 164/244] =?UTF-8?q?=F0=9F=9A=A7=20(context):=20Generaliza?= =?UTF-8?q?=20los=20par=C3=A1metros=20de=20contexto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component/html.rs | 2 +- src/html/context.rs | 181 ++++++++++++++++++++++++++++++------- src/response/page.rs | 21 ++++- tests/component_html.rs | 2 +- 4 files changed, 168 insertions(+), 38 deletions(-) diff --git a/src/base/component/html.rs b/src/base/component/html.rs index cac39eaf..7bde94a0 100644 --- a/src/base/component/html.rs +++ b/src/base/component/html.rs @@ -25,7 +25,7 @@ use crate::prelude::*; /// use pagetop::prelude::*; /// /// let component = Html::with(|cx| { -/// let user = cx.get_param::<String>("username").unwrap_or(String::from("visitor")); +/// let user = cx.param::<String>("username").cloned().unwrap_or(String::from("visitor")); /// html! { /// h1 { "Hello, " (user) } /// } diff --git a/src/html/context.rs b/src/html/context.rs index 8b7afba3..4ebd510e 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -7,10 +7,8 @@ use crate::locale::{LangId, LangMatch, LanguageIdentifier, DEFAULT_LANGID, FALLB use crate::service::HttpRequest; use crate::{builder_fn, join}; +use std::any::Any; use std::collections::HashMap; -use std::error::Error; -use std::fmt::{self, Display}; -use std::str::FromStr; /// Operaciones para modificar el contexto ([`Context`]) del documento. pub enum AssetsOp { @@ -33,32 +31,28 @@ pub enum AssetsOp { RemoveJavaScript(&'static str), } -/// Errores de lectura o conversión de parámetros almacenados en el contexto. +/// Errores de acceso a parámetros dinámicos del contexto. +/// +/// - [`ErrorParam::NotFound`]: la clave no existe. +/// - [`ErrorParam::TypeMismatch`]: la clave existe, pero el valor guardado no coincide con el tipo +/// solicitado. Incluye nombre de la clave (`key`), tipo esperado (`expected`) y tipo realmente +/// guardado (`saved`) para facilitar el diagnóstico. #[derive(Debug)] pub enum ErrorParam { - /// El parámetro solicitado no existe. NotFound, - /// El valor del parámetro no pudo convertirse al tipo requerido. - ParseError(String), + TypeMismatch { + key: &'static str, + expected: &'static str, + saved: &'static str, + }, } -impl Display for ErrorParam { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ErrorParam::NotFound => write!(f, "Parameter not found"), - ErrorParam::ParseError(e) => write!(f, "Parse error: {e}"), - } - } -} - -impl Error for ErrorParam {} - /// Representa el contexto de un documento HTML. /// /// Se crea internamente para manejar información relevante del documento, como la solicitud HTTP de /// origen, el idioma, tema y composición para el renderizado, los recursos *favicon* ([`Favicon`]), -/// hojas de estilo ([`StyleSheet`]) y *scripts* ([`JavaScript`]), así como parámetros de contexto -/// definidos en tiempo de ejecución. +/// hojas de estilo ([`StyleSheet`]) y *scripts* ([`JavaScript`]), así como *parámetros dinámicos +/// heterogéneos* de contexto definidos en tiempo de ejecución. /// /// # Ejemplos /// @@ -95,7 +89,7 @@ impl Error for ErrorParam {} /// assert_eq!(active_theme.short_name(), "aliner"); /// /// // Recupera el parámetro a su tipo original. -/// let id: i32 = cx.get_param("usuario_id").unwrap(); +/// let id: i32 = *cx.get_param::<i32>("usuario_id").unwrap(); /// assert_eq!(id, 42); /// /// // Genera un identificador para un componente de tipo `Menu`. @@ -113,7 +107,7 @@ pub struct Context { favicon : Option<Favicon>, // Favicon, si se ha definido. stylesheets: Assets<StyleSheet>, // Hojas de estilo CSS. javascripts: Assets<JavaScript>, // Scripts JavaScript. - params : HashMap<&'static str, String>, // Parámetros definidos en tiempo de ejecución. + params : HashMap<&'static str, (Box<dyn Any>, &'static str)>, // Parámetros definidos en tiempo de ejecución. id_counter : usize, // Contador para generar identificadores únicos. } @@ -152,7 +146,7 @@ impl Context { favicon : None, stylesheets: Assets::<StyleSheet>::new(), javascripts: Assets::<JavaScript>::new(), - params : HashMap::<&str, String>::new(), + params : HashMap::default(), id_counter : 0, } } @@ -246,29 +240,146 @@ impl Context { // Context PARAMS ****************************************************************************** - /// Añade o modifica un parámetro del contexto almacenando el valor como [`String`]. + /// Añade o modifica un parámetro dinámico del contexto. + /// + /// El valor se guarda conservando el *nombre del tipo* real para mejorar los mensajes de error + /// posteriores. + /// + /// # Ejemplos + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// let cx = Context::new(None) + /// .with_param("usuario_id", 42_i32) + /// .with_param("titulo", String::from("Hola")) + /// .with_param("flags", vec!["a", "b"]); + /// ``` #[builder_fn] - pub fn with_param<T: ToString>(mut self, key: &'static str, value: T) -> Self { - self.params.insert(key, value.to_string()); + pub fn with_param<T: 'static>(mut self, key: &'static str, value: T) -> Self { + let type_name = TypeInfo::FullName.of::<T>(); + self.params.insert(key, (Box::new(value), type_name)); self } - /// Recupera un parámetro del contexto convertido al tipo especificado. + /// Recupera un parámetro como [`Option`], simplificando el acceso. /// - /// Devuelve un error si el parámetro no existe ([`ErrorParam::NotFound`]) o la conversión falla - /// ([`ErrorParam::ParseError`]). - pub fn get_param<T: FromStr>(&self, key: &'static str) -> Result<T, ErrorParam> { - self.params - .get(key) - .ok_or(ErrorParam::NotFound) - .and_then(|v| T::from_str(v).map_err(|_| ErrorParam::ParseError(v.clone()))) + /// A diferencia de [`get_param`](Self::get_param), que devuelve un [`Result`] con información + /// detallada de error, este método devuelve `None` tanto si la clave no existe como si el valor + /// guardado no coincide con el tipo solicitado. + /// + /// Resulta útil en escenarios donde sólo interesa saber si el valor existe y es del tipo + /// correcto, sin necesidad de diferenciar entre error de ausencia o de tipo. + /// + /// # Ejemplo + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// let cx = Context::new(None).with_param("username", String::from("Alice")); + /// + /// // Devuelve Some(&String) si existe y coincide el tipo. + /// assert_eq!(cx.param::<String>("username").map(|s| s.as_str()), Some("Alice")); + /// + /// // Devuelve None si no existe o si el tipo no coincide. + /// assert!(cx.param::<i32>("username").is_none()); + /// assert!(cx.param::<String>("missing").is_none()); + /// + /// // Acceso con valor por defecto. + /// let user = cx.param::<String>("missing") + /// .cloned() + /// .unwrap_or_else(|| "visitor".to_string()); + /// assert_eq!(user, "visitor"); + /// ``` + pub fn param<T: 'static>(&self, key: &'static str) -> Option<&T> { + self.get_param::<T>(key).ok() } - /// Elimina un parámetro del contexto. Devuelve `true` si existía y se eliminó. + /// Recupera una *referencia tipada* al parámetro solicitado. + /// + /// Devuelve: + /// + /// - `Ok(&T)` si la clave existe y el tipo coincide. + /// - `Err(ErrorParam::NotFound)` si la clave no existe. + /// - `Err(ErrorParam::TypeMismatch)` si la clave existe pero el tipo no coincide. + /// + /// # Ejemplos + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// let cx = Context::new(None) + /// .with_param("usuario_id", 42_i32) + /// .with_param("titulo", String::from("Hola")); + /// + /// let id: &i32 = cx.get_param("usuario_id").unwrap(); + /// let titulo: &String = cx.get_param("titulo").unwrap(); + /// + /// // Error de tipo: + /// assert!(cx.get_param::<String>("usuario_id").is_err()); + /// ``` + pub fn get_param<T: 'static>(&self, key: &'static str) -> Result<&T, ErrorParam> { + let (any, type_name) = self.params.get(key).ok_or(ErrorParam::NotFound)?; + any.downcast_ref::<T>() + .ok_or_else(|| ErrorParam::TypeMismatch { + key, + expected: TypeInfo::FullName.of::<T>(), + saved: *type_name, + }) + } + + /// Elimina un parámetro del contexto. Devuelve `true` si la clave existía y se eliminó. + /// + /// Devuelve `false` en caso contrario. Usar cuando solo interesa borrar la entrada. + /// + /// # Ejemplos + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// let mut cx = Context::new(None).with_param("temp", 1u8); + /// assert!(cx.remove_param("temp")); + /// assert!(!cx.remove_param("temp")); // ya no existe + /// ``` pub fn remove_param(&mut self, key: &'static str) -> bool { self.params.remove(key).is_some() } + /// Recupera el parámetro solicitado y lo elimina del contexto. + /// + /// Devuelve: + /// + /// - `Ok(T)` si la clave existía y el tipo coincide. + /// - `Err(ErrorParam::NotFound)` si la clave no existe. + /// - `Err(ErrorParam::TypeMismatch)` si el tipo no coincide. + /// + /// # Ejemplos + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// let mut cx = Context::new(None) + /// .with_param("contador", 7_i32) + /// .with_param("titulo", String::from("Hola")); + /// + /// let n: i32 = cx.take_param("contador").unwrap(); + /// assert!(cx.get_param::<i32>("contador").is_err()); // ya no está + /// + /// // Error de tipo: + /// assert!(cx.take_param::<i32>("titulo").is_err()); + /// ``` + pub fn take_param<T: 'static>(&mut self, key: &'static str) -> Result<T, ErrorParam> { + let (boxed, saved) = self.params.remove(key).ok_or(ErrorParam::NotFound)?; + boxed + .downcast::<T>() + .map(|b| *b) + .map_err(|_| ErrorParam::TypeMismatch { + key, + expected: TypeInfo::FullName.of::<T>(), + saved, + }) + } + // Context EXTRAS ****************************************************************************** /// Genera un identificador único si no se proporciona uno explícito. diff --git a/src/response/page.rs b/src/response/page.rs index 5ac3720c..0942f8c8 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -108,6 +108,12 @@ impl Page { self } + #[builder_fn] + pub fn with_param<T: 'static>(mut self, key: &'static str, value: T) -> Self { + self.context.alter_param(key, value); + self + } + /// Establece el atributo `id` del elemento `<body>`. #[builder_fn] pub fn with_body_id(mut self, id: impl AsRef<str>) -> Self { @@ -214,6 +220,10 @@ impl Page { self.context.layout() } + pub fn param<T: 'static>(&self, key: &'static str) -> Option<&T> { + self.context.param(key) + } + /// Devuelve el identificador del elemento `<body>`. pub fn body_id(&self) -> &AttrId { &self.body_id @@ -223,7 +233,16 @@ impl Page { pub fn body_classes(&self) -> &AttrClasses { &self.body_classes } - + /* + /// Devuelve una referencia mutable al [`Context`] de la página. + /// + /// El [`Context`] actúa como intermediario para muchos métodos de `Page` (idioma, tema, + /// *layout*, recursos, solicitud HTTP, etc.). Resulta especialmente útil cuando un componente + /// o un tema necesita recibir el contexto como parámetro. + pub fn context(&mut self) -> &mut Context { + &mut self.context + } + */ // Page RENDER ********************************************************************************* /// Renderiza los componentes de una región (`regiona_name`) de la página. diff --git a/tests/component_html.rs b/tests/component_html.rs index b9b8e5ec..bd7f3c08 100644 --- a/tests/component_html.rs +++ b/tests/component_html.rs @@ -20,7 +20,7 @@ async fn component_html_renders_using_context_param() { let mut cx = Context::new(None).with_param("username", String::from("Alice")); let component = Html::with(|cx| { - let name = cx.get_param::<String>("username").unwrap_or_default(); + let name = cx.param::<String>("username").cloned().unwrap_or_default(); html! { span { (name) } } From ff76504e781a8fecdee200532a1315a0452b5d6e Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 7 Sep 2025 21:06:41 +0200 Subject: [PATCH 165/244] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(macros):=20Majora?= =?UTF-8?q?=20la=20validaci=C3=B3n=20de=20`builder=5Ffn`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-macros/src/lib.rs | 260 +++++++++++++++++++++--------- 1 file changed, 181 insertions(+), 79 deletions(-) diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 0a60d532..28c6b1b4 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -39,7 +39,7 @@ mod smart_default; use proc_macro::TokenStream; use quote::{quote, quote_spanned}; -use syn::{parse_macro_input, spanned::Spanned, DeriveInput, ItemFn}; +use syn::{parse_macro_input, spanned::Spanned, DeriveInput}; /// Macro para escribir plantillas HTML (basada en [Maud](https://docs.rs/maud)). #[proc_macro] @@ -107,114 +107,216 @@ pub fn derive_auto_default(input: TokenStream) -> TokenStream { /// `alter_...()`, que permitirá más adelante modificar instancias existentes. #[proc_macro_attribute] pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { - let fn_with = parse_macro_input!(item as ItemFn); - let fn_with_name = fn_with.sig.ident.clone(); - let fn_with_name_str = fn_with.sig.ident.to_string(); + use syn::{parse2, FnArg, Ident, ImplItemFn, Pat, ReturnType, TraitItemFn, Type}; + + let ts: proc_macro2::TokenStream = item.clone().into(); + + enum Kind { + Impl(ImplItemFn), + Trait(TraitItemFn), + } + + // Detecta si estamos en `impl` o `trait`. + let kind = if let Ok(it) = parse2::<ImplItemFn>(ts.clone()) { + Kind::Impl(it) + } else if let Ok(tt) = parse2::<TraitItemFn>(ts.clone()) { + Kind::Trait(tt) + } else { + return quote! { + compile_error!("#[builder_fn] only supports methods in `impl` blocks or `trait` items"); + } + .into(); + }; + + // Extrae piezas comunes (sig, attrs, vis, bloque?, es_trait?). + let (sig, attrs, vis, body_opt, is_trait) = match &kind { + Kind::Impl(m) => (&m.sig, &m.attrs, Some(&m.vis), Some(&m.block), false), + Kind::Trait(t) => (&t.sig, &t.attrs, None, t.default.as_ref(), true), + }; + + let with_name = sig.ident.clone(); + let with_name_str = sig.ident.to_string(); // Valida el nombre del método. - if !fn_with_name_str.starts_with("with_") { - let expanded = quote_spanned! { - fn_with.sig.ident.span() => - compile_error!("expected a \"pub fn with_...(mut self, ...) -> Self\" method"); - }; - return expanded.into(); - } - // Valida que el método es público. - if !matches!(fn_with.vis, syn::Visibility::Public(_)) { + if !with_name_str.starts_with("with_") { return quote_spanned! { - fn_with.sig.ident.span() => compile_error!("expected method to be `pub`"); + sig.ident.span() => compile_error!("expected a named `with_...()` method"); } .into(); } - // Valida que el primer argumento es exactamente `mut self`. - if let Some(syn::FnArg::Receiver(receiver)) = fn_with.sig.inputs.first() { - if receiver.mutability.is_none() || receiver.reference.is_some() { - return quote_spanned! { - receiver.span() => compile_error!("expected `mut self` as the first argument"); + + // Sólo se exige `pub` en `impl` (en `trait` no aplica). + let vis_pub = match (is_trait, vis) { + (false, Some(v)) => quote! { #v }, + _ => quote! {}, + }; + + // Validaciones comunes. + if sig.asyncness.is_some() { + return quote_spanned! { + sig.asyncness.span() => compile_error!("`with_...()` cannot be `async`"); + } + .into(); + } + if sig.constness.is_some() { + return quote_spanned! { + sig.constness.span() => compile_error!("`with_...()` cannot be `const`"); + } + .into(); + } + if sig.abi.is_some() { + return quote_spanned! { + sig.abi.span() => compile_error!("`with_...()` cannot be `extern`"); + } + .into(); + } + if sig.unsafety.is_some() { + return quote_spanned! { + sig.unsafety.span() => compile_error!("`with_...()` cannot be `unsafe`"); + } + .into(); + } + + // En `impl` se exige exactamente `mut self`; y en `trait` se exige `self` (sin &). + let receiver_ok = match sig.inputs.first() { + Some(FnArg::Receiver(r)) => { + // Rechaza `self: SomeType`. + if r.colon_token.is_some() { + false + } else if is_trait { + // Exactamente `self` (sin &, sin mut). + r.reference.is_none() && r.mutability.is_none() + } else { + // Exactamente `mut self`. + r.reference.is_none() && r.mutability.is_some() } - .into(); } - } else { + _ => false, + }; + if !receiver_ok { + let msg = if is_trait { + "expected `self` (not `mut self`, `&self` or `&mut self`) in trait method" + } else { + "expected first argument to be exactly `mut self`" + }; + let err = sig + .inputs + .first() + .map(|a| a.span()) + .unwrap_or(sig.ident.span()); return quote_spanned! { - fn_with.sig.ident.span() => compile_error!("expected `mut self` as the first argument"); + err => compile_error!(#msg); } .into(); } + // Valida que el método devuelve exactamente `Self`. - if let syn::ReturnType::Type(_, ty) = &fn_with.sig.output { - if let syn::Type::Path(type_path) = ty.as_ref() { - if type_path.qself.is_some() || !type_path.path.is_ident("Self") { - return quote_spanned! { ty.span() => - compile_error!("expected return type to be exactly `Self`"); + match &sig.output { + ReturnType::Type(_, ty) => match ty.as_ref() { + Type::Path(p) if p.qself.is_none() && p.path.is_ident("Self") => {} + _ => { + return quote_spanned! { + ty.span() => compile_error!("expected return type to be exactly `Self`"); } .into(); } - } else { - return quote_spanned! { ty.span() => - compile_error!("expected return type to be exactly `Self`"); + }, + _ => { + return quote_spanned! { + sig.output.span() => compile_error!("expected return type to be exactly `Self`"); } .into(); } - } else { - return quote_spanned! { - fn_with.sig.output.span() => compile_error!("expected method to return `Self`"); - } - .into(); } // Genera el nombre del método alter_...(). - let fn_alter_name_str = fn_with_name_str.replace("with_", "alter_"); - let fn_alter_name = syn::Ident::new(&fn_alter_name_str, fn_with.sig.ident.span()); + let stem = with_name_str.strip_prefix("with_").expect("validated"); + let alter_ident = Ident::new(&format!("alter_{stem}"), with_name.span()); // Extrae genéricos y cláusulas where. - let fn_generics = &fn_with.sig.generics; - let where_clause = &fn_with.sig.generics.where_clause; + let generics = &sig.generics; + let where_clause = &sig.generics.where_clause; - // Extrae argumentos y parámetros de llamada. - let args: Vec<_> = fn_with.sig.inputs.iter().skip(1).collect(); - let params: Vec<_> = fn_with - .sig - .inputs + // Extrae identificadores de los argumentos para la llamada (sin `mut` ni patrones complejos). + let args: Vec<_> = sig.inputs.iter().skip(1).collect(); + let call_idents: Vec<Ident> = { + let mut v = Vec::new(); + for arg in sig.inputs.iter().skip(1) { + match arg { + FnArg::Typed(pat) => { + if let Pat::Ident(pat_ident) = pat.pat.as_ref() { + v.push(pat_ident.ident.clone()); + } else { + return quote_spanned! { + pat.pat.span() => compile_error!( + "each parameter must be a simple identifier, e.g. `value: T`" + ); + } + .into(); + } + } + _ => { + return quote_spanned! { + arg.span() => compile_error!("unexpected receiver in parameter list"); + } + .into(); + } + } + } + v + }; + + // Extrae atributos descartando la documentación para incluir en `alter_...()`. + let non_doc_attrs: Vec<_> = attrs .iter() - .skip(1) - .map(|arg| match arg { - syn::FnArg::Typed(pat) => &pat.pat, - _ => panic!("unexpected argument type"), - }) + .cloned() + .filter(|a| !a.path().is_ident("doc")) .collect(); - // Extrae bloque del método. - let fn_with_block = &fn_with.block; - - // Extrae documentación y otros atributos del método. - let fn_with_attrs = &fn_with.attrs; - - // Genera el método alter_...() con el código del método with_...(). - let fn_alter_doc = - format!("Equivalente a [`Self::{fn_with_name_str}()`], pero sin usar el patrón *builder*."); - - let fn_alter = quote! { - #[doc = #fn_alter_doc] - pub fn #fn_alter_name #fn_generics(&mut self, #(#args),*) -> &mut Self #where_clause { - #fn_with_block - } - }; - - // Redefine el método with_...() para que llame a alter_...(). - let fn_with = quote! { - #(#fn_with_attrs)* - #[inline] - pub fn #fn_with_name #fn_generics(mut self, #(#args),*) -> Self #where_clause { - self.#fn_alter_name(#(#params),*); - self - } - }; + // Documentación del método alter_...(). + let alter_doc = + format!("Equivalente a [`Self::{with_name_str}()`], pero fuera del patrón *builder*."); // Genera el código final. - let expanded = quote! { - #fn_with - #[inline] - #fn_alter + let expanded = match body_opt { + None => { + quote! { + #(#attrs)* + fn #with_name #generics (self, #(#args),*) -> Self #where_clause; + + #(#non_doc_attrs)* + #[doc = #alter_doc] + fn #alter_ident #generics (&mut self, #(#args),*) -> &mut Self #where_clause; + } + } + Some(body) => { + let with_fn = if is_trait { + quote! { + #vis_pub fn #with_name #generics (self, #(#args),*) -> Self #where_clause { + let mut s = self; + s.#alter_ident(#(#call_idents),*); + s + } + } + } else { + quote! { + #vis_pub fn #with_name #generics (mut self, #(#args),*) -> Self #where_clause { + self.#alter_ident(#(#call_idents),*); + self + } + } + }; + quote! { + #(#attrs)* + #with_fn + + #(#non_doc_attrs)* + #[doc = #alter_doc] + #vis_pub fn #alter_ident #generics (&mut self, #(#args),*) -> &mut Self #where_clause { + #body + } + } + } }; expanded.into() } From b10d0aadf4c998c28a4b07b040de2c91a1f45394 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 7 Sep 2025 21:06:50 +0200 Subject: [PATCH 166/244] =?UTF-8?q?=F0=9F=9A=A7=20(context):=20Define=20un?= =?UTF-8?q?=20`trait`=20com=C3=BAn=20de=20contexto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/global.rs | 13 +- src/html.rs | 4 +- src/html/assets.rs | 16 +- src/html/assets/javascript.rs | 4 +- src/html/assets/stylesheet.rs | 4 +- src/html/context.rs | 416 ++++++++++++++++++++-------------- src/response/page.rs | 158 +++++++------ src/response/page/error.rs | 1 + 8 files changed, 356 insertions(+), 260 deletions(-) diff --git a/src/global.rs b/src/global.rs index 6be0774d..c81eec99 100644 --- a/src/global.rs +++ b/src/global.rs @@ -48,14 +48,13 @@ pub struct App { pub description: String, /// Tema predeterminado. pub theme: String, - /// Idioma por defecto para la aplicación. + /// Idioma por defecto de la aplicación. /// - /// Si no se especifica un valor válido, normalmente se usará el idioma devuelto por la - /// implementación de [`LangId`](crate::locale::LangId) para [`Context`](crate::html::Context), - /// en el siguiente orden: primero, el idioma establecido explícitamente con - /// [`Context::with_langid()`](crate::html::Context::with_langid); si no se ha definido, se - /// usará el indicado en la cabecera `Accept-Language` del navegador; y, si ninguno aplica, se - /// empleará el idioma de respaldo ("en-US"). + /// Si este valor no es válido, el idioma efectivo para el renderizado se resolverá mediante la + /// implementación de [`LangId`](crate::locale::LangId) en este orden: primero, el establecido + /// explícitamente con [`Contextual::with_langid()`](crate::html::Contextual::with_langid); si + /// no se ha definido, se usará el indicado en la cabecera `Accept-Language` del navegador; y, + /// si ninguno aplica, se empleará el idioma de respaldo ("en-US"). pub language: String, /// Banner ASCII mostrado al inicio: *"Off"* (desactivado), *"Slant"*, *"Small"*, *"Speed"* o /// *"Starwars"*. diff --git a/src/html.rs b/src/html.rs index 784457ed..9f3d70cf 100644 --- a/src/html.rs +++ b/src/html.rs @@ -9,12 +9,12 @@ mod assets; pub use assets::favicon::Favicon; pub use assets::javascript::JavaScript; pub use assets::stylesheet::{StyleSheet, TargetMedia}; -pub(crate) use assets::Assets; +pub use assets::{Asset, Assets}; // HTML DOCUMENT CONTEXT *************************************************************************** mod context; -pub use context::{AssetsOp, Context, ErrorParam}; +pub use context::{AssetsOp, Context, Contextual, ErrorParam}; // HTML ATTRIBUTES ********************************************************************************* diff --git a/src/html/assets.rs b/src/html/assets.rs index 894b7e84..e53e8e35 100644 --- a/src/html/assets.rs +++ b/src/html/assets.rs @@ -5,20 +5,20 @@ pub mod stylesheet; use crate::html::{html, Markup, Render}; use crate::{AutoDefault, Weight}; -pub trait AssetsTrait: Render { - // Devuelve el nombre del recurso, utilizado como clave única. +pub trait Asset: Render { + /// Devuelve el nombre del recurso, utilizado como clave única. fn name(&self) -> &str; - // Devuelve el peso del recurso, durante el renderizado se procesan de menor a mayor peso. + /// Devuelve el peso del recurso, durante el renderizado se procesan de menor a mayor peso. fn weight(&self) -> Weight; } #[derive(AutoDefault)] -pub(crate) struct Assets<T>(Vec<T>); +pub struct Assets<T>(Vec<T>); -impl<T: AssetsTrait> Assets<T> { +impl<T: Asset> Assets<T> { pub fn new() -> Self { - Assets::<T>(Vec::<T>::new()) + Self(Vec::new()) } pub fn add(&mut self, asset: T) -> bool { @@ -49,14 +49,14 @@ impl<T: AssetsTrait> Assets<T> { } } -impl<T: AssetsTrait> Render for Assets<T> { +impl<T: Asset> Render for Assets<T> { fn render(&self) -> Markup { let mut assets = self.0.iter().collect::<Vec<_>>(); assets.sort_by_key(|a| a.weight()); html! { @for a in assets { - (a.render()) + (a) } } } diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs index db5754e9..89b5261c 100644 --- a/src/html/assets/javascript.rs +++ b/src/html/assets/javascript.rs @@ -1,4 +1,4 @@ -use crate::html::assets::AssetsTrait; +use crate::html::assets::Asset; use crate::html::{html, Markup, Render}; use crate::{join, join_pair, AutoDefault, Weight}; @@ -137,7 +137,7 @@ impl JavaScript { } } -impl AssetsTrait for JavaScript { +impl Asset for JavaScript { // Para *scripts* externos es la ruta; para *scripts* embebidos, un identificador. fn name(&self) -> &str { match &self.source { diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index bb60b01c..a5537264 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -1,4 +1,4 @@ -use crate::html::assets::AssetsTrait; +use crate::html::assets::Asset; use crate::html::{html, Markup, PreEscaped, Render}; use crate::{join_pair, AutoDefault, Weight}; @@ -142,7 +142,7 @@ impl StyleSheet { } } -impl AssetsTrait for StyleSheet { +impl Asset for StyleSheet { // Para hojas de estilos externas es la ruta; para las embebidas, un identificador. fn name(&self) -> &str { match &self.source { diff --git a/src/html/context.rs b/src/html/context.rs index 4ebd510e..7af884cf 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -10,7 +10,7 @@ use crate::{builder_fn, join}; use std::any::Any; use std::collections::HashMap; -/// Operaciones para modificar el contexto ([`Context`]) del documento. +/// Operaciones para modificar el contexto ([`Context`]) de un documento. pub enum AssetsOp { // Favicon. /// Define el *favicon* del documento. Sobrescribe cualquier valor anterior. @@ -47,7 +47,64 @@ pub enum ErrorParam { }, } -/// Representa el contexto de un documento HTML. +pub trait Contextual: LangId { + // Contextual BUILDER ************************************************************************** + + /// Asigna la fuente de idioma del documento. + #[builder_fn] + fn with_langid(self, language: &impl LangId) -> Self; + + /// Asigna la solicitud HTTP al contexto. + #[builder_fn] + fn with_request(self, request: Option<HttpRequest>) -> Self; + + /// Asigna el tema para renderizar el documento. + #[builder_fn] + fn with_theme(self, theme_name: &'static str) -> Self; + + /// Asigna la composición para renderizar el documento. + #[builder_fn] + fn with_layout(self, layout_name: &'static str) -> Self; + + /// Añade o modifica un parámetro dinámico del contexto. + #[builder_fn] + fn with_param<T: 'static>(self, key: &'static str, value: T) -> Self; + + /// Define los recursos del contexto usando [`AssetsOp`]. + #[builder_fn] + fn with_assets(self, op: AssetsOp) -> Self; + + // Contextual GETTERS ************************************************************************** + + /// Devuelve una referencia a la solicitud HTTP asociada, si existe. + fn request(&self) -> Option<&HttpRequest>; + + /// Devuelve el tema que se usará para renderizar el documento. + fn theme(&self) -> ThemeRef; + + /// Devuelve la composición para renderizar el documento. Por defecto es `"default"`. + fn layout(&self) -> &str; + + /// Recupera un parámetro como [`Option`], simplificando el acceso. + fn param<T: 'static>(&self, key: &'static str) -> Option<&T>; + + /// Devuelve el Favicon de los recursos del contexto. + fn favicon(&self) -> Option<&Favicon>; + + /// Devuelve las hojas de estilo de los recursos del contexto. + fn stylesheets(&self) -> &Assets<StyleSheet>; + + /// Devuelve los scripts JavaScript de los recursos del contexto. + fn javascripts(&self) -> &Assets<JavaScript>; + + // Contextual HELPERS ************************************************************************** + + /// Devuelve un identificador único dentro del contexto para el tipo `T`, si no se proporciona + /// un `id` explícito. + fn required_id<T>(&mut self, id: Option<String>) -> String; +} + +/// Implementa el contexto de un documento HTML. /// /// Se crea internamente para manejar información relevante del documento, como la solicitud HTTP de /// origen, el idioma, tema y composición para el renderizado, los recursos *favicon* ([`Favicon`]), @@ -107,7 +164,7 @@ pub struct Context { favicon : Option<Favicon>, // Favicon, si se ha definido. stylesheets: Assets<StyleSheet>, // Hojas de estilo CSS. javascripts: Assets<JavaScript>, // Scripts JavaScript. - params : HashMap<&'static str, (Box<dyn Any>, &'static str)>, // Parámetros definidos en tiempo de ejecución. + params : HashMap<&'static str, (Box<dyn Any>, &'static str)>, // Parámetros en ejecución. id_counter : usize, // Contador para generar identificadores únicos. } @@ -151,80 +208,6 @@ impl Context { } } - // Context BUILDER ***************************************************************************** - - /// Modifica la fuente de idioma del documento. - #[builder_fn] - pub fn with_langid(mut self, language: &impl LangId) -> Self { - self.langid = language.langid(); - self - } - - /// Modifica el tema que se usará para renderizar el documento. - /// - /// Localiza el tema por su [`short_name()`](crate::core::AnyInfo::short_name), y si no aplica - /// ninguno entonces usará el tema por defecto. - #[builder_fn] - pub fn with_theme(mut self, theme_name: &'static str) -> Self { - self.theme = theme_by_short_name(theme_name).unwrap_or(*DEFAULT_THEME); - self - } - - /// Modifica la composición para renderizar el documento. - #[builder_fn] - pub fn with_layout(mut self, layout_name: &'static str) -> Self { - self.layout = layout_name; - self - } - - /// Define los recursos del contexto usando [`AssetsOp`]. - #[builder_fn] - pub fn with_assets(mut self, op: AssetsOp) -> Self { - match op { - // Favicon. - AssetsOp::SetFavicon(favicon) => { - self.favicon = favicon; - } - AssetsOp::SetFaviconIfNone(icon) => { - if self.favicon.is_none() { - self.favicon = Some(icon); - } - } - // Stylesheets. - AssetsOp::AddStyleSheet(css) => { - self.stylesheets.add(css); - } - AssetsOp::RemoveStyleSheet(path) => { - self.stylesheets.remove(path); - } - // JavaScripts. - AssetsOp::AddJavaScript(js) => { - self.javascripts.add(js); - } - AssetsOp::RemoveJavaScript(path) => { - self.javascripts.remove(path); - } - } - self - } - - // Context GETTERS ***************************************************************************** - - /// Devuelve una referencia a la solicitud HTTP asociada, si existe. - pub fn request(&self) -> Option<&HttpRequest> { - self.request.as_ref() - } - - /// Devuelve el tema que se usará para renderizar el documento. - pub fn theme(&self) -> ThemeRef { - self.theme - } - - /// Devuelve la composición para renderizar el documento. Por defecto es `"default"`. - pub fn layout(&self) -> &str { - self.layout - } - // Context RENDER ****************************************************************************** /// Renderiza los recursos del contexto. @@ -240,61 +223,6 @@ impl Context { // Context PARAMS ****************************************************************************** - /// Añade o modifica un parámetro dinámico del contexto. - /// - /// El valor se guarda conservando el *nombre del tipo* real para mejorar los mensajes de error - /// posteriores. - /// - /// # Ejemplos - /// - /// ```rust - /// use pagetop::prelude::*; - /// - /// let cx = Context::new(None) - /// .with_param("usuario_id", 42_i32) - /// .with_param("titulo", String::from("Hola")) - /// .with_param("flags", vec!["a", "b"]); - /// ``` - #[builder_fn] - pub fn with_param<T: 'static>(mut self, key: &'static str, value: T) -> Self { - let type_name = TypeInfo::FullName.of::<T>(); - self.params.insert(key, (Box::new(value), type_name)); - self - } - - /// Recupera un parámetro como [`Option`], simplificando el acceso. - /// - /// A diferencia de [`get_param`](Self::get_param), que devuelve un [`Result`] con información - /// detallada de error, este método devuelve `None` tanto si la clave no existe como si el valor - /// guardado no coincide con el tipo solicitado. - /// - /// Resulta útil en escenarios donde sólo interesa saber si el valor existe y es del tipo - /// correcto, sin necesidad de diferenciar entre error de ausencia o de tipo. - /// - /// # Ejemplo - /// - /// ```rust - /// use pagetop::prelude::*; - /// - /// let cx = Context::new(None).with_param("username", String::from("Alice")); - /// - /// // Devuelve Some(&String) si existe y coincide el tipo. - /// assert_eq!(cx.param::<String>("username").map(|s| s.as_str()), Some("Alice")); - /// - /// // Devuelve None si no existe o si el tipo no coincide. - /// assert!(cx.param::<i32>("username").is_none()); - /// assert!(cx.param::<String>("missing").is_none()); - /// - /// // Acceso con valor por defecto. - /// let user = cx.param::<String>("missing") - /// .cloned() - /// .unwrap_or_else(|| "visitor".to_string()); - /// assert_eq!(user, "visitor"); - /// ``` - pub fn param<T: 'static>(&self, key: &'static str) -> Option<&T> { - self.get_param::<T>(key).ok() - } - /// Recupera una *referencia tipada* al parámetro solicitado. /// /// Devuelve: @@ -328,23 +256,6 @@ impl Context { }) } - /// Elimina un parámetro del contexto. Devuelve `true` si la clave existía y se eliminó. - /// - /// Devuelve `false` en caso contrario. Usar cuando solo interesa borrar la entrada. - /// - /// # Ejemplos - /// - /// ```rust - /// use pagetop::prelude::*; - /// - /// let mut cx = Context::new(None).with_param("temp", 1u8); - /// assert!(cx.remove_param("temp")); - /// assert!(!cx.remove_param("temp")); // ya no existe - /// ``` - pub fn remove_param(&mut self, key: &'static str) -> bool { - self.params.remove(key).is_some() - } - /// Recupera el parámetro solicitado y lo elimina del contexto. /// /// Devuelve: @@ -380,30 +291,21 @@ impl Context { }) } - // Context EXTRAS ****************************************************************************** - - /// Genera un identificador único si no se proporciona uno explícito. + /// Elimina un parámetro del contexto. Devuelve `true` si la clave existía y se eliminó. /// - /// Si no se proporciona un `id`, se genera un identificador único en la forma `<tipo>-<número>` - /// donde `<tipo>` es el nombre corto del tipo en minúsculas (sin espacios) y `<número>` es un - /// contador interno incremental. - pub fn required_id<T>(&mut self, id: Option<String>) -> String { - if let Some(id) = id { - id - } else { - let prefix = TypeInfo::ShortName - .of::<T>() - .trim() - .replace(' ', "_") - .to_lowercase(); - let prefix = if prefix.is_empty() { - "prefix".to_owned() - } else { - prefix - }; - self.id_counter += 1; - join!(prefix, "-", self.id_counter.to_string()) - } + /// Devuelve `false` en caso contrario. Usar cuando solo interesa borrar la entrada. + /// + /// # Ejemplos + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// let mut cx = Context::new(None).with_param("temp", 1u8); + /// assert!(cx.remove_param("temp")); + /// assert!(!cx.remove_param("temp")); // ya no existe + /// ``` + pub fn remove_param(&mut self, key: &'static str) -> bool { + self.params.remove(key).is_some() } } @@ -423,3 +325,173 @@ impl LangId for Context { self.langid } } + +impl Contextual for Context { + // Contextual BUILDER ************************************************************************** + + #[builder_fn] + fn with_request(mut self, request: Option<HttpRequest>) -> Self { + self.request = request; + self + } + + #[builder_fn] + fn with_langid(mut self, language: &impl LangId) -> Self { + self.langid = language.langid(); + self + } + + /// Asigna el tema para renderizar el documento. + /// + /// Localiza el tema por su [`short_name()`](crate::core::AnyInfo::short_name), y si no aplica + /// ninguno entonces usará el tema por defecto. + #[builder_fn] + fn with_theme(mut self, theme_name: &'static str) -> Self { + self.theme = theme_by_short_name(theme_name).unwrap_or(*DEFAULT_THEME); + self + } + + #[builder_fn] + fn with_layout(mut self, layout_name: &'static str) -> Self { + self.layout = layout_name; + self + } + + /// Añade o modifica un parámetro dinámico del contexto. + /// + /// El valor se guarda conservando el *nombre del tipo* real para mejorar los mensajes de error + /// posteriores. + /// + /// # Ejemplos + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// let cx = Context::new(None) + /// .with_param("usuario_id", 42_i32) + /// .with_param("titulo", String::from("Hola")) + /// .with_param("flags", vec!["a", "b"]); + /// ``` + #[builder_fn] + fn with_param<T: 'static>(mut self, key: &'static str, value: T) -> Self { + let type_name = TypeInfo::FullName.of::<T>(); + self.params.insert(key, (Box::new(value), type_name)); + self + } + + #[builder_fn] + fn with_assets(mut self, op: AssetsOp) -> Self { + match op { + // Favicon. + AssetsOp::SetFavicon(favicon) => { + self.favicon = favicon; + } + AssetsOp::SetFaviconIfNone(icon) => { + if self.favicon.is_none() { + self.favicon = Some(icon); + } + } + // Stylesheets. + AssetsOp::AddStyleSheet(css) => { + self.stylesheets.add(css); + } + AssetsOp::RemoveStyleSheet(path) => { + self.stylesheets.remove(path); + } + // JavaScripts. + AssetsOp::AddJavaScript(js) => { + self.javascripts.add(js); + } + AssetsOp::RemoveJavaScript(path) => { + self.javascripts.remove(path); + } + } + self + } + + // Contextual GETTERS ************************************************************************** + + fn request(&self) -> Option<&HttpRequest> { + self.request.as_ref() + } + + fn theme(&self) -> ThemeRef { + self.theme + } + + fn layout(&self) -> &str { + self.layout + } + + /// Recupera un parámetro como [`Option`], simplificando el acceso. + /// + /// A diferencia de [`get_param`](Self::get_param), que devuelve un [`Result`] con información + /// detallada de error, este método devuelve `None` tanto si la clave no existe como si el valor + /// guardado no coincide con el tipo solicitado. + /// + /// Resulta útil en escenarios donde sólo interesa saber si el valor existe y es del tipo + /// correcto, sin necesidad de diferenciar entre error de ausencia o de tipo. + /// + /// # Ejemplo + /// + /// ```rust + /// use pagetop::prelude::*; + /// + /// let cx = Context::new(None).with_param("username", String::from("Alice")); + /// + /// // Devuelve Some(&String) si existe y coincide el tipo. + /// assert_eq!(cx.param::<String>("username").map(|s| s.as_str()), Some("Alice")); + /// + /// // Devuelve None si no existe o si el tipo no coincide. + /// assert!(cx.param::<i32>("username").is_none()); + /// assert!(cx.param::<String>("missing").is_none()); + /// + /// // Acceso con valor por defecto. + /// let user = cx.param::<String>("missing") + /// .cloned() + /// .unwrap_or_else(|| "visitor".to_string()); + /// assert_eq!(user, "visitor"); + /// ``` + fn param<T: 'static>(&self, key: &'static str) -> Option<&T> { + self.get_param::<T>(key).ok() + } + + fn favicon(&self) -> Option<&Favicon> { + self.favicon.as_ref() + } + + fn stylesheets(&self) -> &Assets<StyleSheet> { + &self.stylesheets + } + + fn javascripts(&self) -> &Assets<JavaScript> { + &self.javascripts + } + + // Contextual HELPERS ************************************************************************** + + /// Devuelve un identificador único dentro del contexto para el tipo `T`, si no se proporciona + /// un `id` explícito. + /// + /// Si no se proporciona un `id`, se genera un identificador único en la forma `<tipo>-<número>` + /// donde `<tipo>` es el nombre corto del tipo en minúsculas (sin espacios) y `<número>` es un + /// contador interno incremental. + fn required_id<T>(&mut self, id: Option<String>) -> String { + if let Some(id) = id { + id + } else { + let prefix = TypeInfo::ShortName + .of::<T>() + .trim() + .replace(' ', "_") + .to_lowercase(); + let prefix = if prefix.is_empty() { + "prefix".to_owned() + } else { + prefix + }; + self.id_counter += 1; + join!(prefix, "-", self.id_counter.to_string()) + } + } +} diff --git a/src/response/page.rs b/src/response/page.rs index 0942f8c8..77bc9c47 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -8,7 +8,8 @@ use crate::builder_fn; use crate::core::component::{Child, ChildOp, Component}; use crate::core::theme::{ChildrenInRegions, ThemeRef, REGION_CONTENT}; use crate::html::{html, Markup, DOCTYPE}; -use crate::html::{AssetsOp, Context}; +use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; +use crate::html::{AssetsOp, Context, Contextual}; use crate::html::{AttrClasses, ClassesOp}; use crate::html::{AttrId, AttrL10n}; use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier}; @@ -25,9 +26,9 @@ pub struct Page { description : AttrL10n, metadata : Vec<(&'static str, &'static str)>, properties : Vec<(&'static str, &'static str)>, - context : Context, body_id : AttrId, body_classes: AttrClasses, + context : Context, regions : ChildrenInRegions, } @@ -43,9 +44,9 @@ impl Page { description : AttrL10n::default(), metadata : Vec::default(), properties : Vec::default(), - context : Context::new(request), body_id : AttrId::default(), body_classes: AttrClasses::default(), + context : Context::new(request), regions : ChildrenInRegions::default(), } } @@ -80,40 +81,6 @@ impl Page { self } - /// Modifica la fuente de idioma de la página ([`Context::with_langid()`]). - #[builder_fn] - pub fn with_langid(mut self, language: &impl LangId) -> Self { - self.context.alter_langid(language); - self - } - - /// Modifica el tema que se usará para renderizar la página ([`Context::with_theme()`]). - #[builder_fn] - pub fn with_theme(mut self, theme_name: &'static str) -> Self { - self.context.alter_theme(theme_name); - self - } - - /// Modifica la composición para renderizar la página ([`Context::with_layout()`]). - #[builder_fn] - pub fn with_layout(mut self, layout_name: &'static str) -> Self { - self.context.alter_layout(layout_name); - self - } - - /// Define los recursos de la página usando [`AssetsOp`]. - #[builder_fn] - pub fn with_assets(mut self, op: AssetsOp) -> Self { - self.context.alter_assets(op); - self - } - - #[builder_fn] - pub fn with_param<T: 'static>(mut self, key: &'static str, value: T) -> Self { - self.context.alter_param(key, value); - self - } - /// Establece el atributo `id` del elemento `<body>`. #[builder_fn] pub fn with_body_id(mut self, id: impl AsRef<str>) -> Self { @@ -205,25 +172,6 @@ impl Page { &self.properties } - /// Devuelve la solicitud HTTP asociada. - pub fn request(&self) -> Option<&HttpRequest> { - self.context.request() - } - - /// Devuelve el tema que se usará para renderizar la página. - pub fn theme(&self) -> ThemeRef { - self.context.theme() - } - - /// Devuelve la composición para renderizar la página. Por defecto es `"default"`. - pub fn layout(&self) -> &str { - self.context.layout() - } - - pub fn param<T: 'static>(&self, key: &'static str) -> Option<&T> { - self.context.param(key) - } - /// Devuelve el identificador del elemento `<body>`. pub fn body_id(&self) -> &AttrId { &self.body_id @@ -233,19 +181,19 @@ impl Page { pub fn body_classes(&self) -> &AttrClasses { &self.body_classes } - /* - /// Devuelve una referencia mutable al [`Context`] de la página. - /// - /// El [`Context`] actúa como intermediario para muchos métodos de `Page` (idioma, tema, - /// *layout*, recursos, solicitud HTTP, etc.). Resulta especialmente útil cuando un componente - /// o un tema necesita recibir el contexto como parámetro. - pub fn context(&mut self) -> &mut Context { - &mut self.context - } - */ + + /// Devuelve una referencia mutable al [`Context`] de la página. + /// + /// El [`Context`] actúa como intermediario para muchos métodos de `Page` (idioma, tema, + /// *layout*, recursos, solicitud HTTP, etc.). Resulta especialmente útil cuando un componente + /// o un tema necesita recibir el contexto como parámetro. + pub fn context(&mut self) -> &mut Context { + &mut self.context + } + // Page RENDER ********************************************************************************* - /// Renderiza los componentes de una región (`regiona_name`) de la página. + /// Renderiza los componentes de una región (`region_name`) de la página. pub fn render_region(&mut self, region_name: &'static str) -> Markup { self.regions .merge_all_components(self.context.theme(), region_name) @@ -302,3 +250,79 @@ impl LangId for Page { self.context.langid() } } + +impl Contextual for Page { + // Contextual BUILDER ************************************************************************** + + #[builder_fn] + fn with_request(mut self, request: Option<HttpRequest>) -> Self { + self.context.alter_request(request); + self + } + + #[builder_fn] + fn with_langid(mut self, language: &impl LangId) -> Self { + self.context.alter_langid(language); + self + } + + #[builder_fn] + fn with_theme(mut self, theme_name: &'static str) -> Self { + self.context.alter_theme(theme_name); + self + } + + #[builder_fn] + fn with_layout(mut self, layout_name: &'static str) -> Self { + self.context.alter_layout(layout_name); + self + } + + #[builder_fn] + fn with_param<T: 'static>(mut self, key: &'static str, value: T) -> Self { + self.context.alter_param(key, value); + self + } + + #[builder_fn] + fn with_assets(mut self, op: AssetsOp) -> Self { + self.context.alter_assets(op); + self + } + + // Contextual GETTERS ************************************************************************** + + fn request(&self) -> Option<&HttpRequest> { + self.context.request() + } + + fn theme(&self) -> ThemeRef { + self.context.theme() + } + + fn layout(&self) -> &str { + self.context.layout() + } + + fn param<T: 'static>(&self, key: &'static str) -> Option<&T> { + self.context.param(key) + } + + fn favicon(&self) -> Option<&Favicon> { + self.context.favicon() + } + + fn stylesheets(&self) -> &Assets<StyleSheet> { + self.context.stylesheets() + } + + fn javascripts(&self) -> &Assets<JavaScript> { + self.context.javascripts() + } + + // Contextual HELPERS ************************************************************************** + + fn required_id<T>(&mut self, id: Option<String>) -> String { + self.context.required_id::<T>(id) + } +} diff --git a/src/response/page/error.rs b/src/response/page/error.rs index ab56338f..be48e3ed 100644 --- a/src/response/page/error.rs +++ b/src/response/page/error.rs @@ -1,4 +1,5 @@ use crate::base::component::Html; +use crate::html::Contextual; use crate::locale::L10n; use crate::response::ResponseError; use crate::service::http::{header::ContentType, StatusCode}; From 6f11207d8ee471d040d7bc5461fe281828d07218 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 8 Sep 2025 00:10:23 +0200 Subject: [PATCH 167/244] =?UTF-8?q?=F0=9F=93=9D=20Mejora=20la=20documentac?= =?UTF-8?q?i=C3=B3n=20de=20recursos=20y=20contexto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/global.rs | 12 ++++---- src/html/assets.rs | 32 ++++++++++++++++++- src/html/assets/javascript.rs | 4 ++- src/html/assets/stylesheet.rs | 4 ++- src/html/context.rs | 58 +++++++++++++++++++++++++++-------- 5 files changed, 88 insertions(+), 22 deletions(-) diff --git a/src/global.rs b/src/global.rs index c81eec99..ccc6d9de 100644 --- a/src/global.rs +++ b/src/global.rs @@ -48,13 +48,13 @@ pub struct App { pub description: String, /// Tema predeterminado. pub theme: String, - /// Idioma por defecto de la aplicación. + /// Idioma por defecto para la aplicación. /// - /// Si este valor no es válido, el idioma efectivo para el renderizado se resolverá mediante la - /// implementación de [`LangId`](crate::locale::LangId) en este orden: primero, el establecido - /// explícitamente con [`Contextual::with_langid()`](crate::html::Contextual::with_langid); si - /// no se ha definido, se usará el indicado en la cabecera `Accept-Language` del navegador; y, - /// si ninguno aplica, se empleará el idioma de respaldo ("en-US"). + /// Si no está definido o no es válido, el idioma efectivo para el renderizado se resolverá + /// según la implementación de [`LangId`](crate::locale::LangId) en este orden: primero intenta + /// con el establecido en [`Contextual::with_langid()`](crate::html::Contextual::with_langid); + /// pero si no se ha definido explícitamente, usará el indicado en la cabecera `Accept-Language` + /// del navegador; y, si ninguno aplica, se empleará el idioma de respaldo ("en-US"). pub language: String, /// Banner ASCII mostrado al inicio: *"Off"* (desactivado), *"Slant"*, *"Small"*, *"Speed"* o /// *"Starwars"*. diff --git a/src/html/assets.rs b/src/html/assets.rs index e53e8e35..ee5431f0 100644 --- a/src/html/assets.rs +++ b/src/html/assets.rs @@ -5,22 +5,49 @@ pub mod stylesheet; use crate::html::{html, Markup, Render}; use crate::{AutoDefault, Weight}; +/// Representación genérica de un *script* [`JavaScript`](crate::html::JavaScript) o una hoja de +/// estilos [`StyleSheet`](crate::html::StyleSheet). +/// +/// Estos recursos se incluyen en los conjuntos de recursos ([`Assets`]) que suelen renderizarse en +/// un documento HTML. +/// +/// Cada recurso se identifica por un **nombre único** ([`Asset::name()`]), usado como clave; y un +/// **peso** ([`Asset::weight()`]), que determina su orden relativo de renderizado. pub trait Asset: Render { /// Devuelve el nombre del recurso, utilizado como clave única. fn name(&self) -> &str; - /// Devuelve el peso del recurso, durante el renderizado se procesan de menor a mayor peso. + /// Devuelve el peso del recurso, usado para ordenar el renderizado de menor a mayor peso. fn weight(&self) -> Weight; } +/// Gestión común para conjuntos de recursos como [`JavaScript`](crate::html::JavaScript) y +/// [`StyleSheet`](crate::html::StyleSheet). +/// +/// Se emplea normalmente para agrupar, administrar y renderizar los recursos de un documento HTML. +/// Cada recurso se identifica por un nombre único ([`Asset::name()`]) y tiene asociado un peso +/// ([`Asset::weight()`]) que determina su orden de renderizado. +/// +/// Durante el renderizado, los recursos se procesan en orden ascendente de peso. En caso de +/// igualdad, se respeta el orden de inserción. #[derive(AutoDefault)] pub struct Assets<T>(Vec<T>); impl<T: Asset> Assets<T> { + /// Crea un nuevo conjunto vacío de recursos. + /// + /// Normalmente no se instancia directamente, sino como parte de la gestión de recursos que + /// hacen páginas o temas. pub fn new() -> Self { Self(Vec::new()) } + /// Inserta un recurso. + /// + /// Si no existe otro con el mismo nombre, lo añade. Si ya existe y su peso era mayor, lo + /// reemplaza. Y si su peso era menor o igual, entonces no realiza ningún cambio. + /// + /// Devuelve `true` si el recurso fue insertado o reemplazado. pub fn add(&mut self, asset: T) -> bool { match self.0.iter().position(|x| x.name() == asset.name()) { Some(index) => { @@ -39,6 +66,9 @@ impl<T: Asset> Assets<T> { } } + /// Elimina un recurso por nombre. + /// + /// Devuelve `true` si el recurso existía y fue eliminado. pub fn remove(&mut self, name: impl AsRef<str>) -> bool { if let Some(index) = self.0.iter().position(|x| x.name() == name.as_ref()) { self.0.remove(index); diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs index 89b5261c..be6f9060 100644 --- a/src/html/assets/javascript.rs +++ b/src/html/assets/javascript.rs @@ -138,7 +138,9 @@ impl JavaScript { } impl Asset for JavaScript { - // Para *scripts* externos es la ruta; para *scripts* embebidos, un identificador. + /// Devuelve el nombre del recurso, utilizado como clave única. + /// + /// Para *scripts* externos es la ruta del recurso; para *scripts* embebidos, un identificador. fn name(&self) -> &str { match &self.source { Source::From(path) => path, diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index a5537264..38a97d7f 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -143,7 +143,9 @@ impl StyleSheet { } impl Asset for StyleSheet { - // Para hojas de estilos externas es la ruta; para las embebidas, un identificador. + /// Devuelve el nombre del recurso, utilizado como clave única. + /// + /// Para hojas de estilos externas es la ruta del recurso; para las embebidas, un identificador. fn name(&self) -> &str { match &self.source { Source::From(path) => path, diff --git a/src/html/context.rs b/src/html/context.rs index 7af884cf..79148b06 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -47,22 +47,52 @@ pub enum ErrorParam { }, } +/// Interfaz para gestionar el **contexto de renderizado** de un documento HTML. +/// +/// `Contextual` extiende [`LangId`] y define los métodos para: +/// +/// - Establecer el **idioma** del documento. +/// - Almacenar la **solicitud HTTP** de origen. +/// - Seleccionar **tema** y **composición** (*layout*) de renderizado. +/// - Administrar **recursos** del documento como el icono [`Favicon`], las hojas de estilo +/// [`StyleSheet`] o los *scripts* [`JavaScript`] mediante [`AssetsOp`]. +/// - Leer y mantener **parámetros dinámicos tipados** de contexto. +/// - Generar **identificadores únicos** por tipo de componente. +/// +/// Lo implementan, típicamente, estructuras que representan el contexto de renderizado, como +/// [`Context`](crate::html::Context) o [`Page`](crate::response::page::Page). +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// fn prepare_context<C: Contextual>(cx: C) -> C { +/// cx.with_langid(&LangMatch::resolve("es-ES")) +/// .with_theme("aliner") +/// .with_layout("default") +/// .with_assets(AssetsOp::SetFavicon(Some(Favicon::new().with_icon("/favicon.ico")))) +/// .with_assets(AssetsOp::AddStyleSheet(StyleSheet::from("/css/app.css"))) +/// .with_assets(AssetsOp::AddJavaScript(JavaScript::defer("/js/app.js"))) +/// .with_param("usuario_id", 42_i32) +/// } +/// ``` pub trait Contextual: LangId { // Contextual BUILDER ************************************************************************** - /// Asigna la fuente de idioma del documento. + /// Establece el idioma del documento. #[builder_fn] fn with_langid(self, language: &impl LangId) -> Self; - /// Asigna la solicitud HTTP al contexto. + /// Almacena la solicitud HTTP de origen en el contexto. #[builder_fn] fn with_request(self, request: Option<HttpRequest>) -> Self; - /// Asigna el tema para renderizar el documento. + /// Especifica el tema para renderizar el documento. #[builder_fn] fn with_theme(self, theme_name: &'static str) -> Self; - /// Asigna la composición para renderizar el documento. + /// Especifica la composición para renderizar el documento. #[builder_fn] fn with_layout(self, layout_name: &'static str) -> Self; @@ -85,7 +115,7 @@ pub trait Contextual: LangId { /// Devuelve la composición para renderizar el documento. Por defecto es `"default"`. fn layout(&self) -> &str; - /// Recupera un parámetro como [`Option`], simplificando el acceso. + /// Recupera un parámetro como [`Option`]. fn param<T: 'static>(&self, key: &'static str) -> Option<&T>; /// Devuelve el Favicon de los recursos del contexto. @@ -94,22 +124,24 @@ pub trait Contextual: LangId { /// Devuelve las hojas de estilo de los recursos del contexto. fn stylesheets(&self) -> &Assets<StyleSheet>; - /// Devuelve los scripts JavaScript de los recursos del contexto. + /// Devuelve los *scripts* JavaScript de los recursos del contexto. fn javascripts(&self) -> &Assets<JavaScript>; // Contextual HELPERS ************************************************************************** - /// Devuelve un identificador único dentro del contexto para el tipo `T`, si no se proporciona - /// un `id` explícito. + /// Genera un identificador único por tipo (`<tipo>-<n>`) cuando no se aporta uno explícito. + /// + /// Es útil para componentes u otros elementos HTML que necesitan un identificador predecible si + /// no se proporciona ninguno. fn required_id<T>(&mut self, id: Option<String>) -> String; } -/// Implementa el contexto de un documento HTML. +/// Implementa un **contexto de renderizado** para un documento HTML. /// -/// Se crea internamente para manejar información relevante del documento, como la solicitud HTTP de -/// origen, el idioma, tema y composición para el renderizado, los recursos *favicon* ([`Favicon`]), -/// hojas de estilo ([`StyleSheet`]) y *scripts* ([`JavaScript`]), así como *parámetros dinámicos -/// heterogéneos* de contexto definidos en tiempo de ejecución. +/// Extiende [`Contextual`] con métodos para **instanciar** y configurar un nuevo contexto, +/// **renderizar los recursos** del documento (incluyendo el [`Favicon`], las hojas de estilo +/// [`StyleSheet`] y los *scripts* [`JavaScript`]), o extender el uso de **parámetros dinámicos +/// tipados** con nuevos métodos. /// /// # Ejemplos /// From 50ba58ed74c4802ec170b0a276aebeab403eedd2 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 8 Sep 2025 18:57:09 +0200 Subject: [PATCH 168/244] =?UTF-8?q?=E2=9C=A8=20(context):=20A=C3=B1ade=20m?= =?UTF-8?q?=C3=A9todos=20auxiliares=20de=20par=C3=A1metros?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html/context.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/html/context.rs b/src/html/context.rs index 79148b06..26e2478c 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -118,6 +118,21 @@ pub trait Contextual: LangId { /// Recupera un parámetro como [`Option`]. fn param<T: 'static>(&self, key: &'static str) -> Option<&T>; + /// Devuelve el parámetro clonado o el **valor por defecto del tipo** (`T::default()`). + fn param_or_default<T: Default + Clone + 'static>(&self, key: &'static str) -> T { + self.param::<T>(key).cloned().unwrap_or_default() + } + + /// Devuelve el parámetro clonado o un **valor por defecto** si no existe. + fn param_or<T: Clone + 'static>(&self, key: &'static str, default: T) -> T { + self.param::<T>(key).cloned().unwrap_or(default) + } + + /// Devuelve el parámetro clonado o el **valor evaluado** por la función `f` si no existe. + fn param_or_else<T: Clone + 'static, F: FnOnce() -> T>(&self, key: &'static str, f: F) -> T { + self.param::<T>(key).cloned().unwrap_or_else(f) + } + /// Devuelve el Favicon de los recursos del contexto. fn favicon(&self) -> Option<&Favicon>; From 415e524f69a82f78f6d0c26fc343b4231b0d09e5 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 8 Sep 2025 23:27:56 +0200 Subject: [PATCH 169/244] =?UTF-8?q?=F0=9F=8E=A8=20Generaliza=20p=C3=A1gina?= =?UTF-8?q?=20de=20bienvenida=20con=20par=C3=A1metros?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/extension/welcome.rs | 4 +++- src/base/theme/basic.rs | 25 +++++++++++++++---------- src/response/page.rs | 11 ++++++----- src/response/page/error.rs | 4 ++-- static/css/intro.css | 23 +++++++++++++++++++++-- 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs index 3c0de3db..eaa9f339 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -24,11 +24,13 @@ impl Extension for Welcome { async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { let app = &global::SETTINGS.app.name; - Page::new(Some(request)) + Page::new(request) .with_theme("basic") .with_layout("intro") .with_title(L10n::l("welcome_title")) .with_description(L10n::l("welcome_intro").with_arg("app", app)) + .with_param("intro_button_text", L10n::l("welcome_powered")) + .with_param("intro_button_link", "https://pagetop.cillero.es".to_owned()) .add_component(Html::with(|cx| { html! { p { (L10n::l("welcome_text1").using(cx)) } diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index dc16f2ac..fbf4caf5 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -41,6 +41,9 @@ fn render_intro(page: &mut Page) -> Markup { let title = page.title().unwrap_or_default(); let intro = page.description().unwrap_or_default(); + let intro_button_text: L10n = page.param_or_default("intro_button_text"); + let intro_button_link: Option<&String> = page.param("intro_button_link"); + html! { body id=[page.body_id().get()] class=[page.body_classes().get()] { header class="intro-header" { @@ -71,16 +74,18 @@ fn render_intro(page: &mut Page) -> Markup { } 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)) + @if intro_button_link.is_some() { + div class="intro-button" { + a + class="intro-button__link" + href=[intro_button_link] + target="_blank" + rel="noreferrer" + { + span {} span {} span {} + div class="intro-button__text" { + (intro_button_text.using(page)) + } } } } diff --git a/src/response/page.rs b/src/response/page.rs index 77bc9c47..86a0bdcc 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -4,7 +4,6 @@ pub use error::ErrorPage; pub use actix_web::Result as ResultPage; use crate::base::action; -use crate::builder_fn; use crate::core::component::{Child, ChildOp, Component}; use crate::core::theme::{ChildrenInRegions, ThemeRef, REGION_CONTENT}; use crate::html::{html, Markup, DOCTYPE}; @@ -14,6 +13,7 @@ use crate::html::{AttrClasses, ClassesOp}; use crate::html::{AttrId, AttrL10n}; use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier}; use crate::service::HttpRequest; +use crate::{builder_fn, AutoDefault}; /// Representa una página HTML completa lista para renderizar. /// @@ -21,6 +21,7 @@ use crate::service::HttpRequest; /// regiones donde disponer los componentes, atributos de `<body>` y otros aspectos del contexto de /// renderizado. #[rustfmt::skip] +#[derive(AutoDefault)] pub struct Page { title : AttrL10n, description : AttrL10n, @@ -35,10 +36,10 @@ pub struct Page { impl Page { /// Crea una nueva instancia de página. /// - /// Si se proporciona la solicitud HTTP, se guardará en el contexto de renderizado de la página - /// para poder ser recuperada por los componentes si es necesario. + /// La solicitud HTTP se guardará en el contexto de renderizado de la página para poder ser + /// recuperada por los componentes si es necesario. #[rustfmt::skip] - pub fn new(request: Option<HttpRequest>) -> Self { + pub fn new(request: HttpRequest) -> Self { Page { title : AttrL10n::default(), description : AttrL10n::default(), @@ -46,7 +47,7 @@ impl Page { properties : Vec::default(), body_id : AttrId::default(), body_classes: AttrClasses::default(), - context : Context::new(request), + context : Context::new(Some(request)), regions : ChildrenInRegions::default(), } } diff --git a/src/response/page/error.rs b/src/response/page/error.rs index be48e3ed..2355d234 100644 --- a/src/response/page/error.rs +++ b/src/response/page/error.rs @@ -29,7 +29,7 @@ impl Display for ErrorPage { ErrorPage::BadRequest(_) => write!(f, "Bad Client Data"), // Error 403. ErrorPage::AccessDenied(request) => { - let mut error_page = Page::new(Some(request.clone())); + let mut error_page = Page::new(request.clone()); let error403 = error_page.theme().error403(&mut error_page); if let Ok(page) = error_page .with_title(L10n::n("Error FORBIDDEN")) @@ -44,7 +44,7 @@ impl Display for ErrorPage { } // Error 404. ErrorPage::NotFound(request) => { - let mut error_page = Page::new(Some(request.clone())); + let mut error_page = Page::new(request.clone()); let error404 = error_page.theme().error404(&mut error_page); if let Ok(page) = error_page .with_title(L10n::n("Error RESOURCE NOT FOUND")) diff --git a/static/css/intro.css b/static/css/intro.css index 5a5461e4..19fa9f15 100644 --- a/static/css/intro.css +++ b/static/css/intro.css @@ -5,9 +5,13 @@ --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; --color-gray: #e4e4e7; --color-link: #1e4eae; + --color-block-1: #fecaca; + --color-block-2: #e6a9e2; + --color-block-3: #b689ff; + --color-block-4: #ffedca; + --color-block-5: #ffffff; --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); @@ -413,9 +417,24 @@ a:hover:visited { left: -15%; width: 130%; z-index: -10; - background: var(--color-red); + background: var(--color-block-1); transform: rotate(2deg); } +.intro-text .block:nth-of-type(5n+1) .block__title:after { + background: var(--color-block-1); +} +.intro-text .block:nth-of-type(5n+2) .block__title:after { + background: var(--color-block-2); +} +.intro-text .block:nth-of-type(5n+3) .block__title:after { + background: var(--color-block-3); +} +.intro-text .block:nth-of-type(5n+4) .block__title:after { + background: var(--color-block-4); +} +.intro-text .block:nth-of-type(5n+5) .block__title:after { + background: var(--color-block-5); +} /* * Footer From b16c9378d05626f4222b4c3c28c72bd7b4fc66e6 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 9 Sep 2025 01:01:18 +0200 Subject: [PATCH 170/244] =?UTF-8?q?=F0=9F=A9=B9=20Corrige=20doc=20y=20c?= =?UTF-8?q?=C3=B3digo=20por=20cambios=20en=20Page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- examples/hello-name.rs | 2 +- examples/hello-world.rs | 2 +- src/lib.rs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9d5efc88..c6c12e0e 100644 --- a/README.md +++ b/README.md @@ -59,8 +59,8 @@ impl Extension for HelloWorld { } async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { - Page::new(Some(request)) - .with_component(Html::with(move |_| html! { h1 { "Hello World!" } })) + Page::new(request) + .add_component(Html::with(move |_| html! { h1 { "Hello World!" } })) .render() } diff --git a/examples/hello-name.rs b/examples/hello-name.rs index 3a491a68..e1285d09 100644 --- a/examples/hello-name.rs +++ b/examples/hello-name.rs @@ -13,7 +13,7 @@ async fn hello_name( path: service::web::Path<String>, ) -> ResultPage<Markup, ErrorPage> { let name = path.into_inner(); - Page::new(Some(request)) + Page::new(request) .add_component(Html::with(move |_| html! { h1 { "Hello " (name) "!" } })) .render() } diff --git a/examples/hello-world.rs b/examples/hello-world.rs index 5550514b..d56f2105 100644 --- a/examples/hello-world.rs +++ b/examples/hello-world.rs @@ -9,7 +9,7 @@ impl Extension for HelloWorld { } async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { - Page::new(Some(request)) + Page::new(request) .add_component(Html::with(move |_| html! { h1 { "Hello World!" } })) .render() } diff --git a/src/lib.rs b/src/lib.rs index e43da2f2..93b8564b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,8 +60,8 @@ impl Extension for HelloWorld { } async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { - Page::new(Some(request)) - .with_component(Html::with(move |_| html! { h1 { "Hello World!" } })) + Page::new(request) + .add_component(Html::with(move |_| html! { h1 { "Hello World!" } })) .render() } From 7179cf08314d36583a4fc9c140fb25aaa56c43b3 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 11 Sep 2025 19:03:34 +0200 Subject: [PATCH 171/244] =?UTF-8?q?=F0=9F=8E=A8=20Unifica=20conversiones?= =?UTF-8?q?=20a=20String=20con=20`to=5Fstring()`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Como `String::from()` y `.to_string()` son equivalentes, se sustituyen todas las ocurrencias de `String::from()` por `to_string()` para mayor coherencia y legibilidad. --- src/app.rs | 2 +- src/base/component/html.rs | 2 +- src/core/theme/regions.rs | 2 +- src/html.rs | 4 ++-- src/html/assets/favicon.rs | 2 +- src/html/attr_classes.rs | 2 +- src/html/attr_l10n.rs | 4 ++-- src/html/attr_value.rs | 2 +- src/html/context.rs | 10 +++++----- src/locale.rs | 4 ++-- src/util.rs | 22 +++++++++++----------- tests/component_html.rs | 2 +- 12 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/app.rs b/src/app.rs index 94d901f1..c8ffba11 100644 --- a/src/app.rs +++ b/src/app.rs @@ -84,7 +84,7 @@ impl Application { if let Some((Width(term_width), _)) = terminal_size() { if term_width >= 80 { let maxlen: usize = ((term_width / 10) - 2).into(); - let mut app = app_name.substring(0, maxlen).to_owned(); + let mut app = app_name.substring(0, maxlen).to_string(); if app_name.len() > maxlen { app = format!("{app}..."); } diff --git a/src/base/component/html.rs b/src/base/component/html.rs index 7bde94a0..8fa56902 100644 --- a/src/base/component/html.rs +++ b/src/base/component/html.rs @@ -25,7 +25,7 @@ use crate::prelude::*; /// use pagetop::prelude::*; /// /// let component = Html::with(|cx| { -/// let user = cx.param::<String>("username").cloned().unwrap_or(String::from("visitor")); +/// let user = cx.param::<String>("username").cloned().unwrap_or("visitor".to_string()); /// html! { /// h1 { "Hello, " (user) } /// } diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index 1a2e0fbb..8082aac9 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -36,7 +36,7 @@ impl Default for Region { fn default() -> Self { Self { key: REGION_CONTENT, - name: String::from(REGION_CONTENT), + name: REGION_CONTENT.to_string(), } } } diff --git a/src/html.rs b/src/html.rs index 9f3d70cf..37ab3f41 100644 --- a/src/html.rs +++ b/src/html.rs @@ -71,11 +71,11 @@ pub type OptionComponent<C: core::component::Component> = core::component::Typed /// use pagetop::prelude::*; /// /// // Texto normal, se escapa automáticamente para evitar inyección de HTML. -/// let fragment = PrepareMarkup::Escaped(String::from("Hola <b>mundo</b>")); +/// let fragment = PrepareMarkup::Escaped("Hola <b>mundo</b>".to_string()); /// assert_eq!(fragment.render().into_string(), "Hola &lt;b&gt;mundo&lt;/b&gt;"); /// /// // HTML literal, se inserta directamente, sin escapado adicional. -/// let raw_html = PrepareMarkup::Raw(String::from("<b>negrita</b>")); +/// let raw_html = PrepareMarkup::Raw("<b>negrita</b>".to_string()); /// assert_eq!(raw_html.render().into_string(), "<b>negrita</b>"); /// /// // Fragmento ya preparado con la macro `html!`. diff --git a/src/html/assets/favicon.rs b/src/html/assets/favicon.rs index 1a8b29e7..e951df58 100644 --- a/src/html/assets/favicon.rs +++ b/src/html/assets/favicon.rs @@ -129,7 +129,7 @@ impl Favicon { icon_color: Option<String>, ) -> Self { let icon_type = match icon_source.rfind('.') { - Some(i) => match icon_source[i..].to_owned().to_lowercase().as_str() { + Some(i) => match icon_source[i..].to_string().to_lowercase().as_str() { ".avif" => Some("image/avif"), ".gif" => Some("image/gif"), ".ico" => Some("image/x-icon"), diff --git a/src/html/attr_classes.rs b/src/html/attr_classes.rs index 91ccfaf0..098c26cd 100644 --- a/src/html/attr_classes.rs +++ b/src/html/attr_classes.rs @@ -37,7 +37,7 @@ pub enum ClassesOp { /// .with_value(ClassesOp::Add, "Active") /// .with_value(ClassesOp::Remove, "btn-primary"); /// -/// assert_eq!(classes.get(), Some(String::from("btn active"))); +/// assert_eq!(classes.get(), Some("btn active".to_string())); /// assert!(classes.contains("active")); /// ``` #[derive(AutoDefault, Clone, Debug)] diff --git a/src/html/attr_l10n.rs b/src/html/attr_l10n.rs index 3e8a4e4b..8250c742 100644 --- a/src/html/attr_l10n.rs +++ b/src/html/attr_l10n.rs @@ -17,13 +17,13 @@ use crate::{builder_fn, AutoDefault}; /// // Español disponible. /// assert_eq!( /// hello.lookup(&LangMatch::resolve("es-ES")), -/// Some(String::from("¡Hola mundo!")) +/// Some("¡Hola mundo!".to_string()) /// ); /// /// // Japonés no disponible, traduce al idioma de respaldo ("en-US"). /// assert_eq!( /// hello.lookup(&LangMatch::resolve("ja-JP")), -/// Some(String::from("Hello world!")) +/// Some("Hello world!".to_string()) /// ); /// /// // Uso típico en un atributo: diff --git a/src/html/attr_value.rs b/src/html/attr_value.rs index c70229f9..4e03120b 100644 --- a/src/html/attr_value.rs +++ b/src/html/attr_value.rs @@ -36,7 +36,7 @@ impl AttrValue { self.0 = if value.is_empty() { None } else { - Some(value.to_owned()) + Some(value.to_string()) }; self } diff --git a/src/html/context.rs b/src/html/context.rs index 26e2478c..8ef3a053 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -285,7 +285,7 @@ impl Context { /// /// let cx = Context::new(None) /// .with_param("usuario_id", 42_i32) - /// .with_param("titulo", String::from("Hola")); + /// .with_param("titulo", "Hola".to_string()); /// /// let id: &i32 = cx.get_param("usuario_id").unwrap(); /// let titulo: &String = cx.get_param("titulo").unwrap(); @@ -318,7 +318,7 @@ impl Context { /// /// let mut cx = Context::new(None) /// .with_param("contador", 7_i32) - /// .with_param("titulo", String::from("Hola")); + /// .with_param("titulo", "Hola".to_string()); /// /// let n: i32 = cx.take_param("contador").unwrap(); /// assert!(cx.get_param::<i32>("contador").is_err()); // ya no está @@ -416,7 +416,7 @@ impl Contextual for Context { /// /// let cx = Context::new(None) /// .with_param("usuario_id", 42_i32) - /// .with_param("titulo", String::from("Hola")) + /// .with_param("titulo", "Hola".to_string()) /// .with_param("flags", vec!["a", "b"]); /// ``` #[builder_fn] @@ -484,7 +484,7 @@ impl Contextual for Context { /// ```rust /// use pagetop::prelude::*; /// - /// let cx = Context::new(None).with_param("username", String::from("Alice")); + /// let cx = Context::new(None).with_param("username", "Alice".to_string()); /// /// // Devuelve Some(&String) si existe y coincide el tipo. /// assert_eq!(cx.param::<String>("username").map(|s| s.as_str()), Some("Alice")); @@ -533,7 +533,7 @@ impl Contextual for Context { .replace(' ', "_") .to_lowercase(); let prefix = if prefix.is_empty() { - "prefix".to_owned() + "prefix".to_string() } else { prefix }; diff --git a/src/locale.rs b/src/locale.rs index cf44dd82..2bf0da90 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -165,7 +165,7 @@ pub trait LangId { /// /// // Idioma no soportado. /// let lang = LangMatch::resolve("ja-JP"); -/// assert_eq!(lang, LangMatch::Unsupported(String::from("ja-JP"))); +/// assert_eq!(lang, LangMatch::Unsupported("ja-JP".to_string())); /// ``` /// /// Con la siguiente instrucción siempre se obtiene un [`LanguageIdentifier`] válido, ya sea porque @@ -222,7 +222,7 @@ impl LangMatch { } // En caso contrario, indica que el idioma no está soportado. - Self::Unsupported(String::from(language)) + Self::Unsupported(language.to_string()) } /// Devuelve el [`LanguageIdentifier`] si el idioma fue reconocido. diff --git a/src/util.rs b/src/util.rs index 808014b2..56b098d8 100644 --- a/src/util.rs +++ b/src/util.rs @@ -110,15 +110,15 @@ macro_rules! hm { /// /// // Concatena todos los fragmentos directamente. /// let result = join!("Hello", " ", "World"); -/// assert_eq!(result, String::from("Hello World")); +/// assert_eq!(result, "Hello World".to_string()); /// /// // También funciona con valores vacíos. /// let result_with_empty = join!("Hello", "", "World"); -/// assert_eq!(result_with_empty, String::from("HelloWorld")); +/// assert_eq!(result_with_empty, "HelloWorld".to_string()); /// /// // Un único fragmento devuelve el mismo valor. /// let single_result = join!("Hello"); -/// assert_eq!(single_result, String::from("Hello")); +/// assert_eq!(single_result, "Hello".to_string()); /// ``` #[macro_export] macro_rules! join { @@ -141,11 +141,11 @@ macro_rules! join { /// /// // Concatena los fragmentos no vacíos con un espacio como separador. /// let result_with_separator = join_opt!(["Hello", "", "World"]; " "); -/// assert_eq!(result_with_separator, Some(String::from("Hello World"))); +/// assert_eq!(result_with_separator, Some("Hello World".to_string())); /// /// // Concatena los fragmentos no vacíos sin un separador. /// let result_without_separator = join_opt!(["Hello", "", "World"]); -/// assert_eq!(result_without_separator, Some(String::from("HelloWorld"))); +/// assert_eq!(result_without_separator, Some("HelloWorld".to_string())); /// /// // Devuelve `None` si todos los fragmentos están vacíos. /// let result_empty = join_opt!(["", "", ""]); @@ -185,19 +185,19 @@ macro_rules! join_opt { /// /// // Concatena los dos fragmentos cuando ambos no están vacíos. /// let result = join_pair!(first, separator, second); -/// assert_eq!(result, String::from("Hello-World")); +/// assert_eq!(result, "Hello-World".to_string()); /// /// // Si el primer fragmento está vacío, devuelve el segundo. /// let result_empty_first = join_pair!("", separator, second); -/// assert_eq!(result_empty_first, String::from("World")); +/// assert_eq!(result_empty_first, "World".to_string()); /// /// // Si el segundo fragmento está vacío, devuelve el primero. /// let result_empty_second = join_pair!(first, separator, ""); -/// assert_eq!(result_empty_second, String::from("Hello")); +/// assert_eq!(result_empty_second, "Hello".to_string()); /// /// // Si ambos fragmentos están vacíos, devuelve una cadena vacía. /// let result_both_empty = join_pair!("", separator, ""); -/// assert_eq!(result_both_empty, String::from("")); +/// assert_eq!(result_both_empty, "".to_string()); /// ``` #[macro_export] macro_rules! join_pair { @@ -224,11 +224,11 @@ macro_rules! join_pair { /// /// // Concatena los fragmentos. /// let result = join_strict!(["Hello", "World"]); -/// assert_eq!(result, Some(String::from("HelloWorld"))); +/// assert_eq!(result, Some("HelloWorld".to_string())); /// /// // Concatena los fragmentos con un separador. /// let result_with_separator = join_strict!(["Hello", "World"]; " "); -/// assert_eq!(result_with_separator, Some(String::from("Hello World"))); +/// assert_eq!(result_with_separator, Some("Hello World".to_string())); /// /// // Devuelve `None` si alguno de los fragmentos está vacío. /// let result_with_empty = join_strict!(["Hello", "", "World"]); diff --git a/tests/component_html.rs b/tests/component_html.rs index bd7f3c08..851315a9 100644 --- a/tests/component_html.rs +++ b/tests/component_html.rs @@ -17,7 +17,7 @@ async fn component_html_renders_static_markup() { #[pagetop::test] async fn component_html_renders_using_context_param() { - let mut cx = Context::new(None).with_param("username", String::from("Alice")); + let mut cx = Context::new(None).with_param("username", "Alice".to_string()); let component = Html::with(|cx| { let name = cx.param::<String>("username").cloned().unwrap_or_default(); From a96a3fdf9f933ddaddbc90146fbb1fcfe10c49e8 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 11 Sep 2025 19:58:50 +0200 Subject: [PATCH 172/244] =?UTF-8?q?=F0=9F=94=A5=20Elimina=20`Render`=20par?= =?UTF-8?q?a=20usar=20siempre=20el=20contexto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/component/definition.rs | 2 +- src/core/theme.rs | 2 +- src/html.rs | 6 +- src/html/assets.rs | 16 ++-- src/html/assets/favicon.rs | 10 ++- src/html/assets/javascript.rs | 144 +++++++++++++++++++++---------- src/html/assets/stylesheet.rs | 34 ++++---- src/html/context.rs | 39 ++++++--- src/html/maud.rs | 21 +---- src/response/page.rs | 2 +- tests/component_poweredby.rs | 31 ++++--- tests/html.rs | 44 +++++----- 12 files changed, 205 insertions(+), 146 deletions(-) diff --git a/src/core/component/definition.rs b/src/core/component/definition.rs index d547c4b3..333cf694 100644 --- a/src/core/component/definition.rs +++ b/src/core/component/definition.rs @@ -1,6 +1,6 @@ use crate::base::action; use crate::core::{AnyInfo, TypeInfo}; -use crate::html::{html, Context, Markup, PrepareMarkup, Render}; +use crate::html::{html, Context, Markup, PrepareMarkup}; /// Define la función de renderizado para todos los componentes. /// diff --git a/src/core/theme.rs b/src/core/theme.rs index 5889dcf7..61d820b4 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -7,7 +7,7 @@ //! Un tema **declara las regiones** (*cabecera*, *barra lateral*, *pie*, etc.) que estarán //! disponibles para colocar contenido. Los temas son responsables últimos de los estilos, //! tipografías, espaciados y cualquier otro detalle visual o de comportamiento (como animaciones, -//! *scripts* de interfaz, etc.). +//! scripts de interfaz, etc.). //! //! Los temas son extensiones que implementan [`Extension`](crate::core::extension::Extension); por //! lo que se instancian, declaran sus dependencias y se inician igual que el resto de extensiones; diff --git a/src/html.rs b/src/html.rs index 37ab3f41..4858bbfa 100644 --- a/src/html.rs +++ b/src/html.rs @@ -1,7 +1,7 @@ //! HTML en código. mod maud; -pub use maud::{display, html, html_private, Escaper, Markup, PreEscaped, Render, DOCTYPE}; +pub use maud::{display, html, html_private, Escaper, Markup, PreEscaped, DOCTYPE}; // HTML DOCUMENT ASSETS **************************************************************************** @@ -119,11 +119,9 @@ impl PrepareMarkup { PrepareMarkup::With(markup) => markup.is_empty(), } } -} -impl Render for PrepareMarkup { /// Integra el renderizado fácilmente en la macro [`html!`]. - fn render(&self) -> Markup { + pub fn render(&self) -> Markup { match self { PrepareMarkup::None => html! {}, PrepareMarkup::Escaped(text) => html! { (text) }, diff --git a/src/html/assets.rs b/src/html/assets.rs index ee5431f0..41cd4710 100644 --- a/src/html/assets.rs +++ b/src/html/assets.rs @@ -2,10 +2,10 @@ pub mod favicon; pub mod javascript; pub mod stylesheet; -use crate::html::{html, Markup, Render}; +use crate::html::{html, Context, Markup}; use crate::{AutoDefault, Weight}; -/// Representación genérica de un *script* [`JavaScript`](crate::html::JavaScript) o una hoja de +/// Representación genérica de un script [`JavaScript`](crate::html::JavaScript) o una hoja de /// estilos [`StyleSheet`](crate::html::StyleSheet). /// /// Estos recursos se incluyen en los conjuntos de recursos ([`Assets`]) que suelen renderizarse en @@ -13,12 +13,15 @@ use crate::{AutoDefault, Weight}; /// /// Cada recurso se identifica por un **nombre único** ([`Asset::name()`]), usado como clave; y un /// **peso** ([`Asset::weight()`]), que determina su orden relativo de renderizado. -pub trait Asset: Render { +pub trait Asset { /// Devuelve el nombre del recurso, utilizado como clave única. fn name(&self) -> &str; /// Devuelve el peso del recurso, usado para ordenar el renderizado de menor a mayor peso. fn weight(&self) -> Weight; + + /// Renderiza el recurso en el contexto proporcionado. + fn render(&self, cx: &mut Context) -> Markup; } /// Gestión común para conjuntos de recursos como [`JavaScript`](crate::html::JavaScript) y @@ -77,16 +80,13 @@ impl<T: Asset> Assets<T> { false } } -} -impl<T: Asset> Render for Assets<T> { - fn render(&self) -> Markup { + pub fn render(&self, cx: &mut Context) -> Markup { let mut assets = self.0.iter().collect::<Vec<_>>(); assets.sort_by_key(|a| a.weight()); - html! { @for a in assets { - (a) + (a.render(cx)) } } } diff --git a/src/html/assets/favicon.rs b/src/html/assets/favicon.rs index e951df58..d731b8f5 100644 --- a/src/html/assets/favicon.rs +++ b/src/html/assets/favicon.rs @@ -1,4 +1,4 @@ -use crate::html::{html, Markup, Render}; +use crate::html::{html, Context, Markup}; use crate::AutoDefault; /// Un **Favicon** es un recurso gráfico que usa el navegador como icono asociado al sitio. @@ -151,10 +151,12 @@ impl Favicon { }); self } -} -impl Render for Favicon { - fn render(&self) -> Markup { + /// Renderiza el **Favicon** completo con todas las etiquetas declaradas. + /// + /// El parámetro `Context` se acepta por coherencia con el resto de *assets*, aunque en este + /// caso es ignorado. + pub fn render(&self, _cx: &mut Context) -> Markup { html! { @for item in &self.0 { (item) diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs index be6f9060..a8ed3e8c 100644 --- a/src/html/assets/javascript.rs +++ b/src/html/assets/javascript.rs @@ -1,35 +1,45 @@ use crate::html::assets::Asset; -use crate::html::{html, Markup, Render}; +use crate::html::{html, Context, Markup, PreEscaped}; use crate::{join, join_pair, AutoDefault, Weight}; // Define el origen del recurso JavaScript y cómo debe cargarse en el navegador. // // Los distintos modos de carga permiten optimizar el rendimiento y controlar el comportamiento del -// script. +// script en relación con el análisis del documento HTML y la ejecución del resto de scripts. // -// - [`From`] – Carga el script de forma estándar con la etiqueta `<script src="...">`. -// - [`Defer`] – Igual que [`From`], pero con el atributo `defer`. -// - [`Async`] – Igual que [`From`], pero con el atributo `async`. -// - [`Inline`] – Inserta el código directamente en la etiqueta `<script>`. -// - [`OnLoad`] – Inserta el código JavaScript y lo ejecuta tras el evento `DOMContentLoaded`. +// - [`From`] – Carga estándar con la etiqueta `<script src="...">`. +// - [`Defer`] – Igual que [`From`], pero con el atributo `defer`, descarga en paralelo y se +// ejecuta tras el análisis del documento HTML, respetando el orden de +// aparición. +// - [`Async`] – Igual que [`From`], pero con el atributo `async`, descarga en paralelo y se +// ejecuta en cuanto esté listo, **sin garantizar** el orden relativo respecto a +// otros scripts. +// - [`Inline`] – Inserta el código directamente en la etiqueta `<script>`. +// - [`OnLoad`] – Inserta el código JavaScript y lo ejecuta tras el evento `DOMContentLoaded`. +// - [`OnLoadAsync`] – Igual que [`OnLoad`], pero con manejador asíncrono (`async`), útil si dentro +// del código JavaScript se utiliza `await`. #[derive(AutoDefault)] enum Source { #[default] From(String), Defer(String), Async(String), - Inline(String, String), - OnLoad(String, String), + // `name`, `closure(Context) -> String`. + Inline(String, Box<dyn Fn(&mut Context) -> String + Send + Sync>), + // `name`, `closure(Context) -> String` (se ejecuta tras `DOMContentLoaded`). + OnLoad(String, Box<dyn Fn(&mut Context) -> String + Send + Sync>), + // `name`, `closure(Context) -> String` (manejador `async` tras `DOMContentLoaded`). + OnLoadAsync(String, Box<dyn Fn(&mut Context) -> String + Send + Sync>), } /// Define un recurso **JavaScript** para incluir en un documento HTML. /// -/// Este tipo permite añadir *scripts* externos o embebidos con distintas estrategias de carga +/// Este tipo permite añadir scripts externos o embebidos con distintas estrategias de carga /// (`defer`, `async`, *inline*, etc.) y [pesos](crate::Weight) para controlar el orden de inserción /// en el documento. /// /// > **Nota** -/// > Los archivos de los *scripts* deben estar disponibles en el servidor web de la aplicación. +/// > Los archivos de los scripts deben estar disponibles en el servidor web de la aplicación. /// > Pueden servirse usando [`static_files_service!`](crate::static_files_service). /// /// # Ejemplo @@ -37,23 +47,37 @@ enum Source { /// ```rust /// use pagetop::prelude::*; /// -/// // Script externo con carga diferida, versión para control de caché y prioriza el renderizado. +/// // Script externo con carga diferida, versión de caché y prioridad en el renderizado. /// let script = JavaScript::defer("/assets/js/app.js") /// .with_version("1.2.3") /// .with_weight(-10); /// /// // Script embebido que se ejecuta tras la carga del documento. -/// let script = JavaScript::on_load("init_tooltips", r#" +/// let script = JavaScript::on_load("init_tooltips", |_| r#" /// const tooltips = document.querySelectorAll('[data-tooltip]'); /// for (const el of tooltips) { /// el.addEventListener('mouseenter', showTooltip); /// } -/// "#); +/// "#.to_string()); +/// +/// // Script embebido con manejador asíncrono (`async`) que puede usar `await`. +/// let mut cx = Context::new(None).with_param("user_id", 7u32); +/// +/// let js = JavaScript::on_load_async("hydrate", |cx| { +/// // Ejemplo: lectura de un parámetro del contexto para inyectarlo en el código. +/// let uid: u32 = cx.param_or_default("user_id"); +/// format!(r#" +/// const USER_ID = {}; +/// await Promise.resolve(USER_ID); +/// // Aquí se podría hidratar la interfaz o cargar módulos dinámicos: +/// // await import('/assets/js/hydrate.js'); +/// "#, uid) +/// }); /// ``` #[rustfmt::skip] #[derive(AutoDefault)] pub struct JavaScript { - source : Source, // Fuente y modo de carga del script. + source : Source, // Fuente y estrategia de carga del script. version: String, // Versión del recurso para la caché del navegador. weight : Weight, // Peso que determina el orden. } @@ -70,11 +94,11 @@ impl JavaScript { } } - /// Crea un **script externo** con el atributo `defer`, que se carga en segundo plano y se - /// ejecuta tras analizar completamente el documento HTML. + /// Crea un **script externo** con el atributo `defer`, que se descarga en paralelo y se ejecuta + /// tras analizar completamente el documento HTML, **respetando el orden** de inserción. /// - /// Equivale a `<script src="..." defer>`. Útil para mantener el orden de ejecución y evitar - /// bloquear el análisis del documento HTML. + /// Equivale a `<script src="..." defer>`. Suele ser la opción recomendada para scripts no + /// críticos. pub fn defer(path: impl Into<String>) -> Self { JavaScript { source: Source::Defer(path.into()), @@ -82,11 +106,10 @@ impl JavaScript { } } - /// Crea un **script externo** con el atributo `async`, que se carga y ejecuta de forma - /// asíncrona tan pronto como esté disponible. + /// Crea un **script externo** con el atributo `async`, que se descarga en paralelo y se ejecuta + /// tan pronto como esté disponible. /// - /// Equivale a `<script src="..." async>`. La ejecución puede producirse fuera de orden respecto - /// a otros *scripts*. + /// Equivale a `<script src="..." async>`. **No garantiza** el orden relativo con otros scripts. pub fn asynchronous(path: impl Into<String>) -> Self { JavaScript { source: Source::Async(path.into()), @@ -97,37 +120,68 @@ impl JavaScript { /// Crea un **script embebido** directamente en el documento HTML. /// /// Equivale a `<script>...</script>`. El parámetro `name` se usa como identificador interno del - /// *script*. - pub fn inline(name: impl Into<String>, script: impl Into<String>) -> Self { + /// script. + /// + /// La función *closure* recibirá el [`Context`] por si se necesita durante el renderizado. + pub fn inline<F>(name: impl Into<String>, f: F) -> Self + where + F: Fn(&mut Context) -> String + Send + Sync + 'static, + { JavaScript { - source: Source::Inline(name.into(), script.into()), + source: Source::Inline(name.into(), Box::new(f)), ..Default::default() } } - /// Crea un **script embebido** que se ejecuta automáticamente al terminar de cargarse el - /// documento HTML. + /// Crea un **script embebido** que se ejecuta cuando **el DOM está listo**. /// - /// El código se envuelve automáticamente en un `addEventListener('DOMContentLoaded', ...)`. El - /// parámetro `name` se usa como identificador interno del *script*. - pub fn on_load(name: impl Into<String>, script: impl Into<String>) -> Self { + /// El código se envuelve en un `addEventListener('DOMContentLoaded',function(){...})` que lo + /// ejecuta tras analizar el documento HTML, **no** espera imágenes ni otros recursos externos. + /// Útil para inicializaciones que no dependen de `await`. El parámetro `name` se usa como + /// identificador interno del script. + /// + /// Los scripts con `defer` se ejecutan antes de `DOMContentLoaded`. + /// + /// La función *closure* recibirá el [`Context`] por si se necesita durante el renderizado. + pub fn on_load<F>(name: impl Into<String>, f: F) -> Self + where + F: Fn(&mut Context) -> String + Send + Sync + 'static, + { JavaScript { - source: Source::OnLoad(name.into(), script.into()), + source: Source::OnLoad(name.into(), Box::new(f)), + ..Default::default() + } + } + + /// Crea un **script embebido** con un **manejador asíncrono**. + /// + /// El código se envuelve en un `addEventListener('DOMContentLoaded',async()=>{...})`, que + /// emplea una función `async` para que el cuerpo devuelto por la función *closure* pueda usar + /// `await`. Ideal para hidratar la interfaz, cargar módulos dinámicos o realizar lecturas + /// iniciales. + /// + /// La función *closure* recibirá el [`Context`] por si se necesita durante el renderizado. + pub fn on_load_async<F>(name: impl Into<String>, f: F) -> Self + where + F: Fn(&mut Context) -> String + Send + Sync + 'static, + { + JavaScript { + source: Source::OnLoadAsync(name.into(), Box::new(f)), ..Default::default() } } // JavaScript BUILDER ************************************************************************** - /// Asocia una versión al recurso (usada para control de la caché del navegador). + /// Asocia una **versión** al recurso (usada para control de la caché del navegador). /// - /// Si `version` está vacío, no se añade ningún parámetro a la URL. + /// Si `version` está vacío, **no** se añade ningún parámetro a la URL. pub fn with_version(mut self, version: impl Into<String>) -> Self { self.version = version.into(); self } - /// Modifica el peso del recurso. + /// Modifica el **peso** del recurso. /// /// Los recursos se renderizan de menor a mayor peso. Por defecto es `0`, que respeta el orden /// de creación. @@ -140,7 +194,7 @@ impl JavaScript { impl Asset for JavaScript { /// Devuelve el nombre del recurso, utilizado como clave única. /// - /// Para *scripts* externos es la ruta del recurso; para *scripts* embebidos, un identificador. + /// Para scripts externos es la ruta del recurso; para scripts embebidos, un identificador. fn name(&self) -> &str { match &self.source { Source::From(path) => path, @@ -148,16 +202,15 @@ impl Asset for JavaScript { Source::Async(path) => path, Source::Inline(name, _) => name, Source::OnLoad(name, _) => name, + Source::OnLoadAsync(name, _) => name, } } fn weight(&self) -> Weight { self.weight } -} -impl Render for JavaScript { - fn render(&self) -> Markup { + fn render(&self, cx: &mut Context) -> Markup { match &self.source { Source::From(path) => html! { script src=(join_pair!(path, "?v=", self.version.as_str())) {}; @@ -168,12 +221,15 @@ impl Render for JavaScript { Source::Async(path) => html! { script src=(join_pair!(path, "?v=", self.version.as_str())) async {}; }, - Source::Inline(_, code) => html! { - script { (code) }; + Source::Inline(_, f) => html! { + script { (PreEscaped((f)(cx))) }; }, - Source::OnLoad(_, code) => html! { (join!( - "document.addEventListener('DOMContentLoaded',function(){", code, "});" - )) }, + Source::OnLoad(_, f) => html! { script { (PreEscaped(join!( + "document.addEventListener(\"DOMContentLoaded\",function(){", (f)(cx), "});" + ))) } }, + Source::OnLoadAsync(_, f) => html! { script { (PreEscaped(join!( + "document.addEventListener(\"DOMContentLoaded\",async()=>{", (f)(cx), "});" + ))) } }, } } } diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index 38a97d7f..3ecc77fc 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -1,5 +1,5 @@ use crate::html::assets::Asset; -use crate::html::{html, Markup, PreEscaped, Render}; +use crate::html::{html, Context, Markup, PreEscaped}; use crate::{join_pair, AutoDefault, Weight}; // Define el origen del recurso CSS y cómo se incluye en el documento. @@ -14,7 +14,8 @@ use crate::{join_pair, AutoDefault, Weight}; enum Source { #[default] From(String), - Inline(String, String), + // `name`, `closure(Context) -> String`. + Inline(String, Box<dyn Fn(&mut Context) -> String + Send + Sync>), } /// Define el medio objetivo para la hoja de estilos. @@ -34,7 +35,7 @@ pub enum TargetMedia { Speech, } -/// Devuelve el texto asociado al punto de interrupción usado por Bootstrap. +/// Devuelve el valor para el atributo `media` (`Some(...)`) o `None` para `Default`. #[rustfmt::skip] impl TargetMedia { fn as_str_opt(&self) -> Option<&str> { @@ -69,12 +70,12 @@ impl TargetMedia { /// .with_weight(-10); /// /// // Crea una hoja de estilos embebida en el documento HTML. -/// let embedded = StyleSheet::inline("custom_theme", r#" +/// let embedded = StyleSheet::inline("custom_theme", |_| r#" /// body { /// background-color: #f5f5f5; /// font-family: 'Segoe UI', sans-serif; /// } -/// "#); +/// "#.to_string()); /// ``` #[rustfmt::skip] #[derive(AutoDefault)] @@ -100,9 +101,14 @@ impl StyleSheet { /// /// Equivale a `<style>...</style>`. El parámetro `name` se usa como identificador interno del /// recurso. - pub fn inline(name: impl Into<String>, styles: impl Into<String>) -> Self { + /// + /// La función *closure* recibirá el [`Context`] por si se necesita durante el renderizado. + pub fn inline<F>(name: impl Into<String>, f: F) -> Self + where + F: Fn(&mut Context) -> String + Send + Sync + 'static, + { StyleSheet { - source: Source::Inline(name.into(), styles.into()), + source: Source::Inline(name.into(), Box::new(f)), ..Default::default() } } @@ -133,9 +139,9 @@ impl StyleSheet { /// Según el argumento `media`: /// /// - `TargetMedia::Default` - Se aplica en todos los casos (medio por defecto). - /// - `TargetMedia::Print` - Se aplican cuando el documento se imprime. - /// - `TargetMedia::Screen` - Se aplican en pantallas. - /// - `TargetMedia::Speech` - Se aplican en dispositivos que convierten el texto a voz. + /// - `TargetMedia::Print` - Se aplica cuando el documento se imprime. + /// - `TargetMedia::Screen` - Se aplica en pantallas. + /// - `TargetMedia::Speech` - Se aplica en dispositivos que convierten el texto a voz. pub fn for_media(mut self, media: TargetMedia) -> Self { self.media = media; self @@ -156,10 +162,8 @@ impl Asset for StyleSheet { fn weight(&self) -> Weight { self.weight } -} -impl Render for StyleSheet { - fn render(&self) -> Markup { + fn render(&self, cx: &mut Context) -> Markup { match &self.source { Source::From(path) => html! { link @@ -167,8 +171,8 @@ impl Render for StyleSheet { href=(join_pair!(path, "?v=", self.version.as_str())) media=[self.media.as_str_opt()]; }, - Source::Inline(_, code) => html! { - style { (PreEscaped(code)) }; + Source::Inline(_, f) => html! { + style { (PreEscaped((f)(cx))) }; }, } } diff --git a/src/html/context.rs b/src/html/context.rs index 8ef3a053..2f3e0f07 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -25,9 +25,9 @@ pub enum AssetsOp { RemoveStyleSheet(&'static str), // JavaScripts. - /// Añade un *script* JavaScript al documento. + /// Añade un script JavaScript al documento. AddJavaScript(JavaScript), - /// Elimina un *script* por su ruta o identificador. + /// Elimina un script por su ruta o identificador. RemoveJavaScript(&'static str), } @@ -55,7 +55,7 @@ pub enum ErrorParam { /// - Almacenar la **solicitud HTTP** de origen. /// - Seleccionar **tema** y **composición** (*layout*) de renderizado. /// - Administrar **recursos** del documento como el icono [`Favicon`], las hojas de estilo -/// [`StyleSheet`] o los *scripts* [`JavaScript`] mediante [`AssetsOp`]. +/// [`StyleSheet`] o los scripts [`JavaScript`] mediante [`AssetsOp`]. /// - Leer y mantener **parámetros dinámicos tipados** de contexto. /// - Generar **identificadores únicos** por tipo de componente. /// @@ -139,7 +139,7 @@ pub trait Contextual: LangId { /// Devuelve las hojas de estilo de los recursos del contexto. fn stylesheets(&self) -> &Assets<StyleSheet>; - /// Devuelve los *scripts* JavaScript de los recursos del contexto. + /// Devuelve los scripts JavaScript de los recursos del contexto. fn javascripts(&self) -> &Assets<JavaScript>; // Contextual HELPERS ************************************************************************** @@ -155,7 +155,7 @@ pub trait Contextual: LangId { /// /// Extiende [`Contextual`] con métodos para **instanciar** y configurar un nuevo contexto, /// **renderizar los recursos** del documento (incluyendo el [`Favicon`], las hojas de estilo -/// [`StyleSheet`] y los *scripts* [`JavaScript`]), o extender el uso de **parámetros dinámicos +/// [`StyleSheet`] y los scripts [`JavaScript`]), o extender el uso de **parámetros dinámicos /// tipados** con nuevos métodos. /// /// # Ejemplos @@ -258,14 +258,29 @@ impl Context { // Context RENDER ****************************************************************************** /// Renderiza los recursos del contexto. - pub fn render_assets(&self) -> Markup { - html! { - @if let Some(favicon) = &self.favicon { - (favicon) + pub fn render_assets(&mut self) -> Markup { + use std::mem::take as mem_take; + + // Extrae temporalmente los recursos. + let favicon = mem_take(&mut self.favicon); // Deja valor por defecto (None) en self. + let stylesheets = mem_take(&mut self.stylesheets); // Assets<StyleSheet>::default() en self. + let javascripts = mem_take(&mut self.javascripts); // Assets<JavaScript>::default() en self. + + // Renderiza con `&mut self` como contexto. + let markup = html! { + @if let Some(fi) = &favicon { + (fi.render(self)) } - (self.stylesheets) - (self.javascripts) - } + (stylesheets.render(self)) + (javascripts.render(self)) + }; + + // Restaura los campos tal y como estaban. + self.favicon = favicon; + self.stylesheets = stylesheets; + self.javascripts = javascripts; + + markup } // Context PARAMS ****************************************************************************** diff --git a/src/html/maud.rs b/src/html/maud.rs index 9bf179ec..65360360 100644 --- a/src/html/maud.rs +++ b/src/html/maud.rs @@ -69,23 +69,6 @@ impl fmt::Write for Escaper<'_> { /// `.render()` or `.render_to()`. Since the default definitions of /// these methods call each other, not doing this will result in /// infinite recursion. -/// -/// # Example -/// -/// ```rust -/// use pagetop::prelude::*; -/// -/// /// Provides a shorthand for linking to a CSS stylesheet. -/// pub struct Stylesheet(&'static str); -/// -/// impl Render for Stylesheet { -/// fn render(&self) -> Markup { -/// html! { -/// link rel="stylesheet" type="text/css" href=(self.0); -/// } -/// } -/// } -/// ``` pub trait Render { /// Renders `self` as a block of `Markup`. fn render(&self) -> Markup { @@ -238,6 +221,10 @@ impl Markup { pub fn is_empty(&self) -> bool { self.0.is_empty() } + + pub fn as_str(&self) -> &str { + self.0.as_str() + } } impl<T: Into<String>> PreEscaped<T> { diff --git a/src/response/page.rs b/src/response/page.rs index 86a0bdcc..2dc27f9f 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -202,7 +202,7 @@ impl Page { } /// Renderiza los recursos de la página. - pub fn render_assets(&self) -> Markup { + pub fn render_assets(&mut self) -> Markup { self.context.render_assets() } diff --git a/tests/component_poweredby.rs b/tests/component_poweredby.rs index 9f8e8222..e4551d17 100644 --- a/tests/component_poweredby.rs +++ b/tests/component_poweredby.rs @@ -8,10 +8,10 @@ async fn poweredby_default_shows_only_pagetop_recognition() { let html = render_component(&p); // Debe mostrar el bloque de reconocimiento a PageTop. - assert!(html.contains("poweredby__pagetop")); + assert!(html.as_str().contains("poweredby__pagetop")); // Y NO debe mostrar el bloque de copyright. - assert!(!html.contains("poweredby__copyright")); + assert!(!html.as_str().contains("poweredby__copyright")); } #[pagetop::test] @@ -22,17 +22,20 @@ async fn poweredby_new_includes_current_year_and_app_name() { let html = render_component(&p); let year = Utc::now().format("%Y").to_string(); - assert!(html.contains(&year), "HTML should include the current year"); + assert!( + html.as_str().contains(&year), + "HTML should include the current year" + ); // El nombre de la app proviene de `global::SETTINGS.app.name`. let app_name = &global::SETTINGS.app.name; assert!( - html.contains(app_name), + html.as_str().contains(app_name), "HTML should include the application name" ); // Debe existir el span de copyright. - assert!(html.contains("poweredby__copyright")); + assert!(html.as_str().contains("poweredby__copyright")); } #[pagetop::test] @@ -43,8 +46,8 @@ async fn poweredby_with_copyright_overrides_text() { let p = PoweredBy::default().with_copyright(Some(custom)); let html = render_component(&p); - assert!(html.contains(custom)); - assert!(html.contains("poweredby__copyright")); + assert!(html.as_str().contains(custom)); + assert!(html.as_str().contains("poweredby__copyright")); } #[pagetop::test] @@ -54,9 +57,9 @@ async fn poweredby_with_copyright_none_hides_text() { let p = PoweredBy::new().with_copyright(None::<String>); let html = render_component(&p); - assert!(!html.contains("poweredby__copyright")); + assert!(!html.as_str().contains("poweredby__copyright")); // El reconocimiento a PageTop siempre debe aparecer. - assert!(html.contains("poweredby__pagetop")); + assert!(html.as_str().contains("poweredby__pagetop")); } #[pagetop::test] @@ -67,7 +70,7 @@ async fn poweredby_link_points_to_crates_io() { let html = render_component(&p); assert!( - html.contains("https://pagetop.cillero.es"), + html.as_str().contains("https://pagetop.cillero.es"), "Link should point to pagetop.cillero.es" ); } @@ -89,12 +92,8 @@ async fn poweredby_getter_reflects_internal_state() { // HELPERS ***************************************************************************************** -fn render(x: &impl Render) -> String { - x.render().into_string() -} - -fn render_component<C: Component>(c: &C) -> String { +fn render_component<C: Component>(c: &C) -> Markup { let mut cx = Context::default(); let pm = c.prepare_component(&mut cx); - render(&pm) + pm.render() } diff --git a/tests/html.rs b/tests/html.rs index 1499c709..ae4517bc 100644 --- a/tests/html.rs +++ b/tests/html.rs @@ -2,19 +2,19 @@ use pagetop::prelude::*; #[pagetop::test] async fn prepare_markup_render_none_is_empty_string() { - assert_eq!(render(&PrepareMarkup::None), ""); + assert_eq!(PrepareMarkup::None.render().as_str(), ""); } #[pagetop::test] async fn prepare_markup_render_escaped_escapes_html_and_ampersands() { - let pm = PrepareMarkup::Escaped(String::from("<b>& \" ' </b>")); - assert_eq!(render(&pm), "&lt;b&gt;&amp; &quot; ' &lt;/b&gt;"); + let pm = PrepareMarkup::Escaped("<b>& \" ' </b>".to_string()); + assert_eq!(pm.render().as_str(), "&lt;b&gt;&amp; &quot; ' &lt;/b&gt;"); } #[pagetop::test] async fn prepare_markup_render_raw_is_inserted_verbatim() { - let pm = PrepareMarkup::Raw(String::from("<b>bold</b><script>1<2</script>")); - assert_eq!(render(&pm), "<b>bold</b><script>1<2</script>"); + let pm = PrepareMarkup::Raw("<b>bold</b><script>1<2</script>".to_string()); + assert_eq!(pm.render().as_str(), "<b>bold</b><script>1<2</script>"); } #[pagetop::test] @@ -24,7 +24,7 @@ async fn prepare_markup_render_with_keeps_structure() { p { "This is a paragraph." } }); assert_eq!( - render(&pm), + pm.render().as_str(), "<h2>Sample title</h2><p>This is a paragraph.</p>" ); } @@ -33,7 +33,7 @@ async fn prepare_markup_render_with_keeps_structure() { async fn prepare_markup_does_not_double_escape_when_wrapped_in_html_macro() { // Escaped: dentro de `html!` no debe volver a escaparse. let escaped = PrepareMarkup::Escaped("<i>x</i>".into()); - let wrapped_escaped = html! { div { (escaped) } }; + let wrapped_escaped = html! { div { (escaped.render()) } }; assert_eq!( wrapped_escaped.into_string(), "<div>&lt;i&gt;x&lt;/i&gt;</div>" @@ -41,12 +41,12 @@ async fn prepare_markup_does_not_double_escape_when_wrapped_in_html_macro() { // Raw: tampoco debe escaparse al integrarlo. let raw = PrepareMarkup::Raw("<i>x</i>".into()); - let wrapped_raw = html! { div { (raw) } }; + let wrapped_raw = html! { div { (raw.render()) } }; assert_eq!(wrapped_raw.into_string(), "<div><i>x</i></div>"); // With: debe incrustar el Markup tal cual. let with = PrepareMarkup::With(html! { span.title { "ok" } }); - let wrapped_with = html! { div { (with) } }; + let wrapped_with = html! { div { (with.render()) } }; assert_eq!( wrapped_with.into_string(), "<div><span class=\"title\">ok</span></div>" @@ -57,11 +57,14 @@ async fn prepare_markup_does_not_double_escape_when_wrapped_in_html_macro() { async fn prepare_markup_unicode_is_preserved() { // Texto con acentos y emojis debe conservarse (salvo el escape HTML de signos). let esc = PrepareMarkup::Escaped("Hello, tomorrow coffee ☕ & donuts!".into()); - assert_eq!(render(&esc), "Hello, tomorrow coffee ☕ &amp; donuts!"); + assert_eq!( + esc.render().as_str(), + "Hello, tomorrow coffee ☕ &amp; donuts!" + ); // Raw debe pasar íntegro. let raw = PrepareMarkup::Raw("Title — section © 2025".into()); - assert_eq!(render(&raw), "Title — section © 2025"); + assert_eq!(raw.render().as_str(), "Title — section © 2025"); } #[pagetop::test] @@ -69,11 +72,11 @@ async fn prepare_markup_is_empty_semantics() { assert!(PrepareMarkup::None.is_empty()); assert!(PrepareMarkup::Escaped(String::new()).is_empty()); - assert!(PrepareMarkup::Escaped(String::from("")).is_empty()); - assert!(!PrepareMarkup::Escaped(String::from("x")).is_empty()); + assert!(PrepareMarkup::Escaped("".to_string()).is_empty()); + assert!(!PrepareMarkup::Escaped("x".to_string()).is_empty()); assert!(PrepareMarkup::Raw(String::new()).is_empty()); - assert!(PrepareMarkup::Raw(String::from("")).is_empty()); + assert!(PrepareMarkup::Raw("".to_string()).is_empty()); assert!(!PrepareMarkup::Raw("a".into()).is_empty()); assert!(PrepareMarkup::With(html! {}).is_empty()); @@ -94,17 +97,12 @@ async fn prepare_markup_equivalence_between_render_and_inline_in_html_macro() { ]; for pm in cases { - let rendered = render(&pm); - let in_macro = html! { (pm) }.into_string(); + let rendered = pm.render(); + let in_macro = html! { (rendered) }.into_string(); assert_eq!( - rendered, in_macro, + rendered.as_str(), + in_macro, "The output of Render and (pm) inside html! must match" ); } } - -// HELPERS ***************************************************************************************** - -fn render(x: &impl Render) -> String { - x.render().into_string() -} From cc03a0ea324ae43e31bc486234db5881c904241b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 12 Sep 2025 01:13:17 +0200 Subject: [PATCH 173/244] =?UTF-8?q?=E2=9C=A8=20(util):=20A=C3=B1ade=20`ind?= =?UTF-8?q?oc`=20para=20indentar=20c=C3=B3digo=20bien?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 7 +++ Cargo.toml | 1 + src/lib.rs | 2 +- src/util.rs | 128 +++++++++++++++++++++++++++------------------------- 4 files changed, 75 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 944027d8..3053e20c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1307,6 +1307,12 @@ dependencies = [ "hashbrown 0.15.4", ] +[[package]] +name = "indoc" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" + [[package]] name = "inout" version = "0.1.4" @@ -1568,6 +1574,7 @@ dependencies = [ "config", "figlet-rs", "fluent-templates", + "indoc", "itoa", "pagetop-build", "pagetop-macros", diff --git a/Cargo.toml b/Cargo.toml index 8ccd69ec..ab7551f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ colored = "3.0.0" concat-string = "1.0.1" config = { version = "0.15.13", default-features = false, features = ["toml"] } figlet-rs = "0.1.5" +indoc = "2.0.6" itoa = "1.0.15" parking_lot = "0.12.4" paste = { package = "pastey", version = "0.1.0" } diff --git a/src/lib.rs b/src/lib.rs index 93b8564b..1c1ba2c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,7 +138,7 @@ pub type Weight = i8; // API ********************************************************************************************* -// Funciones y macros útiles. +// Macros y funciones útiles. pub mod util; // Carga las opciones de configuración. pub mod config; diff --git a/src/util.rs b/src/util.rs index 56b098d8..cb101763 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,4 +1,4 @@ -//! Funciones y macros útiles. +//! Macros y funciones útiles. use crate::trace; @@ -6,67 +6,7 @@ use std::env; use std::io; use std::path::{Path, PathBuf}; -// FUNCIONES ÚTILES ******************************************************************************** - -/// Resuelve y valida la ruta de un directorio existente, devolviendo una ruta absoluta. -/// -/// - Si la ruta es relativa, se resuelve respecto al directorio del proyecto según la variable de -/// entorno `CARGO_MANIFEST_DIR` (si existe) o, en su defecto, respecto al directorio actual de -/// trabajo. -/// - Normaliza y valida la ruta final (resuelve `.`/`..` y enlaces simbólicos). -/// - Devuelve error si la ruta no existe o no es un directorio. -/// -/// # Ejemplos -/// -/// ```rust,no_run -/// use pagetop::prelude::*; -/// -/// // Ruta relativa, se resuelve respecto a CARGO_MANIFEST_DIR o al directorio actual (`cwd`). -/// println!("{:#?}", util::resolve_absolute_dir("documents")); -/// -/// // Ruta absoluta, se normaliza y valida tal cual. -/// println!("{:#?}", util::resolve_absolute_dir("/var/www")); -/// ``` -pub fn resolve_absolute_dir<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { - let path = path.as_ref(); - - let candidate = if path.is_absolute() { - path.to_path_buf() - } else { - // Directorio base CARGO_MANIFEST_DIR si está disponible; o current_dir() en su defecto. - env::var_os("CARGO_MANIFEST_DIR") - .map(PathBuf::from) - .or_else(|| env::current_dir().ok()) - .unwrap_or_else(|| PathBuf::from(".")) - .join(path) - }; - - // Resuelve `.`/`..`, enlaces simbólicos y obtiene la ruta absoluta en un único paso. - let absolute_dir = candidate.canonicalize()?; - - // Asegura que realmente es un directorio existente. - if absolute_dir.is_dir() { - Ok(absolute_dir) - } else { - Err({ - let msg = format!("Path \"{}\" is not a directory", absolute_dir.display()); - trace::warn!(msg); - io::Error::new(io::ErrorKind::InvalidInput, msg) - }) - } -} - -/// **Obsoleto desde la versión 0.3.0**: usar [`resolve_absolute_dir()`] en su lugar. -#[deprecated(since = "0.3.0", note = "Use `resolve_absolute_dir()` instead")] -pub fn absolute_dir<P, Q>(root_path: P, relative_path: Q) -> io::Result<PathBuf> -where - P: AsRef<Path>, - Q: AsRef<Path>, -{ - resolve_absolute_dir(root_path.as_ref().join(relative_path.as_ref())) -} - -// MACROS ÚTILES *********************************************************************************** +// MACROS INTEGRADAS ******************************************************************************* #[doc(hidden)] pub use paste::paste; @@ -74,6 +14,10 @@ pub use paste::paste; #[doc(hidden)] pub use concat_string::concat_string; +pub use indoc::{concatdoc, formatdoc, indoc}; + +// MACROS ÚTILES *********************************************************************************** + #[macro_export] /// Macro para construir una colección de pares clave-valor. /// @@ -253,3 +197,63 @@ macro_rules! join_strict { } }}; } + +// FUNCIONES ÚTILES ******************************************************************************** + +/// Resuelve y valida la ruta de un directorio existente, devolviendo una ruta absoluta. +/// +/// - Si la ruta es relativa, se resuelve respecto al directorio del proyecto según la variable de +/// entorno `CARGO_MANIFEST_DIR` (si existe) o, en su defecto, respecto al directorio actual de +/// trabajo. +/// - Normaliza y valida la ruta final (resuelve `.`/`..` y enlaces simbólicos). +/// - Devuelve error si la ruta no existe o no es un directorio. +/// +/// # Ejemplos +/// +/// ```rust,no_run +/// use pagetop::prelude::*; +/// +/// // Ruta relativa, se resuelve respecto a CARGO_MANIFEST_DIR o al directorio actual (`cwd`). +/// println!("{:#?}", util::resolve_absolute_dir("documents")); +/// +/// // Ruta absoluta, se normaliza y valida tal cual. +/// println!("{:#?}", util::resolve_absolute_dir("/var/www")); +/// ``` +pub fn resolve_absolute_dir<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { + let path = path.as_ref(); + + let candidate = if path.is_absolute() { + path.to_path_buf() + } else { + // Directorio base CARGO_MANIFEST_DIR si está disponible; o current_dir() en su defecto. + env::var_os("CARGO_MANIFEST_DIR") + .map(PathBuf::from) + .or_else(|| env::current_dir().ok()) + .unwrap_or_else(|| PathBuf::from(".")) + .join(path) + }; + + // Resuelve `.`/`..`, enlaces simbólicos y obtiene la ruta absoluta en un único paso. + let absolute_dir = candidate.canonicalize()?; + + // Asegura que realmente es un directorio existente. + if absolute_dir.is_dir() { + Ok(absolute_dir) + } else { + Err({ + let msg = format!("Path \"{}\" is not a directory", absolute_dir.display()); + trace::warn!(msg); + io::Error::new(io::ErrorKind::InvalidInput, msg) + }) + } +} + +/// **Obsoleto desde la versión 0.3.0**: usar [`resolve_absolute_dir()`] en su lugar. +#[deprecated(since = "0.3.0", note = "Use `resolve_absolute_dir()` instead")] +pub fn absolute_dir<P, Q>(root_path: P, relative_path: Q) -> io::Result<PathBuf> +where + P: AsRef<Path>, + Q: AsRef<Path>, +{ + resolve_absolute_dir(root_path.as_ref().join(relative_path.as_ref())) +} From c6e323b21dae5f48bcb9a47b426571592dc1b7cb Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 18 Sep 2025 14:06:33 +0200 Subject: [PATCH 174/244] =?UTF-8?q?=F0=9F=9A=A8=20Ajustes=20menores=20suge?= =?UTF-8?q?ridos=20por=20clippy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-macros/src/lib.rs | 2 +- src/html/context.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 28c6b1b4..5af5f9c9 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -269,8 +269,8 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { // Extrae atributos descartando la documentación para incluir en `alter_...()`. let non_doc_attrs: Vec<_> = attrs .iter() + .filter(|&a| !a.path().is_ident("doc")) .cloned() - .filter(|a| !a.path().is_ident("doc")) .collect(); // Documentación del método alter_...(). diff --git a/src/html/context.rs b/src/html/context.rs index 2f3e0f07..7b782681 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -314,7 +314,7 @@ impl Context { .ok_or_else(|| ErrorParam::TypeMismatch { key, expected: TypeInfo::FullName.of::<T>(), - saved: *type_name, + saved: type_name, }) } From 25a71bf526f7a52e1f903c31ab5615c457946385 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 18 Sep 2025 14:17:01 +0200 Subject: [PATCH 175/244] =?UTF-8?q?=F0=9F=8E=A8=20Mejora=20la=20p=C3=A1gin?= =?UTF-8?q?a=20de=20bienvenida=20y=20el=20tema=20b=C3=A1sico?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convierte la estructura de la página de bienvenida en una composición del tema básico para ser usada en otros contextos. Por ejemplo, para la página de mantenimiento, o la página de inicio de la guía de uso de PageTop. --- src/base/extension/welcome.rs | 52 +++++++++++++++++++++++++++-------- src/base/theme/basic.rs | 4 +-- src/locale/en-US/base.ftl | 4 +++ src/locale/en-US/welcome.ftl | 29 +++++++++---------- src/locale/es-ES/base.ftl | 6 +++- src/locale/es-ES/welcome.ftl | 25 +++++++++-------- 6 files changed, 79 insertions(+), 41 deletions(-) diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs index eaa9f339..e2a77128 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -30,22 +30,50 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { .with_title(L10n::l("welcome_title")) .with_description(L10n::l("welcome_intro").with_arg("app", app)) .with_param("intro_button_text", L10n::l("welcome_powered")) - .with_param("intro_button_link", "https://pagetop.cillero.es".to_owned()) - .add_component(Html::with(|cx| { - html! { - p { (L10n::l("welcome_text1").using(cx)) } - p { (L10n::l("welcome_text2").using(cx)) } + .with_param("intro_button_link", "https://pagetop.cillero.es".to_string()) + .with_assets(AssetsOp::AddJavaScript(JavaScript::on_load_async("welcome-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("welcome-release").src = `https://img.shields.io/badge/Release%20date-${encodeURIComponent(formatted)}-blue?label=LABEL&style=for-the-badge`; + document.getElementById("welcome-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("welcome_release_label").using(cx).as_str()) + .to_string(), + ))) + .add_component(Html::with(|cx| html! { + p { (L10n::l("welcome_text1").using(cx)) } + div id="welcome-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("welcome_pagetop_label").lookup(cx)] {} (" ") + img + id="welcome-release" + alt=[L10n::l("welcome_release_label").lookup(cx)] {} (" ") + img + src=(format!( + "https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label={}&style=for-the-badge", + L10n::l("welcome_license_label").lookup(cx).unwrap_or_default() + )) + alt=[L10n::l("welcome_license_label").lookup(cx)] {} + } + p { (L10n::l("welcome_text2").using(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)) } - } + .with_title(L10n::l("welcome_notice_title")) + .add_component(Html::with(move |cx| html! { + p { (L10n::l("welcome_notice_1").using(cx)) } + p { (L10n::l("welcome_notice_2").using(cx)) } + p { (L10n::l("welcome_notice_3").using(cx)) } + p { (L10n::l("welcome_notice_4").with_arg("app", app).using(cx)) } })), ) .render() diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index fbf4caf5..e6525489 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -111,8 +111,8 @@ fn render_intro(page: &mut Page) -> Markup { 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)) } + 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)) } } } } diff --git a/src/locale/en-US/base.ftl b/src/locale/en-US/base.ftl index b2c92564..7a9701de 100644 --- a/src/locale/en-US/base.ftl +++ b/src/locale/en-US/base.ftl @@ -1,2 +1,6 @@ +# Basic theme, intro layout. +intro_code = Code +intro_have_fun = Coding is creating + # PoweredBy component. poweredby_pagetop = Powered by { $pagetop_link } diff --git a/src/locale/en-US/welcome.ftl b/src/locale/en-US/welcome.ftl index 7b7d74d8..0a227f1d 100644 --- a/src/locale/en-US/welcome.ftl +++ b/src/locale/en-US/welcome.ftl @@ -1,20 +1,21 @@ -welcome_extension_name = Default homepage -welcome_extension_description = Displays a landing page when none is configured. +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_page = Welcome page +welcome_title = Hello, world! welcome_intro = Discover⚡{ $app } -welcome_powered = A web solution powered by <strong>PageTop!</strong> +welcome_powered = A web solution powered by <strong>PageTop</strong> -welcome_text1 = If you can read this page, it means that the <strong>PageTop</strong> 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 <strong>contact your system administrator</strong> for assistance. +welcome_pagetop_label = PageTop version on Crates.io +welcome_release_label = Release date +welcome_license_label = License -welcome_about = About -welcome_pagetop = <strong>PageTop</strong> is a <a href="https://www.rust-lang.org" target="_blank">Rust</a>-based web development framework for building modular, extensible, and configurable web solutions. +welcome_text1 = PageTop is <strong>a Rust-based web development framework</strong> designed to build modular, extensible, and configurable web solutions. +welcome_text2 = PageTop brings back the essence of the classic web, renders on the server (SSR) and uses <em>HTML-first</em> components, CSS and JavaScript, <strong>with the performance and security of Rust</strong>. -welcome_issues1 = To report issues related to the <strong>PageTop</strong> framework, please use <a href="https://git.cillero.es/manuelcillero/pagetop/issues" target="_blank">SoloGit</a>. Before opening a new issue, check existing reports to avoid duplicates. -welcome_issues2 = For issues related specifically to <strong>{ $app }</strong>, please refer to its official repository or support channel, rather than directly to <strong>PageTop</strong>. - -welcome_code = Code -welcome_have_fun = Coding is creating +welcome_notice_title = Notice +welcome_notice_1 = If you can see this page, 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_notice_2 = If the issue persists, please <strong>contact the system administrator</strong>. +welcome_notice_3 = 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>. Before opening a new issue, review the existing ones to avoid duplicates. +welcome_notice_4 = For issues specific to the application (<strong>{ $app }</strong>), please use its official repository or support channel. diff --git a/src/locale/es-ES/base.ftl b/src/locale/es-ES/base.ftl index 74eb62e8..99f6c7e8 100644 --- a/src/locale/es-ES/base.ftl +++ b/src/locale/es-ES/base.ftl @@ -1,2 +1,6 @@ +# Basic theme, intro layout. +intro_code = Código +intro_have_fun = Programar es crear + # PoweredBy component. -poweredby_pagetop = Funciona con { $pagetop_link } \ No newline at end of file +poweredby_pagetop = Funciona con { $pagetop_link } diff --git a/src/locale/es-ES/welcome.ftl b/src/locale/es-ES/welcome.ftl index 78238322..b98d9199 100644 --- a/src/locale/es-ES/welcome.ftl +++ b/src/locale/es-ES/welcome.ftl @@ -1,20 +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_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_powered = Una solución web creada con <strong>PageTop</strong> -welcome_text1 = Si puedes leer esta página, significa que el servidor de <strong>PageTop</strong> 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 <strong>contacta con el administrador del sistema</strong> para recibir asistencia técnica. +welcome_pagetop_label = Versión de PageTop en Crates.io +welcome_release_label = Lanzamiento +welcome_license_label = Licencia -welcome_about = Acerca de -welcome_pagetop = <strong>PageTop</strong> es un entorno de desarrollo web basado en <a href="https://www.rust-lang.org/es" target="_blank">Rust</a>, diseñado para crear soluciones web modulares, extensibles y configurables. +welcome_text1 = PageTop es un <strong>entorno de desarrollo web basado en Rust</strong>, pensado para construir soluciones web modulares, extensibles y configurables. +welcome_text2 = PageTop reivindica la esencia de la web clásica, renderiza en el servidor (SSR) utilizando componentes <em>HTML-first</em>, CSS y JavaScript, <strong>con el rendimiento y la seguridad de Rust</strong>. -welcome_issues1 = Para comunicar cualquier problema con <strong>PageTop</strong>, utiliza <a href="https://git.cillero.es/manuelcillero/pagetop/issues" target="_blank">SoloGit</a>. Antes de informar de una incidencia, revisa los informes ya existentes para evitar duplicados. -welcome_issues2 = Si se trata de fallos específicos de <strong>{ $app }</strong>, por favor acude a su repositorio oficial o canal de soporte, y no al de <strong>PageTop</strong> directamente. - -welcome_code = Código -welcome_have_fun = Programar es crear +welcome_notice_title = Aviso +welcome_notice_1 = Si puedes ver esta página, 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_notice_2 = Si el problema persiste, por favor, <strong>contacta con el administrador del sistema</strong>. +welcome_notice_3 = 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>. Antes de abrir una nueva incidencia, revisa las existentes para evitar duplicados. +welcome_notice_4 = Para fallos específicos de la aplicación (<strong>{ $app }</strong>), utiliza su repositorio oficial o su canal de soporte. From 2b2ce2c50164f53e90c76e292889dfd87188e9a4 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 18 Sep 2025 23:38:25 +0200 Subject: [PATCH 176/244] =?UTF-8?q?=F0=9F=8E=A8=20Unifica=20par=C3=A1metro?= =?UTF-8?q?s=20y=20estilos=20del=20tema=20b=C3=A1sico?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ofrece dos composiciones de página dirigidas a una introducción de contenidos neutra o con referencias a PageTop. --- src/base/extension/welcome.rs | 65 +++++++++------------------ src/base/theme/basic.rs | 85 +++++++++++++++++++++++++++++++---- src/core/theme/definition.rs | 10 ++--- src/locale/en-US/base.ftl | 7 +++ src/locale/en-US/welcome.ftl | 17 +++---- src/locale/es-ES/base.ftl | 7 +++ src/locale/es-ES/welcome.ftl | 17 +++---- static/css/intro.css | 6 +-- 8 files changed, 130 insertions(+), 84 deletions(-) diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs index e2a77128..5c6fec5a 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -25,55 +25,30 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { let app = &global::SETTINGS.app.name; Page::new(request) - .with_theme("basic") - .with_layout("intro") + .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_text", L10n::l("welcome_powered")) - .with_param("intro_button_link", "https://pagetop.cillero.es".to_string()) - .with_assets(AssetsOp::AddJavaScript(JavaScript::on_load_async("welcome-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("welcome-release").src = `https://img.shields.io/badge/Release%20date-${encodeURIComponent(formatted)}-blue?label=LABEL&style=for-the-badge`; - document.getElementById("welcome-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("welcome_release_label").using(cx).as_str()) - .to_string(), - ))) - .add_component(Html::with(|cx| html! { - p { (L10n::l("welcome_text1").using(cx)) } - div id="welcome-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("welcome_pagetop_label").lookup(cx)] {} (" ") - img - id="welcome-release" - alt=[L10n::l("welcome_release_label").lookup(cx)] {} (" ") - img - src=(format!( - "https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label={}&style=for-the-badge", - L10n::l("welcome_license_label").lookup(cx).unwrap_or_default() - )) - alt=[L10n::l("welcome_license_label").lookup(cx)] {} - } - p { (L10n::l("welcome_text2").using(cx)) } - })) + .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_notice_title")) - .add_component(Html::with(move |cx| html! { - p { (L10n::l("welcome_notice_1").using(cx)) } - p { (L10n::l("welcome_notice_2").using(cx)) } - p { (L10n::l("welcome_notice_3").using(cx)) } - p { (L10n::l("welcome_notice_4").with_arg("app", app).using(cx)) } + .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() diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index e6525489..2f492748 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -1,8 +1,33 @@ -//! Es el tema básico que incluye PageTop por defecto. - +/// Es el tema básico que incluye PageTop por defecto. use crate::prelude::*; /// 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. pub struct Basic; impl Extension for Basic { @@ -14,14 +39,16 @@ impl Extension for Basic { impl Theme for Basic { fn render_page_body(&self, page: &mut Page) -> Markup { match page.layout() { - "intro" => render_intro(page), + "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 styles = match page.layout() { - "intro" => "/css/intro.css", + "Intro" => "/css/intro.css", + "PageTopIntro" => "/css/intro.css", _ => "/css/basic.css", }; page.alter_assets(AssetsOp::AddStyleSheet( @@ -41,8 +68,8 @@ fn render_intro(page: &mut Page) -> Markup { let title = page.title().unwrap_or_default(); let intro = page.description().unwrap_or_default(); - let intro_button_text: L10n = page.param_or_default("intro_button_text"); - let intro_button_link: Option<&String> = page.param("intro_button_link"); + let intro_button_txt: L10n = page.param_or_default("intro_button_txt"); + let intro_button_lnk: Option<&String> = page.param("intro_button_lnk"); html! { body id=[page.body_id().get()] class=[page.body_classes().get()] { @@ -74,17 +101,17 @@ fn render_intro(page: &mut Page) -> Markup { } main class="intro-content" { section class="intro-content__body" { - @if intro_button_link.is_some() { + @if intro_button_lnk.is_some() { div class="intro-button" { a class="intro-button__link" - href=[intro_button_link] + href=[intro_button_lnk] target="_blank" rel="noreferrer" { span {} span {} span {} div class="intro-button__text" { - (intro_button_text.using(page)) + (intro_button_txt.using(page)) } } } @@ -119,3 +146,43 @@ fn render_intro(page: &mut Page) -> Markup { } } } + +fn render_pagetop_intro(page: &mut Page) -> Markup { + page.alter_assets(AssetsOp::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) +} diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index a4faf0b8..38a0bfc4 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -125,18 +125,18 @@ pub trait Theme: Extension + ThemePage + Send + Sync { /// 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. + /// Devuelve una **lista estática** de pares `(Region, L10n)` que se usará para renderizar todas + /// las regiones que componen una página en el orden indicado . /// - /// Requisitos y recomendaciones: + /// Si un tema necesita un conjunto distinto de regiones, se puede **sobrescribir** este método + /// con los siguientes 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: + /// Por defecto devuelve: /// /// - `"header"`: cabecera. /// - `"content"`: contenido principal (**obligatoria**). diff --git a/src/locale/en-US/base.ftl b/src/locale/en-US/base.ftl index 7a9701de..16b1a3ef 100644 --- a/src/locale/en-US/base.ftl +++ b/src/locale/en-US/base.ftl @@ -1,4 +1,11 @@ # Basic theme, intro layout. +intro_pagetop_label = PageTop version on Crates.io +intro_release_label = Release date +intro_license_label = License + +intro_text1 = PageTop is <strong>an opinionated Rust web development framework</strong> designed to build modular, extensible, and configurable web solutions. +intro_text2 = PageTop brings back the essence of the classic web, renders on the server (SSR) and uses <em>HTML-first</em> components, CSS and JavaScript, <strong>with the performance and security of Rust</strong>. + intro_code = Code intro_have_fun = Coding is creating diff --git a/src/locale/en-US/welcome.ftl b/src/locale/en-US/welcome.ftl index 0a227f1d..20faf964 100644 --- a/src/locale/en-US/welcome.ftl +++ b/src/locale/en-US/welcome.ftl @@ -7,15 +7,10 @@ welcome_title = Hello, world! welcome_intro = Discover⚡{ $app } welcome_powered = A web solution powered by <strong>PageTop</strong> -welcome_pagetop_label = PageTop version on Crates.io -welcome_release_label = Release date -welcome_license_label = License +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_text1 = PageTop is <strong>a Rust-based web development framework</strong> designed to build modular, extensible, and configurable web solutions. -welcome_text2 = PageTop brings back the essence of the classic web, renders on the server (SSR) and uses <em>HTML-first</em> components, CSS and JavaScript, <strong>with the performance and security of Rust</strong>. - -welcome_notice_title = Notice -welcome_notice_1 = If you can see this page, 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_notice_2 = If the issue persists, please <strong>contact the system administrator</strong>. -welcome_notice_3 = 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>. Before opening a new issue, review the existing ones to avoid duplicates. -welcome_notice_4 = For issues specific to the application (<strong>{ $app }</strong>), please use its official repository or support channel. +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_2 = For issues specific to the application (<strong>{ $app }</strong>), please use its official repository or support channel. diff --git a/src/locale/es-ES/base.ftl b/src/locale/es-ES/base.ftl index 99f6c7e8..fee21a93 100644 --- a/src/locale/es-ES/base.ftl +++ b/src/locale/es-ES/base.ftl @@ -1,4 +1,11 @@ # Basic theme, intro layout. +intro_pagetop_label = Versión de PageTop en Crates.io +intro_release_label = Lanzamiento +intro_license_label = Licencia + +intro_text1 = PageTop es un <strong>entorno de desarrollo web basado en Rust</strong>, pensado para construir soluciones web modulares, extensibles y configurables. +intro_text2 = PageTop reivindica la esencia de la web clásica, renderiza en el servidor (SSR) utilizando componentes <em>HTML-first</em>, CSS y JavaScript, <strong>con el rendimiento y la seguridad de Rust</strong>. + intro_code = Código intro_have_fun = Programar es crear diff --git a/src/locale/es-ES/welcome.ftl b/src/locale/es-ES/welcome.ftl index b98d9199..13330dbf 100644 --- a/src/locale/es-ES/welcome.ftl +++ b/src/locale/es-ES/welcome.ftl @@ -7,15 +7,10 @@ welcome_title = ¡Hola, mundo! welcome_intro = Descubre⚡{ $app } welcome_powered = Una solución web creada con <strong>PageTop</strong> -welcome_pagetop_label = Versión de PageTop en Crates.io -welcome_release_label = Lanzamiento -welcome_license_label = Licencia +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_text1 = PageTop es un <strong>entorno de desarrollo web basado en Rust</strong>, pensado para construir soluciones web modulares, extensibles y configurables. -welcome_text2 = PageTop reivindica la esencia de la web clásica, renderiza en el servidor (SSR) utilizando componentes <em>HTML-first</em>, CSS y JavaScript, <strong>con el rendimiento y la seguridad de Rust</strong>. - -welcome_notice_title = Aviso -welcome_notice_1 = Si puedes ver esta página, 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_notice_2 = Si el problema persiste, por favor, <strong>contacta con el administrador del sistema</strong>. -welcome_notice_3 = 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>. Antes de abrir una nueva incidencia, revisa las existentes para evitar duplicados. -welcome_notice_4 = Para fallos específicos de la aplicación (<strong>{ $app }</strong>), utiliza su repositorio oficial o su canal de soporte. +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_2 = Para fallos específicos de la aplicación (<strong>{ $app }</strong>), utiliza su repositorio oficial o su canal de soporte. diff --git a/static/css/intro.css b/static/css/intro.css index 19fa9f15..39c9d6ad 100644 --- a/static/css/intro.css +++ b/static/css/intro.css @@ -7,9 +7,9 @@ --color: #1a202c; --color-gray: #e4e4e7; --color-link: #1e4eae; - --color-block-1: #fecaca; - --color-block-2: #e6a9e2; - --color-block-3: #b689ff; + --color-block-1: #b689ff; + --color-block-2: #fecaca; + --color-block-3: #e6a9e2; --color-block-4: #ffedca; --color-block-5: #ffffff; --focus-outline: 2px solid var(--color-link); From 6d5e1dfdb483470c9fff935c71afed3bd2c16418 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 20 Sep 2025 13:08:47 +0200 Subject: [PATCH 177/244] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20(pagetop):=20Actua?= =?UTF-8?q?liza=20dependencias=20para=200.4.0=20(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://git.cillero.es/manuelcillero/pagetop/pulls/7 Co-authored-by: Manuel Cillero <manuel@cillero.es> Co-committed-by: Manuel Cillero <manuel@cillero.es> --- Cargo.lock | 179 +++++++++++++++++++---------- Cargo.toml | 40 +++---- helpers/pagetop-build/Cargo.toml | 2 +- helpers/pagetop-macros/Cargo.toml | 8 +- helpers/pagetop-statics/Cargo.toml | 4 +- 5 files changed, 146 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3053e20c..be745714 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -145,16 +145,16 @@ dependencies = [ [[package]] name = "actix-session" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efe6976a74f34f1b6d07a6c05aadc0ed0359304a7781c367fa5b4029418db08f" +checksum = "400c27fd4cdbe0082b7bbd29ac44a3070cbda1b2114138dc106ba39fe2f90dff" dependencies = [ "actix-service", "actix-utils", "actix-web", "anyhow", - "derive_more 1.0.0", - "rand 0.8.5", + "derive_more 2.0.1", + "rand 0.9.1", "serde", "serde_json", "tracing", @@ -334,9 +334,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.19" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", @@ -364,22 +364,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -406,7 +406,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -512,7 +512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "159fa412eae48a1d94d0b9ecdb85c97ce56eb2a347c62394d3fdbf221adabc1a" dependencies = [ "path-matchers", - "path-slash", + "path-slash 0.1.5", ] [[package]] @@ -541,18 +541,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.41" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.41" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" dependencies = [ "anstream", "anstyle", @@ -729,34 +729,13 @@ dependencies = [ "syn", ] -[[package]] -name = "derive_more" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" -dependencies = [ - "derive_more-impl 1.0.0", -] - [[package]] name = "derive_more" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" dependencies = [ - "derive_more-impl 2.0.1", -] - -[[package]] -name = "derive_more-impl" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", + "derive_more-impl", ] [[package]] @@ -815,7 +794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1619,7 +1598,7 @@ dependencies = [ "derive_more 0.99.20", "futures-util", "mime_guess", - "path-slash", + "path-slash 0.2.1", ] [[package]] @@ -1642,7 +1621,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1666,6 +1645,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498a099351efa4becc6a19c72aa9270598e8fd274ca47052e37455241c88b696" +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + [[package]] name = "pathdiff" version = "0.2.3" @@ -1802,9 +1787,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -2207,9 +2192,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -2229,15 +2214,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.20.0" +version = "3.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -2798,7 +2783,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -2807,7 +2792,16 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", ] [[package]] @@ -2816,14 +2810,31 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -2832,48 +2843,96 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.7.11" diff --git a/Cargo.toml b/Cargo.toml index ab7551f6..54f16c34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,29 +15,29 @@ license.workspace = true authors.workspace = true [dependencies] -chrono = "0.4.41" -colored = "3.0.0" -concat-string = "1.0.1" -config = { version = "0.15.13", default-features = false, features = ["toml"] } -figlet-rs = "0.1.5" -indoc = "2.0.6" -itoa = "1.0.15" -parking_lot = "0.12.4" -paste = { package = "pastey", version = "0.1.0" } -substring = "1.4.5" -terminal_size = "0.4.2" +chrono = "0.4" +colored = "3.0" +concat-string = "1.0" +config = { version = "0.15", default-features = false, features = ["toml"] } +figlet-rs = "0.1" +indoc = "2.0" +itoa = "1.0" +parking_lot = "0.12" +paste = { package = "pastey", version = "0.1" } +substring = "1.4" +terminal_size = "0.4" -tracing = "0.1.41" -tracing-appender = "0.2.3" -tracing-subscriber = { version = "0.3.19", features = ["json", "env-filter"] } -tracing-actix-web = "0.7.19" +tracing = "0.1" +tracing-appender = "0.2" +tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] } +tracing-actix-web = "0.7" -fluent-templates = "0.13.0" -unic-langid = { version = "0.9.6", features = ["macros"] } +fluent-templates = "0.13" +unic-langid = { version = "0.9", features = ["macros"] } actix-web = { workspace = true, default-features = true } -actix-session = { version = "0.10.1", features = ["cookie-session"] } -actix-web-files = { package = "actix-files", version = "0.6.6" } +actix-session = { version = "0.11", features = ["cookie-session"] } +actix-web-files = { package = "actix-files", version = "0.6" } serde = { version = "1.0", features = ["derive"] } @@ -49,7 +49,7 @@ default = [] testing = [] [dev-dependencies] -tempfile = "3.20.0" +tempfile = "3.22" [build-dependencies] pagetop-build.workspace = true diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index e0f5ef76..25fb6187 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -16,5 +16,5 @@ license.workspace = true authors.workspace = true [dependencies] -grass = "0.13.4" +grass = "0.13" pagetop-statics.workspace = true diff --git a/helpers/pagetop-macros/Cargo.toml b/helpers/pagetop-macros/Cargo.toml index d5ceb1b6..5c508dc8 100644 --- a/helpers/pagetop-macros/Cargo.toml +++ b/helpers/pagetop-macros/Cargo.toml @@ -18,7 +18,7 @@ authors.workspace = true proc-macro = true [dependencies] -proc-macro2 = "1.0.95" -proc-macro2-diagnostics = { version = "0.10.1", default-features = false } -quote = "1.0.40" -syn = { version = "2.0.104", features = ["full", "extra-traits"] } +proc-macro2 = "1.0" +proc-macro2-diagnostics = { version = "0.10", default-features = false } +quote = "1.0" +syn = { version = "2.0", features = ["full", "extra-traits"] } diff --git a/helpers/pagetop-statics/Cargo.toml b/helpers/pagetop-statics/Cargo.toml index 2afe3739..1f6deede 100644 --- a/helpers/pagetop-statics/Cargo.toml +++ b/helpers/pagetop-statics/Cargo.toml @@ -21,7 +21,7 @@ sort = [] [dependencies] change-detection = { version = "1.2", optional = true } mime_guess = "2.0" -path-slash = "0.1" +path-slash = "0.2" actix-web.workspace = true derive_more = "0.99.17" @@ -30,4 +30,4 @@ futures-util = { version = "0.3", default-features = false, features = ["std"] } [build-dependencies] change-detection = { version = "1.2", optional = true } mime_guess = "2.0" -path-slash = "0.1" +path-slash = "0.2" From b808c00eb1a7fd35ee34cb5bd75139fa0ab46c83 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 20 Sep 2025 13:14:52 +0200 Subject: [PATCH 178/244] =?UTF-8?q?=F0=9F=A9=B9=20Corrige=20dependencia=20?= =?UTF-8?q?no=20actualizada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 54f16c34..750aaaa8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ license = "MIT OR Apache-2.0" authors = ["Manuel Cillero <manuel@cillero.es>"] [workspace.dependencies] -actix-web = { version = "4.11.0", default-features = false } +actix-web = { version = "4.11", default-features = false } pagetop-build = { version = "0.3", path = "helpers/pagetop-build" } pagetop-macros = { version = "0.1", path = "helpers/pagetop-macros" } From adec5c2636f2ac0443bb061a8fecc2199516edf5 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 20 Sep 2025 13:19:14 +0200 Subject: [PATCH 179/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-statics=200.1.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- helpers/pagetop-statics/CHANGELOG.md | 12 +++++++++++- helpers/pagetop-statics/Cargo.toml | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index be745714..c5db7142 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1591,7 +1591,7 @@ dependencies = [ [[package]] name = "pagetop-statics" -version = "0.1.1" +version = "0.1.2" dependencies = [ "actix-web", "change-detection", diff --git a/helpers/pagetop-statics/CHANGELOG.md b/helpers/pagetop-statics/CHANGELOG.md index 811a77f4..0d6f5b1b 100644 --- a/helpers/pagetop-statics/CHANGELOG.md +++ b/helpers/pagetop-statics/CHANGELOG.md @@ -8,11 +8,21 @@ Resume la evolución del proyecto para usuarios y colaboradores, destacando nuev correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o internos pueden omitirse si no afectan al uso del proyecto. +## 0.1.2 (2025-09-20) + +### Dependencias + +- Actualiza dependencias para 0.4.0 + +### Documentado + +- Normaliza referencias al nombre PageTop + ## 0.1.1 (2025-08-16) ### Documentado -- Cambia el formato para la documentación (#4) +- Cambia el formato para la documentación ## 0.1.0 (2025-08-09) diff --git a/helpers/pagetop-statics/Cargo.toml b/helpers/pagetop-statics/Cargo.toml index 1f6deede..0172a190 100644 --- a/helpers/pagetop-statics/Cargo.toml +++ b/helpers/pagetop-statics/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-statics" -version = "0.1.1" +version = "0.1.2" edition = "2021" description = """ From ccafedaa0e4b3ba36bdededdd3493199318bef1f Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 20 Sep 2025 13:22:23 +0200 Subject: [PATCH 180/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-build=200.3.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- helpers/pagetop-build/CHANGELOG.md | 18 ++++++++++++++---- helpers/pagetop-build/Cargo.toml | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5db7142..bbe745b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1573,7 +1573,7 @@ dependencies = [ [[package]] name = "pagetop-build" -version = "0.3.0" +version = "0.3.1" dependencies = [ "grass", "pagetop-statics", diff --git a/helpers/pagetop-build/CHANGELOG.md b/helpers/pagetop-build/CHANGELOG.md index 3e3801e8..5bd9caf3 100644 --- a/helpers/pagetop-build/CHANGELOG.md +++ b/helpers/pagetop-build/CHANGELOG.md @@ -8,22 +8,32 @@ Resume la evolución del proyecto para usuarios y colaboradores, destacando nuev correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o internos pueden omitirse si no afectan al uso del proyecto. +## 0.3.1 (2025-09-20) + +### Dependencias + +- Actualiza dependencias para 0.4.0 + +### Documentado + +- Normaliza referencias al nombre PageTop + ## 0.3.0 (2025-08-16) ### Cambiado -- Mejora función `from_dir` por compatibilidad (#3) -- Mejora la integración de archivos estáticos +- Mejora función `from_dir` por compatibilidad +- Mejora la integración de archivos estáticos ### Documentado -- Cambia el formato para la documentación (#4) +- Cambia el formato para la documentación ## 0.2.0 (2025-08-09) ### Añadido -- Añade librería propia para gestionar recursos estáticos (#1) +- Añade librería propia para gestionar recursos estáticos ### Otros cambios diff --git a/helpers/pagetop-build/Cargo.toml b/helpers/pagetop-build/Cargo.toml index 25fb6187..cea1de3e 100644 --- a/helpers/pagetop-build/Cargo.toml +++ b/helpers/pagetop-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-build" -version = "0.3.0" +version = "0.3.1" edition = "2021" description = """ From e4a9a72fa791acbba2fcfac8b860152dba82213d Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 20 Sep 2025 13:25:59 +0200 Subject: [PATCH 181/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop-macros=200.2.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 2 +- Cargo.toml | 2 +- helpers/pagetop-macros/CHANGELOG.md | 19 +++++++++++++++++++ helpers/pagetop-macros/Cargo.toml | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bbe745b5..d125b63f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1581,7 +1581,7 @@ dependencies = [ [[package]] name = "pagetop-macros" -version = "0.1.1" +version = "0.2.0" dependencies = [ "proc-macro2", "proc-macro2-diagnostics", diff --git a/Cargo.toml b/Cargo.toml index 750aaaa8..0fd702e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,5 +73,5 @@ authors = ["Manuel Cillero <manuel@cillero.es>"] actix-web = { version = "4.11", default-features = false } pagetop-build = { version = "0.3", path = "helpers/pagetop-build" } -pagetop-macros = { version = "0.1", path = "helpers/pagetop-macros" } +pagetop-macros = { version = "0.2", path = "helpers/pagetop-macros" } pagetop-statics = { version = "0.1", path = "helpers/pagetop-statics" } diff --git a/helpers/pagetop-macros/CHANGELOG.md b/helpers/pagetop-macros/CHANGELOG.md index b61471a1..66a5f8d4 100644 --- a/helpers/pagetop-macros/CHANGELOG.md +++ b/helpers/pagetop-macros/CHANGELOG.md @@ -8,6 +8,25 @@ Resume la evolución del proyecto para usuarios y colaboradores, destacando nuev correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o internos pueden omitirse si no afectan al uso del proyecto. +## 0.2.0 (2025-09-20) + +### Cambiado + +- Retoques en el código +- Majora la validación de `builder_fn` + +### Dependencias + +- Actualiza dependencias para 0.4.0 + +### Documentado + +- Normaliza referencias al nombre PageTop + +### Otros cambios + +- 🚨 Ajustes menores sugeridos por clippy + ## 0.1.1 (2025-08-16) ### Documentado diff --git a/helpers/pagetop-macros/Cargo.toml b/helpers/pagetop-macros/Cargo.toml index 5c508dc8..601c551d 100644 --- a/helpers/pagetop-macros/Cargo.toml +++ b/helpers/pagetop-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop-macros" -version = "0.1.1" +version = "0.2.0" edition = "2021" description = """ From 6fac597a163706a6a5d4645b339d854eaf7e8c16 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 20 Sep 2025 13:43:36 +0200 Subject: [PATCH 182/244] =?UTF-8?q?=F0=9F=94=A8=20(tools):=20Fuerza=20puls?= =?UTF-8?q?ar=20intro=20para=20confirmar=20input?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/changelog.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/changelog.sh b/tools/changelog.sh index 2668ec67..211e896a 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -88,12 +88,12 @@ git-cliff --unreleased "${COMMON_ARGS[@]}" echo "CHANGELOG generated at '$CHANGELOG_FILE'" # Pregunta por la revisión del archivo de cambios generado -read -p "Do you want to review the changelog before continuing? (y/n) " -n 1 -r || exit 1 +read -p "Do you want to review the changelog before continuing? (y/n) " -r || exit 1 echo if [[ "$REPLY" =~ ^[Yy]$ ]]; then ${EDITOR:-nano} "$CHANGELOG_FILE" fi -read -p "Do you want to proceed with the release of $CRATE? (y/n) " -n 1 -r || exit 1 +read -p "Do you want to proceed with the release of $CRATE? (y/n) " -r || exit 1 echo if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then echo "Aborting release process." >&2 From 9536003badba7e3b59b79390e22cc25c2da0ba5d Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 20 Sep 2025 14:00:09 +0200 Subject: [PATCH 183/244] =?UTF-8?q?=F0=9F=94=96=20Prepara=20publicaci?= =?UTF-8?q?=C3=B3n=20de=20pagetop=200.4.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++--- Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e187143..f2926a69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,53 @@ Resume la evolución del proyecto para usuarios y colaboradores, destacando nuev correcciones, mejoras durante el desarrollo o cambios en la documentación. Cambios menores o internos pueden omitirse si no afectan al uso del proyecto. +## 0.4.0 (2025-09-20) + +### Añadido + +- [app] Añade manejo de rutas no encontradas +- [context] Añade métodos auxiliares de parámetros +- [util] Añade `indoc` para indentar código bien +- Añade componente `PoweredBy` para copyright + +### Cambiado + +- [html] Cambia tipos `Option...` por `Attr...` +- [html] Implementa `Default` en `Context` +- [welcome] Crea página de bienvenida desde intro +- [context] Generaliza los parámetros de contexto +- [context] Define un `trait` común de contexto +- Modifica tipos para atributos HTML a minúsculas +- Renombra `with_component` por `add_component` + +### Corregido + +- [welcome] Corrige giro botón con ancho estrecho +- [welcome] Corrige centrado del pie de página +- Corrige nombre de función en prueba de `Html` +- Corrige doc y código por cambios en Page + +### Dependencias + +- Actualiza dependencias para 0.4.0 + +### Documentado + +- [component] Amplía documentación de preparación +- Normaliza referencias al nombre PageTop +- Simplifica documentación de obsoletos +- Mejora la documentación de recursos y contexto + +### Otros cambios + +- 🎨 [theme] Mejora gestión de regiones en páginas +- ✅ [tests] Amplía pruebas para `PrepareMarkup' +- 🎨 [locale] Mejora el uso de `lookup` / `using` +- 🔨 [tools] Fuerza pulsar intro para confirmar input +- 💄 Aplica BEM a estilos de bienvenida y componente +- 🎨 Unifica conversiones a String con `to_string()` +- 🔥 Elimina `Render` para usar siempre el contexto + ## 0.3.0 (2025-08-16) ### Cambiado @@ -17,14 +64,14 @@ internos pueden omitirse si no afectan al uso del proyecto. ### Documentado -- Cambia el formato para la documentación (#4) +- Cambia el formato para la documentación ## 0.2.0 (2025-08-09) ### Añadido -- Añade librería para gestionar recursos estáticos (#1) -- Añade soporte a changelog de `pagetop-statics` (#2) +- Añade librería para gestionar recursos estáticos +- Añade soporte a changelog de `pagetop-statics` ### Documentado diff --git a/Cargo.lock b/Cargo.lock index d125b63f..01140831 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1542,7 +1542,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pagetop" -version = "0.3.0" +version = "0.4.0" dependencies = [ "actix-files", "actix-session", diff --git a/Cargo.toml b/Cargo.toml index 0fd702e6..913f3d7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pagetop" -version = "0.3.0" +version = "0.4.0" edition = "2021" description = """ From 95777379a9d0b45d8f3f0e1e66b60d2f5b84adcb Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 20 Sep 2025 17:55:44 +0200 Subject: [PATCH 184/244] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20=20Actualiza=20dep?= =?UTF-8?q?endencias=20mirando?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 553 +++++++++++++++++++++++++++-------------------------- 1 file changed, 286 insertions(+), 267 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 01140831..e0d497c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,9 +21,9 @@ dependencies = [ [[package]] name = "actix-files" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0773d59061dedb49a8aed04c67291b9d8cf2fe0b60130a381aab53c6dd86e9be" +checksum = "6c0d87f10d70e2948ad40e8edea79c8e77c6c66e0250a4c1f09b690465199576" dependencies = [ "actix-http", "actix-service", @@ -31,7 +31,7 @@ dependencies = [ "actix-web", "bitflags", "bytes", - "derive_more 0.99.20", + "derive_more 2.0.1", "futures-core", "http-range", "log", @@ -44,9 +44,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.11.0" +version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44dfe5c9e0004c623edc65391dfd51daa201e7e30ebd9c9bedf873048ec32bc2" +checksum = "44cceded2fb55f3c4b67068fa64962e2ca59614edc5b03167de9ff82ae803da0" dependencies = [ "actix-codec", "actix-rt", @@ -72,7 +72,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand 0.9.1", + "rand 0.9.2", "sha1", "smallvec", "tokio", @@ -108,9 +108,9 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" +checksum = "92589714878ca59a7626ea19734f0e07a6a875197eec751bb5d3f99e64998c63" dependencies = [ "futures-core", "tokio", @@ -128,7 +128,7 @@ dependencies = [ "futures-core", "futures-util", "mio", - "socket2", + "socket2 0.5.10", "tokio", "tracing", ] @@ -154,7 +154,7 @@ dependencies = [ "actix-web", "anyhow", "derive_more 2.0.1", - "rand 0.9.1", + "rand 0.9.2", "serde", "serde_json", "tracing", @@ -207,7 +207,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2", + "socket2 0.5.10", "time", "tracing", "url", @@ -317,12 +317,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -384,9 +378,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "autocfg" @@ -423,9 +417,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "block-buffer" @@ -438,9 +432,9 @@ dependencies = [ [[package]] name = "brotli" -version = "8.0.1" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -481,19 +475,20 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "bytestring" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" +checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289" dependencies = [ "bytes", ] [[package]] name = "cc" -version = "1.2.27" +version = "1.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -501,9 +496,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "change-detection" @@ -517,16 +512,15 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -595,12 +589,12 @@ checksum = "7439becb5fafc780b6f4de382b1a7a3e70234afe783854a4702ee8adbb838609" [[package]] name = "config" -version = "0.15.13" +version = "0.15.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b1eb4fb07bc7f012422df02766c7bd5971effb894f573865642f06fa3265440" +checksum = "cef036f0ecf99baef11555578630e2cca559909b4c50822dbba828c252d21c49" dependencies = [ "pathdiff", - "serde", + "serde_core", "toml", "winnow", ] @@ -709,9 +703,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" dependencies = [ "powerfmt", ] @@ -789,12 +783,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -809,6 +803,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4742a071cd9694fc86f9fa1a08fa3e53d40cc899d7ee532295da2d085639fbc5" +[[package]] +name = "find-msvc-tools" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" + [[package]] name = "flate2" version = "1.1.2" @@ -821,16 +821,16 @@ dependencies = [ [[package]] name = "fluent-bundle" -version = "0.15.3" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493" +checksum = "01203cb8918f5711e73891b347816d932046f95f54207710bda99beaeb423bf4" dependencies = [ "fluent-langneg", "fluent-syntax", "intl-memoizer", "intl_pluralrules", - "rustc-hash 1.1.0", - "self_cell 0.10.3", + "rustc-hash", + "self_cell", "smallvec", "unic-langid", ] @@ -846,18 +846,19 @@ dependencies = [ [[package]] name = "fluent-syntax" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" +checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198" dependencies = [ - "thiserror", + "memchr", + "thiserror 2.0.16", ] [[package]] name = "fluent-template-macros" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ed02449601d0dacdc05cb5e13db5dab8f2b98d773aff5c53b62fad43a1b19a1" +checksum = "e6222b8a208b9f0e7b984da3616651b0cc74e4461571b118cb1c713e0f7617ee" dependencies = [ "flume", "ignore", @@ -869,9 +870,9 @@ dependencies = [ [[package]] name = "fluent-templates" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69855a5fe87629495efca79aec72adfa97954f1006f928e3a2ec750cb3e85386" +checksum = "f8a893d77c0e48dc3f78421e9cba5d82e02bcb85d4520c506cec2fbebd0f513b" dependencies = [ "fluent-bundle", "fluent-langneg", @@ -881,7 +882,7 @@ dependencies = [ "ignore", "intl-memoizer", "log", - "thiserror", + "thiserror 1.0.69", "unic-langid", ] @@ -908,9 +909,9 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -978,7 +979,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] @@ -999,9 +1000,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "globset" @@ -1012,8 +1013,8 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", + "regex-automata", + "regex-syntax", ] [[package]] @@ -1072,9 +1073,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "hkdf" @@ -1125,9 +1126,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1235,9 +1236,9 @@ dependencies = [ [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -1264,7 +1265,7 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata 0.4.9", + "regex-automata", "same-file", "walkdir", "winapi-util", @@ -1278,12 +1279,12 @@ checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" [[package]] name = "indexmap" -version = "2.10.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.16.0", ] [[package]] @@ -1320,6 +1321,17 @@ dependencies = [ "unic-langid", ] +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -1334,9 +1346,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ "getrandom 0.3.3", "libc", @@ -1344,9 +1356,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" dependencies = [ "once_cell", "wasm-bindgen", @@ -1375,15 +1387,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.174" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" @@ -1420,17 +1432,17 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "matchers" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "regex-automata 0.1.10", + "regex-automata", ] [[package]] @@ -1484,12 +1496,11 @@ checksum = "e94e1e6445d314f972ff7395df2de295fe51b71821694f0b0e1e79c4f12c8577" [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" dependencies = [ - "overload", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -1534,12 +1545,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "pagetop" version = "0.4.0" @@ -1626,9 +1631,9 @@ dependencies = [ [[package]] name = "pastey" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3a8cb46bdc156b1c90460339ae6bfd45ba0394e5effbaa640badb4987fdc261" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" [[package]] name = "path-matchers" @@ -1659,9 +1664,9 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" @@ -1757,9 +1762,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" dependencies = [ "zerovec", ] @@ -1834,9 +1839,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", @@ -1882,74 +1887,53 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", + "regex-automata", + "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.1.10" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.5", + "regex-syntax", ] [[package]] name = "regex-lite" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" +checksum = "943f41321c63ef1c92fd763bfe054d2668f7f225a5c29f0105903dc2fc04ba30" [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "rustc-demangle" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" @@ -1968,22 +1952,22 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -2006,15 +1990,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "self_cell" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" -dependencies = [ - "self_cell 1.2.0", -] - [[package]] name = "self_cell" version = "1.2.0" @@ -2023,24 +1998,34 @@ checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.225" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" dependencies = [ "proc-macro2", "quote", @@ -2049,23 +2034,24 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] name = "serde_spanned" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -2119,9 +2105,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] @@ -2134,9 +2120,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" @@ -2154,6 +2140,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "spin" version = "0.9.8" @@ -2222,17 +2218,17 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] name = "terminal_size" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" dependencies = [ "rustix", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -2241,7 +2237,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +dependencies = [ + "thiserror-impl 2.0.16", ] [[package]] @@ -2255,6 +2260,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.9" @@ -2266,9 +2282,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", @@ -2281,15 +2297,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -2307,26 +2323,28 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.1" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", - "windows-sys 0.52.0", + "slab", + "socket2 0.6.0", + "windows-sys 0.59.0", ] [[package]] name = "tokio-util" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", @@ -2337,11 +2355,11 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.0" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f271e09bde39ab52250160a67e88577e0559ad77e9085de6e9051a2c4353f8f8" +checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" dependencies = [ - "serde", + "serde_core", "serde_spanned", "toml_datetime", "toml_parser", @@ -2350,18 +2368,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" dependencies = [ - "serde", + "serde_core", ] [[package]] name = "toml_parser" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5c1c469eda89749d2230d8156a5969a69ffe0d6d01200581cdc6110674d293e" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" dependencies = [ "winnow", ] @@ -2398,7 +2416,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" dependencies = [ "crossbeam-channel", - "thiserror", + "thiserror 1.0.69", "time", "tracing-subscriber", ] @@ -2447,14 +2465,14 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" dependencies = [ "matchers", "nu-ansi-term", "once_cell", - "regex", + "regex-automata", "serde", "serde_json", "sharded-slab", @@ -2472,7 +2490,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90" dependencies = [ - "rustc-hash 2.1.1", + "rustc-hash", ] [[package]] @@ -2532,9 +2550,9 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-xid" @@ -2554,13 +2572,14 @@ dependencies = [ [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -2577,9 +2596,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.17.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "getrandom 0.3.3", "js-sys", @@ -2622,30 +2641,40 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" dependencies = [ - "wit-bindgen-rt", + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" dependencies = [ "bumpalo", "log", @@ -2657,9 +2686,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2667,9 +2696,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" dependencies = [ "proc-macro2", "quote", @@ -2680,53 +2709,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" dependencies = [ "unicode-ident", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-core" -version = "0.61.2" +version = "0.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" dependencies = [ "windows-implement", "windows-interface", - "windows-link", + "windows-link 0.2.0", "windows-result", "windows-strings", ] @@ -2760,21 +2767,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] -name = "windows-result" -version = "0.3.4" +name = "windows-link" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" dependencies = [ - "windows-link", + "windows-link 0.2.0", ] [[package]] name = "windows-strings" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" dependencies = [ - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -2804,6 +2817,15 @@ dependencies = [ "windows-targets 0.53.3", ] +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -2826,7 +2848,7 @@ version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -2935,21 +2957,18 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" @@ -2983,18 +3002,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", @@ -3035,9 +3054,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", @@ -3075,9 +3094,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.15+zstd.1.5.7" +version = "2.0.16+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" dependencies = [ "cc", "pkg-config", From f8202aef2edc19d860a3b98cad5aabaaf4a8c3a4 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 20 Sep 2025 18:07:37 +0200 Subject: [PATCH 185/244] =?UTF-8?q?=F0=9F=94=A8=20(tools):=20Homogeiniza?= =?UTF-8?q?=20inputs=20de=20distintas=20fuentes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/changelog.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/changelog.sh b/tools/changelog.sh index 211e896a..722cdb7f 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -88,12 +88,13 @@ git-cliff --unreleased "${COMMON_ARGS[@]}" echo "CHANGELOG generated at '$CHANGELOG_FILE'" # Pregunta por la revisión del archivo de cambios generado -read -p "Do you want to review the changelog before continuing? (y/n) " -r || exit 1 -echo +echo "Do you want to review the changelog before continuing? [y/N]" +read -r REPLY if [[ "$REPLY" =~ ^[Yy]$ ]]; then ${EDITOR:-nano} "$CHANGELOG_FILE" fi -read -p "Do you want to proceed with the release of $CRATE? (y/n) " -r || exit 1 +echo "Do you want to proceed with the release of $CRATE? [y/N]" +read -r REPLY echo if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then echo "Aborting release process." >&2 From ce4557684e278fbd44103043c7269e09b4231c57 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 25 Sep 2025 21:36:37 +0200 Subject: [PATCH 186/244] =?UTF-8?q?=F0=9F=9A=9A=20Renombra=20`TypedSlot`?= =?UTF-8?q?=20por=20`TypedOpt`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/component.rs | 4 +-- src/core/component/optional.rs | 59 +++++++++++++++++++++++++++++++ src/core/component/slot.rs | 64 ---------------------------------- src/html.rs | 6 ++-- 4 files changed, 64 insertions(+), 69 deletions(-) create mode 100644 src/core/component/optional.rs delete mode 100644 src/core/component/slot.rs diff --git a/src/core/component.rs b/src/core/component.rs index 36914722..e5858cbf 100644 --- a/src/core/component.rs +++ b/src/core/component.rs @@ -8,5 +8,5 @@ pub use children::Children; pub use children::{Child, ChildOp}; pub use children::{Typed, TypedOp}; -mod slot; -pub use slot::TypedSlot; +mod optional; +pub use optional::TypedOpt; diff --git a/src/core/component/optional.rs b/src/core/component/optional.rs new file mode 100644 index 00000000..c13b8335 --- /dev/null +++ b/src/core/component/optional.rs @@ -0,0 +1,59 @@ +use crate::core::component::{Component, Typed}; +use crate::html::{html, Context, Markup}; +use crate::{builder_fn, AutoDefault}; + +/// Contenedor **opcional** para un componente [`Typed`]. +/// +/// Un `TypedOpt` actúa como un contenedor para incluir o no un subcomponente tipado. Internamente +/// encapsula `Option<Typed<C>>`, pero ofrece una API más sencilla para construir estructuras +/// jerárquicas o contenidas de componentes. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// let icon = Icon::default(); +/// let icon = TypedOpt::new(icon); +/// assert!(icon.get().is_some()); +/// ``` +#[derive(AutoDefault)] +pub struct TypedOpt<C: Component>(Option<Typed<C>>); + +impl<C: Component> TypedOpt<C> { + /// Crea un nuevo [`TypedOpt`]. + /// + /// El componente se envuelve automáticamente en un [`Typed`] y se almacena. + pub fn new(component: C) -> Self { + TypedOpt(Some(Typed::with(component))) + } + + // TypedOpt BUILDER **************************************************************************** + + /// Establece un componente nuevo, o lo vacía. + /// + /// Si se proporciona `Some(component)`, se guarda como [`Typed`]; y si es `None`, se limpia. + #[builder_fn] + pub fn with_component(mut self, component: Option<C>) -> Self { + self.0 = component.map(Typed::with); + self + } + + // TypedOpt GETTERS **************************************************************************** + + /// Devuelve un clon (incrementa el contador `Arc`) de [`Typed<C>`], si existe. + pub fn get(&self) -> Option<Typed<C>> { + self.0.clone() + } + + // TypedOpt RENDER ***************************************************************************** + + /// Renderiza el componente, si existe. + pub fn render(&self, cx: &mut Context) -> Markup { + if let Some(component) = &self.0 { + component.render(cx) + } else { + html! {} + } + } +} diff --git a/src/core/component/slot.rs b/src/core/component/slot.rs deleted file mode 100644 index 19ed72ac..00000000 --- a/src/core/component/slot.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::builder_fn; -use crate::core::component::{Component, Typed}; -use crate::html::{html, Context, Markup}; - -/// Contenedor para un componente [`Typed`] opcional. -/// -/// Un `TypedSlot` actúa como un contenedor dentro de otro componente para incluir o no un -/// subcomponente. Internamente encapsula `Option<Typed<C>>`, pero proporciona una API más sencilla -/// para construir estructuras jerárquicas. -/// -/// # Ejemplo -/// -/// ```rust,ignore -/// use pagetop::prelude::*; -/// -/// let comp = MyComponent::new(); -/// let opt = TypedSlot::new(comp); -/// assert!(opt.get().is_some()); -/// ``` -pub struct TypedSlot<C: Component>(Option<Typed<C>>); - -impl<C: Component> Default for TypedSlot<C> { - fn default() -> Self { - TypedSlot(None) - } -} - -impl<C: Component> TypedSlot<C> { - /// Crea un nuevo [`TypedSlot`]. - /// - /// El componente se envuelve automáticamente en un [`Typed`] y se almacena. - pub fn new(component: C) -> Self { - TypedSlot(Some(Typed::with(component))) - } - - // TypedSlot BUILDER ********************************************************************* - - /// Establece un componente nuevo, o lo vacía. - /// - /// Si se proporciona `Some(component)`, se guarda en [`Typed`]; y si es `None`, se limpia. - #[builder_fn] - pub fn with_value(mut self, component: Option<C>) -> Self { - self.0 = component.map(Typed::with); - self - } - - // TypedSlot GETTERS ********************************************************************* - - /// Devuelve un clon (incrementa el contador `Arc`) de [`Typed<C>`], si existe. - pub fn get(&self) -> Option<Typed<C>> { - self.0.clone() - } - - // TypedSlot RENDER ************************************************************************ - - /// Renderiza el componente, si existe. - pub fn render(&self, cx: &mut Context) -> Markup { - if let Some(component) = &self.0 { - component.render(cx) - } else { - html! {} - } - } -} diff --git a/src/html.rs b/src/html.rs index 4858bbfa..89d19d4e 100644 --- a/src/html.rs +++ b/src/html.rs @@ -50,14 +50,14 @@ pub type OptionClasses = AttrClasses; use crate::{core, AutoDefault}; -/// **Obsoleto desde la versión 0.4.0**: usar [`TypedSlot`](crate::core::component::TypedSlot) en su +/// **Obsoleto desde la versión 0.4.0**: usar [`TypedOpt`](crate::core::component::TypedOpt) en su /// lugar. #[deprecated( since = "0.4.0", - note = "Use `pagetop::core::component::TypedSlot` instead" + note = "Use `pagetop::core::component::TypedOpt` instead" )] #[allow(type_alias_bounds)] -pub type OptionComponent<C: core::component::Component> = core::component::TypedSlot<C>; +pub type OptionComponent<C: core::component::Component> = core::component::TypedOpt<C>; /// Prepara contenido HTML para su conversión a [`Markup`]. /// From 2ac3c2a9c4a0210a13c8745d2277f859c2e57579 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 27 Sep 2025 21:18:54 +0200 Subject: [PATCH 187/244] =?UTF-8?q?=F0=9F=94=A5=20Elimina=20definitivament?= =?UTF-8?q?e=20`TypedOpt`=20por=20`Typed`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/component.rs | 3 -- src/core/component/children.rs | 77 +++++++++++++++++++++++----------- src/core/component/optional.rs | 59 -------------------------- src/html.rs | 7 ++-- 4 files changed, 56 insertions(+), 90 deletions(-) delete mode 100644 src/core/component/optional.rs diff --git a/src/core/component.rs b/src/core/component.rs index e5858cbf..17b9b735 100644 --- a/src/core/component.rs +++ b/src/core/component.rs @@ -7,6 +7,3 @@ mod children; pub use children::Children; pub use children::{Child, ChildOp}; pub use children::{Typed, TypedOp}; - -mod optional; -pub use optional::TypedOpt; diff --git a/src/core/component/children.rs b/src/core/component/children.rs index cb112e16..2b16f068 100644 --- a/src/core/component/children.rs +++ b/src/core/component/children.rs @@ -1,6 +1,6 @@ use crate::core::component::Component; use crate::html::{html, Context, Markup}; -use crate::{builder_fn, UniqueId}; +use crate::{builder_fn, AutoDefault, UniqueId}; use parking_lot::RwLock; @@ -11,76 +11,105 @@ use std::vec::IntoIter; /// /// Esta estructura permite manipular y renderizar un componente que implemente [`Component`], y /// habilita acceso concurrente mediante [`Arc<RwLock<_>>`]. -#[derive(Clone)] -pub struct Child(Arc<RwLock<dyn Component>>); +#[derive(AutoDefault, Clone)] +pub struct Child(Option<Arc<RwLock<dyn Component>>>); impl Child { /// Crea un nuevo `Child` a partir de un componente. pub fn with(component: impl Component) -> Self { - Child(Arc::new(RwLock::new(component))) + Child(Some(Arc::new(RwLock::new(component)))) + } + + // Child BUILDER ******************************************************************************* + + /// Establece un componente nuevo, o lo vacía. + /// + /// Si se proporciona `Some(component)`, se encapsula como [`Child`]; y si es `None`, se limpia. + #[builder_fn] + pub fn with_component<C: Component>(mut self, component: Option<C>) -> Self { + if let Some(c) = component { + self.0 = Some(Arc::new(RwLock::new(c))); + } else { + self.0 = None; + } + self } // Child GETTERS ******************************************************************************* - /// Devuelve el identificador del componente, si está definido. + /// Devuelve el identificador del componente, si existe y está definido. + #[inline] pub fn id(&self) -> Option<String> { - self.0.read().id() + self.0.as_ref().and_then(|c| c.read().id()) } // Child RENDER ******************************************************************************** /// Renderiza el componente con el contexto proporcionado. pub fn render(&self, cx: &mut Context) -> Markup { - self.0.write().render(cx) + self.0.as_ref().map_or(html! {}, |c| c.write().render(cx)) } // Child HELPERS ******************************************************************************* - // Devuelve el [`UniqueId`] del tipo del componente. - fn type_id(&self) -> UniqueId { - self.0.read().type_id() + // Devuelve el [`UniqueId`] del tipo del componente, si existe. + #[inline] + fn type_id(&self) -> Option<UniqueId> { + self.0.as_ref().map(|c| c.read().type_id()) } } // ************************************************************************************************* -/// Variante tipada de [`Child`] para evitar conversiones durante el uso. +/// Variante tipada de [`Child`] para evitar conversiones de tipo durante el uso. /// /// Esta estructura permite manipular y renderizar un componente concreto que implemente /// [`Component`], y habilita acceso concurrente mediante [`Arc<RwLock<_>>`]. -pub struct Typed<C: Component>(Arc<RwLock<C>>); - -impl<C: Component> Clone for Typed<C> { - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} +#[derive(AutoDefault, Clone)] +pub struct Typed<C: Component>(Option<Arc<RwLock<C>>>); impl<C: Component> Typed<C> { /// Crea un nuevo `Typed` a partir de un componente. pub fn with(component: C) -> Self { - Typed(Arc::new(RwLock::new(component))) + Typed(Some(Arc::new(RwLock::new(component)))) + } + + // Typed BUILDER ******************************************************************************* + + /// Establece un componente nuevo, o lo vacía. + /// + /// Si se proporciona `Some(component)`, se encapsula como [`Typed`]; y si es `None`, se limpia. + #[builder_fn] + pub fn with_component(mut self, component: Option<C>) -> Self { + self.0 = component.map(|c| Arc::new(RwLock::new(c))); + self } // Typed GETTERS ******************************************************************************* - /// Devuelve el identificador del componente, si está definido. + /// Devuelve el identificador del componente, si existe y está definido. + #[inline] pub fn id(&self) -> Option<String> { - self.0.read().id() + self.0.as_ref().and_then(|c| c.read().id()) } // Typed RENDER ******************************************************************************** /// Renderiza el componente con el contexto proporcionado. pub fn render(&self, cx: &mut Context) -> Markup { - self.0.write().render(cx) + self.0.as_ref().map_or(html! {}, |c| c.write().render(cx)) } // Typed HELPERS ******************************************************************************* // Convierte el componente tipado en un [`Child`]. + #[inline] fn into_child(self) -> Child { - Child(self.0.clone()) + if let Some(c) = &self.0 { + Child(Some(c.clone())) + } else { + Child(None) + } } } @@ -201,7 +230,7 @@ impl Children { /// Devuelve un iterador sobre los componentes hijo con el identificador de tipo ([`UniqueId`]) /// indicado. pub fn iter_by_type_id(&self, type_id: UniqueId) -> impl Iterator<Item = &Child> { - self.0.iter().filter(move |&c| c.type_id() == type_id) + self.0.iter().filter(move |&c| c.type_id() == Some(type_id)) } // Children RENDER ***************************************************************************** diff --git a/src/core/component/optional.rs b/src/core/component/optional.rs deleted file mode 100644 index c13b8335..00000000 --- a/src/core/component/optional.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::core::component::{Component, Typed}; -use crate::html::{html, Context, Markup}; -use crate::{builder_fn, AutoDefault}; - -/// Contenedor **opcional** para un componente [`Typed`]. -/// -/// Un `TypedOpt` actúa como un contenedor para incluir o no un subcomponente tipado. Internamente -/// encapsula `Option<Typed<C>>`, pero ofrece una API más sencilla para construir estructuras -/// jerárquicas o contenidas de componentes. -/// -/// # Ejemplo -/// -/// ```rust -/// use pagetop::prelude::*; -/// -/// let icon = Icon::default(); -/// let icon = TypedOpt::new(icon); -/// assert!(icon.get().is_some()); -/// ``` -#[derive(AutoDefault)] -pub struct TypedOpt<C: Component>(Option<Typed<C>>); - -impl<C: Component> TypedOpt<C> { - /// Crea un nuevo [`TypedOpt`]. - /// - /// El componente se envuelve automáticamente en un [`Typed`] y se almacena. - pub fn new(component: C) -> Self { - TypedOpt(Some(Typed::with(component))) - } - - // TypedOpt BUILDER **************************************************************************** - - /// Establece un componente nuevo, o lo vacía. - /// - /// Si se proporciona `Some(component)`, se guarda como [`Typed`]; y si es `None`, se limpia. - #[builder_fn] - pub fn with_component(mut self, component: Option<C>) -> Self { - self.0 = component.map(Typed::with); - self - } - - // TypedOpt GETTERS **************************************************************************** - - /// Devuelve un clon (incrementa el contador `Arc`) de [`Typed<C>`], si existe. - pub fn get(&self) -> Option<Typed<C>> { - self.0.clone() - } - - // TypedOpt RENDER ***************************************************************************** - - /// Renderiza el componente, si existe. - pub fn render(&self, cx: &mut Context) -> Markup { - if let Some(component) = &self.0 { - component.render(cx) - } else { - html! {} - } - } -} diff --git a/src/html.rs b/src/html.rs index 89d19d4e..4a965cab 100644 --- a/src/html.rs +++ b/src/html.rs @@ -50,14 +50,13 @@ pub type OptionClasses = AttrClasses; use crate::{core, AutoDefault}; -/// **Obsoleto desde la versión 0.4.0**: usar [`TypedOpt`](crate::core::component::TypedOpt) en su -/// lugar. +/// **Obsoleto desde la versión 0.4.0**: usar [`Typed`](crate::core::component::Typed) en su lugar. #[deprecated( since = "0.4.0", - note = "Use `pagetop::core::component::TypedOpt` instead" + note = "Use `pagetop::core::component::Typed` instead" )] #[allow(type_alias_bounds)] -pub type OptionComponent<C: core::component::Component> = core::component::TypedOpt<C>; +pub type OptionComponent<C: core::component::Component> = core::component::Typed<C>; /// Prepara contenido HTML para su conversión a [`Markup`]. /// From 31435f30d3b53d9219dc4ce27384b9816d7fa4fc Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 28 Sep 2025 08:51:21 +0200 Subject: [PATCH 188/244] =?UTF-8?q?=F0=9F=92=A1=20Mejora=20legibilidad=20d?= =?UTF-8?q?e=20comentarios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component/block.rs | 6 +++--- src/base/component/html.rs | 4 ++-- src/base/component/poweredby.rs | 4 ++-- src/core/action/all.rs | 6 +++--- src/core/component/children.rs | 24 ++++++++++++------------ src/core/extension/all.rs | 10 +++++----- src/core/theme/all.rs | 6 +++--- src/html.rs | 6 +++--- src/html/assets/favicon.rs | 4 +++- src/html/assets/javascript.rs | 4 +++- src/html/assets/stylesheet.rs | 6 ++++-- src/html/attr_classes.rs | 4 ++-- src/html/attr_id.rs | 4 ++-- src/html/attr_l10n.rs | 4 ++-- src/html/attr_name.rs | 4 ++-- src/html/attr_value.rs | 4 ++-- src/html/context.rs | 16 ++++++++-------- src/lib.rs | 6 +++--- src/response/page.rs | 12 ++++++------ src/util.rs | 6 +++--- tests/component_poweredby.rs | 2 +- 21 files changed, 74 insertions(+), 68 deletions(-) diff --git a/src/base/component/block.rs b/src/base/component/block.rs index c96f2baf..9a04c4ea 100644 --- a/src/base/component/block.rs +++ b/src/base/component/block.rs @@ -47,7 +47,7 @@ impl Component for Block { } impl Block { - // Block BUILDER ******************************************************************************* + // **< Block BUILDER >************************************************************************** /// Establece el identificador único (`id`) del bloque. #[builder_fn] @@ -77,14 +77,14 @@ impl Block { self } - /// Modifica la lista de hijos (`children`) aplicando una operación. + /// 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 } - // Block GETTERS ******************************************************************************* + // **< Block GETTERS >************************************************************************** /// Devuelve las clases CSS asociadas al bloque. pub fn classes(&self) -> &AttrClasses { diff --git a/src/base/component/html.rs b/src/base/component/html.rs index 8fa56902..b8c4aaaa 100644 --- a/src/base/component/html.rs +++ b/src/base/component/html.rs @@ -49,7 +49,7 @@ impl Component for Html { } impl Html { - // Html BUILDER ******************************************************************************** + // **< Html BUILDER >*************************************************************************** /// Crea una instancia que generará el `Markup`, con acceso opcional al contexto. /// @@ -77,7 +77,7 @@ impl Html { self } - // Html GETTERS ******************************************************************************** + // **< Html GETTERS >*************************************************************************** /// Aplica la función interna de renderizado con el [`Context`] proporcionado. /// diff --git a/src/base/component/poweredby.rs b/src/base/component/poweredby.rs index bfe38351..4b54af36 100644 --- a/src/base/component/poweredby.rs +++ b/src/base/component/poweredby.rs @@ -39,7 +39,7 @@ impl Component for PoweredBy { } impl PoweredBy { - // PoweredBy BUILDER *************************************************************************** + // **< PoweredBy BUILDER >********************************************************************** /// Establece el texto de copyright que mostrará el componente. /// @@ -58,7 +58,7 @@ impl PoweredBy { self } - // PoweredBy GETTERS *************************************************************************** + // **< PoweredBy GETTERS >********************************************************************** /// Devuelve el texto de copyright actual, si existe. pub fn copyright(&self) -> Option<&str> { diff --git a/src/core/action/all.rs b/src/core/action/all.rs index 7fff970c..fbbf8427 100644 --- a/src/core/action/all.rs +++ b/src/core/action/all.rs @@ -5,12 +5,12 @@ use parking_lot::RwLock; use std::collections::HashMap; use std::sync::LazyLock; -// ACCIONES **************************************************************************************** +// **< ACCIONES >*********************************************************************************** static ACTIONS: LazyLock<RwLock<HashMap<ActionKey, ActionsList>>> = LazyLock::new(|| RwLock::new(HashMap::new())); -// AÑADIR ACCIONES ********************************************************************************* +// **< AÑADIR ACCIONES >**************************************************************************** // Registra una nueva acción en el sistema. // @@ -36,7 +36,7 @@ pub fn add_action(action: ActionBox) { } } -// DESPLEGAR ACCIONES ****************************************************************************** +// **< DESPLEGAR ACCIONES >************************************************************************* /// Despacha y ejecuta las funciones asociadas a una [`ActionKey`]. /// diff --git a/src/core/component/children.rs b/src/core/component/children.rs index 2b16f068..920dacf8 100644 --- a/src/core/component/children.rs +++ b/src/core/component/children.rs @@ -20,7 +20,7 @@ impl Child { Child(Some(Arc::new(RwLock::new(component)))) } - // Child BUILDER ******************************************************************************* + // **< Child BUILDER >************************************************************************** /// Establece un componente nuevo, o lo vacía. /// @@ -35,7 +35,7 @@ impl Child { self } - // Child GETTERS ******************************************************************************* + // **< Child GETTERS >************************************************************************** /// Devuelve el identificador del componente, si existe y está definido. #[inline] @@ -43,14 +43,14 @@ impl Child { self.0.as_ref().and_then(|c| c.read().id()) } - // Child RENDER ******************************************************************************** + // **< Child RENDER >*************************************************************************** /// Renderiza el componente con el contexto proporcionado. pub fn render(&self, cx: &mut Context) -> Markup { self.0.as_ref().map_or(html! {}, |c| c.write().render(cx)) } - // Child HELPERS ******************************************************************************* + // **< Child HELPERS >************************************************************************** // Devuelve el [`UniqueId`] del tipo del componente, si existe. #[inline] @@ -74,7 +74,7 @@ impl<C: Component> Typed<C> { Typed(Some(Arc::new(RwLock::new(component)))) } - // Typed BUILDER ******************************************************************************* + // **< Typed BUILDER >************************************************************************** /// Establece un componente nuevo, o lo vacía. /// @@ -85,7 +85,7 @@ impl<C: Component> Typed<C> { self } - // Typed GETTERS ******************************************************************************* + // **< Typed GETTERS >************************************************************************** /// Devuelve el identificador del componente, si existe y está definido. #[inline] @@ -93,14 +93,14 @@ impl<C: Component> Typed<C> { self.0.as_ref().and_then(|c| c.read().id()) } - // Typed RENDER ******************************************************************************** + // **< Typed RENDER >*************************************************************************** /// Renderiza el componente con el contexto proporcionado. pub fn render(&self, cx: &mut Context) -> Markup { self.0.as_ref().map_or(html! {}, |c| c.write().render(cx)) } - // Typed HELPERS ******************************************************************************* + // **< Typed HELPERS >************************************************************************** // Convierte el componente tipado en un [`Child`]. #[inline] @@ -165,7 +165,7 @@ impl Children { opt } - // Children BUILDER **************************************************************************** + // **< Children BUILDER >*********************************************************************** /// Ejecuta una operación con [`ChildOp`] en la lista. #[builder_fn] @@ -204,7 +204,7 @@ impl Children { self } - // Children GETTERS **************************************************************************** + // **< Children GETTERS >*********************************************************************** /// Devuelve el número de componentes hijo de la lista. pub fn len(&self) -> usize { @@ -233,7 +233,7 @@ impl Children { self.0.iter().filter(move |&c| c.type_id() == Some(type_id)) } - // Children RENDER ***************************************************************************** + // **< Children RENDER >************************************************************************ /// Renderiza todos los componentes hijo, en orden. pub fn render(&self, cx: &mut Context) -> Markup { @@ -244,7 +244,7 @@ impl Children { } } - // Children HELPERS **************************************************************************** + // **< Children HELPERS >*********************************************************************** // Inserta un hijo después del componente con el `id` dado, o al final si no se encuentra. #[inline] diff --git a/src/core/extension/all.rs b/src/core/extension/all.rs index a243778c..fa67671d 100644 --- a/src/core/extension/all.rs +++ b/src/core/extension/all.rs @@ -7,7 +7,7 @@ use parking_lot::RwLock; use std::sync::LazyLock; -// EXTENSIONES ************************************************************************************* +// **< EXTENSIONES >******************************************************************************** static ENABLED_EXTENSIONS: LazyLock<RwLock<Vec<ExtensionRef>>> = LazyLock::new(|| RwLock::new(Vec::new())); @@ -15,7 +15,7 @@ static ENABLED_EXTENSIONS: LazyLock<RwLock<Vec<ExtensionRef>>> = static DROPPED_EXTENSIONS: LazyLock<RwLock<Vec<ExtensionRef>>> = LazyLock::new(|| RwLock::new(Vec::new())); -// REGISTRO DE LAS EXTENSIONES ********************************************************************* +// **< REGISTRO DE LAS EXTENSIONES >**************************************************************** pub fn register_extensions(root_extension: Option<ExtensionRef>) { // Prepara la lista de extensiones habilitadas. @@ -104,7 +104,7 @@ fn add_to_dropped(list: &mut Vec<ExtensionRef>, extension: ExtensionRef) { } } -// REGISTRO DE LAS ACCIONES ************************************************************************ +// **< REGISTRO DE LAS ACCIONES >******************************************************************* pub fn register_actions() { for extension in ENABLED_EXTENSIONS.read().iter() { @@ -114,7 +114,7 @@ pub fn register_actions() { } } -// INICIALIZA LAS EXTENSIONES ********************************************************************** +// **< INICIALIZA LAS EXTENSIONES >***************************************************************** pub fn initialize_extensions() { trace::info!("Calling application bootstrap"); @@ -123,7 +123,7 @@ pub fn initialize_extensions() { } } -// CONFIGURA LOS SERVICIOS ************************************************************************* +// **< CONFIGURA LOS SERVICIOS >******************************************************************** pub fn configure_services(scfg: &mut service::web::ServiceConfig) { // Sólo compila durante el desarrollo, para evitar errores 400 en la traza de eventos. diff --git a/src/core/theme/all.rs b/src/core/theme/all.rs index ebb28481..5e6b65b0 100644 --- a/src/core/theme/all.rs +++ b/src/core/theme/all.rs @@ -5,11 +5,11 @@ use parking_lot::RwLock; use std::sync::LazyLock; -// TEMAS ******************************************************************************************* +// **< TEMAS >************************************************************************************** pub static THEMES: LazyLock<RwLock<Vec<ThemeRef>>> = LazyLock::new(|| RwLock::new(Vec::new())); -// TEMA PREDETERMINADO ***************************************************************************** +// **< TEMA PREDETERMINADO >************************************************************************ pub static DEFAULT_THEME: LazyLock<ThemeRef> = LazyLock::new(|| match theme_by_short_name(&global::SETTINGS.app.theme) { @@ -17,7 +17,7 @@ pub static DEFAULT_THEME: LazyLock<ThemeRef> = None => &crate::base::theme::Basic, }); -// TEMA POR NOMBRE ********************************************************************************* +// **< TEMA POR NOMBRE >**************************************************************************** // Devuelve el tema identificado por su [`short_name()`](AnyInfo::short_name). pub fn theme_by_short_name(short_name: &'static str) -> Option<ThemeRef> { diff --git a/src/html.rs b/src/html.rs index 4a965cab..b6815ece 100644 --- a/src/html.rs +++ b/src/html.rs @@ -3,7 +3,7 @@ mod maud; pub use maud::{display, html, html_private, Escaper, Markup, PreEscaped, DOCTYPE}; -// HTML DOCUMENT ASSETS **************************************************************************** +// **< HTML DOCUMENT ASSETS >*********************************************************************** mod assets; pub use assets::favicon::Favicon; @@ -11,12 +11,12 @@ pub use assets::javascript::JavaScript; pub use assets::stylesheet::{StyleSheet, TargetMedia}; pub use assets::{Asset, Assets}; -// HTML DOCUMENT CONTEXT *************************************************************************** +// **< HTML DOCUMENT CONTEXT >********************************************************************** mod context; pub use context::{AssetsOp, Context, Contextual, ErrorParam}; -// HTML ATTRIBUTES ********************************************************************************* +// **< HTML ATTRIBUTES >**************************************************************************** mod attr_id; pub use attr_id::AttrId; diff --git a/src/html/assets/favicon.rs b/src/html/assets/favicon.rs index d731b8f5..56c39056 100644 --- a/src/html/assets/favicon.rs +++ b/src/html/assets/favicon.rs @@ -52,7 +52,7 @@ impl Favicon { Favicon::default() } - // Favicon BUILDER ***************************************************************************** + // **< Favicon BUILDER >************************************************************************ /// Le añade un icono genérico apuntando a `image`. El tipo MIME se infiere automáticamente a /// partir de la extensión. @@ -152,6 +152,8 @@ impl Favicon { self } + // **< Favicon RENDER >************************************************************************* + /// Renderiza el **Favicon** completo con todas las etiquetas declaradas. /// /// El parámetro `Context` se acepta por coherencia con el resto de *assets*, aunque en este diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs index a8ed3e8c..4649cdb4 100644 --- a/src/html/assets/javascript.rs +++ b/src/html/assets/javascript.rs @@ -171,7 +171,7 @@ impl JavaScript { } } - // JavaScript BUILDER ************************************************************************** + // **< JavaScript BUILDER >********************************************************************* /// Asocia una **versión** al recurso (usada para control de la caché del navegador). /// @@ -210,6 +210,8 @@ impl Asset for JavaScript { self.weight } + // **< JavaScript RENDER >********************************************************************** + fn render(&self, cx: &mut Context) -> Markup { match &self.source { Source::From(path) => html! { diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index 3ecc77fc..b54f4cf3 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -113,7 +113,7 @@ impl StyleSheet { } } - // StyleSheet BUILDER ************************************************************************** + // **< StyleSheet BUILDER >********************************************************************* /// Asocia una versión al recurso (usada para control de la caché del navegador). /// @@ -132,7 +132,7 @@ impl StyleSheet { self } - // StyleSheet EXTRAS *************************************************************************** + // **< StyleSheet HELPERS >********************************************************************* /// Especifica el medio donde se aplican los estilos. /// @@ -163,6 +163,8 @@ impl Asset for StyleSheet { self.weight } + // **< StyleSheet RENDER >********************************************************************** + fn render(&self, cx: &mut Context) -> Markup { match &self.source { Source::From(path) => html! { diff --git a/src/html/attr_classes.rs b/src/html/attr_classes.rs index 098c26cd..80fdad79 100644 --- a/src/html/attr_classes.rs +++ b/src/html/attr_classes.rs @@ -48,7 +48,7 @@ impl AttrClasses { AttrClasses::default().with_value(ClassesOp::Prepend, classes) } - // AttrClasses BUILDER ************************************************************************* + // **< AttrClasses BUILDER >******************************************************************** #[builder_fn] pub fn with_value(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { @@ -114,7 +114,7 @@ impl AttrClasses { } } - // AttrClasses GETTERS ************************************************************************* + // **< AttrClasses GETTERS >******************************************************************** /// Devuelve la cadena de clases, si existe. pub fn get(&self) -> Option<String> { diff --git a/src/html/attr_id.rs b/src/html/attr_id.rs index 8bb1d33b..3d5f3eb4 100644 --- a/src/html/attr_id.rs +++ b/src/html/attr_id.rs @@ -29,7 +29,7 @@ impl AttrId { AttrId::default().with_value(value) } - // AttrId BUILDER ****************************************************************************** + // **< AttrId BUILDER >************************************************************************* /// Establece un identificador nuevo normalizando el valor. #[builder_fn] @@ -39,7 +39,7 @@ impl AttrId { self } - // AttrId GETTERS ****************************************************************************** + // **< AttrId GETTERS >************************************************************************* /// Devuelve el identificador normalizado, si existe. pub fn get(&self) -> Option<String> { diff --git a/src/html/attr_l10n.rs b/src/html/attr_l10n.rs index 8250c742..37fc80fa 100644 --- a/src/html/attr_l10n.rs +++ b/src/html/attr_l10n.rs @@ -39,7 +39,7 @@ impl AttrL10n { AttrL10n(value) } - // AttrL10n BUILDER **************************************************************************** + // **< AttrL10n BUILDER >*********************************************************************** /// Establece una traducción nueva. #[builder_fn] @@ -48,7 +48,7 @@ impl AttrL10n { self } - // AttrL10n GETTERS **************************************************************************** + // **< AttrL10n GETTERS >*********************************************************************** /// Devuelve la traducción para `language`, si existe. pub fn lookup(&self, language: &impl LangId) -> Option<String> { diff --git a/src/html/attr_name.rs b/src/html/attr_name.rs index 928f841f..9bc9659e 100644 --- a/src/html/attr_name.rs +++ b/src/html/attr_name.rs @@ -29,7 +29,7 @@ impl AttrName { AttrName::default().with_value(value) } - // AttrName BUILDER **************************************************************************** + // **< AttrName BUILDER >*********************************************************************** /// Establece un nombre nuevo normalizando el valor. #[builder_fn] @@ -39,7 +39,7 @@ impl AttrName { self } - // AttrName GETTERS **************************************************************************** + // **< AttrName GETTERS >*********************************************************************** /// Devuelve el nombre normalizado, si existe. pub fn get(&self) -> Option<String> { diff --git a/src/html/attr_value.rs b/src/html/attr_value.rs index 4e03120b..eff80660 100644 --- a/src/html/attr_value.rs +++ b/src/html/attr_value.rs @@ -27,7 +27,7 @@ impl AttrValue { AttrValue::default().with_value(value) } - // AttrValue BUILDER *************************************************************************** + // **< AttrValue BUILDER >********************************************************************** /// Establece una cadena nueva normalizando el valor. #[builder_fn] @@ -41,7 +41,7 @@ impl AttrValue { self } - // AttrValue GETTERS *************************************************************************** + // **< AttrValue GETTERS >********************************************************************** /// Devuelve la cadena normalizada, si existe. pub fn get(&self) -> Option<String> { diff --git a/src/html/context.rs b/src/html/context.rs index 7b782681..355ccead 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -78,7 +78,7 @@ pub enum ErrorParam { /// } /// ``` pub trait Contextual: LangId { - // Contextual BUILDER ************************************************************************** + // **< Contextual BUILDER >********************************************************************* /// Establece el idioma del documento. #[builder_fn] @@ -104,7 +104,7 @@ pub trait Contextual: LangId { #[builder_fn] fn with_assets(self, op: AssetsOp) -> Self; - // Contextual GETTERS ************************************************************************** + // **< Contextual GETTERS >********************************************************************* /// Devuelve una referencia a la solicitud HTTP asociada, si existe. fn request(&self) -> Option<&HttpRequest>; @@ -142,7 +142,7 @@ pub trait Contextual: LangId { /// Devuelve los scripts JavaScript de los recursos del contexto. fn javascripts(&self) -> &Assets<JavaScript>; - // Contextual HELPERS ************************************************************************** + // **< Contextual HELPERS >********************************************************************* /// Genera un identificador único por tipo (`<tipo>-<n>`) cuando no se aporta uno explícito. /// @@ -255,7 +255,7 @@ impl Context { } } - // Context RENDER ****************************************************************************** + // **< Context RENDER >************************************************************************* /// Renderiza los recursos del contexto. pub fn render_assets(&mut self) -> Markup { @@ -283,7 +283,7 @@ impl Context { markup } - // Context PARAMS ****************************************************************************** + // **< Context PARAMS >************************************************************************* /// Recupera una *referencia tipada* al parámetro solicitado. /// @@ -389,7 +389,7 @@ impl LangId for Context { } impl Contextual for Context { - // Contextual BUILDER ************************************************************************** + // **< Contextual BUILDER >********************************************************************* #[builder_fn] fn with_request(mut self, request: Option<HttpRequest>) -> Self { @@ -471,7 +471,7 @@ impl Contextual for Context { self } - // Contextual GETTERS ************************************************************************** + // **< Contextual GETTERS >********************************************************************* fn request(&self) -> Option<&HttpRequest> { self.request.as_ref() @@ -530,7 +530,7 @@ impl Contextual for Context { &self.javascripts } - // Contextual HELPERS ************************************************************************** + // **< Contextual HELPERS >********************************************************************* /// Devuelve un identificador único dentro del contexto para el tipo `T`, si no se proporciona /// un `id` explícito. diff --git a/src/lib.rs b/src/lib.rs index 1c1ba2c1..6f5c5cfb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -97,7 +97,7 @@ extern crate self as pagetop; use std::collections::HashMap; use std::ops::Deref; -// RE-EXPORTED ************************************************************************************* +// **< RE-EXPORTED >******************************************************************************** pub use pagetop_macros::{builder_fn, html, main, test, AutoDefault}; @@ -136,7 +136,7 @@ pub type UniqueId = std::any::TypeId; /// antes en la ordenación. pub type Weight = i8; -// API ********************************************************************************************* +// **< API >**************************************************************************************** // Macros y funciones útiles. pub mod util; @@ -163,6 +163,6 @@ pub mod base; // Prepara y ejecuta la aplicación. pub mod app; -// PRELUDE ***************************************************************************************** +// **< PRELUDE >************************************************************************************ pub mod prelude; diff --git a/src/response/page.rs b/src/response/page.rs index 2dc27f9f..e9d30671 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -52,7 +52,7 @@ impl Page { } } - // Page BUILDER ******************************************************************************** + // **< Page BUILDER >*************************************************************************** /// Establece el título de la página como un valor traducible. #[builder_fn] @@ -151,7 +151,7 @@ impl Page { self } - // Page GETTERS ******************************************************************************** + // **< Page GETTERS >*************************************************************************** /// Devuelve el título traducido para el idioma de la página, si existe. pub fn title(&mut self) -> Option<String> { @@ -192,7 +192,7 @@ impl Page { &mut self.context } - // Page RENDER ********************************************************************************* + // **< Page RENDER >**************************************************************************** /// Renderiza los componentes de una región (`region_name`) de la página. pub fn render_region(&mut self, region_name: &'static str) -> Markup { @@ -253,7 +253,7 @@ impl LangId for Page { } impl Contextual for Page { - // Contextual BUILDER ************************************************************************** + // **< Contextual BUILDER >********************************************************************* #[builder_fn] fn with_request(mut self, request: Option<HttpRequest>) -> Self { @@ -291,7 +291,7 @@ impl Contextual for Page { self } - // Contextual GETTERS ************************************************************************** + // **< Contextual GETTERS >********************************************************************* fn request(&self) -> Option<&HttpRequest> { self.context.request() @@ -321,7 +321,7 @@ impl Contextual for Page { self.context.javascripts() } - // Contextual HELPERS ************************************************************************** + // **< Contextual HELPERS >********************************************************************* fn required_id<T>(&mut self, id: Option<String>) -> String { self.context.required_id::<T>(id) diff --git a/src/util.rs b/src/util.rs index cb101763..a4daf677 100644 --- a/src/util.rs +++ b/src/util.rs @@ -6,7 +6,7 @@ use std::env; use std::io; use std::path::{Path, PathBuf}; -// MACROS INTEGRADAS ******************************************************************************* +// **< MACROS INTEGRADAS >************************************************************************** #[doc(hidden)] pub use paste::paste; @@ -16,7 +16,7 @@ pub use concat_string::concat_string; pub use indoc::{concatdoc, formatdoc, indoc}; -// MACROS ÚTILES *********************************************************************************** +// **< MACROS ÚTILES >****************************************************************************** #[macro_export] /// Macro para construir una colección de pares clave-valor. @@ -198,7 +198,7 @@ macro_rules! join_strict { }}; } -// FUNCIONES ÚTILES ******************************************************************************** +// **< FUNCIONES ÚTILES >*************************************************************************** /// Resuelve y valida la ruta de un directorio existente, devolviendo una ruta absoluta. /// diff --git a/tests/component_poweredby.rs b/tests/component_poweredby.rs index e4551d17..27683d95 100644 --- a/tests/component_poweredby.rs +++ b/tests/component_poweredby.rs @@ -90,7 +90,7 @@ async fn poweredby_getter_reflects_internal_state() { assert!(c1.contains(&global::SETTINGS.app.name)); } -// HELPERS ***************************************************************************************** +// **< HELPERS >************************************************************************************ fn render_component<C: Component>(c: &C) -> Markup { let mut cx = Context::default(); From df1f386241c3b2d8cb09de5bbaa115297bf91cbc Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 28 Sep 2025 13:46:02 +0200 Subject: [PATCH 189/244] =?UTF-8?q?=F0=9F=9A=A7=20(base):=20A=C3=B1ade=20n?= =?UTF-8?q?uevo=20componente=20`Icon`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component.rs | 3 + src/base/component/icon.rs | 134 +++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 src/base/component/icon.rs diff --git a/src/base/component.rs b/src/base/component.rs index 4df64ff1..5bbe746d 100644 --- a/src/base/component.rs +++ b/src/base/component.rs @@ -8,3 +8,6 @@ pub use block::Block; mod poweredby; pub use poweredby::PoweredBy; + +mod icon; +pub use icon::{Icon, IconKind}; diff --git a/src/base/component/icon.rs b/src/base/component/icon.rs new file mode 100644 index 00000000..73e5ac4e --- /dev/null +++ b/src/base/component/icon.rs @@ -0,0 +1,134 @@ +use crate::prelude::*; + +const DEFAULT_VIEWBOX: &str = "0 0 16 16"; + +#[derive(AutoDefault)] +pub enum IconKind { + #[default] + None, + Font(FontSize), + Svg { + shapes: Markup, + viewbox: AttrValue, + }, +} + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Icon { + classes : AttrClasses, + icon_kind : IconKind, + aria_label: AttrL10n, +} + +impl Component for Icon { + fn new() -> Self { + Icon::default() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + if !matches!(self.icon_kind(), IconKind::None) { + self.alter_classes(ClassesOp::Prepend, "icon"); + } + if let IconKind::Font(font_size) = self.icon_kind() { + self.alter_classes(ClassesOp::Add, font_size.as_str()); + } + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + match self.icon_kind() { + IconKind::None => PrepareMarkup::None, + IconKind::Font(_) => { + let aria_label = self.aria_label().lookup(cx); + let has_label = aria_label.is_some(); + PrepareMarkup::With(html! { + i + class=[self.classes().get()] + role=[has_label.then_some("img")] + aria-label=[aria_label] + aria-hidden=[(!has_label).then_some("true")] + {} + }) + } + IconKind::Svg { shapes, viewbox } => { + let aria_label = self.aria_label().lookup(cx); + let has_label = aria_label.is_some(); + let viewbox = viewbox.get().unwrap_or_else(|| DEFAULT_VIEWBOX.to_string()); + PrepareMarkup::With(html! { + svg + xmlns="http://www.w3.org/2000/svg" + viewBox=(viewbox) + fill="currentColor" + focusable="false" + class=[self.classes().get()] + role=[has_label.then_some("img")] + aria-label=[aria_label] + aria-hidden=[(!has_label).then_some("true")] + { + (shapes) + } + }) + } + } + } +} + +impl Icon { + pub fn font() -> Self { + Icon::default().with_icon_kind(IconKind::Font(FontSize::default())) + } + + pub fn font_sized(font_size: FontSize) -> Self { + Icon::default().with_icon_kind(IconKind::Font(font_size)) + } + + pub fn svg(shapes: Markup) -> Self { + Icon::default().with_icon_kind(IconKind::Svg { + shapes, + viewbox: AttrValue::default(), + }) + } + + pub fn svg_with_viewbox(shapes: Markup, viewbox: impl AsRef<str>) -> Self { + Icon::default().with_icon_kind(IconKind::Svg { + shapes, + viewbox: AttrValue::new(viewbox), + }) + } + + // **< Icon BUILDER >*************************************************************************** + + /// Modifica la lista de clases CSS aplicadas al icono. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + #[builder_fn] + pub fn with_icon_kind(mut self, icon_kind: IconKind) -> Self { + self.icon_kind = icon_kind; + self + } + + #[builder_fn] + pub fn with_aria_label(mut self, label: L10n) -> Self { + self.aria_label.alter_value(label); + self + } + + // **< Icon GETTERS >*************************************************************************** + + /// Devuelve las clases CSS asociadas al icono. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + pub fn icon_kind(&self) -> &IconKind { + &self.icon_kind + } + + pub fn aria_label(&self) -> &AttrL10n { + &self.aria_label + } +} From 67a9b057ee172676934891035305001d921bb81b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 28 Sep 2025 13:47:33 +0200 Subject: [PATCH 190/244] =?UTF-8?q?=F0=9F=9A=A7=20(base):=20A=C3=B1ade=20n?= =?UTF-8?q?uevo=20componente=20`menu`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component.rs | 50 +++++ src/base/component/menu.rs | 17 ++ src/base/component/menu/element.rs | 56 +++++ src/base/component/menu/group.rs | 58 +++++ src/base/component/menu/item.rs | 183 ++++++++++++++++ src/base/component/menu/megamenu.rs | 57 +++++ src/base/component/menu/menu_menu.rs | 106 +++++++++ src/base/component/menu/submenu.rs | 73 +++++++ src/base/theme/basic.rs | 23 +- src/html.rs | 1 + static/css/basic.css | 6 - static/css/components.css | 12 ++ static/css/menu.css | 309 +++++++++++++++++++++++++++ static/css/root.css | 211 ++++++++++++++++++ static/js/menu.js | 94 ++++++++ 15 files changed, 1249 insertions(+), 7 deletions(-) create mode 100644 src/base/component/menu.rs create mode 100644 src/base/component/menu/element.rs create mode 100644 src/base/component/menu/group.rs create mode 100644 src/base/component/menu/item.rs create mode 100644 src/base/component/menu/megamenu.rs create mode 100644 src/base/component/menu/menu_menu.rs create mode 100644 src/base/component/menu/submenu.rs create mode 100644 static/css/components.css create mode 100644 static/css/menu.css create mode 100644 static/css/root.css create mode 100644 static/js/menu.js diff --git a/src/base/component.rs b/src/base/component.rs index 5bbe746d..4edfc9a9 100644 --- a/src/base/component.rs +++ b/src/base/component.rs @@ -1,5 +1,53 @@ //! Componentes nativos proporcionados por PageTop. +use crate::AutoDefault; + +use std::fmt; + +// **< FontSize >*********************************************************************************** + +#[derive(AutoDefault)] +pub enum FontSize { + ExtraLarge, + XxLarge, + XLarge, + Large, + Medium, + #[default] + Normal, + Small, + XSmall, + XxSmall, + ExtraSmall, +} + +#[rustfmt::skip] +impl FontSize { + #[inline] + pub const fn as_str(&self) -> &'static str { + match self { + FontSize::ExtraLarge => "fs__x3l", + FontSize::XxLarge => "fs__x2l", + FontSize::XLarge => "fs__xl", + FontSize::Large => "fs__l", + FontSize::Medium => "fs__m", + FontSize::Normal => "", + FontSize::Small => "fs__s", + FontSize::XSmall => "fs__xs", + FontSize::XxSmall => "fs__x2s", + FontSize::ExtraSmall => "fs__x3s", + } + } +} + +impl fmt::Display for FontSize { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +// ************************************************************************************************* + mod html; pub use html::Html; @@ -11,3 +59,5 @@ pub use poweredby::PoweredBy; mod icon; pub use icon::{Icon, IconKind}; + +pub mod menu; diff --git a/src/base/component/menu.rs b/src/base/component/menu.rs new file mode 100644 index 00000000..14f75898 --- /dev/null +++ b/src/base/component/menu.rs @@ -0,0 +1,17 @@ +mod menu_menu; +pub use menu_menu::Menu; + +mod item; +pub use item::{Item, ItemKind}; + +mod submenu; +pub use submenu::Submenu; + +mod megamenu; +pub use megamenu::Megamenu; + +mod group; +pub use group::Group; + +mod element; +pub use element::{Element, ElementType}; diff --git a/src/base/component/menu/element.rs b/src/base/component/menu/element.rs new file mode 100644 index 00000000..6d142048 --- /dev/null +++ b/src/base/component/menu/element.rs @@ -0,0 +1,56 @@ +use crate::prelude::*; + +type Content = Typed<Html>; +type SubmenuItems = Typed<menu::Submenu>; + +#[derive(AutoDefault)] +pub enum ElementType { + #[default] + Void, + Html(Content), + Submenu(SubmenuItems), +} + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Element { + element_type: ElementType, +} + +impl Component for Element { + fn new() -> Self { + Element::default() + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + match self.element_type() { + ElementType::Void => PrepareMarkup::None, + ElementType::Html(content) => PrepareMarkup::With(html! { + (content.render(cx)) + }), + ElementType::Submenu(submenu) => PrepareMarkup::With(html! { + (submenu.render(cx)) + }), + } + } +} + +impl Element { + pub fn html(content: Html) -> Self { + Element { + element_type: ElementType::Html(Content::with(content)), + } + } + + pub fn submenu(submenu: menu::Submenu) -> Self { + Element { + element_type: ElementType::Submenu(SubmenuItems::with(submenu)), + } + } + + // **< Element GETTERS >************************************************************************ + + pub fn element_type(&self) -> &ElementType { + &self.element_type + } +} diff --git a/src/base/component/menu/group.rs b/src/base/component/menu/group.rs new file mode 100644 index 00000000..41279b4e --- /dev/null +++ b/src/base/component/menu/group.rs @@ -0,0 +1,58 @@ +use crate::prelude::*; + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Group { + id : AttrId, + elements: Children, +} + +impl Component for Group { + fn new() -> Self { + Group::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + PrepareMarkup::With(html! { + div id=[self.id()] class="menu-group" { + (self.elements().render(cx)) + } + }) + } +} + +impl Group { + // **< Group BUILDER >************************************************************************** + + /// Establece el identificador único (`id`) del grupo. + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + /// Añade un nuevo elemento al menú. + pub fn add_element(mut self, element: menu::Element) -> Self { + self.elements + .alter_typed(TypedOp::Add(Typed::with(element))); + self + } + + /// Modifica la lista de elementos (`children`) aplicando una operación [`TypedOp`]. + #[builder_fn] + pub fn with_elements(mut self, op: TypedOp<menu::Element>) -> Self { + self.elements.alter_typed(op); + self + } + + // **< Group GETTERS >************************************************************************** + + /// Devuelve la lista de elementos (`children`) del grupo. + pub fn elements(&self) -> &Children { + &self.elements + } +} diff --git a/src/base/component/menu/item.rs b/src/base/component/menu/item.rs new file mode 100644 index 00000000..07d629ae --- /dev/null +++ b/src/base/component/menu/item.rs @@ -0,0 +1,183 @@ +use crate::prelude::*; + +//use super::{Megamenu, Submenu}; + +type Label = L10n; +type Content = Typed<Html>; +type SubmenuItems = Typed<menu::Submenu>; +//type MegamenuGroups = Typed<Megamenu>; + +#[derive(AutoDefault)] +pub enum ItemKind { + #[default] + Void, + Label(Label), + Link(Label, FnPathByContext), + LinkBlank(Label, FnPathByContext), + Html(Content), + Submenu(Label, SubmenuItems), + // Megamenu(Label, MegamenuGroups), +} + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Item { + item_kind : ItemKind, + description: AttrL10n, + left_icon : Typed<Icon>, + right_icon : Typed<Icon>, +} + +impl Component for Item { + fn new() -> Self { + Item::default() + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let description = self.description().lookup(cx); + let left_icon = self.left_icon().render(cx); + let right_icon = self.right_icon().render(cx); + + match self.item_kind() { + ItemKind::Void => PrepareMarkup::None, + ItemKind::Label(label) => PrepareMarkup::With(html! { + li class="menu__label" { + span title=[description] { + (left_icon) + (label.using(cx)) + (right_icon) + } + } + }), + ItemKind::Link(label, path) => PrepareMarkup::With(html! { + li class="menu__link" { + a href=(path(cx)) title=[description] { + (left_icon) + (label.using(cx)) + (right_icon) + } + } + }), + ItemKind::LinkBlank(label, path) => PrepareMarkup::With(html! { + li class="menu__link" { + a href=(path(cx)) title=[description] target="_blank" { + (left_icon) + (label.using(cx)) + (right_icon) + } + } + }), + ItemKind::Html(content) => PrepareMarkup::With(html! { + li class="menu__html" { + (content.render(cx)) + } + }), + ItemKind::Submenu(label, submenu) => PrepareMarkup::With(html! { + li class="menu__children" { + a href="#" title=[description] { + (left_icon) + (label.using(cx)) i class="menu__icon bi-chevron-down" {} + } + div class="menu__subs" { + (submenu.render(cx)) + } + } + }), + /* + ItemKind::Megamenu(label, megamenu) => PrepareMarkup::With(html! { + li class="menu__children" { + a href="#" title=[description] { + (left_icon) + (label.escaped(cx.langid())) i class="menu__icon bi-chevron-down" {} + } + div class="menu__subs menu__mega" { + (megamenu.render(cx)) + } + } + }), + */ + } + } +} + +impl Item { + pub fn label(label: L10n) -> Self { + Item { + item_kind: ItemKind::Label(label), + ..Default::default() + } + } + + pub fn link(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link(label, path), + ..Default::default() + } + } + + pub fn link_blank(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::LinkBlank(label, path), + ..Default::default() + } + } + + pub fn html(content: Html) -> Self { + Item { + item_kind: ItemKind::Html(Content::with(content)), + ..Default::default() + } + } + + pub fn submenu(label: L10n, submenu: menu::Submenu) -> Self { + Item { + item_kind: ItemKind::Submenu(label, SubmenuItems::with(submenu)), + ..Default::default() + } + } + /* + pub fn megamenu(label: L10n, megamenu: Megamenu) -> Self { + Item { + item_kind: ItemKind::Megamenu(label, MegamenuGroups::with(megamenu)), + ..Default::default() + } + } + */ + // **< Item BUILDER >*************************************************************************** + + #[builder_fn] + pub fn with_description(mut self, text: L10n) -> Self { + self.description.alter_value(text); + self + } + + #[builder_fn] + pub fn with_left_icon<I: Into<Icon>>(mut self, icon: Option<I>) -> Self { + self.left_icon.alter_component(icon.map(Into::into)); + self + } + + #[builder_fn] + pub fn with_right_icon<I: Into<Icon>>(mut self, icon: Option<I>) -> Self { + self.right_icon.alter_component(icon.map(Into::into)); + self + } + + // **< Item GETTERS >*************************************************************************** + + pub fn item_kind(&self) -> &ItemKind { + &self.item_kind + } + + pub fn description(&self) -> &AttrL10n { + &self.description + } + + pub fn left_icon(&self) -> &Typed<Icon> { + &self.left_icon + } + + pub fn right_icon(&self) -> &Typed<Icon> { + &self.right_icon + } +} diff --git a/src/base/component/menu/megamenu.rs b/src/base/component/menu/megamenu.rs new file mode 100644 index 00000000..f22b184e --- /dev/null +++ b/src/base/component/menu/megamenu.rs @@ -0,0 +1,57 @@ +use crate::prelude::*; + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Megamenu { + id : AttrId, + groups: Children, +} + +impl Component for Megamenu { + fn new() -> Self { + Megamenu::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + PrepareMarkup::With(html! { + div id=[self.id()] class="menu__groups" { + (self.groups().render(cx)) + } + }) + } +} + +impl Megamenu { + // **< Megamenu BUILDER >*********************************************************************** + + /// Establece el identificador único (`id`) del megamenú. + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + /// Añade un nuevo grupo al menú. + pub fn add_group(mut self, group: menu::Group) -> Self { + self.groups.alter_typed(TypedOp::Add(Typed::with(group))); + self + } + + /// Modifica la lista de grupos (`children`) aplicando una operación [`TypedOp`]. + #[builder_fn] + pub fn with_groups(mut self, op: TypedOp<menu::Group>) -> Self { + self.groups.alter_typed(op); + self + } + + // **< Megamenu GETTERS >*********************************************************************** + + /// Devuelve la lista de grupos (`children`) del megamenú. + pub fn groups(&self) -> &Children { + &self.groups + } +} diff --git a/src/base/component/menu/menu_menu.rs b/src/base/component/menu/menu_menu.rs new file mode 100644 index 00000000..a7f91be1 --- /dev/null +++ b/src/base/component/menu/menu_menu.rs @@ -0,0 +1,106 @@ +use crate::prelude::*; + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Menu { + id : AttrId, + classes: AttrClasses, + items : Children, +} + +impl Component for Menu { + fn new() -> Self { + Menu::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes(ClassesOp::Prepend, "menu"); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + // cx.set_param::<bool>(PARAM_BASE_INCLUDE_MENU_ASSETS, &true); + // cx.set_param::<bool>(PARAM_BASE_INCLUDE_ICONS, &true); + + PrepareMarkup::With(html! { + div id=[self.id()] class=[self.classes().get()] { + div class="menu__wrapper" { + div class="menu__panel" { + div class="menu__overlay" {} + nav class="menu__nav" { + div class="menu__header" { + button type="button" class="menu__back" { + (Icon::svg(html! { + path fill-rule="evenodd" d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0" {} + }).render(cx)) + } + div class="menu__title" {} + button type="button" class="menu__close" { + (Icon::svg(html! { + path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z" {} + }).render(cx)) + } + } + ul class="menu__list" { + (self.items().render(cx)) + } + } + } + button + type="button" + class="menu__trigger" + title=[L10n::l("menu_toggle").lookup(cx)] + { + span {} span {} span {} + } + } + } + }) + } +} + +impl Menu { + // **< Menu BUILDER >*************************************************************************** + + /// Establece el identificador único (`id`) del menú. + #[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 menú. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + /// Añade un nuevo ítem al menú. + pub fn add_item(mut self, item: menu::Item) -> Self { + self.items.alter_typed(TypedOp::Add(Typed::with(item))); + self + } + + /// Modifica la lista de ítems (`children`) aplicando una operación [`TypedOp`]. + #[builder_fn] + pub fn with_items(mut self, op: TypedOp<menu::Item>) -> Self { + self.items.alter_typed(op); + self + } + + // **< Menu GETTERS >*************************************************************************** + + /// Devuelve las clases CSS asociadas al menú. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve la lista de ítems (`children`) del menú. + pub fn items(&self) -> &Children { + &self.items + } +} diff --git a/src/base/component/menu/submenu.rs b/src/base/component/menu/submenu.rs new file mode 100644 index 00000000..58770529 --- /dev/null +++ b/src/base/component/menu/submenu.rs @@ -0,0 +1,73 @@ +use crate::prelude::*; + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Submenu { + id : AttrId, + title: AttrL10n, + items: Children, +} + +impl Component for Submenu { + fn new() -> Self { + Submenu::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + PrepareMarkup::With(html! { + div id=[self.id()] class="menu__items" { + @if let Some(title) = self.title().lookup(cx) { + h4 class="menu__title" { (title) } + } + ul { + (self.items().render(cx)) + } + } + }) + } +} + +impl Submenu { + // **< Submenu BUILDER >************************************************************************ + + /// Establece el identificador único (`id`) del submenú. + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + #[builder_fn] + pub fn with_title(mut self, title: L10n) -> Self { + self.title.alter_value(title); + self + } + + /// Añade un nuevo ítem al submenú. + pub fn add_item(mut self, item: menu::Item) -> Self { + self.items.alter_typed(TypedOp::Add(Typed::with(item))); + self + } + + /// Modifica la lista de ítems (`children`) aplicando una operación [`TypedOp`]. + #[builder_fn] + pub fn with_items(mut self, op: TypedOp<menu::Item>) -> Self { + self.items.alter_typed(op); + self + } + + // **< Submenu GETTERS >************************************************************************ + + pub fn title(&self) -> &AttrL10n { + &self.title + } + + /// Devuelve la lista de ítems (`children`) del submenú. + pub fn items(&self) -> &Children { + &self.items + } +} diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index 2f492748..20f51994 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -51,14 +51,35 @@ impl Theme for Basic { "PageTopIntro" => "/css/intro.css", _ => "/css/basic.css", }; + let pkg_version = env!("CARGO_PKG_VERSION"); 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/root.css") + .with_version(pkg_version) + .with_weight(-99), + )) + .alter_assets(AssetsOp::AddStyleSheet( + StyleSheet::from("/css/components.css") + .with_version(pkg_version) + .with_weight(-99), + )) + .alter_assets(AssetsOp::AddStyleSheet( + StyleSheet::from("/css/menu.css") + .with_version(pkg_version) + .with_weight(-99), + )) .alter_assets(AssetsOp::AddStyleSheet( StyleSheet::from(styles) - .with_version(env!("CARGO_PKG_VERSION")) + .with_version(pkg_version) + .with_weight(-99), + )) + .alter_assets(AssetsOp::AddJavaScript( + JavaScript::defer("/js/menu.js") + .with_version(pkg_version) .with_weight(-99), )); } diff --git a/src/html.rs b/src/html.rs index b6815ece..c4195a9d 100644 --- a/src/html.rs +++ b/src/html.rs @@ -15,6 +15,7 @@ pub use assets::{Asset, Assets}; mod context; pub use context::{AssetsOp, Context, Contextual, ErrorParam}; +pub type FnPathByContext = fn(cx: &Context) -> &str; // **< HTML ATTRIBUTES >**************************************************************************** diff --git a/static/css/basic.css b/static/css/basic.css index 312ddf09..04801dd0 100644 --- a/static/css/basic.css +++ b/static/css/basic.css @@ -3,9 +3,3 @@ .region--footer { padding-bottom: 2rem; } - -/* PoweredBy component */ - -.poweredby { - text-align: center; -} diff --git a/static/css/components.css b/static/css/components.css new file mode 100644 index 00000000..ec5d3f00 --- /dev/null +++ b/static/css/components.css @@ -0,0 +1,12 @@ +/* Icon component */ + +.icon { + width: 1rem; + height: 1rem; +} + +/* PoweredBy component */ + +.poweredby { + text-align: center; +} diff --git a/static/css/menu.css b/static/css/menu.css new file mode 100644 index 00000000..a8b2854c --- /dev/null +++ b/static/css/menu.css @@ -0,0 +1,309 @@ +.menu { + width: 100%; + height: auto; + margin: 0; + padding: 0; + z-index: 9999; + border: none; + outline: none; + background: var(--val-menu--color-bg); +} + +.menu__wrapper { + padding-right: var(--val-gap); +} +.menu__wrapper a, +.menu__wrapper button { + cursor: pointer; + border: none; + background: none; + text-decoration: none; +} + +.menu__nav ul { + margin: 0; + padding: 0; +} +.menu__nav li { + display: inline-block; + margin: 0 0 0 1.5rem; + padding: var(--val-menu--line-padding) 0; + line-height: var(--val-menu--line-height); + list-style: none; + list-style-type: none; +} + +.menu__nav li.menu__label, +.menu__nav li > a { + position: relative; + font-weight: 500; + color: var(--val-color--text); + text-rendering: optimizeLegibility; +} +.menu__nav li > a { + border: none; + transition: color 0.3s ease-in-out; +} +.menu__nav li:hover > a, +.menu__nav li > a:focus { + color: var(--val-menu--color-highlight); +} +.menu__nav li > a > i.menu__icon { + margin-left: 0.25rem; +} + +.menu__nav li .menu__subs { + position: absolute; + max-width: 100%; + height: auto; + padding: 1rem 2rem; + border: none; + outline: none; + background: var(--val-menu--color-bg); + border-radius: var(--val-menu--border-radius); + border-top: 3px solid var(--val-menu--color-highlight); + z-index: 500; + opacity: 0; + visibility: hidden; + box-shadow: 0 4px 6px -1px var(--val-menu--color-border), 0 2px 4px -1px var(--val-menu--color-shadow); + transition: all 0.5s ease-in-out; +} + +.menu__nav li.menu__children:hover > .menu__subs, +.menu__nav li.menu__children > a:focus + .menu__subs, +.menu__nav li.menu__children .menu__subs:focus-within { + margin-top: 0.4rem; + opacity: 1; + visibility: visible; +} + +.menu__nav li .menu__items { + min-width: var(--val-menu--item-width-min); + max-width: var(--val-menu--item-width-max); +} +.menu__nav li .menu__items .menu__title { + font-family: inherit; + font-size: 1rem; + font-weight: 500; + margin: 0; + padding: var(--val-menu--line-padding) 0; + line-height: var(--val-menu--line-height); + border: none; + outline: none; + color: var(--val-menu--color-highlight); + text-transform: uppercase; + text-rendering: optimizeLegibility; +} +.menu__nav li .menu__items li { + display: block; + margin-left: 0; +} + +.menu__nav li .menu__mega { + left: 50%; + transform: translateX(-50%); +} + +.menu__nav li .menu__groups { + display: flex; + flex-wrap: nowrap; +} + +.menu__header, +.menu__trigger { + display: none; +} + +/* Applies <= 992px */ +@media only screen and (max-width: 62rem) { + .menu { + border-radius: var(--val-border-radius); + } + .menu__wrapper { + padding-right: var(--val-gap-0-5); + } + .menu__wrapper button { + margin: var(--val-gap-0-5) 0 var(--val-gap-0-5) var(--val-gap-0-5); + } + .menu__trigger { + cursor: pointer; + width: var(--val-menu--trigger-width); + height: var(--val-menu--item-height); + border: none; + outline: none; + background: none; + display: flex; + flex-direction: column; + justify-content: center; + } + .menu__trigger span { + width: 100%; + height: 2px; + margin: 12.675% 0; + border-radius: var(--val-border-radius); + background: var(--val-color--text); + } + + .menu__nav { + position: fixed; + top: 0; + left: 0; + width: var(--val-menu--side-width); + height: 100%; + z-index: 9099; + overflow: hidden; + background: var(--val-menu--color-bg); + transform: translate(-100%); + transition: all 0.5s ease-in-out; + } + .menu__panel .menu__nav.active { + transform: translate(0%); + } + + .menu__nav li { + display: block; + margin: 0; + padding: 0; + } + .menu__nav li.menu__label, + .menu__nav li > a { + display: block; + padding: var(--val-menu--line-padding) var(--val-menu--item-height) var(--val-menu--line-padding) var(--val-menu--item-gap); + border-bottom: 1px solid var(--val-menu--color-border); + } + .menu__nav li ul li.menu__label, + .menu__nav li ul li > a { + border-bottom: 0; + } + .menu__nav li > a > i.menu__icon { + position: absolute; + top: var(--val-menu--line-padding); + right: var(--val-menu--line-padding); + font-size: 1.25rem; + transform: rotate(-90deg); + } + + .menu__nav li .menu__subs { + position: absolute; + display: none; + top: 0; + left: 0; + max-width: none; + min-width: auto; + width: 100%; + height: 100%; + margin: 0 !important; + padding: 0; + border-top: 0; + opacity: 1; + overflow-y: auto; + visibility: visible; + transform: translateX(0%); + box-shadow: none; + } + .menu__nav li .menu__subs.active { + display: block; + } + .menu__nav li .menu__subs > :first-child { + margin-top: 4rem; + } + + .menu__nav li .menu__items .menu__title { + padding: var(--val-menu--line-padding) var(--val-menu--item-height) var(--val-menu--line-padding) var(--val-menu--item-gap); + } + + .menu__nav li .menu__groups { + display: block; + } + + .menu__nav .menu__header { + position: sticky; + display: flex; + align-items: center; + justify-content: space-between; + top: 0; + height: var(--val-menu--item-height); + border-bottom: 1px solid var(--val-menu--color-border); + background: var(--val-menu--color-bg); + z-index: 501; + } + .menu__nav .menu__header .menu__title { + padding: var(--val-menu--line-padding); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .menu__nav .menu__header .menu__close, + .menu__nav .menu__header .menu__back { + width: var(--val-menu--item-height); + min-width: var(--val-menu--item-height); + height: var(--val-menu--item-height); + line-height: var(--val-menu--item-height); + color: var(--val-color--text); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + } + .menu__nav .menu__header .menu__close { + font-size: 2.25rem; + border-left: 1px solid var(--val-menu--color-border); + } + .menu__nav .menu__header .menu__back { + font-size: 1.25rem; + border-right: 1px solid var(--val-menu--color-border); + display: none; + } + .menu__nav .menu__header.active .menu__back { + display: flex; + } + + .menu__nav .menu__list { + height: 100%; + overflow-y: auto; + overflow-x: hidden; + padding: 0; + margin: 0; + } + + .menu__overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 9098; + opacity: 0; + visibility: hidden; + background: rgba(0, 0, 0, 0.55); + transition: all 0.5s ease-in-out; + } + .menu__overlay.active { + opacity: 1; + visibility: visible; + } +} + +/* ANIMATIONS */ + +@keyframes slideLeft { + 0% { + opacity: 0; + transform: translateX(100%); + } + 100% { + opacity: 1; + transform: translateX(0%); + } +} + +@keyframes slideRight { + 0% { + opacity: 1; + transform: translateX(0%); + } + 100% { + opacity: 0; + transform: translateX(100%); + } +} diff --git a/static/css/root.css b/static/css/root.css new file mode 100644 index 00000000..bc55a443 --- /dev/null +++ b/static/css/root.css @@ -0,0 +1,211 @@ +: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; + --val-font-monospace: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; + --val-font-family: var(--val-font-sans); + + /* Font size */ + --val-fs--x3l: 2.5rem; + --val-fs--x2l: 2rem; + --val-fs--xl: 1.75rem; + --val-fs--l: 1.5rem; + --val-fs--m: 1.25rem; + --val-fs--base: 1rem; + --val-fs--s: 0.875rem; + --val-fs--xs: 0.75rem; + --val-fs--x2s: 0.5625rem; + --val-fs--x3s: 0.375rem; + + /* Font weight */ + --val-fw--light: 300; + --val-fw--base: 400; + --val-fw--bold: 500; + + /* Line height */ + --val-lh--base: 1.5; + --val-lh--header: 1.2; + + --val-max-width: 90rem; +/* + --val-color-rgb: 33,37,41; + --val-main--bg-rgb: 255,255,255; + --val-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); + + --line-height-base: 1.6875rem; + --line-height-s: 1.125rem; + --max-bg-color: 98.125rem; +*/ + --val-gap: 1.125rem; +/* + --content-left: 5.625rem; + --site-header-height-wide: var(--val-gap10); + --container-padding: var(--val-gap); +*/ +} +/* +@media (min-width: 75rem) { + :root { + --container-padding:var(--val-gap2); + } +} + +:root { + --scrollbar-width: 0px; + --grid-col-count: 6; + --grid-gap: var(--val-gap); + --grid-gap-count: calc(var(--grid-col-count) - 1); + --grid-full-width: calc(100vw - var(--val-gap2) - var(--scrollbar-width)); + --grid-col-width: calc((var(--grid-full-width) - (var(--grid-gap-count) * var(--grid-gap))) / var(--grid-col-count)); +} + +@media (min-width: 43.75rem) { + :root { + --grid-col-count:14; + --grid-gap: var(--val-gap2); + } +} + +@media (min-width: 62.5rem) { + :root { + --scrollbar-width:0.9375rem; + } +} + +@media (min-width: 75rem) { + :root { + --grid-full-width:calc(100vw - var(--scrollbar-width) - var(--content-left) - var(--val-gap4)); + } +} + +@media (min-width: 90rem) { + :root { + --grid-full-width:calc(var(--max-width) - var(--val-gap4)); + } +} +*/ +:root { + --val-gap-0-15: calc(0.15 * var(--val-gap)); + --val-gap-0-25: calc(0.25 * var(--val-gap)); + --val-gap-0-35: calc(0.35 * var(--val-gap)); + --val-gap-0-5: calc(0.5 * var(--val-gap)); + --val-gap-0-75: calc(0.75 * var(--val-gap)); + --val-gap-1-5: calc(1.5 * var(--val-gap)); + --val-gap-2: calc(2 * var(--val-gap)); + + --primary-hue: 216; + --primary-sat: 60%; + --val-color--primary: hsl(var(--primary-hue), var(--primary-sat), 50%); + --val-color--primary-light: hsl(var(--primary-hue), var(--primary-sat), 60%); + --val-color--primary-dark: hsl(var(--primary-hue), var(--primary-sat), 40%); + --val-color--primary-link: hsl(var(--primary-hue), var(--primary-sat), 55%); + --val-color--primary-link-hover: hsl(var(--primary-hue), var(--primary-sat), 30%); + --val-color--primary-link-active: hsl(var(--primary-hue), var(--primary-sat), 70%); + + --info-hue: 190; + --info-sat: 90%; + --val-color--info: hsl(var(--info-hue), var(--info-sat), 54%); + --val-color--info-light: hsl(var(--info-hue), var(--info-sat), 70%); + --val-color--info-dark: hsl(var(--info-hue), var(--info-sat), 45%); + --val-color--info-link: hsl(var(--info-hue), var(--info-sat), 30%); + --val-color--info-link-hover: hsl(var(--info-hue), var(--info-sat), 20%); + --val-color--info-link-active: hsl(var(--info-hue), var(--info-sat), 40%); + + --success-hue: 150; + --success-sat: 50%; + --val-color--success: hsl(var(--success-hue), var(--success-sat), 50%); + --val-color--success-light: hsl(var(--success-hue), var(--success-sat), 68%); + --val-color--success-dark: hsl(var(--success-hue), var(--success-sat), 38%); + --val-color--success-link: hsl(var(--success-hue), var(--success-sat), 26%); + --val-color--success-link-hover: hsl(var(--success-hue), var(--success-sat), 18%); + --val-color--success-link-active: hsl(var(--success-hue), var(--success-sat), 36%); + + --warning-hue: 44; + --warning-sat: 100%; + --val-color--warning: hsl(var(--warning-hue), var(--warning-sat), 50%); + --val-color--warning-light: hsl(var(--warning-hue), var(--warning-sat), 60%); + --val-color--warning-dark: hsl(var(--warning-hue), var(--warning-sat), 40%); + --val-color--warning-link: hsl(var(--warning-hue), var(--warning-sat), 30%); + --val-color--warning-link-hover: hsl(var(--warning-hue), var(--warning-sat), 20%); + --val-color--warning-link-active: hsl(var(--warning-hue), var(--warning-sat), 38%); + + --danger-hue: 348; + --danger-sat: 86%; + --val-color--danger: hsl(var(--danger-hue), var(--danger-sat), 50%); + --val-color--danger-light: hsl(var(--danger-hue), var(--danger-sat), 60%); + --val-color--danger-dark: hsl(var(--danger-hue), var(--danger-sat), 35%); + --val-color--danger-link: hsl(var(--danger-hue), var(--danger-sat), 25%); + --val-color--danger-link-hover: hsl(var(--danger-hue), var(--danger-sat), 10%); + --val-color--danger-link-active: hsl(var(--danger-hue), var(--danger-sat), 30%); + + --light-hue: 0; + --light-sat: 0%; + --val-color--light: hsl(var(--light-hue), var(--light-sat), 96%); + --val-color--light-light: hsl(var(--light-hue), var(--light-sat), 98%); + --val-color--light-dark: hsl(var(--light-hue), var(--light-sat), 92%); + + --dark-hue: 0; + --dark-sat: 0%; + --val-color--dark: hsl(var(--dark-hue), var(--dark-sat), 25%); + --val-color--dark-light: hsl(var(--dark-hue), var(--dark-sat), 40%); + --val-color--dark-dark: hsl(var(--dark-hue), var(--dark-sat), 8%); + --val-color--dark-link: hsl(var(--dark-hue), var(--dark-sat), 90%); + --val-color--dark-link-hover: hsl(var(--dark-hue), var(--dark-sat), 100%); + --val-color--dark-link-active: hsl(var(--dark-hue), var(--dark-sat), 70%); + + + + + --gray-hue: 201; + --gray-sat: 15%; + --val-color--gray-5: hsl(var(--gray-hue), var(--gray-sat), 5%); + --val-color--gray-10: hsl(var(--gray-hue), var(--gray-sat) ,11%); + --val-color--gray-20: hsl(var(--gray-hue), var(--gray-sat),20%); + --val-color--gray-45: hsl(var(--gray-hue), var(--gray-sat), 44%); + --val-color--gray-60: hsl(var(--gray-hue), var(--gray-sat), 57%); + --val-color--gray-65: hsl(var(--gray-hue), var(--gray-sat), 63%); + --val-color--gray-70: hsl(var(--gray-hue), var(--gray-sat), 72%); + --val-color--gray-90: hsl(var(--gray-hue), var(--gray-sat), 88%); + --val-color--gray-95: hsl(var(--gray-hue), var(--gray-sat), 93%); + --val-color--gray-100: hsl(var(--gray-hue), var(--gray-sat), 97%); + + + + + --val-color--bg: #fafafa; + --val-color--text: #212529; + --val-color--white: #fff; + +/* + + + --color-text-neutral-soft: var(--color--gray-45); + --color-text-neutral-medium: var(--color--gray-20); + --color-text-neutral-loud: var(--color--gray-5); + --color-text-primary-medium: var(--val-color--primary-40); + --color-text-primary-loud: var(--val-color--primary-30); + --color--black: #000; +*/ +/* + --color--red: #e33f1e; + --color--gold: #fdca40; + --color--green: #3fa21c; + --header-height-wide-when-fixed: calc(6 * var(--val-gap)); + --mobile-nav-width: 31.25rem; +*/ + --val-border-radius: 0.375rem; + + /* Menu component */ + --val-menu--color-bg: var(--val-color--bg); + --val-menu--color-highlight: #e91e63; + --val-menu--color-border: rgba(0, 0, 0, 0.1); + --val-menu--color-shadow: rgba(0, 0, 0, 0.06); + --val-menu--line-padding: 0.625rem; + --val-menu--line-height: calc(1.875rem + 1px); + --val-menu--item-height: calc(var(--val-menu--line-padding) + var(--val-menu--line-height)); + --val-menu--item-width-min: 14rem; + --val-menu--item-width-max: 20rem; + --val-menu--item-gap: 1rem; + --val-menu--border-radius: 0.625rem; + --val-menu--trigger-width: var(--val-menu--item-height); + --val-menu--side-width: 20rem; +} diff --git a/static/js/menu.js b/static/js/menu.js new file mode 100644 index 00000000..2f3b332e --- /dev/null +++ b/static/js/menu.js @@ -0,0 +1,94 @@ +function menu__showChildren(nav, children) { + let submenu = children[0].querySelector('.menu__subs'); + submenu.classList.add('active'); + submenu.style.animation = 'slideLeft 0.5s ease forwards'; + + let title = children[0].querySelector('i').parentNode.childNodes[0].textContent; + nav.querySelector('.menu__title').innerHTML = title; + nav.querySelector('.menu__header').classList.add('active'); +} + +function menu__hideChildren(nav, children) { + let submenu = children[0].querySelector('.menu__subs'); + submenu.style.animation = 'slideRight 0.5s ease forwards'; + setTimeout(() => { + submenu.classList.remove('active'); + submenu.style.removeProperty('animation'); + }, 300); + + children.shift(); + if (children.length > 0) { + let title = children[0].querySelector('i').parentNode.childNodes[0].textContent; + nav.querySelector('.menu__title').innerHTML = title; + } else { + nav.querySelector('.menu__header').classList.remove('active'); + nav.querySelector('.menu__title').innerHTML = ''; + } +} + +function menu__toggle(nav, overlay) { + nav.classList.toggle('active'); + overlay.classList.toggle('active'); +} + +function menu__reset(menu, nav, overlay) { + menu__toggle(nav, overlay); + setTimeout(() => { + nav.querySelector('.menu__header').classList.remove('active'); + nav.querySelector('.menu__title').innerHTML = ''; + menu.querySelectorAll('.menu__subs').forEach(submenu => { + submenu.classList.remove('active'); + submenu.style.removeProperty('animation'); + }); + }, 300); + return []; +} + +document.querySelectorAll('.menu').forEach(menu => { + + let menuChildren = []; + const menuNav = menu.querySelector('.menu__nav'); + const menuOverlay = menu.querySelector('.menu__overlay'); + + menu.querySelector('.menu__list').addEventListener('click', (e) => { + if (menuNav.classList.contains('active')) { + let target = e.target.closest('.menu__children'); + if (target && target != menuChildren[0]) { + menuChildren.unshift(target); + menu__showChildren(menuNav, menuChildren); + } + } + }); + + menu.querySelector('.menu__back').addEventListener('click', () => { + menu__hideChildren(menuNav, menuChildren); + }); + + menu.querySelector('.menu__close').addEventListener('click', () => { + menuChildren = menu__reset(menu, menuNav, menuOverlay); + }); + + menu.querySelectorAll('.menu__link > a[target="_blank"]').forEach(link => { + link.addEventListener('click', (e) => { + menuChildren = menu__reset(menu, menuNav, menuOverlay); + e.target.blur(); + }); + }); + + menu.querySelector('.menu__trigger').addEventListener('click', () => { + menu__toggle(menuNav, menuOverlay); + }); + + menuOverlay.addEventListener('click', () => { + menu__toggle(menuNav, menuOverlay); + }); + + window.onresize = function () { + if (menuNav.classList.contains('active')) { + var fontSizeRoot = parseFloat(getComputedStyle(document.documentElement).fontSize); + if (this.innerWidth >= 62 * fontSizeRoot) { + menuChildren = menu__reset(menu, menuNav, menuOverlay); + } + } + }; +}); From 0f1296c216e6bd6110edb752f313d9a082775209 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 29 Sep 2025 02:07:10 +0200 Subject: [PATCH 191/244] =?UTF-8?q?=F0=9F=8E=A8=20Mejora=20la=20estructura?= =?UTF-8?q?=20y=20estilos=20del=20men=C3=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rrenombra clases, ajusta estilos CSS y actualiza la lógica de JavaScript para una mejor gestión de submenús. --- src/base/component/menu/group.rs | 2 +- src/base/component/menu/item.rs | 40 ++++++------ src/base/component/menu/megamenu.rs | 2 +- src/base/component/menu/menu_menu.rs | 4 +- src/base/component/menu/submenu.rs | 4 +- static/css/menu.css | 91 +++++++++++++--------------- static/css/root.css | 5 +- static/js/menu.js | 21 ++++--- 8 files changed, 84 insertions(+), 85 deletions(-) diff --git a/src/base/component/menu/group.rs b/src/base/component/menu/group.rs index 41279b4e..ba188934 100644 --- a/src/base/component/menu/group.rs +++ b/src/base/component/menu/group.rs @@ -18,7 +18,7 @@ impl Component for Group { fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { PrepareMarkup::With(html! { - div id=[self.id()] class="menu-group" { + div id=[self.id()] class="menu__group" { (self.elements().render(cx)) } }) diff --git a/src/base/component/menu/item.rs b/src/base/component/menu/item.rs index 07d629ae..7a36fbbf 100644 --- a/src/base/component/menu/item.rs +++ b/src/base/component/menu/item.rs @@ -1,11 +1,9 @@ use crate::prelude::*; -//use super::{Megamenu, Submenu}; - type Label = L10n; type Content = Typed<Html>; type SubmenuItems = Typed<menu::Submenu>; -//type MegamenuGroups = Typed<Megamenu>; +type MegamenuGroups = Typed<menu::Megamenu>; #[derive(AutoDefault)] pub enum ItemKind { @@ -16,7 +14,7 @@ pub enum ItemKind { LinkBlank(Label, FnPathByContext), Html(Content), Submenu(Label, SubmenuItems), - // Megamenu(Label, MegamenuGroups), + Megamenu(Label, MegamenuGroups), } #[rustfmt::skip] @@ -41,61 +39,65 @@ impl Component for Item { match self.item_kind() { ItemKind::Void => PrepareMarkup::None, ItemKind::Label(label) => PrepareMarkup::With(html! { - li class="menu__label" { + li class="menu__item menu__item--label" { span title=[description] { (left_icon) - (label.using(cx)) + span class="menu__label" { (label.using(cx)) } (right_icon) } } }), ItemKind::Link(label, path) => PrepareMarkup::With(html! { - li class="menu__link" { + li class="menu__item menu__item--link" { a href=(path(cx)) title=[description] { (left_icon) - (label.using(cx)) + span class="menu__label" { (label.using(cx)) } (right_icon) } } }), ItemKind::LinkBlank(label, path) => PrepareMarkup::With(html! { - li class="menu__link" { + li class="menu__item menu__item--link" { a href=(path(cx)) title=[description] target="_blank" { (left_icon) - (label.using(cx)) + span class="menu__label" { (label.using(cx)) } (right_icon) } } }), ItemKind::Html(content) => PrepareMarkup::With(html! { - li class="menu__html" { + li class="menu__item menu__item--html" { (content.render(cx)) } }), ItemKind::Submenu(label, submenu) => PrepareMarkup::With(html! { - li class="menu__children" { + li class="menu__item menu__item--children" { a href="#" title=[description] { (left_icon) - (label.using(cx)) i class="menu__icon bi-chevron-down" {} + span class="menu__label" { (label.using(cx)) } + (Icon::svg(html! { + path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708" {} + }).render(cx)) } - div class="menu__subs" { + div class="menu__children menu__children--submenu" { (submenu.render(cx)) } } }), - /* ItemKind::Megamenu(label, megamenu) => PrepareMarkup::With(html! { - li class="menu__children" { + li class="menu__item menu__item--children" { a href="#" title=[description] { (left_icon) - (label.escaped(cx.langid())) i class="menu__icon bi-chevron-down" {} + span class="menu__label" { (label.using(cx)) } + (Icon::svg(html! { + path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708" {} + }).render(cx)) } - div class="menu__subs menu__mega" { + div class="menu__children menu__children--mega" { (megamenu.render(cx)) } } }), - */ } } } diff --git a/src/base/component/menu/megamenu.rs b/src/base/component/menu/megamenu.rs index f22b184e..e435e753 100644 --- a/src/base/component/menu/megamenu.rs +++ b/src/base/component/menu/megamenu.rs @@ -18,7 +18,7 @@ impl Component for Megamenu { fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { PrepareMarkup::With(html! { - div id=[self.id()] class="menu__groups" { + div id=[self.id()] class="menu__mega" { (self.groups().render(cx)) } }) diff --git a/src/base/component/menu/menu_menu.rs b/src/base/component/menu/menu_menu.rs index a7f91be1..58a4c21d 100644 --- a/src/base/component/menu/menu_menu.rs +++ b/src/base/component/menu/menu_menu.rs @@ -54,7 +54,9 @@ impl Component for Menu { class="menu__trigger" title=[L10n::l("menu_toggle").lookup(cx)] { - span {} span {} span {} + (Icon::svg(html! { + path fill-rule="evenodd" d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5" {} + }).render(cx)) } } } diff --git a/src/base/component/menu/submenu.rs b/src/base/component/menu/submenu.rs index 58770529..a5957ef9 100644 --- a/src/base/component/menu/submenu.rs +++ b/src/base/component/menu/submenu.rs @@ -19,9 +19,9 @@ impl Component for Submenu { fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { PrepareMarkup::With(html! { - div id=[self.id()] class="menu__items" { + div id=[self.id()] class="menu__submenu" { @if let Some(title) = self.title().lookup(cx) { - h4 class="menu__title" { (title) } + h4 class="menu__submenu-title" { (title) } } ul { (self.items().render(cx)) diff --git a/static/css/menu.css b/static/css/menu.css index a8b2854c..5520e398 100644 --- a/static/css/menu.css +++ b/static/css/menu.css @@ -27,13 +27,13 @@ .menu__nav li { display: inline-block; margin: 0 0 0 1.5rem; - padding: var(--val-menu--line-padding) 0; - line-height: var(--val-menu--line-height); + padding: 0; + line-height: var(--val-menu--item-height); list-style: none; list-style-type: none; } -.menu__nav li.menu__label, +.menu__item--label, .menu__nav li > a { position: relative; font-weight: 500; @@ -48,19 +48,18 @@ .menu__nav li > a:focus { color: var(--val-menu--color-highlight); } -.menu__nav li > a > i.menu__icon { +.menu__nav li > a > svg.icon { margin-left: 0.25rem; } -.menu__nav li .menu__subs { +.menu__children { position: absolute; max-width: 100%; height: auto; - padding: 1rem 2rem; + padding: var(--val-gap-0-5) var(--val-gap-1-5); border: none; outline: none; background: var(--val-menu--color-bg); - border-radius: var(--val-menu--border-radius); border-top: 3px solid var(--val-menu--color-highlight); z-index: 500; opacity: 0; @@ -69,19 +68,19 @@ transition: all 0.5s ease-in-out; } -.menu__nav li.menu__children:hover > .menu__subs, -.menu__nav li.menu__children > a:focus + .menu__subs, -.menu__nav li.menu__children .menu__subs:focus-within { +.menu__item--children:hover > .menu__children, +.menu__item--children > a:focus + .menu__children, +.menu__item--children .menu__children:focus-within { margin-top: 0.4rem; opacity: 1; visibility: visible; } -.menu__nav li .menu__items { +.menu__submenu { min-width: var(--val-menu--item-width-min); max-width: var(--val-menu--item-width-max); } -.menu__nav li .menu__items .menu__title { +.menu__submenu-title { font-family: inherit; font-size: 1rem; font-weight: 500; @@ -94,17 +93,17 @@ text-transform: uppercase; text-rendering: optimizeLegibility; } -.menu__nav li .menu__items li { +.menu__submenu li { display: block; - margin-left: 0; + margin: 0; } -.menu__nav li .menu__mega { +.menu__children--mega { left: 50%; transform: translateX(-50%); } -.menu__nav li .menu__groups { +.menu__mega { display: flex; flex-wrap: nowrap; } @@ -116,15 +115,9 @@ /* Applies <= 992px */ @media only screen and (max-width: 62rem) { - .menu { - border-radius: var(--val-border-radius); - } .menu__wrapper { padding-right: var(--val-gap-0-5); } - .menu__wrapper button { - margin: var(--val-gap-0-5) 0 var(--val-gap-0-5) var(--val-gap-0-5); - } .menu__trigger { cursor: pointer; width: var(--val-menu--trigger-width); @@ -136,14 +129,10 @@ flex-direction: column; justify-content: center; } - .menu__trigger span { - width: 100%; - height: 2px; - margin: 12.675% 0; - border-radius: var(--val-border-radius); - background: var(--val-color--text); + .menu__trigger svg.icon { + width: 2rem; + height: 2rem; } - .menu__nav { position: fixed; top: 0; @@ -156,34 +145,36 @@ transform: translate(-100%); transition: all 0.5s ease-in-out; } - .menu__panel .menu__nav.active { + .menu__nav.active { transform: translate(0%); } .menu__nav li { display: block; margin: 0; - padding: 0; + line-height: var(--val-menu--line-height); } - .menu__nav li.menu__label, + + .menu__item--label, .menu__nav li > a { display: block; padding: var(--val-menu--line-padding) var(--val-menu--item-height) var(--val-menu--line-padding) var(--val-menu--item-gap); border-bottom: 1px solid var(--val-menu--color-border); } - .menu__nav li ul li.menu__label, + .menu__nav li ul li.menu__item--label, .menu__nav li ul li > a { border-bottom: 0; } - .menu__nav li > a > i.menu__icon { + .menu__nav li > a > svg.icon { position: absolute; top: var(--val-menu--line-padding); right: var(--val-menu--line-padding); + height: var(--val-menu--line-height); font-size: 1.25rem; transform: rotate(-90deg); } - .menu__nav li .menu__subs { + .menu__children { position: absolute; display: none; top: 0; @@ -201,22 +192,22 @@ transform: translateX(0%); box-shadow: none; } - .menu__nav li .menu__subs.active { + .menu__children.active { display: block; } - .menu__nav li .menu__subs > :first-child { - margin-top: 4rem; + .menu__children > :first-child { + margin-top: 2.675rem; } - .menu__nav li .menu__items .menu__title { + .menu__submenu-title { padding: var(--val-menu--line-padding) var(--val-menu--item-height) var(--val-menu--line-padding) var(--val-menu--item-gap); } - .menu__nav li .menu__groups { + .menu__mega { display: block; } - .menu__nav .menu__header { + .menu__header { position: sticky; display: flex; align-items: center; @@ -227,14 +218,14 @@ background: var(--val-menu--color-bg); z-index: 501; } - .menu__nav .menu__header .menu__title { + .menu__title { padding: var(--val-menu--line-padding); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } - .menu__nav .menu__header .menu__close, - .menu__nav .menu__header .menu__back { + .menu__close, + .menu__back { width: var(--val-menu--item-height); min-width: var(--val-menu--item-height); height: var(--val-menu--item-height); @@ -245,20 +236,20 @@ align-items: center; justify-content: center; } - .menu__nav .menu__header .menu__close { + .menu__close { font-size: 2.25rem; - border-left: 1px solid var(--val-menu--color-border); + border-left: 1px solid var(--val-menu--color-border) !important; } - .menu__nav .menu__header .menu__back { + .menu__back { font-size: 1.25rem; - border-right: 1px solid var(--val-menu--color-border); + border-right: 1px solid var(--val-menu--color-border) !important; display: none; } - .menu__nav .menu__header.active .menu__back { + .menu__header.active .menu__back { display: flex; } - .menu__nav .menu__list { + .menu__list { height: 100%; overflow-y: auto; overflow-x: hidden; diff --git a/static/css/root.css b/static/css/root.css index bc55a443..aeab1c67 100644 --- a/static/css/root.css +++ b/static/css/root.css @@ -191,6 +191,8 @@ --color--green: #3fa21c; --header-height-wide-when-fixed: calc(6 * var(--val-gap)); --mobile-nav-width: 31.25rem; + + --val-menu--border-radius: 0.625rem; */ --val-border-radius: 0.375rem; @@ -205,7 +207,6 @@ --val-menu--item-width-min: 14rem; --val-menu--item-width-max: 20rem; --val-menu--item-gap: 1rem; - --val-menu--border-radius: 0.625rem; - --val-menu--trigger-width: var(--val-menu--item-height); + --val-menu--trigger-width: 2.675rem; --val-menu--side-width: 20rem; } diff --git a/static/js/menu.js b/static/js/menu.js index 2f3b332e..6b5ae1b0 100644 --- a/static/js/menu.js +++ b/static/js/menu.js @@ -1,15 +1,17 @@ function menu__showChildren(nav, children) { - let submenu = children[0].querySelector('.menu__subs'); + const li = children[0]; + const submenu = li.querySelector('.menu__children'); submenu.classList.add('active'); submenu.style.animation = 'slideLeft 0.5s ease forwards'; - let title = children[0].querySelector('i').parentNode.childNodes[0].textContent; + const labelEl = li.querySelector('.menu__label'); + const title = labelEl ? labelEl.textContent.trim() : (li.querySelector('a')?.textContent?.trim() ?? ''); nav.querySelector('.menu__title').innerHTML = title; nav.querySelector('.menu__header').classList.add('active'); } function menu__hideChildren(nav, children) { - let submenu = children[0].querySelector('.menu__subs'); + const submenu = children[0].querySelector('.menu__children'); submenu.style.animation = 'slideRight 0.5s ease forwards'; setTimeout(() => { submenu.classList.remove('active'); @@ -18,11 +20,12 @@ function menu__hideChildren(nav, children) { children.shift(); if (children.length > 0) { - let title = children[0].querySelector('i').parentNode.childNodes[0].textContent; - nav.querySelector('.menu__title').innerHTML = title; + const a = children[0].querySelector('a'); + const title = (a && a.textContent ? a.textContent.trim() : ''); + nav.querySelector('.menu__title').textContent = title; } else { nav.querySelector('.menu__header').classList.remove('active'); - nav.querySelector('.menu__title').innerHTML = ''; + nav.querySelector('.menu__title').textContent = ''; } } @@ -36,7 +39,7 @@ function menu__reset(menu, nav, overlay) { setTimeout(() => { nav.querySelector('.menu__header').classList.remove('active'); nav.querySelector('.menu__title').innerHTML = ''; - menu.querySelectorAll('.menu__subs').forEach(submenu => { + menu.querySelectorAll('.menu__children').forEach(submenu => { submenu.classList.remove('active'); submenu.style.removeProperty('animation'); }); @@ -52,7 +55,7 @@ document.querySelectorAll('.menu').forEach(menu => { menu.querySelector('.menu__list').addEventListener('click', (e) => { if (menuNav.classList.contains('active')) { - let target = e.target.closest('.menu__children'); + let target = e.target.closest('.menu__item--children'); if (target && target != menuChildren[0]) { menuChildren.unshift(target); menu__showChildren(menuNav, menuChildren); @@ -68,7 +71,7 @@ document.querySelectorAll('.menu').forEach(menu => { menuChildren = menu__reset(menu, menuNav, menuOverlay); }); - menu.querySelectorAll('.menu__link > a[target="_blank"]').forEach(link => { + menu.querySelectorAll('.menu__item--link > a[target="_blank"]').forEach(link => { link.addEventListener('click', (e) => { menuChildren = menu__reset(menu, menuNav, menuOverlay); e.target.blur(); From 6b08b92635c697674a8bcb81e75a470a188a09d9 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 30 Sep 2025 20:21:06 +0200 Subject: [PATCH 192/244] =?UTF-8?q?=F0=9F=9A=9A=20Renombra=20`AssetsOp`=20?= =?UTF-8?q?por=20`ContextOp`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/theme/basic.rs | 14 +++++++------- src/html.rs | 3 ++- src/html/context.rs | 40 ++++++++++++++++++++++------------------ src/response/page.rs | 4 ++-- 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index 20f51994..ecd64856 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -52,32 +52,32 @@ impl Theme for Basic { _ => "/css/basic.css", }; let pkg_version = env!("CARGO_PKG_VERSION"); - page.alter_assets(AssetsOp::AddStyleSheet( + page.alter_assets(ContextOp::AddStyleSheet( StyleSheet::from("/css/normalize.css") .with_version("8.0.1") .with_weight(-99), )) - .alter_assets(AssetsOp::AddStyleSheet( + .alter_assets(ContextOp::AddStyleSheet( StyleSheet::from("/css/root.css") .with_version(pkg_version) .with_weight(-99), )) - .alter_assets(AssetsOp::AddStyleSheet( + .alter_assets(ContextOp::AddStyleSheet( StyleSheet::from("/css/components.css") .with_version(pkg_version) .with_weight(-99), )) - .alter_assets(AssetsOp::AddStyleSheet( + .alter_assets(ContextOp::AddStyleSheet( StyleSheet::from("/css/menu.css") .with_version(pkg_version) .with_weight(-99), )) - .alter_assets(AssetsOp::AddStyleSheet( + .alter_assets(ContextOp::AddStyleSheet( StyleSheet::from(styles) .with_version(pkg_version) .with_weight(-99), )) - .alter_assets(AssetsOp::AddJavaScript( + .alter_assets(ContextOp::AddJavaScript( JavaScript::defer("/js/menu.js") .with_version(pkg_version) .with_weight(-99), @@ -169,7 +169,7 @@ fn render_intro(page: &mut Page) -> Markup { } fn render_pagetop_intro(page: &mut Page) -> Markup { - page.alter_assets(AssetsOp::AddJavaScript(JavaScript::on_load_async("intro-js", |cx| + 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"); diff --git a/src/html.rs b/src/html.rs index c4195a9d..679d433a 100644 --- a/src/html.rs +++ b/src/html.rs @@ -14,7 +14,8 @@ pub use assets::{Asset, Assets}; // **< HTML DOCUMENT CONTEXT >********************************************************************** mod context; -pub use context::{AssetsOp, Context, Contextual, ErrorParam}; +#[allow(deprecated)] +pub use context::{AssetsOp, Context, ContextOp, Contextual, ErrorParam}; pub type FnPathByContext = fn(cx: &Context) -> &str; // **< HTML ATTRIBUTES >**************************************************************************** diff --git a/src/html/context.rs b/src/html/context.rs index 355ccead..94f24bf7 100644 --- a/src/html/context.rs +++ b/src/html/context.rs @@ -10,8 +10,12 @@ use crate::{builder_fn, join}; use std::any::Any; use std::collections::HashMap; -/// Operaciones para modificar el contexto ([`Context`]) de un documento. -pub enum AssetsOp { +/// **Obsoleto desde la versión 0.4.0**: usar [`ContextOp`] en su lugar. +#[deprecated(since = "0.5.0", note = "Use `ContextOp` instead")] +pub type AssetsOp = ContextOp; + +/// Operaciones para modificar los recursos asociados al contexto ([`Context`]) de un documento. +pub enum ContextOp { // Favicon. /// Define el *favicon* del documento. Sobrescribe cualquier valor anterior. SetFavicon(Option<Favicon>), @@ -55,7 +59,7 @@ pub enum ErrorParam { /// - Almacenar la **solicitud HTTP** de origen. /// - Seleccionar **tema** y **composición** (*layout*) de renderizado. /// - Administrar **recursos** del documento como el icono [`Favicon`], las hojas de estilo -/// [`StyleSheet`] o los scripts [`JavaScript`] mediante [`AssetsOp`]. +/// [`StyleSheet`] o los scripts [`JavaScript`] mediante [`ContextOp`]. /// - Leer y mantener **parámetros dinámicos tipados** de contexto. /// - Generar **identificadores únicos** por tipo de componente. /// @@ -71,9 +75,9 @@ pub enum ErrorParam { /// cx.with_langid(&LangMatch::resolve("es-ES")) /// .with_theme("aliner") /// .with_layout("default") -/// .with_assets(AssetsOp::SetFavicon(Some(Favicon::new().with_icon("/favicon.ico")))) -/// .with_assets(AssetsOp::AddStyleSheet(StyleSheet::from("/css/app.css"))) -/// .with_assets(AssetsOp::AddJavaScript(JavaScript::defer("/js/app.js"))) +/// .with_assets(ContextOp::SetFavicon(Some(Favicon::new().with_icon("/favicon.ico")))) +/// .with_assets(ContextOp::AddStyleSheet(StyleSheet::from("/css/app.css"))) +/// .with_assets(ContextOp::AddJavaScript(JavaScript::defer("/js/app.js"))) /// .with_param("usuario_id", 42_i32) /// } /// ``` @@ -100,9 +104,9 @@ pub trait Contextual: LangId { #[builder_fn] fn with_param<T: 'static>(self, key: &'static str, value: T) -> Self; - /// Define los recursos del contexto usando [`AssetsOp`]. + /// Define los recursos del contexto usando [`ContextOp`]. #[builder_fn] - fn with_assets(self, op: AssetsOp) -> Self; + fn with_assets(self, op: ContextOp) -> Self; // **< Contextual GETTERS >********************************************************************* @@ -172,11 +176,11 @@ pub trait Contextual: LangId { /// // Selecciona un tema (por su nombre corto). /// .with_theme("aliner") /// // Asigna un favicon. -/// .with_assets(AssetsOp::SetFavicon(Some(Favicon::new().with_icon("/favicon.ico")))) +/// .with_assets(ContextOp::SetFavicon(Some(Favicon::new().with_icon("/favicon.ico")))) /// // Añade una hoja de estilo externa. -/// .with_assets(AssetsOp::AddStyleSheet(StyleSheet::from("/css/style.css"))) +/// .with_assets(ContextOp::AddStyleSheet(StyleSheet::from("/css/style.css"))) /// // Añade un script JavaScript. -/// .with_assets(AssetsOp::AddJavaScript(JavaScript::defer("/js/main.js"))) +/// .with_assets(ContextOp::AddJavaScript(JavaScript::defer("/js/main.js"))) /// // Añade un parámetro dinámico al contexto. /// .with_param("usuario_id", 42) /// } @@ -442,29 +446,29 @@ impl Contextual for Context { } #[builder_fn] - fn with_assets(mut self, op: AssetsOp) -> Self { + fn with_assets(mut self, op: ContextOp) -> Self { match op { // Favicon. - AssetsOp::SetFavicon(favicon) => { + ContextOp::SetFavicon(favicon) => { self.favicon = favicon; } - AssetsOp::SetFaviconIfNone(icon) => { + ContextOp::SetFaviconIfNone(icon) => { if self.favicon.is_none() { self.favicon = Some(icon); } } // Stylesheets. - AssetsOp::AddStyleSheet(css) => { + ContextOp::AddStyleSheet(css) => { self.stylesheets.add(css); } - AssetsOp::RemoveStyleSheet(path) => { + ContextOp::RemoveStyleSheet(path) => { self.stylesheets.remove(path); } // JavaScripts. - AssetsOp::AddJavaScript(js) => { + ContextOp::AddJavaScript(js) => { self.javascripts.add(js); } - AssetsOp::RemoveJavaScript(path) => { + ContextOp::RemoveJavaScript(path) => { self.javascripts.remove(path); } } diff --git a/src/response/page.rs b/src/response/page.rs index e9d30671..135ab19e 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -8,9 +8,9 @@ use crate::core::component::{Child, ChildOp, Component}; use crate::core::theme::{ChildrenInRegions, ThemeRef, REGION_CONTENT}; use crate::html::{html, Markup, DOCTYPE}; use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; -use crate::html::{AssetsOp, Context, Contextual}; use crate::html::{AttrClasses, ClassesOp}; use crate::html::{AttrId, AttrL10n}; +use crate::html::{Context, ContextOp, Contextual}; use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier}; use crate::service::HttpRequest; use crate::{builder_fn, AutoDefault}; @@ -286,7 +286,7 @@ impl Contextual for Page { } #[builder_fn] - fn with_assets(mut self, op: AssetsOp) -> Self { + fn with_assets(mut self, op: ContextOp) -> Self { self.context.alter_assets(op); self } From 075f61bf09ce4e52b03182ac81e2dd11e7f005b2 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 30 Sep 2025 23:36:09 +0200 Subject: [PATCH 193/244] =?UTF-8?q?=F0=9F=9A=A7=20(core):=20Mueve=20`Conte?= =?UTF-8?q?xt`=20al=20=C3=A1mbito=20de=20componentes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/component.rs | 6 +++++ src/core/component/children.rs | 4 ++-- src/{html => core/component}/context.rs | 10 +++----- src/core/component/definition.rs | 3 ++- src/global.rs | 10 ++++---- src/html.rs | 32 +++++++++++++++++++++---- src/html/assets.rs | 3 ++- src/html/assets/favicon.rs | 3 ++- src/html/assets/javascript.rs | 3 ++- src/html/assets/stylesheet.rs | 3 ++- src/prelude.rs | 9 ++++++- src/response/page.rs | 3 +-- src/response/page/error.rs | 2 +- 13 files changed, 64 insertions(+), 27 deletions(-) rename src/{html => core/component}/context.rs (97%) diff --git a/src/core/component.rs b/src/core/component.rs index 17b9b735..a002e3d5 100644 --- a/src/core/component.rs +++ b/src/core/component.rs @@ -7,3 +7,9 @@ mod children; pub use children::Children; pub use children::{Child, ChildOp}; pub use children::{Typed, TypedOp}; + +// **< HTML DOCUMENT CONTEXT >********************************************************************** + +mod context; +pub use context::{Context, ContextOp, Contextual, ErrorParam}; +pub type FnPathByContext = fn(cx: &Context) -> &str; diff --git a/src/core/component/children.rs b/src/core/component/children.rs index 920dacf8..c0c8841e 100644 --- a/src/core/component/children.rs +++ b/src/core/component/children.rs @@ -1,5 +1,5 @@ -use crate::core::component::Component; -use crate::html::{html, Context, Markup}; +use crate::core::component::{Component, Context}; +use crate::html::{html, Markup}; use crate::{builder_fn, AutoDefault, UniqueId}; use parking_lot::RwLock; diff --git a/src/html/context.rs b/src/core/component/context.rs similarity index 97% rename from src/html/context.rs rename to src/core/component/context.rs index 94f24bf7..9333e484 100644 --- a/src/html/context.rs +++ b/src/core/component/context.rs @@ -10,11 +10,7 @@ use crate::{builder_fn, join}; use std::any::Any; use std::collections::HashMap; -/// **Obsoleto desde la versión 0.4.0**: usar [`ContextOp`] en su lugar. -#[deprecated(since = "0.5.0", note = "Use `ContextOp` instead")] -pub type AssetsOp = ContextOp; - -/// Operaciones para modificar los recursos asociados al contexto ([`Context`]) de un documento. +/// Operaciones para modificar recursos asociados al contexto ([`Context`]) de un documento. pub enum ContextOp { // Favicon. /// Define el *favicon* del documento. Sobrescribe cualquier valor anterior. @@ -64,7 +60,7 @@ pub enum ErrorParam { /// - Generar **identificadores únicos** por tipo de componente. /// /// Lo implementan, típicamente, estructuras que representan el contexto de renderizado, como -/// [`Context`](crate::html::Context) o [`Page`](crate::response::page::Page). +/// [`Context`](crate::core::component::Context) o [`Page`](crate::response::page::Page). /// /// # Ejemplo /// @@ -375,7 +371,7 @@ impl Context { } } -/// Permite a [`Context`](crate::html::Context) actuar como proveedor de idioma. +/// Permite a [`Context`](crate::core::component::Context) actuar como proveedor de idioma. /// /// Devuelve un [`LanguageIdentifier`] siguiendo este orden de prioridad: /// diff --git a/src/core/component/definition.rs b/src/core/component/definition.rs index 333cf694..c0573b44 100644 --- a/src/core/component/definition.rs +++ b/src/core/component/definition.rs @@ -1,6 +1,7 @@ use crate::base::action; +use crate::core::component::Context; use crate::core::{AnyInfo, TypeInfo}; -use crate::html::{html, Context, Markup, PrepareMarkup}; +use crate::html::{html, Markup, PrepareMarkup}; /// Define la función de renderizado para todos los componentes. /// diff --git a/src/global.rs b/src/global.rs index ccc6d9de..c8805a30 100644 --- a/src/global.rs +++ b/src/global.rs @@ -50,11 +50,11 @@ pub struct App { pub theme: String, /// Idioma por defecto para la aplicación. /// - /// Si no está definido o no es válido, el idioma efectivo para el renderizado se resolverá - /// según la implementación de [`LangId`](crate::locale::LangId) en este orden: primero intenta - /// con el establecido en [`Contextual::with_langid()`](crate::html::Contextual::with_langid); - /// pero si no se ha definido explícitamente, usará el indicado en la cabecera `Accept-Language` - /// del navegador; y, si ninguno aplica, se empleará el idioma de respaldo ("en-US"). + /// Si no está definido o no es válido, [`LangId`](crate::locale::LangId) determinará el idioma + /// efectivo para el renderizado en este orden: primero intentará usar el establecido mediante + /// [`Contextual::with_langid()`](crate::core::component::Contextual::with_langid); si no se ha + /// definido explícitamente, probará el indicado en la cabecera `Accept-Language` del navegador; + /// y, si ninguno aplica, se empleará el idioma de respaldo ("en-US"). pub language: String, /// Banner ASCII mostrado al inicio: *"Off"* (desactivado), *"Slant"*, *"Small"*, *"Speed"* o /// *"Starwars"*. diff --git a/src/html.rs b/src/html.rs index 679d433a..079811a2 100644 --- a/src/html.rs +++ b/src/html.rs @@ -13,10 +13,34 @@ pub use assets::{Asset, Assets}; // **< HTML DOCUMENT CONTEXT >********************************************************************** -mod context; -#[allow(deprecated)] -pub use context::{AssetsOp, Context, ContextOp, Contextual, ErrorParam}; -pub type FnPathByContext = fn(cx: &Context) -> &str; +/// **Obsoleto desde la versión 0.5.0**: usar [`core::component::Context`] en su lugar. +#[deprecated(since = "0.5.0", note = "Moved to `pagetop::core::component::Context`")] +pub type Context = crate::core::component::Context; + +/// **Obsoleto desde la versión 0.5.0**: usar [`core::component::ContextOp`] en su lugar. +#[deprecated( + since = "0.5.0", + note = "Moved to `pagetop::core::component::ContextOp`" +)] +pub type ContextOp = crate::core::component::ContextOp; + +/// **Obsoleto desde la versión 0.5.0**: usar [`core::component::Contextual`] en su lugar. +#[deprecated( + since = "0.5.0", + note = "Moved to `pagetop::core::component::Contextual`" +)] +pub trait Contextual: crate::core::component::Contextual {} + +/// **Obsoleto desde la versión 0.5.0**: usar [`core::component::ErrorParam`] en su lugar. +#[deprecated( + since = "0.5.0", + note = "Moved to `pagetop::core::component::ErrorParam`" +)] +pub type ErrorParam = crate::core::component::ErrorParam; + +/// **Obsoleto desde la versión 0.5.0**: usar [`ContextOp`] en su lugar. +#[deprecated(since = "0.5.0", note = "Use `ContextOp` instead")] +pub type AssetsOp = crate::core::component::ContextOp; // **< HTML ATTRIBUTES >**************************************************************************** diff --git a/src/html/assets.rs b/src/html/assets.rs index 41cd4710..fe5f5b7c 100644 --- a/src/html/assets.rs +++ b/src/html/assets.rs @@ -2,7 +2,8 @@ pub mod favicon; pub mod javascript; pub mod stylesheet; -use crate::html::{html, Context, Markup}; +use crate::core::component::Context; +use crate::html::{html, Markup}; use crate::{AutoDefault, Weight}; /// Representación genérica de un script [`JavaScript`](crate::html::JavaScript) o una hoja de diff --git a/src/html/assets/favicon.rs b/src/html/assets/favicon.rs index 56c39056..c2280aab 100644 --- a/src/html/assets/favicon.rs +++ b/src/html/assets/favicon.rs @@ -1,4 +1,5 @@ -use crate::html::{html, Context, Markup}; +use crate::core::component::Context; +use crate::html::{html, Markup}; use crate::AutoDefault; /// Un **Favicon** es un recurso gráfico que usa el navegador como icono asociado al sitio. diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs index 4649cdb4..dde5f945 100644 --- a/src/html/assets/javascript.rs +++ b/src/html/assets/javascript.rs @@ -1,5 +1,6 @@ +use crate::core::component::Context; use crate::html::assets::Asset; -use crate::html::{html, Context, Markup, PreEscaped}; +use crate::html::{html, Markup, PreEscaped}; use crate::{join, join_pair, AutoDefault, Weight}; // Define el origen del recurso JavaScript y cómo debe cargarse en el navegador. diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index b54f4cf3..49cb9911 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -1,5 +1,6 @@ +use crate::core::component::Context; use crate::html::assets::Asset; -use crate::html::{html, Context, Markup, PreEscaped}; +use crate::html::{html, Markup, PreEscaped}; use crate::{join_pair, AutoDefault, Weight}; // Define el origen del recurso CSS y cómo se incluye en el documento. diff --git a/src/prelude.rs b/src/prelude.rs index 484e53c1..a71375e1 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -28,7 +28,14 @@ pub use crate::global; pub use crate::trace; -pub use crate::html::*; +// No se usa `pub use crate::html::*;` para evitar duplicar alias marcados como obsoletos +// (*deprecated*) porque han sido trasladados a `crate::core::component`. Cuando se retiren estos +// alias obsoletos se volverá a declarar como `pub use crate::html::*;`. +pub use crate::html::{ + display, html_private, Asset, Assets, AttrClasses, AttrId, AttrL10n, AttrName, AttrValue, + ClassesOp, Escaper, Favicon, JavaScript, Markup, PreEscaped, PrepareMarkup, StyleSheet, + TargetMedia, DOCTYPE, +}; pub use crate::locale::*; diff --git a/src/response/page.rs b/src/response/page.rs index 135ab19e..f81c9806 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -4,13 +4,12 @@ pub use error::ErrorPage; pub use actix_web::Result as ResultPage; use crate::base::action; -use crate::core::component::{Child, ChildOp, Component}; +use crate::core::component::{Child, ChildOp, Component, Context, ContextOp, Contextual}; use crate::core::theme::{ChildrenInRegions, ThemeRef, REGION_CONTENT}; use crate::html::{html, Markup, DOCTYPE}; use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; use crate::html::{AttrClasses, ClassesOp}; use crate::html::{AttrId, AttrL10n}; -use crate::html::{Context, ContextOp, Contextual}; use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier}; use crate::service::HttpRequest; use crate::{builder_fn, AutoDefault}; diff --git a/src/response/page/error.rs b/src/response/page/error.rs index 2355d234..50e1c77b 100644 --- a/src/response/page/error.rs +++ b/src/response/page/error.rs @@ -1,5 +1,5 @@ use crate::base::component::Html; -use crate::html::Contextual; +use crate::core::component::Contextual; use crate::locale::L10n; use crate::response::ResponseError; use crate::service::http::{header::ContentType, StatusCode}; From 843aed86c7acc2566b9786b183adc7290e8826a2 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 30 Sep 2025 23:45:13 +0200 Subject: [PATCH 194/244] =?UTF-8?q?=F0=9F=9A=9A=20Renombra=20`ErrorParam`?= =?UTF-8?q?=20por=20`ContextError`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/component.rs | 4 +--- src/core/component/context.rs | 34 +++++++++++++++++----------------- src/html.rs | 6 +++--- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/core/component.rs b/src/core/component.rs index a002e3d5..be9bbad1 100644 --- a/src/core/component.rs +++ b/src/core/component.rs @@ -8,8 +8,6 @@ pub use children::Children; pub use children::{Child, ChildOp}; pub use children::{Typed, TypedOp}; -// **< HTML DOCUMENT CONTEXT >********************************************************************** - mod context; -pub use context::{Context, ContextOp, Contextual, ErrorParam}; +pub use context::{Context, ContextError, ContextOp, Contextual}; pub type FnPathByContext = fn(cx: &Context) -> &str; diff --git a/src/core/component/context.rs b/src/core/component/context.rs index 9333e484..9dad7f5f 100644 --- a/src/core/component/context.rs +++ b/src/core/component/context.rs @@ -33,14 +33,14 @@ pub enum ContextOp { /// Errores de acceso a parámetros dinámicos del contexto. /// -/// - [`ErrorParam::NotFound`]: la clave no existe. -/// - [`ErrorParam::TypeMismatch`]: la clave existe, pero el valor guardado no coincide con el tipo -/// solicitado. Incluye nombre de la clave (`key`), tipo esperado (`expected`) y tipo realmente -/// guardado (`saved`) para facilitar el diagnóstico. +/// - [`ContextError::ParamNotFound`]: la clave no existe. +/// - [`ContextError::ParamTypeMismatch`]: la clave existe, pero el valor guardado no coincide con +/// el tipo solicitado. Incluye nombre de la clave (`key`), tipo esperado (`expected`) y tipo +/// realmente guardado (`saved`) para facilitar el diagnóstico. #[derive(Debug)] -pub enum ErrorParam { - NotFound, - TypeMismatch { +pub enum ContextError { + ParamNotFound, + ParamTypeMismatch { key: &'static str, expected: &'static str, saved: &'static str, @@ -290,8 +290,8 @@ impl Context { /// Devuelve: /// /// - `Ok(&T)` si la clave existe y el tipo coincide. - /// - `Err(ErrorParam::NotFound)` si la clave no existe. - /// - `Err(ErrorParam::TypeMismatch)` si la clave existe pero el tipo no coincide. + /// - `Err(ContextError::ParamNotFound)` si la clave no existe. + /// - `Err(ContextError::ParamTypeMismatch)` si la clave existe pero el tipo no coincide. /// /// # Ejemplos /// @@ -308,10 +308,10 @@ impl Context { /// // Error de tipo: /// assert!(cx.get_param::<String>("usuario_id").is_err()); /// ``` - pub fn get_param<T: 'static>(&self, key: &'static str) -> Result<&T, ErrorParam> { - let (any, type_name) = self.params.get(key).ok_or(ErrorParam::NotFound)?; + pub fn get_param<T: 'static>(&self, key: &'static str) -> Result<&T, ContextError> { + let (any, type_name) = self.params.get(key).ok_or(ContextError::ParamNotFound)?; any.downcast_ref::<T>() - .ok_or_else(|| ErrorParam::TypeMismatch { + .ok_or_else(|| ContextError::ParamTypeMismatch { key, expected: TypeInfo::FullName.of::<T>(), saved: type_name, @@ -323,8 +323,8 @@ impl Context { /// Devuelve: /// /// - `Ok(T)` si la clave existía y el tipo coincide. - /// - `Err(ErrorParam::NotFound)` si la clave no existe. - /// - `Err(ErrorParam::TypeMismatch)` si el tipo no coincide. + /// - `Err(ContextError::ParamNotFound)` si la clave no existe. + /// - `Err(ContextError::ParamTypeMismatch)` si el tipo no coincide. /// /// # Ejemplos /// @@ -341,12 +341,12 @@ impl Context { /// // Error de tipo: /// assert!(cx.take_param::<i32>("titulo").is_err()); /// ``` - pub fn take_param<T: 'static>(&mut self, key: &'static str) -> Result<T, ErrorParam> { - let (boxed, saved) = self.params.remove(key).ok_or(ErrorParam::NotFound)?; + pub fn take_param<T: 'static>(&mut self, key: &'static str) -> Result<T, ContextError> { + let (boxed, saved) = self.params.remove(key).ok_or(ContextError::ParamNotFound)?; boxed .downcast::<T>() .map(|b| *b) - .map_err(|_| ErrorParam::TypeMismatch { + .map_err(|_| ContextError::ParamTypeMismatch { key, expected: TypeInfo::FullName.of::<T>(), saved, diff --git a/src/html.rs b/src/html.rs index 079811a2..a86c9f76 100644 --- a/src/html.rs +++ b/src/html.rs @@ -31,12 +31,12 @@ pub type ContextOp = crate::core::component::ContextOp; )] pub trait Contextual: crate::core::component::Contextual {} -/// **Obsoleto desde la versión 0.5.0**: usar [`core::component::ErrorParam`] en su lugar. +/// **Obsoleto desde la versión 0.5.0**: usar [`core::component::ContextError`] en su lugar. #[deprecated( since = "0.5.0", - note = "Moved to `pagetop::core::component::ErrorParam`" + note = "Moved to `pagetop::core::component::ContextError`" )] -pub type ErrorParam = crate::core::component::ErrorParam; +pub type ContextError = crate::core::component::ContextError; /// **Obsoleto desde la versión 0.5.0**: usar [`ContextOp`] en su lugar. #[deprecated(since = "0.5.0", note = "Use `ContextOp` instead")] From 200f8c0f4f5fb1206cd932de931c155b831f95ab Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 2 Oct 2025 18:48:20 +0200 Subject: [PATCH 195/244] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Dep?= =?UTF-8?q?ura=20atributos=20`#[inline]`=20en=20`builder=5Ffn`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-macros/src/lib.rs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 5af5f9c9..709ce572 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -266,10 +266,13 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { v }; - // Extrae atributos descartando la documentación para incluir en `alter_...()`. - let non_doc_attrs: Vec<_> = attrs + // Filtra los atributos descartando `#[doc]` y `#[inline]` para el método `alter_...()`. + let non_doc_or_inline_attrs: Vec<_> = attrs .iter() - .filter(|&a| !a.path().is_ident("doc")) + .filter(|a| { + let p = a.path(); + !p.is_ident("doc") && !p.is_ident("inline") + }) .cloned() .collect(); @@ -284,14 +287,21 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { #(#attrs)* fn #with_name #generics (self, #(#args),*) -> Self #where_clause; - #(#non_doc_attrs)* + #(#non_doc_or_inline_attrs)* #[doc = #alter_doc] fn #alter_ident #generics (&mut self, #(#args),*) -> &mut Self #where_clause; } } Some(body) => { + // Si no se indicó ninguna forma de `inline`, fuerza `#[inline]` para `with_...()`. + let force_inline = if attrs.iter().any(|a| a.path().is_ident("inline")) { + quote! {} + } else { + quote! { #[inline] } + }; let with_fn = if is_trait { quote! { + #force_inline #vis_pub fn #with_name #generics (self, #(#args),*) -> Self #where_clause { let mut s = self; s.#alter_ident(#(#call_idents),*); @@ -300,6 +310,7 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { } } else { quote! { + #force_inline #vis_pub fn #with_name #generics (mut self, #(#args),*) -> Self #where_clause { self.#alter_ident(#(#call_idents),*); self @@ -310,7 +321,7 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { #(#attrs)* #with_fn - #(#non_doc_attrs)* + #(#non_doc_or_inline_attrs)* #[doc = #alter_doc] #vis_pub fn #alter_ident #generics (&mut self, #(#args),*) -> &mut Self #where_clause { #body From e23bd0294ce9f795760b587cfa406b3d0801c60b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Thu, 2 Oct 2025 21:24:19 +0200 Subject: [PATCH 196/244] =?UTF-8?q?=F0=9F=8E=A8=20Mejora=20uso=20de=20las?= =?UTF-8?q?=20regiones=20en=20contexto=20y=20p=C3=A1gina?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/theme/basic.rs | 116 +++++++++++++++++----------------- src/core/component/context.rs | 22 ++++++- src/core/theme/definition.rs | 86 ++++++++++++------------- src/core/theme/regions.rs | 2 +- src/response/page.rs | 37 ++++++----- 5 files changed, 142 insertions(+), 121 deletions(-) diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index ecd64856..28d93890 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -93,76 +93,74 @@ fn render_intro(page: &mut Page) -> Markup { let intro_button_lnk: Option<&String> = page.param("intro_button_lnk"); 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) - } + 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"; - } + } + 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" { - @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)) - } + } + main class="intro-content" { + section class="intro-content__body" { + @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)) } } } - div class="intro-text" { (page.render_region("content")) } } + 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("intro_code").using(page)) } - em { (L10n::l("intro_have_fun").using(page)) } + } + 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)) } + } } } } diff --git a/src/core/component/context.rs b/src/core/component/context.rs index 9dad7f5f..b344c860 100644 --- a/src/core/component/context.rs +++ b/src/core/component/context.rs @@ -1,5 +1,6 @@ +use crate::core::component::ChildOp; use crate::core::theme::all::{theme_by_short_name, DEFAULT_THEME}; -use crate::core::theme::ThemeRef; +use crate::core::theme::{ChildrenInRegions, ThemeRef}; use crate::core::TypeInfo; use crate::html::{html, Markup}; use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; @@ -104,6 +105,10 @@ pub trait Contextual: LangId { #[builder_fn] fn with_assets(self, op: ContextOp) -> Self; + /// Opera con [`ChildOp`] en una región (`region_name`) de la página. + #[builder_fn] + fn with_child_in(self, region_name: &'static str, op: ChildOp) -> Self; + // **< Contextual GETTERS >********************************************************************* /// Devuelve una referencia a la solicitud HTTP asociada, si existe. @@ -211,6 +216,7 @@ pub struct Context { favicon : Option<Favicon>, // Favicon, si se ha definido. stylesheets: Assets<StyleSheet>, // Hojas de estilo CSS. javascripts: Assets<JavaScript>, // Scripts JavaScript. + regions : ChildrenInRegions, // Regiones de componentes para renderizar. params : HashMap<&'static str, (Box<dyn Any>, &'static str)>, // Parámetros en ejecución. id_counter : usize, // Contador para generar identificadores únicos. } @@ -250,6 +256,7 @@ impl Context { favicon : None, stylesheets: Assets::<StyleSheet>::new(), javascripts: Assets::<JavaScript>::new(), + regions : ChildrenInRegions::default(), params : HashMap::default(), id_counter : 0, } @@ -283,6 +290,13 @@ impl Context { markup } + /// Renderiza los componentes de una región (`region_name`). + pub fn render_region(&mut self, region_name: &'static str) -> Markup { + self.regions + .merge_all_components(self.theme, region_name) + .render(self) + } + // **< Context PARAMS >************************************************************************* /// Recupera una *referencia tipada* al parámetro solicitado. @@ -471,6 +485,12 @@ impl Contextual for Context { self } + #[builder_fn] + fn with_child_in(mut self, region_name: &'static str, op: ChildOp) -> Self { + self.regions.alter_child_in(region_name, op); + self + } + // **< Contextual GETTERS >********************************************************************* fn request(&self) -> Option<&HttpRequest> { diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 38a0bfc4..643bfffd 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -26,65 +26,65 @@ pub type ThemeRef = &'static dyn Theme; /// - `<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. + /// Renderiza el **contenido interior** del `<body>` de la página. /// /// 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. + /// contenedor con `role="region"` y un `aria-label` localizado. + /// Se asume que cada identificador de región es **único** dentro de la página. + /// + /// La etiqueta `<body>` no se incluye aquí; únicamente renderiza su contenido. 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 regions { - @let output = page.render_region(region.key()); - @if !output.is_empty() { - @let region_name = region.name(); - div - id=(region_name) - class={ "region region--" (region_name) } - role="region" - aria-label=[region_label.lookup(page)] - { - (output) - } + @for (region, region_label) in regions { + @let output = page.render_region(region.key()); + @if !output.is_empty() { + @let region_name = region.name(); + div + id=(region_name) + class={ "region region--" (region_name) } + role="region" + aria-label=[region_label.lookup(page)] + { + (output) } } } } } - /// Renderiza el contenido del `<head>` de la página. + /// Renderiza el **contenido interior** del `<head>` de la página. /// - /// 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. + /// Recorre y genera por defecto 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. + /// + /// La etiqueta `<head>` no se incluye aquí; únicamente renderiza su contenido. fn render_head(&self, page: &mut Page) -> Markup { let viewport = "width=device-width, initial-scale=1, shrink-to-fit=no"; html! { - head { - meta charset="utf-8"; + meta charset="utf-8"; - @if let Some(title) = page.title() { - title { (global::SETTINGS.app.name) (" | ") (title) } - } @else { - title { (global::SETTINGS.app.name) } - } - - @if let Some(description) = page.description() { - meta name="description" content=(description); - } - - meta name="viewport" content=(viewport); - @for (name, content) in page.metadata() { - meta name=(name) content=(content) {} - } - - meta http-equiv="X-UA-Compatible" content="IE=edge"; - @for (property, content) in page.properties() { - meta property=(property) content=(content) {} - } - - (page.render_assets()) + @if let Some(title) = page.title() { + title { (global::SETTINGS.app.name) (" | ") (title) } + } @else { + title { (global::SETTINGS.app.name) } } + + @if let Some(description) = page.description() { + meta name="description" content=(description); + } + + meta name="viewport" content=(viewport); + @for (name, content) in page.metadata() { + meta name=(name) content=(content) {} + } + + meta http-equiv="X-UA-Compatible" content="IE=edge"; + @for (property, content) in page.properties() { + meta property=(property) content=(content) {} + } + + (page.render_assets()) } } } diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index 8082aac9..f14645c0 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -64,7 +64,7 @@ impl Region { self.key } - /// Devuelve el nombre normalizado de la región (para atributos y búsquedas). + /// Devuelve el nombre normalizado de la región (para identificadores y atributos HTML). #[inline] pub fn name(&self) -> &str { &self.name diff --git a/src/response/page.rs b/src/response/page.rs index f81c9806..deab452b 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -5,7 +5,7 @@ pub use actix_web::Result as ResultPage; use crate::base::action; use crate::core::component::{Child, ChildOp, Component, Context, ContextOp, Contextual}; -use crate::core::theme::{ChildrenInRegions, ThemeRef, REGION_CONTENT}; +use crate::core::theme::{ThemeRef, REGION_CONTENT}; use crate::html::{html, Markup, DOCTYPE}; use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; use crate::html::{AttrClasses, ClassesOp}; @@ -29,7 +29,6 @@ pub struct Page { body_id : AttrId, body_classes: AttrClasses, context : Context, - regions : ChildrenInRegions, } impl Page { @@ -47,7 +46,6 @@ impl Page { body_id : AttrId::default(), body_classes: AttrClasses::default(), context : Context::new(Some(request)), - regions : ChildrenInRegions::default(), } } @@ -111,7 +109,7 @@ impl Page { /// Añade un componente a la región de contenido por defecto. pub fn add_component(mut self, component: impl Component) -> Self { - self.regions + self.context .alter_child_in(REGION_CONTENT, ChildOp::Add(Child::with(component))); self } @@ -122,7 +120,7 @@ impl Page { region_name: &'static str, component: impl Component, ) -> Self { - self.regions + self.context .alter_child_in(region_name, ChildOp::Add(Child::with(component))); self } @@ -143,13 +141,6 @@ impl Page { self } - /// Opera con [`ChildOp`] en una región (`region_name`) de la página. - #[builder_fn] - pub fn with_child_in(mut self, region_name: &'static str, op: ChildOp) -> Self { - self.regions.alter_child_in(region_name, op); - self - } - // **< Page GETTERS >*************************************************************************** /// Devuelve el título traducido para el idioma de la página, si existe. @@ -194,13 +185,13 @@ impl Page { // **< Page RENDER >**************************************************************************** /// Renderiza los componentes de una región (`region_name`) de la página. + #[inline] pub fn render_region(&mut self, region_name: &'static str) -> Markup { - self.regions - .merge_all_components(self.context.theme(), region_name) - .render(&mut self.context) + self.context.render_region(region_name) } /// Renderiza los recursos de la página. + #[inline] pub fn render_assets(&mut self) -> Markup { self.context.render_assets() } @@ -238,8 +229,14 @@ impl Page { Ok(html! { (DOCTYPE) html lang=(lang) dir=(dir) { - (head) - (body) + head { + (head) + } + body id=[self.body_id().get()] class=[self.body_classes().get()] { + (self.render_region("page-top")) + (body) + (self.render_region("page-bottom")) + } } }) } @@ -290,6 +287,12 @@ impl Contextual for Page { self } + #[builder_fn] + fn with_child_in(mut self, region_name: &'static str, op: ChildOp) -> Self { + self.context.alter_child_in(region_name, op); + self + } + // **< Contextual GETTERS >********************************************************************* fn request(&self) -> Option<&HttpRequest> { From 7b941cb02c1e6f7fa4b61f3514bca48889ad6c56 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 3 Oct 2025 01:55:03 +0200 Subject: [PATCH 197/244] =?UTF-8?q?=F0=9F=9A=9A=20Renombra=20`region=5Fnam?= =?UTF-8?q?e`=20a=20`region=5Fkey`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/theme/basic.rs | 4 +++- src/core/component/context.rs | 14 ++++++------ src/core/theme/definition.rs | 4 ++-- src/core/theme/regions.rs | 38 +++++++++++++++---------------- src/response/page.rs | 42 +++++++++++------------------------ 5 files changed, 44 insertions(+), 58 deletions(-) diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index 28d93890..54660a96 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -136,7 +136,9 @@ fn render_intro(page: &mut Page) -> Markup { } } } - div class="intro-text" { (page.render_region("content")) } + div class="intro-text" { + (page.context().render_components_of("content")) + } } } footer class="intro-footer" { diff --git a/src/core/component/context.rs b/src/core/component/context.rs index b344c860..f58d3816 100644 --- a/src/core/component/context.rs +++ b/src/core/component/context.rs @@ -105,9 +105,9 @@ pub trait Contextual: LangId { #[builder_fn] fn with_assets(self, op: ContextOp) -> Self; - /// Opera con [`ChildOp`] en una región (`region_name`) de la página. + /// Opera con [`ChildOp`] en una región (`region_key`) de la página. #[builder_fn] - fn with_child_in(self, region_name: &'static str, op: ChildOp) -> Self; + fn with_child_in(self, region_key: &'static str, op: ChildOp) -> Self; // **< Contextual GETTERS >********************************************************************* @@ -290,10 +290,10 @@ impl Context { markup } - /// Renderiza los componentes de una región (`region_name`). - pub fn render_region(&mut self, region_name: &'static str) -> Markup { + /// Renderiza los componentes de una región (`region_key`). + pub fn render_components_of(&mut self, region_key: &'static str) -> Markup { self.regions - .merge_all_components(self.theme, region_name) + .merge_all_components(self.theme, region_key) .render(self) } @@ -486,8 +486,8 @@ impl Contextual for Context { } #[builder_fn] - fn with_child_in(mut self, region_name: &'static str, op: ChildOp) -> Self { - self.regions.alter_child_in(region_name, op); + fn with_child_in(mut self, region_key: &'static str, op: ChildOp) -> Self { + self.regions.alter_child_in(region_key, op); self } diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 643bfffd..4478ad0b 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -36,7 +36,7 @@ pub trait ThemePage { fn render_body(&self, page: &mut Page, regions: &[(Region, L10n)]) -> Markup { html! { @for (region, region_label) in regions { - @let output = page.render_region(region.key()); + @let output = page.context().render_components_of(region.key()); @if !output.is_empty() { @let region_name = region.name(); div @@ -84,7 +84,7 @@ pub trait ThemePage { meta property=(property) content=(content) {} } - (page.render_assets()) + (page.context().render_assets()) } } } diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index f14645c0..3fdfe099 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -76,30 +76,30 @@ impl Region { pub struct ChildrenInRegions(HashMap<&'static str, Children>); impl ChildrenInRegions { - pub fn with(region_name: &'static str, child: Child) -> Self { - ChildrenInRegions::default().with_child_in(region_name, ChildOp::Add(child)) + pub fn with(region_key: &'static str, child: Child) -> Self { + ChildrenInRegions::default().with_child_in(region_key, ChildOp::Add(child)) } #[builder_fn] - pub fn with_child_in(mut self, region_name: &'static str, op: ChildOp) -> Self { - if let Some(region) = self.0.get_mut(region_name) { + pub fn with_child_in(mut self, region_key: &'static str, op: ChildOp) -> Self { + if let Some(region) = self.0.get_mut(region_key) { region.alter_child(op); } else { - self.0.insert(region_name, Children::new().with_child(op)); + self.0.insert(region_key, Children::new().with_child(op)); } self } - pub fn merge_all_components(&self, theme_ref: ThemeRef, region_name: &'static str) -> Children { + pub fn merge_all_components(&self, theme_ref: ThemeRef, region_key: &'static str) -> Children { let common = COMMON_REGIONS.read(); if let Some(r) = THEME_REGIONS.read().get(&theme_ref.type_id()) { Children::merge(&[ - common.0.get(region_name), - self.0.get(region_name), - r.0.get(region_name), + common.0.get(region_key), + self.0.get(region_key), + r.0.get(region_key), ]) } else { - Children::merge(&[common.0.get(region_name), self.0.get(region_name)]) + Children::merge(&[common.0.get(region_key), self.0.get(region_key)]) } } } @@ -114,9 +114,9 @@ impl ChildrenInRegions { pub enum InRegion { /// Región de contenido por defecto. Content, - /// Región identificada por el nombre proporcionado. - Named(&'static str), - /// Región identificada por un nombre y asociada a un tema concreto. + /// Región identificada por la clave proporcionado. + Key(&'static str), + /// Región identificada por una clave para un tema concreto. OfTheme(&'static str, ThemeRef), } @@ -134,7 +134,7 @@ impl InRegion { /// ))); /// /// // Texto en la región "sidebar". - /// InRegion::Named("sidebar").add(Child::with(Html::with(|_| + /// InRegion::Key("sidebar").add(Child::with(Html::with(|_| /// html! { ("Publicidad") } /// ))); /// ``` @@ -145,19 +145,19 @@ impl InRegion { .write() .alter_child_in(REGION_CONTENT, ChildOp::Add(child)); } - InRegion::Named(region_name) => { + InRegion::Key(region_key) => { COMMON_REGIONS .write() - .alter_child_in(region_name, ChildOp::Add(child)); + .alter_child_in(region_key, ChildOp::Add(child)); } - InRegion::OfTheme(region_name, theme_ref) => { + InRegion::OfTheme(region_key, theme_ref) => { let mut regions = THEME_REGIONS.write(); if let Some(r) = regions.get_mut(&theme_ref.type_id()) { - r.alter_child_in(region_name, ChildOp::Add(child)); + r.alter_child_in(region_key, ChildOp::Add(child)); } else { regions.insert( theme_ref.type_id(), - ChildrenInRegions::with(region_name, child), + ChildrenInRegions::with(region_key, child), ); } } diff --git a/src/response/page.rs b/src/response/page.rs index deab452b..1649d543 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -103,8 +103,8 @@ impl Page { /// **Obsoleto desde la versión 0.4.0**: usar [`add_component_in()`](Self::add_component_in) en /// su lugar. #[deprecated(since = "0.4.0", note = "Use `add_component_in()` instead")] - pub fn with_component_in(self, region_name: &'static str, component: impl Component) -> Self { - self.add_component_in(region_name, component) + pub fn with_component_in(self, region_key: &'static str, component: impl Component) -> Self { + self.add_component_in(region_key, component) } /// Añade un componente a la región de contenido por defecto. @@ -114,30 +114,26 @@ impl Page { self } - /// Añade un componente en una región (`region_name`) de la página. - pub fn add_component_in( - mut self, - region_name: &'static str, - component: impl Component, - ) -> Self { + /// Añade un componente en una región (`region_key`) de la página. + pub fn add_component_in(mut self, region_key: &'static str, component: impl Component) -> Self { self.context - .alter_child_in(region_name, ChildOp::Add(Child::with(component))); + .alter_child_in(region_key, ChildOp::Add(Child::with(component))); self } /// **Obsoleto desde la versión 0.4.0**: usar [`with_child_in()`](Self::with_child_in) en su /// lugar. #[deprecated(since = "0.4.0", note = "Use `with_child_in()` instead")] - pub fn with_child_in_region(mut self, region_name: &'static str, op: ChildOp) -> Self { - self.alter_child_in(region_name, op); + pub fn with_child_in_region(mut self, region_key: &'static str, op: ChildOp) -> Self { + self.alter_child_in(region_key, op); self } /// **Obsoleto desde la versión 0.4.0**: usar [`alter_child_in()`](Self::alter_child_in) en su /// lugar. #[deprecated(since = "0.4.0", note = "Use `alter_child_in()` instead")] - pub fn alter_child_in_region(&mut self, region_name: &'static str, op: ChildOp) -> &mut Self { - self.alter_child_in(region_name, op); + pub fn alter_child_in_region(&mut self, region_key: &'static str, op: ChildOp) -> &mut Self { + self.alter_child_in(region_key, op); self } @@ -184,18 +180,6 @@ impl Page { // **< Page RENDER >**************************************************************************** - /// Renderiza los componentes de una región (`region_name`) de la página. - #[inline] - pub fn render_region(&mut self, region_name: &'static str) -> Markup { - self.context.render_region(region_name) - } - - /// Renderiza los recursos de la página. - #[inline] - pub fn render_assets(&mut self) -> Markup { - self.context.render_assets() - } - /// Renderiza la página completa en formato HTML. /// /// Ejecuta las acciones correspondientes antes y después de renderizar el `<body>`, @@ -233,9 +217,9 @@ impl Page { (head) } body id=[self.body_id().get()] class=[self.body_classes().get()] { - (self.render_region("page-top")) + (self.context.render_components_of("page-top")) (body) - (self.render_region("page-bottom")) + (self.context.render_components_of("page-bottom")) } } }) @@ -288,8 +272,8 @@ impl Contextual for Page { } #[builder_fn] - fn with_child_in(mut self, region_name: &'static str, op: ChildOp) -> Self { - self.context.alter_child_in(region_name, op); + fn with_child_in(mut self, region_key: &'static str, op: ChildOp) -> Self { + self.context.alter_child_in(region_key, op); self } From 5f64d500808858b3baa39fc8baa3277707678b73 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 4 Oct 2025 08:25:04 +0200 Subject: [PATCH 198/244] =?UTF-8?q?=F0=9F=8E=A8=20Mejora=20`Region`=20para?= =?UTF-8?q?=20declarar=20las=20regiones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/theme/definition.rs | 32 ++++++++++++++++---------------- src/core/theme/regions.rs | 12 +++++++++++- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 4478ad0b..0322a31e 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -28,14 +28,14 @@ pub type ThemeRef = &'static dyn Theme; pub trait ThemePage { /// Renderiza el **contenido interior** del `<body>` de la página. /// - /// Recorre `regions` en el **orden declarado** y, para cada región con contenido, genera un - /// contenedor con `role="region"` y un `aria-label` localizado. + /// Esta implementación 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. /// /// La etiqueta `<body>` no se incluye aquí; únicamente renderiza su contenido. - fn render_body(&self, page: &mut Page, regions: &[(Region, L10n)]) -> Markup { + fn render_body(&self, page: &mut Page, regions: &[Region]) -> Markup { html! { - @for (region, region_label) in regions { + @for region in regions { @let output = page.context().render_components_of(region.key()); @if !output.is_empty() { @let region_name = region.name(); @@ -43,7 +43,7 @@ pub trait ThemePage { id=(region_name) class={ "region region--" (region_name) } role="region" - aria-label=[region_label.lookup(page)] + aria-label=[region.label().lookup(page)] { (output) } @@ -125,31 +125,31 @@ pub trait Theme: Extension + ThemePage + Send + Sync { /// 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 todas - /// las regiones que componen una página en el orden indicado . + /// Devuelve una **lista estática** de regiones ([`Region`](crate::core::theme::Region)) con la + /// información necesaria para renderizar el contenedor de cada región. /// /// Si un tema necesita un conjunto distinto de regiones, se puede **sobrescribir** este método /// con los siguientes 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. + /// - La región `"content"` es **obligatoria** porque se usa por defecto para añadir componentes + /// para renderizar. Se puede utilizar [`Region::default()`] para declararla. + /// - La etiqueta `L10n` se evaluará con el idioma activo de la página. /// /// 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(|| { + fn page_regions(&self) -> &'static [Region] { + static REGIONS: LazyLock<[Region; 3]> = LazyLock::new(|| { [ - (Region::declare("header"), L10n::l("region_header")), - (Region::default(), L10n::l("region_content")), - (Region::declare("footer"), L10n::l("region_footer")), + Region::declare("header", L10n::l("region_header")), + Region::default(), + Region::declare("footer", L10n::l("region_footer")), ] }); - &REGIONS[..] + &*REGIONS } /// Acciones específicas del tema antes de renderizar el `<body>` de la página. diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index 3fdfe099..00ff60cb 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -1,5 +1,6 @@ use crate::core::component::{Child, ChildOp, Children}; use crate::core::theme::ThemeRef; +use crate::locale::L10n; use crate::{builder_fn, AutoDefault, UniqueId}; use parking_lot::RwLock; @@ -29,6 +30,7 @@ pub const REGION_CONTENT: &str = "content"; pub struct Region { key: &'static str, name: String, + label: L10n, } impl Default for Region { @@ -37,6 +39,7 @@ impl Default for Region { Self { key: REGION_CONTENT, name: REGION_CONTENT.to_string(), + label: L10n::l("region_content"), } } } @@ -51,10 +54,11 @@ impl Region { /// sencillos, limitando los caracteres a `[a-z0-9-]` (p.ej., `"sidebar"` o `"main-menu"`), cuyo /// nombre normalizado coincidirá con la clave. #[inline] - pub fn declare(key: &'static str) -> Self { + pub fn declare(key: &'static str, label: L10n) -> Self { Self { key, name: key.trim().to_ascii_lowercase().replace(' ', "-"), + label, } } @@ -69,6 +73,12 @@ impl Region { pub fn name(&self) -> &str { &self.name } + + /// Devuelve la etiqueta localizada asociada a la región. + #[inline] + pub fn label(&self) -> &L10n { + &self.label + } } // Contenedor interno de componentes agrupados por región. From cac50b21cb6f724b06070d2dc5f24582bb3a42b7 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 6 Oct 2025 04:09:26 +0200 Subject: [PATCH 199/244] =?UTF-8?q?=F0=9F=9A=A7=20Depura=20la=20estructura?= =?UTF-8?q?=20y=20estilos=20del=20men=C3=BA=20e=20intro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component/menu/item.rs | 8 +- src/base/theme/basic.rs | 55 +++++----- src/core/theme/definition.rs | 83 +++++++++++----- static/css/basic.css | 16 +++ static/css/intro.css | 112 +++++++++------------ static/css/menu.css | 171 +++++++++++++++++++++++--------- static/css/root.css | 19 ++++ static/js/menu.js | 1 - 8 files changed, 302 insertions(+), 163 deletions(-) diff --git a/src/base/component/menu/item.rs b/src/base/component/menu/item.rs index 7a36fbbf..c9f79033 100644 --- a/src/base/component/menu/item.rs +++ b/src/base/component/menu/item.rs @@ -49,7 +49,7 @@ impl Component for Item { }), ItemKind::Link(label, path) => PrepareMarkup::With(html! { li class="menu__item menu__item--link" { - a href=(path(cx)) title=[description] { + a class="menu__link" href=(path(cx)) title=[description] { (left_icon) span class="menu__label" { (label.using(cx)) } (right_icon) @@ -58,7 +58,7 @@ impl Component for Item { }), ItemKind::LinkBlank(label, path) => PrepareMarkup::With(html! { li class="menu__item menu__item--link" { - a href=(path(cx)) title=[description] target="_blank" { + a class="menu__link" href=(path(cx)) title=[description] target="_blank" { (left_icon) span class="menu__label" { (label.using(cx)) } (right_icon) @@ -72,7 +72,7 @@ impl Component for Item { }), ItemKind::Submenu(label, submenu) => PrepareMarkup::With(html! { li class="menu__item menu__item--children" { - a href="#" title=[description] { + button type="button" class="menu__link" title=[description] { (left_icon) span class="menu__label" { (label.using(cx)) } (Icon::svg(html! { @@ -86,7 +86,7 @@ impl Component for Item { }), ItemKind::Megamenu(label, megamenu) => PrepareMarkup::With(html! { li class="menu__item menu__item--children" { - a href="#" title=[description] { + button type="button" class="menu__link" title=[description] { (left_icon) span class="menu__label" { (label.using(cx)) } (Icon::svg(html! { diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index 54660a96..97d28b82 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -46,12 +46,8 @@ impl Theme for Basic { } fn after_render_page_body(&self, page: &mut Page) { - let styles = match page.layout() { - "Intro" => "/css/intro.css", - "PageTopIntro" => "/css/intro.css", - _ => "/css/basic.css", - }; let pkg_version = env!("CARGO_PKG_VERSION"); + page.alter_assets(ContextOp::AddStyleSheet( StyleSheet::from("/css/normalize.css") .with_version("8.0.1") @@ -62,6 +58,11 @@ impl Theme for Basic { .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) @@ -72,11 +73,6 @@ impl Theme for Basic { .with_version(pkg_version) .with_weight(-99), )) - .alter_assets(ContextOp::AddStyleSheet( - StyleSheet::from(styles) - .with_version(pkg_version) - .with_weight(-99), - )) .alter_assets(ContextOp::AddJavaScript( JavaScript::defer("/js/menu.js") .with_version(pkg_version) @@ -86,9 +82,18 @@ impl Theme for Basic { } 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, "header"); + let c = theme.render_page_region(page, "content"); + let f = theme.render_page_region(page, "footer"); + let intro_button_txt: L10n = page.param_or_default("intro_button_txt"); let intro_button_lnk: Option<&String> = page.param("intro_button_lnk"); @@ -118,26 +123,27 @@ fn render_intro(page: &mut Page) -> Markup { } } } + (h) } main class="intro-content" { section class="intro-content__body" { - @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)) + 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)) + } } } } - } - div class="intro-text" { - (page.context().render_components_of("content")) + (c) } } } @@ -164,6 +170,7 @@ fn render_intro(page: &mut Page) -> Markup { em { (L10n::l("intro_have_fun").using(page)) } } } + (f) } } } diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 0322a31e..5756fb23 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -15,50 +15,70 @@ pub type ThemeRef = &'static dyn Theme; /// Métodos predefinidos de renderizado para las páginas de un tema. /// -/// 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. +/// Contiene las implementaciones base para renderizar 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. /// -/// 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*): +/// Si un tema **sobrescribe** uno o más de estos métodos de [`Theme`]: +/// +/// - [`render_page_region()`](Theme::render_page_region), +/// - [`render_page_head()`](Theme::render_page_head), o +/// - [`render_page_body()`](Theme::render_page_body); +/// +/// es posible volver al comportamiento por defecto usando FQS (*Fully Qualified Syntax*): /// /// - `<Self as ThemePage>::render_body(self, page, self.page_regions())` /// - `<Self as ThemePage>::render_head(self, page)` pub trait ThemePage { + /// Renderiza el **contenedor** de una región concreta del `<body>` de la página. + /// + /// Obtiene los componentes asociados a `region.key()` desde el contexto de la página y, si hay + /// salida, envuelve el contenido en un contenedor `<div>` predefinido. + /// + /// Si la región **no produce contenido**, devuelve un `Markup` vacío. + #[inline] + fn render_region(&self, page: &mut Page, region: &Region) -> Markup { + html! { + @let output = page.context().render_components_of(region.key()); + @if !output.is_empty() { + @let region_name = region.name(); + div + id=(region_name) + class={ "region region--" (region_name) } + role="region" + aria-label=[region.label().lookup(page)] + { + (output) + } + } + } + } + /// Renderiza el **contenido interior** del `<body>` de la página. /// - /// Esta implementación 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. + /// Recorre `regions` en el **orden declarado** y, para cada región con contenido, delega en + /// [`render_region()`](Self::render_region) la generación del contenedor. Las regiones sin + /// contenido **no** producen salida. Se asume que cada identificador de región es **único** + /// dentro de la página. /// /// La etiqueta `<body>` no se incluye aquí; únicamente renderiza su contenido. + #[inline] fn render_body(&self, page: &mut Page, regions: &[Region]) -> Markup { html! { @for region in regions { - @let output = page.context().render_components_of(region.key()); - @if !output.is_empty() { - @let region_name = region.name(); - div - id=(region_name) - class={ "region region--" (region_name) } - role="region" - aria-label=[region.label().lookup(page)] - { - (output) - } - } + (self.render_region(page, region)) } } } /// Renderiza el **contenido interior** del `<head>` de la página. /// - /// Recorre y genera por defecto 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. + /// Incluye por defecto 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. /// - /// La etiqueta `<head>` no se incluye aquí; únicamente renderiza su contenido. + /// La etiqueta `<head>` no se incluye aquí; únicamente se renderiza su contenido. + #[inline] fn render_head(&self, page: &mut Page) -> Markup { let viewport = "width=device-width, initial-scale=1, shrink-to-fit=no"; html! { @@ -152,6 +172,19 @@ pub trait Theme: Extension + ThemePage + Send + Sync { &*REGIONS } + /// Renderiza una región de la página **por clave**. + /// + /// Busca en [`page_regions()`](Self::page_regions) la región asociada a una clave y, si existe, + /// delega en [`ThemePage::render_region()`] su renderizado. Si no se encuentra la clave o la + /// región no produce contenido, devuelve un `Markup` vacío. + fn render_page_region(&self, page: &mut Page, key: &str) -> Markup { + html! { + @if let Some(region) = self.page_regions().iter().find(|r| r.key() == key) { + (self.render_region(page, region)) + } + } + } + /// Acciones específicas del tema antes de renderizar el `<body>` de la página. /// /// Útil para preparar clases, inyectar recursos o ajustar metadatos. diff --git a/static/css/basic.css b/static/css/basic.css index 04801dd0..058e1736 100644 --- a/static/css/basic.css +++ b/static/css/basic.css @@ -1,3 +1,19 @@ +html { + scroll-behavior: smooth; +} + +body { + margin: 0; + font-family: var(--val-font-family); + font-size: var(--val-fs--base); + font-weight: var(--val-fw--base); + line-height: var(--val-lh--base); + color: var(--val-color--text); + background-color: var(--val-color--bg); + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: transparent; +} + /* Page layout */ .region--footer { diff --git a/static/css/intro.css b/static/css/intro.css index 39c9d6ad..774bbb2a 100644 --- a/static/css/intro.css +++ b/static/css/intro.css @@ -1,37 +1,15 @@ -:root { - --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-gray: #e4e4e7; - --color-link: #1e4eae; - --color-block-1: #b689ff; - --color-block-2: #fecaca; - --color-block-3: #e6a9e2; - --color-block-4: #ffedca; - --color-block-5: #ffffff; - --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; + color: var(--intro-color); + background-color: var(--intro-bg-color); width: 100%; display: flex; @@ -51,12 +29,12 @@ a { transition: font-size 0.2s, text-decoration-color 0.2s; } a:focus-visible { - outline: var(--focus-outline); - outline-offset: var(--focus-outline-offset); + outline: var(--intro-focus-outline); + outline-offset: var(--intro-focus-outline-offset); } a:hover, a:hover:visited { - text-decoration-color: var(--color-link); + text-decoration-color: var(--intro-color-link); } /* @@ -69,9 +47,9 @@ a:hover:visited { width: 100%; max-width: 80rem; margin: 0 auto; - padding-bottom: 9rem; - background-image: var(--bg-img-sm); - background-image: var(--bg-img-sm-set); + padding-bottom: 4rem; + background-image: var(--intro-bg-img-sm); + background-image: var(--intro-bg-img-sm-set); background-position: top center; background-position-y: -1rem; background-size: contain; @@ -119,8 +97,8 @@ a:hover:visited { } @media (min-width: 64rem) { .intro-header { - background-image: var(--bg-img); - background-image: var(--bg-img-set); + background-image: var(--intro-bg-img); + background-image: var(--intro-bg-img-set); } .intro-header__title { padding: 1.2rem 2rem 2.6rem 2rem; @@ -180,8 +158,7 @@ a:hover:visited { .intro-button { width: 100%; - margin: 0 auto 3rem; - z-index: 10; + margin: 0 auto; } .intro-button__link { background: #7f1d1d; @@ -306,6 +283,9 @@ a:hover:visited { animation-play-state: paused; } @media (max-width: 48rem) { + .intro-header { + padding-bottom: 9rem;; + } .intro-button__link { height: 6.25rem; min-width: auto; @@ -342,17 +322,15 @@ a:hover:visited { font-size: 1.3125rem; font-weight: 400; line-height: 1.5; - margin-top: -6rem; margin-bottom: 0; background: #fff; position: relative; +} +.region--content { padding: 2.5rem 1.063rem 0.75rem; overflow: hidden; } -.intro-button + .intro-text { - padding-top: 6rem; -} -.intro-text p { +.region--content p { width: 100%; line-height: 150%; font-weight: 400; @@ -364,31 +342,39 @@ a:hover:visited { font-size: 1.375rem; line-height: 2rem; } - .intro-button + .intro-text { + .intro-button + .region--content { padding-top: 7rem; } } @media (min-width: 64rem) { - .intro-text { + .intro-header { + padding-bottom: 9rem;; + } + .intro-text, + .region--content { border-radius: 0.75rem; - box-shadow: var(--shadow); + } + .intro-text { + box-shadow: var(--intro-shadow); max-width: 60rem; margin: 0 auto 6rem; + } + .region--content { padding-left: 4.5rem; padding-right: 4.5rem; } } -.intro-text .block { +.region--content .block { position: relative; } -.intro-text .block__title { +.region--content .block__title { margin: 1em 0 .8em; } -.intro-text .block__title span { +.region--content .block__title span { display: inline-block; padding: 10px 30px 14px; - margin: 0 0 0 20px; + margin: 30px 0 0 20px; background: white; border: 5px solid; border-radius: 30px; @@ -396,7 +382,7 @@ a:hover:visited { border-color: orangered; transform: rotate(-3deg) translateY(-25%); } -.intro-text .block__title:before { +.region--content .block__title:before { content: ""; height: 5px; position: absolute; @@ -409,7 +395,7 @@ a:hover:visited { transform: rotate(2deg) translateY(-50%); transform-origin: top left; } -.intro-text .block__title:after { +.region--content .block__title:after { content: ""; height: 70rem; position: absolute; @@ -417,23 +403,23 @@ a:hover:visited { left: -15%; width: 130%; z-index: -10; - background: var(--color-block-1); + background: var(--intro-bg-block-1); transform: rotate(2deg); } -.intro-text .block:nth-of-type(5n+1) .block__title:after { - background: var(--color-block-1); +.region--content .block:nth-of-type(5n+1) .block__title:after { + background: var(--intro-bg-block-1); } -.intro-text .block:nth-of-type(5n+2) .block__title:after { - background: var(--color-block-2); +.region--content .block:nth-of-type(5n+2) .block__title:after { + background: var(--intro-bg-block-2); } -.intro-text .block:nth-of-type(5n+3) .block__title:after { - background: var(--color-block-3); +.region--content .block:nth-of-type(5n+3) .block__title:after { + background: var(--intro-bg-block-3); } -.intro-text .block:nth-of-type(5n+4) .block__title:after { - background: var(--color-block-4); +.region--content .block:nth-of-type(5n+4) .block__title:after { + background: var(--intro-bg-block-4); } -.intro-text .block:nth-of-type(5n+5) .block__title:after { - background: var(--color-block-5); +.region--content .block:nth-of-type(5n+5) .block__title:after { + background: var(--intro-bg-block-5); } /* @@ -443,7 +429,7 @@ a:hover:visited { .intro-footer { width: 100%; background-color: black; - color: var(--color-gray); + color: var(--intro-color-gray); padding-bottom: 2rem; } @@ -459,7 +445,7 @@ a:hover:visited { line-height: 100%; } .intro-footer__body a:visited { - color: var(--color-gray); + color: var(--intro-color-gray); } .intro-footer__logo, .intro-footer__links { @@ -492,5 +478,5 @@ a:hover:visited { /* PoweredBy component */ .poweredby a:visited { - color: var(--color-gray); + color: var(--intro-color-gray); } diff --git a/static/css/menu.css b/static/css/menu.css index 5520e398..6522f4a7 100644 --- a/static/css/menu.css +++ b/static/css/menu.css @@ -1,54 +1,92 @@ +/* Aislamiento & normalización */ + .menu { + isolation: isolate; +} +@supports (all: revert) { + .menu { + all: revert; + display: block; } +} +.menu { + box-sizing: border-box; + line-height: var(--val-menu--line-height, 1.5); + color: var(--val-color--text); + text-align: left; + text-transform: none; + letter-spacing: normal; + word-spacing: normal; + white-space: normal; + cursor: default; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + width: 100%; height: auto; margin: 0; padding: 0; z-index: 9999; - border: none; - outline: none; + border: 0; background: var(--val-menu--color-bg); } +.menu *, +.menu *::before, +.menu *::after { + box-sizing: inherit; +} +.menu :where(a, button) { + appearance: none; + background: none; + border: 0; + font: inherit; + color: inherit; + text-decoration: none; + cursor: pointer; + -webkit-tap-highlight-color: transparent; +} +.menu :where(a, button):focus-visible { + outline: 2px solid var(--val-menu--color-highlight); + outline-offset: 2px; +} +.menu :where(ul, ol) { + list-style: none; + margin: 0; + padding: 0; +} +.menu svg { + fill: currentColor; +} + +/* Estructura */ .menu__wrapper { padding-right: var(--val-gap); } -.menu__wrapper a, -.menu__wrapper button { - cursor: pointer; - border: none; - background: none; - text-decoration: none; -} -.menu__nav ul { - margin: 0; - padding: 0; -} .menu__nav li { display: inline-block; - margin: 0 0 0 1.5rem; + margin: 0; + margin-inline-start: 1.5rem; padding: 0; line-height: var(--val-menu--item-height); list-style: none; - list-style-type: none; } .menu__item--label, -.menu__nav li > a { +.menu__nav li > .menu__link { position: relative; - font-weight: 500; - color: var(--val-color--text); + font-weight: normal; text-rendering: optimizeLegibility; + font-size: 1.45rem; } -.menu__nav li > a { - border: none; +.menu__nav li > .menu__link { transition: color 0.3s ease-in-out; } -.menu__nav li:hover > a, -.menu__nav li > a:focus { +.menu__nav li:hover > .menu__link, +.menu__nav li > .menu__link:focus { color: var(--val-menu--color-highlight); } -.menu__nav li > a > svg.icon { +.menu__nav li > .menu__link > svg.icon { margin-left: 0.25rem; } @@ -57,19 +95,18 @@ max-width: 100%; height: auto; padding: var(--val-gap-0-5) var(--val-gap-1-5); - border: none; - outline: none; + border: 0; background: var(--val-menu--color-bg); border-top: 3px solid var(--val-menu--color-highlight); z-index: 500; opacity: 0; visibility: hidden; box-shadow: 0 4px 6px -1px var(--val-menu--color-border), 0 2px 4px -1px var(--val-menu--color-shadow); - transition: all 0.5s ease-in-out; + transition: all 0.3s ease-in-out; } .menu__item--children:hover > .menu__children, -.menu__item--children > a:focus + .menu__children, +.menu__item--children > .menu__link:focus + .menu__children, .menu__item--children .menu__children:focus-within { margin-top: 0.4rem; opacity: 1; @@ -81,14 +118,12 @@ max-width: var(--val-menu--item-width-max); } .menu__submenu-title { - font-family: inherit; font-size: 1rem; - font-weight: 500; + font-weight: normal; margin: 0; padding: var(--val-menu--line-padding) 0; line-height: var(--val-menu--line-height); - border: none; - outline: none; + border: 0; color: var(--val-menu--color-highlight); text-transform: uppercase; text-rendering: optimizeLegibility; @@ -113,18 +148,15 @@ display: none; } -/* Applies <= 992px */ -@media only screen and (max-width: 62rem) { +/* Responsive <= 62rem (992px) */ + +@media (max-width: 62rem) { .menu__wrapper { padding-right: var(--val-gap-0-5); } .menu__trigger { - cursor: pointer; width: var(--val-menu--trigger-width); height: var(--val-menu--item-height); - border: none; - outline: none; - background: none; display: flex; flex-direction: column; justify-content: center; @@ -133,6 +165,13 @@ width: 2rem; height: 2rem; } + + .menu__nav, + .menu__children { + overscroll-behavior: contain; + -webkit-overflow-scrolling: touch; + } + .menu__nav { position: fixed; top: 0; @@ -143,10 +182,16 @@ overflow: hidden; background: var(--val-menu--color-bg); transform: translate(-100%); - transition: all 0.5s ease-in-out; + transition: transform .5s ease-in-out, opacity .5s ease-in-out; + will-change: transform; + backface-visibility: hidden; + visibility: hidden; + pointer-events: none; } .menu__nav.active { transform: translate(0%); + visibility: visible; + pointer-events: auto; } .menu__nav li { @@ -156,16 +201,18 @@ } .menu__item--label, - .menu__nav li > a { + .menu__nav li > .menu__link { display: block; + text-align: inherit; + width: 100%; padding: var(--val-menu--line-padding) var(--val-menu--item-height) var(--val-menu--line-padding) var(--val-menu--item-gap); border-bottom: 1px solid var(--val-menu--color-border); } .menu__nav li ul li.menu__item--label, - .menu__nav li ul li > a { + .menu__nav li ul li > .menu__link { border-bottom: 0; } - .menu__nav li > a > svg.icon { + .menu__nav li > .menu__link > svg.icon { position: absolute; top: var(--val-menu--line-padding); right: var(--val-menu--line-padding); @@ -191,6 +238,7 @@ visibility: visible; transform: translateX(0%); box-shadow: none; + transition: opacity .5s ease-in-out, transform .5s ease-in-out, margin-top .5s ease-in-out; } .menu__children.active { display: block; @@ -223,6 +271,16 @@ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + font-size: 1.45rem; + font-weight: normal; + opacity: 0; + transform: translateY(.25rem); + transition: opacity .5s ease-in-out, transform .5s ease-in-out; + will-change: opacity, transform; + } + .menu__header.active .menu__title { + opacity: 1; + transform: translateY(0); } .menu__close, .menu__back { @@ -231,18 +289,20 @@ height: var(--val-menu--item-height); line-height: var(--val-menu--item-height); color: var(--val-color--text); - cursor: pointer; display: flex; align-items: center; justify-content: center; + background: var(--val-menu--color-bg); } .menu__close { font-size: 2.25rem; - border-left: 1px solid var(--val-menu--color-border) !important; + border: 1px solid var(--val-menu--color-border) !important; + border-width: 0 0 1px 1px !important; } .menu__back { font-size: 1.25rem; - border-right: 1px solid var(--val-menu--color-border) !important; + border: 1px solid var(--val-menu--color-border) !important; + border-width: 0 1px 1px 0 !important; display: none; } .menu__header.active .menu__back { @@ -267,15 +327,34 @@ opacity: 0; visibility: hidden; background: rgba(0, 0, 0, 0.55); - transition: all 0.5s ease-in-out; + transition: opacity .5s ease-in-out, visibility 0s linear .5s; } .menu__overlay.active { opacity: 1; visibility: visible; + transition-delay: 0s, 0s; + } +} + +@media (hover: hover) and (pointer: fine) { + .menu__item--children:hover > .menu__children { + margin-top: 0.4rem; + opacity: 1; + visibility: visible; } } -/* ANIMATIONS */ +@media (prefers-reduced-motion: reduce) { + .menu__nav, + .menu__children, + .menu__title, + .menu__overlay { + transition: none !important; + animation: none !important; + } +} + +/* Animaciones */ @keyframes slideLeft { 0% { diff --git a/static/css/root.css b/static/css/root.css index aeab1c67..270c1b3f 100644 --- a/static/css/root.css +++ b/static/css/root.css @@ -1,3 +1,22 @@ +: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; diff --git a/static/js/menu.js b/static/js/menu.js index 6b5ae1b0..1f09bfe5 100644 --- a/static/js/menu.js +++ b/static/js/menu.js @@ -48,7 +48,6 @@ function menu__reset(menu, nav, overlay) { } document.querySelectorAll('.menu').forEach(menu => { - let menuChildren = []; const menuNav = menu.querySelector('.menu__nav'); const menuOverlay = menu.querySelector('.menu__overlay'); From b076e22c2bdd0727f053313ec5e973a9b7341f3c Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Tue, 7 Oct 2025 05:56:32 +0200 Subject: [PATCH 200/244] =?UTF-8?q?=F0=9F=8E=A8=20Mejora=20el=20uso=20de?= =?UTF-8?q?=20regiones=20y=20a=C3=B1ade=20`BasicRegion`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/theme.rs | 2 +- src/base/theme/basic.rs | 9 ++- src/core/theme.rs | 4 +- src/core/theme/definition.rs | 121 ++++++++++++++++++++++++----------- src/core/theme/regions.rs | 110 ++++++++++++++++--------------- 5 files changed, 148 insertions(+), 98 deletions(-) diff --git a/src/base/theme.rs b/src/base/theme.rs index 40129bfa..a4b2df5b 100644 --- a/src/base/theme.rs +++ b/src/base/theme.rs @@ -1,4 +1,4 @@ //! Temas básicos soportados por PageTop. mod basic; -pub use basic::Basic; +pub use basic::{Basic, BasicRegion}; diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index 97d28b82..b6a982f6 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -1,6 +1,9 @@ /// Es el tema básico que incluye PageTop por defecto. 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*): @@ -90,9 +93,9 @@ fn render_intro(page: &mut Page) -> Markup { let intro = page.description().unwrap_or_default(); let theme = page.context().theme(); - let h = theme.render_page_region(page, "header"); - let c = theme.render_page_region(page, "content"); - let f = theme.render_page_region(page, "footer"); + 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"); diff --git a/src/core/theme.rs b/src/core/theme.rs index 61d820b4..64f40f33 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -15,10 +15,10 @@ //! [`Theme`]. mod definition; -pub use definition::{Theme, ThemePage, ThemeRef}; +pub use definition::{Theme, ThemePage, ThemeRef, ThemeRegion}; mod regions; pub(crate) use regions::{ChildrenInRegions, REGION_CONTENT}; -pub use regions::{InRegion, Region}; +pub use regions::{InRegion, Region, RegionRef}; pub(crate) mod all; diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 5756fb23..7ef95c46 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -1,9 +1,9 @@ use crate::core::extension::Extension; -use crate::core::theme::Region; -use crate::global; +use crate::core::theme::{Region, RegionRef, REGION_CONTENT}; use crate::html::{html, Markup}; use crate::locale::L10n; use crate::response::page::Page; +use crate::{global, join}; use std::sync::LazyLock; @@ -13,6 +13,46 @@ use std::sync::LazyLock; /// implementen [`Theme`] y, a su vez, [`Extension`]. pub type ThemeRef = &'static dyn Theme; +/// Conjunto de regiones que los temas pueden exponer para el renderizado. +/// +/// `ThemeRegion` define un conjunto de regiones predefinidas para estructurar un documento HTML. +/// Proporciona **identificadores estables** (vía [`Region::key()`]) y **etiquetas localizables** +/// (vía [`Region::label()`]) a las regiones donde se añadirán los componentes. +/// +/// Se usa por defecto en [`Theme::page_regions()`](crate::core::theme::Theme::page_regions) y sus +/// variantes representan el conjunto mínimo recomendado para cualquier tema. Sin embargo, cada tema +/// podría exponer su propio conjunto de regiones. +pub enum ThemeRegion { + /// Cabecera de la página. + /// + /// Clave: `"header"`. Suele contener *branding*, navegación principal o avisos globales. + Header, + + /// Contenido principal de la página (**obligatoria**). + /// + /// Clave: `"content"`. Es el destino por defecto para insertar componentes a nivel de página. + Content, + + /// Pie de página. + /// + /// Clave: `"footer"`. Suele contener enlaces legales, créditos o navegación secundaria. + Footer, +} + +impl Region for ThemeRegion { + fn key(&self) -> &str { + match self { + ThemeRegion::Header => "header", + ThemeRegion::Content => REGION_CONTENT, + ThemeRegion::Footer => "footer", + } + } + + fn label(&self) -> L10n { + L10n::l(join!("region_", self.key())) + } +} + /// Métodos predefinidos de renderizado para las páginas de un tema. /// /// Contiene las implementaciones base para renderizar las **secciones** `<head>` y `<body>`. Se @@ -37,14 +77,14 @@ pub trait ThemePage { /// /// Si la región **no produce contenido**, devuelve un `Markup` vacío. #[inline] - fn render_region(&self, page: &mut Page, region: &Region) -> Markup { + fn render_region(&self, page: &mut Page, region: RegionRef) -> Markup { html! { - @let output = page.context().render_components_of(region.key()); + @let key = region.key(); + @let output = page.context().render_components_of(key); @if !output.is_empty() { - @let region_name = region.name(); div - id=(region_name) - class={ "region region--" (region_name) } + id=(key) + class={ "region region--" (key) } role="region" aria-label=[region.label().lookup(page)] { @@ -63,10 +103,10 @@ pub trait ThemePage { /// /// La etiqueta `<body>` no se incluye aquí; únicamente renderiza su contenido. #[inline] - fn render_body(&self, page: &mut Page, regions: &[Region]) -> Markup { + fn render_body(&self, page: &mut Page, regions: &[RegionRef]) -> Markup { html! { @for region in regions { - (self.render_region(page, region)) + (self.render_region(page, *region)) } } } @@ -145,44 +185,53 @@ pub trait Theme: Extension + ThemePage + Send + Sync { /// Declaración ordenada de las regiones disponibles en la página. /// - /// Devuelve una **lista estática** de regiones ([`Region`](crate::core::theme::Region)) con la - /// información necesaria para renderizar el contenedor de cada región. + /// Retorna una **lista estática** de referencias ([`RegionRef`](crate::core::theme::RegionRef)) + /// que representan las regiones que el tema admite dentro del `<body>`. /// - /// Si un tema necesita un conjunto distinto de regiones, se puede **sobrescribir** este método - /// con los siguientes requisitos y recomendaciones: + /// Cada referencia apunta a una instancia que implementa [`Region`](crate::core::theme::Region) + /// para definir cada región de forma segura y estable. Y si un tema necesita un conjunto + /// distinto de regiones, puede **sobrescribir** este método siguiendo estas recomendaciones: /// - /// - Los identificadores deben ser **estables** (p. ej. `"sidebar-left"`, `"content"`). - /// - La región `"content"` es **obligatoria** porque se usa por defecto para añadir componentes - /// para renderizar. Se puede utilizar [`Region::default()`] para declararla. - /// - La etiqueta `L10n` se evaluará con el idioma activo de la página. + /// - Los identificadores devueltos por [`Region::key()`](crate::core::theme::Region::key) + /// deben ser **estables** (p. ej. `"sidebar-left"`, `"content"`). + /// - La región `"content"` es **obligatoria**, ya que se usa como destino por defecto para + /// insertar componentes y renderizarlos. + /// - El orden de la lista podría tener relevancia como **orden de renderizado** dentro del + /// `<body>` segun la implementación de [`render_page_body()`](Self::render_page_body). + /// - Las etiquetas (`L10n`) de cada región se evaluarán con el idioma activo de la página. /// - /// Por defecto devuelve: + /// # Ejemplo /// - /// - `"header"`: cabecera. - /// - `"content"`: contenido principal (**obligatoria**). - /// - `"footer"`: pie. - fn page_regions(&self) -> &'static [Region] { - static REGIONS: LazyLock<[Region; 3]> = LazyLock::new(|| { + /// ```rust,ignore + /// fn page_regions(&self) -> &'static [RegionRef] { + /// static REGIONS: LazyLock<[RegionRef; 4]> = LazyLock::new(|| { + /// [ + /// &ThemeRegion::Header, + /// &ThemeRegion::Content, + /// &ThemeRegion::Footer, + /// ] + /// }); + /// &*REGIONS + /// } + /// ``` + fn page_regions(&self) -> &'static [RegionRef] { + static REGIONS: LazyLock<[RegionRef; 3]> = LazyLock::new(|| { [ - Region::declare("header", L10n::l("region_header")), - Region::default(), - Region::declare("footer", L10n::l("region_footer")), + &ThemeRegion::Header, + &ThemeRegion::Content, + &ThemeRegion::Footer, ] }); &*REGIONS } - /// Renderiza una región de la página **por clave**. + /// Renderiza una región de la página. /// - /// Busca en [`page_regions()`](Self::page_regions) la región asociada a una clave y, si existe, - /// delega en [`ThemePage::render_region()`] su renderizado. Si no se encuentra la clave o la - /// región no produce contenido, devuelve un `Markup` vacío. - fn render_page_region(&self, page: &mut Page, key: &str) -> Markup { - html! { - @if let Some(region) = self.page_regions().iter().find(|r| r.key() == key) { - (self.render_region(page, region)) - } - } + /// Si se sobrescribe este método, se puede volver al comportamiento base con: + /// `<Self as ThemePage>::render_region(self, page, region)`. + #[inline] + fn render_page_region(&self, page: &mut Page, region: RegionRef) -> Markup { + <Self as ThemePage>::render_region(self, page, region) } /// Acciones específicas del tema antes de renderizar el `<body>` de la página. diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index 00ff60cb..ecb5eb50 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -19,68 +19,66 @@ static COMMON_REGIONS: LazyLock<RwLock<ChildrenInRegions>> = /// Nombre de la región de contenido por defecto (`"content"`). pub const REGION_CONTENT: &str = "content"; -/// Identificador de una región de página. +/// Define la interfaz mínima que describe una **región de renderizado** dentro de una página. /// -/// Incluye una **clave estática** ([`key()`](Self::key)) que identifica la región en el tema, y un -/// **nombre normalizado** ([`name()`](Self::name)) en minúsculas para su uso en atributos HTML -/// (p.ej., clases `region__{name}`). +/// Una *región* representa una zona del documento HTML (por ejemplo: `"header"`, `"content"` o +/// `"sidebar-left"`), en la que se pueden incluir y renderizar componentes dinámicamente. /// -/// Se utiliza para declarar las regiones que componen una página en un tema (ver -/// [`page_regions()`](crate::core::theme::Theme::page_regions)). -pub struct Region { - key: &'static str, - name: String, - label: L10n, -} - -impl Default for Region { - #[inline] - fn default() -> Self { - Self { - key: REGION_CONTENT, - name: REGION_CONTENT.to_string(), - label: L10n::l("region_content"), - } - } -} - -impl Region { - /// Declara una región a partir de su clave estática. +/// Este `trait` abstrae los metadatos básicos de cada región, esencialmente: +/// +/// - su **clave interna** (`key()`), que la identifica de forma única dentro de la página, y +/// - su **etiqueta localizada** (`label()`), que se usa como texto accesible (por ejemplo en +/// `aria-label` o en descripciones semánticas del contenedor). +/// +/// Las implementaciones típicas son *enumeraciones estáticas* declaradas por cada tema (ver como +/// ejemplo [`ThemeRegion`](crate::core::theme::ThemeRegion)), de modo que las claves y etiquetas +/// permanecen inmutables y fácilmente referenciables. +/// +/// # Ejemplo +/// +/// ```rust +/// use pagetop::prelude::*; +/// +/// pub enum MyThemeRegion { +/// Header, +/// Content, +/// Footer, +/// } +/// +/// impl Region for MyThemeRegion { +/// fn key(&self) -> &str { +/// match self { +/// MyThemeRegion::Header => "header", +/// MyThemeRegion::Content => "content", +/// MyThemeRegion::Footer => "footer", +/// } +/// } +/// +/// fn label(&self) -> L10n { +/// L10n::l(join!("region__", self.key())) +/// } +/// } +/// ``` +pub trait Region: Send + Sync { + /// Devuelve la **clave interna** que identifica de forma única una región. /// - /// Genera además un nombre normalizado de la clave, eliminando espacios iniciales y finales, - /// convirtiendo a minúsculas y sustituyendo los espacios intermedios por guiones (`-`). + /// La clave se utiliza para asociar los componentes de la región con su contenedor HTML + /// correspondiente. Por convención, se emplean nombres en minúsculas y con guiones (`"header"`, + /// `"main"`, `"sidebar-right"`, etc.), y la región `"content"` es **obligatoria** en todos los + /// temas. + fn key(&self) -> &str; + + /// Devuelve la **etiqueta localizada** (`L10n`) asociada a la región. /// - /// Esta clave se usará para añadir componentes a la región; por ello se recomiendan nombres - /// sencillos, limitando los caracteres a `[a-z0-9-]` (p.ej., `"sidebar"` o `"main-menu"`), cuyo - /// nombre normalizado coincidirá con la clave. - #[inline] - pub fn declare(key: &'static str, label: L10n) -> Self { - Self { - key, - name: key.trim().to_ascii_lowercase().replace(' ', "-"), - label, - } - } - - /// Devuelve la clave estática asignada a la región. - #[inline] - pub fn key(&self) -> &'static str { - self.key - } - - /// Devuelve el nombre normalizado de la región (para identificadores y atributos HTML). - #[inline] - pub fn name(&self) -> &str { - &self.name - } - - /// Devuelve la etiqueta localizada asociada a la región. - #[inline] - pub fn label(&self) -> &L10n { - &self.label - } + /// Esta etiqueta se evalúa en el idioma activo de la página y se utiliza principalmente para + /// accesibilidad, como el valor de `aria-label` en el contenedor generado por + /// [`ThemePage::render_region()`](crate::core::theme::ThemePage::render_region). + fn label(&self) -> L10n; } +/// Referencia estática a una región. +pub type RegionRef = &'static dyn Region; + // Contenedor interno de componentes agrupados por región. #[derive(AutoDefault)] pub struct ChildrenInRegions(HashMap<&'static str, Children>); From fe1a6d1baa0a8c5a1d01a5db405ff8cca043bf23 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 10 Oct 2025 10:55:51 +0200 Subject: [PATCH 201/244] =?UTF-8?q?=F0=9F=9A=A7=20Revisi=C3=B3n=20del=20es?= =?UTF-8?q?tado=20de=20los=20men=C3=BAs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component/menu/item.rs | 6 +++--- static/css/menu.css | 5 +++++ static/js/menu.js | 23 +++++++++++------------ 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/base/component/menu/item.rs b/src/base/component/menu/item.rs index c9f79033..c6342186 100644 --- a/src/base/component/menu/item.rs +++ b/src/base/component/menu/item.rs @@ -137,14 +137,14 @@ impl Item { ..Default::default() } } - /* - pub fn megamenu(label: L10n, megamenu: Megamenu) -> Self { + + pub fn megamenu(label: L10n, megamenu: menu::Megamenu) -> Self { Item { item_kind: ItemKind::Megamenu(label, MegamenuGroups::with(megamenu)), ..Default::default() } } - */ + // **< Item BUILDER >*************************************************************************** #[builder_fn] diff --git a/static/css/menu.css b/static/css/menu.css index 6522f4a7..428ba157 100644 --- a/static/css/menu.css +++ b/static/css/menu.css @@ -342,6 +342,11 @@ opacity: 1; visibility: visible; } + .menu.menu--closing .menu__children { + margin-top: 0 !important; + opacity: 0 !important; + visibility: hidden !important; + } } @media (prefers-reduced-motion: reduce) { diff --git a/static/js/menu.js b/static/js/menu.js index 1f09bfe5..dca8e4df 100644 --- a/static/js/menu.js +++ b/static/js/menu.js @@ -1,12 +1,12 @@ +const getTitle = (li) => li.querySelector('.menu__label')?.textContent.trim() ?? ''; + function menu__showChildren(nav, children) { const li = children[0]; const submenu = li.querySelector('.menu__children'); submenu.classList.add('active'); submenu.style.animation = 'slideLeft 0.5s ease forwards'; - const labelEl = li.querySelector('.menu__label'); - const title = labelEl ? labelEl.textContent.trim() : (li.querySelector('a')?.textContent?.trim() ?? ''); - nav.querySelector('.menu__title').innerHTML = title; + nav.querySelector('.menu__title').textContent = getTitle(li);; nav.querySelector('.menu__header').classList.add('active'); } @@ -20,9 +20,7 @@ function menu__hideChildren(nav, children) { children.shift(); if (children.length > 0) { - const a = children[0].querySelector('a'); - const title = (a && a.textContent ? a.textContent.trim() : ''); - nav.querySelector('.menu__title').textContent = title; + nav.querySelector('.menu__title').textContent = getTitle(children[0]); } else { nav.querySelector('.menu__header').classList.remove('active'); nav.querySelector('.menu__title').textContent = ''; @@ -38,7 +36,7 @@ function menu__reset(menu, nav, overlay) { menu__toggle(nav, overlay); setTimeout(() => { nav.querySelector('.menu__header').classList.remove('active'); - nav.querySelector('.menu__title').innerHTML = ''; + nav.querySelector('.menu__title').textContent = ''; menu.querySelectorAll('.menu__children').forEach(submenu => { submenu.classList.remove('active'); submenu.style.removeProperty('animation'); @@ -85,12 +83,13 @@ document.querySelectorAll('.menu').forEach(menu => { menu__toggle(menuNav, menuOverlay); }); - window.onresize = function () { + let resizeTimeout; + window.addEventListener('resize', () => { if (menuNav.classList.contains('active')) { - var fontSizeRoot = parseFloat(getComputedStyle(document.documentElement).fontSize); - if (this.innerWidth >= 62 * fontSizeRoot) { + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(() => { menuChildren = menu__reset(menu, menuNav, menuOverlay); - } + }, 150); } - }; + }); }); From 8eafa436cdb1a0a221aecfa8a0cf3ca9b071d7f2 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 11 Oct 2025 21:36:06 +0200 Subject: [PATCH 202/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20nuevo=20tema?= =?UTF-8?q?=20para=20pruebas=20llamado=20`Aliner`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 289 +++++++------- Cargo.toml | 12 +- extensions/pagetop-aliner/Cargo.toml | 21 ++ extensions/pagetop-aliner/README.md | 100 +++++ extensions/pagetop-aliner/build.rs | 7 + extensions/pagetop-aliner/src/lib.rs | 118 ++++++ .../pagetop-aliner/static/css/styles.css | 356 ++++++++++++++++++ 7 files changed, 761 insertions(+), 142 deletions(-) create mode 100644 extensions/pagetop-aliner/Cargo.toml create mode 100644 extensions/pagetop-aliner/README.md create mode 100644 extensions/pagetop-aliner/build.rs create mode 100644 extensions/pagetop-aliner/src/lib.rs create mode 100644 extensions/pagetop-aliner/static/css/styles.css diff --git a/Cargo.lock b/Cargo.lock index e0d497c8..cab741ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,9 +44,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.11.1" +version = "3.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cceded2fb55f3c4b67068fa64962e2ca59614edc5b03167de9ff82ae803da0" +checksum = "7926860314cbe2fb5d1f13731e387ab43bd32bca224e82e6e2db85de0a3dba49" dependencies = [ "actix-codec", "actix-rt", @@ -227,9 +227,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] @@ -328,9 +328,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.20" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -343,9 +343,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" @@ -390,9 +390,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.75" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -400,7 +400,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -484,9 +484,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.38" +version = "1.2.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ "find-msvc-tools", "jobserver", @@ -520,7 +520,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -589,9 +589,9 @@ checksum = "7439becb5fafc780b6f4de382b1a7a3e70234afe783854a4702ee8adbb838609" [[package]] name = "config" -version = "0.15.16" +version = "0.15.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef036f0ecf99baef11555578630e2cca559909b4c50822dbba828c252d21c49" +checksum = "180e549344080374f9b32ed41bf3b6b57885ff6a289367b3dbc10eea8acc1918" dependencies = [ "pathdiff", "serde_core", @@ -703,9 +703,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" dependencies = [ "powerfmt", ] @@ -788,7 +788,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -805,15 +805,15 @@ checksum = "4742a071cd9694fc86f9fa1a08fa3e53d40cc899d7ee532295da2d085639fbc5" [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" dependencies = [ "crc32fast", "miniz_oxide", @@ -851,7 +851,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198" dependencies = [ "memchr", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -994,9 +994,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "glob" @@ -1356,9 +1356,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.80" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" dependencies = [ "once_cell", "wasm-bindgen", @@ -1387,9 +1387,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.175" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "linux-raw-sys" @@ -1422,11 +1422,10 @@ checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] @@ -1447,9 +1446,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mime" @@ -1474,6 +1473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -1520,9 +1520,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -1560,6 +1560,7 @@ dependencies = [ "fluent-templates", "indoc", "itoa", + "pagetop-aliner", "pagetop-build", "pagetop-macros", "pagetop-statics", @@ -1576,6 +1577,14 @@ dependencies = [ "unic-langid", ] +[[package]] +name = "pagetop-aliner" +version = "0.0.9" +dependencies = [ + "pagetop", + "pagetop-build", +] + [[package]] name = "pagetop-build" version = "0.3.1" @@ -1608,9 +1617,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -1618,15 +1627,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -1813,9 +1822,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -1887,18 +1896,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.11.2" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" dependencies = [ "aho-corasick", "memchr", @@ -1908,9 +1917,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" dependencies = [ "aho-corasick", "memchr", @@ -1960,7 +1969,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -2004,9 +2013,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -2014,18 +2023,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -2047,9 +2056,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ "serde_core", ] @@ -2112,6 +2121,12 @@ dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "siphasher" version = "1.0.1" @@ -2161,9 +2176,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "strsim" @@ -2210,15 +2225,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.22.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -2242,11 +2257,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -2262,9 +2277,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -2355,9 +2370,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ "serde_core", "serde_spanned", @@ -2368,18 +2383,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ "serde_core", ] [[package]] name = "toml_parser" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow", ] @@ -2495,9 +2510,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unic-langid" @@ -2659,9 +2674,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" dependencies = [ "cfg-if", "once_cell", @@ -2672,9 +2687,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" dependencies = [ "bumpalo", "log", @@ -2686,9 +2701,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2696,9 +2711,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", @@ -2709,9 +2724,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" dependencies = [ "unicode-ident", ] @@ -2722,27 +2737,27 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] name = "windows-core" -version = "0.62.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.0", + "windows-link", "windows-result", "windows-strings", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -2751,9 +2766,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -2762,32 +2777,26 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -2814,16 +2823,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -2844,19 +2853,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -2867,9 +2876,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -2879,9 +2888,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -2891,9 +2900,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -2903,9 +2912,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -2915,9 +2924,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -2927,9 +2936,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -2939,9 +2948,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -2951,9 +2960,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" diff --git a/Cargo.toml b/Cargo.toml index 913f3d7c..fe101436 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,8 @@ default = [] testing = [] [dev-dependencies] -tempfile = "3.22" +tempfile = "3.23" +pagetop-aliner.workspace = true [build-dependencies] pagetop-build.workspace = true @@ -58,9 +59,12 @@ pagetop-build.workspace = true [workspace] resolver = "2" members = [ + # Helpers "helpers/pagetop-build", "helpers/pagetop-macros", "helpers/pagetop-statics", + # Extensions + "extensions/pagetop-aliner", ] [workspace.package] @@ -71,7 +75,11 @@ authors = ["Manuel Cillero <manuel@cillero.es>"] [workspace.dependencies] actix-web = { version = "4.11", default-features = false } - +# Helpers pagetop-build = { version = "0.3", path = "helpers/pagetop-build" } pagetop-macros = { version = "0.2", path = "helpers/pagetop-macros" } pagetop-statics = { version = "0.1", path = "helpers/pagetop-statics" } +# Extensions +pagetop-aliner = { version = "0.0", path = "extensions/pagetop-aliner" } +# PageTop +pagetop = { version = "0.4", path = "." } diff --git a/extensions/pagetop-aliner/Cargo.toml b/extensions/pagetop-aliner/Cargo.toml new file mode 100644 index 00000000..1c1101fb --- /dev/null +++ b/extensions/pagetop-aliner/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "pagetop-aliner" +version = "0.0.9" +edition = "2021" + +description = """ + Tema para PageTop que muestra esquemáticamente la composición de las páginas HTML +""" +categories = ["web-programming", "gui"] +keywords = ["pagetop", "theme", "css"] + +repository.workspace = true +homepage.workspace = true +license.workspace = true +authors.workspace = true + +[dependencies] +pagetop.workspace = true + +[build-dependencies] +pagetop-build.workspace = true diff --git a/extensions/pagetop-aliner/README.md b/extensions/pagetop-aliner/README.md new file mode 100644 index 00000000..88e3d782 --- /dev/null +++ b/extensions/pagetop-aliner/README.md @@ -0,0 +1,100 @@ +<div align="center"> + +<h1>PageTop Aliner</h1> + +<p>Tema para <strong>PageTop</strong> que muestra esquemáticamente la composición de las páginas HTML.</p> + +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) +[![Doc API](https://img.shields.io/docsrs/pagetop-aliner?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-aliner) +[![Crates.io](https://img.shields.io/crates/v/pagetop-aliner.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-aliner) +[![Descargas](https://img.shields.io/crates/d/pagetop-aliner.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-aliner) + +<br> +</div> + +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + + +# ⚡️ Guía rápida + +Igual que con otras extensiones, **añade la dependencia** a tu `Cargo.toml`: + +```toml +[dependencies] +pagetop-aliner = "..." +``` + +**Declara la extensión** en tu aplicación (o extensión que la requiera). Recuerda que el orden en +`dependencies()` determina la prioridad relativa frente a las otras extensiones: + +```rust,no_run +use pagetop::prelude::*; + +struct MyApp; + +impl Extension for MyApp { + fn dependencies(&self) -> Vec<ExtensionRef> { + vec![ + // ... + &pagetop_aliner::Aliner, + // ... + ] + } +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&MyApp).run()?.await +} +``` + +Y **selecciona el tema en la configuración** de la aplicación: + +```toml +[app] +theme = "Aliner" +``` + +…o **fuerza el tema por código** en una página concreta: + +```rust,no_run +use pagetop::prelude::*; + +async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { + Page::new(request) + .with_theme("Aliner") + .add_component( + Block::new() + .with_title(L10n::l("sample_title")) + .add_component(Html::with(|cx| html! { + p { (L10n::l("sample_content").using(cx)) } + })), + ) + .render() +} +``` + + +# 🚧 Advertencia + +**PageTop** es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su +ecosistema. Su API está sujeta a cambios frecuentes. No se recomienda su uso en producción, al menos +hasta que se libere la versión **1.0.0**. + + +# 📜 Licencia + +El código está disponible bajo una doble licencia: + + * **Licencia MIT** + ([LICENSE-MIT](LICENSE-MIT) o también https://opensource.org/licenses/MIT) + + * **Licencia Apache, Versión 2.0** + ([LICENSE-APACHE](LICENSE-APACHE) o también https://www.apache.org/licenses/LICENSE-2.0) + +Puedes elegir la licencia que prefieras. Este enfoque de doble licencia es el estándar de facto en +el ecosistema Rust. diff --git a/extensions/pagetop-aliner/build.rs b/extensions/pagetop-aliner/build.rs new file mode 100644 index 00000000..26713f52 --- /dev/null +++ b/extensions/pagetop-aliner/build.rs @@ -0,0 +1,7 @@ +use pagetop_build::StaticFilesBundle; + +fn main() -> std::io::Result<()> { + StaticFilesBundle::from_dir("./static", None) + .with_name("aliner") + .build() +} diff --git a/extensions/pagetop-aliner/src/lib.rs b/extensions/pagetop-aliner/src/lib.rs new file mode 100644 index 00000000..8e9b03ab --- /dev/null +++ b/extensions/pagetop-aliner/src/lib.rs @@ -0,0 +1,118 @@ +/*! +<div align="center"> + +<h1>PageTop Aliner</h1> + +<p>Tema para <strong>PageTop</strong> que muestra esquemáticamente la composición de las páginas HTML.</p> + +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) +[![Doc API](https://img.shields.io/docsrs/pagetop-aliner?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-aliner) +[![Crates.io](https://img.shields.io/crates/v/pagetop-aliner.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-aliner) +[![Descargas](https://img.shields.io/crates/d/pagetop-aliner.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-aliner) + +<br> +</div> + +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + + +# ⚡️ Guía rápida + +Igual que con otras extensiones, **añade la dependencia** a tu `Cargo.toml`: + +```toml +[dependencies] +pagetop-aliner = "..." +``` + +**Declara la extensión** en tu aplicación (o extensión que la requiera). Recuerda que el orden en +`dependencies()` determina la prioridad relativa frente a las otras extensiones: + +```rust,no_run +use pagetop::prelude::*; + +struct MyApp; + +impl Extension for MyApp { + fn dependencies(&self) -> Vec<ExtensionRef> { + vec![ + // ... + &pagetop_aliner::Aliner, + // ... + ] + } +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&MyApp).run()?.await +} +``` + +Y **selecciona el tema en la configuración** de la aplicación: + +```toml +[app] +theme = "Aliner" +``` + +…o **fuerza el tema por código** en una página concreta: + +```rust,no_run +use pagetop::prelude::*; + +async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { + Page::new(request) + .with_theme("Aliner") + .add_component( + Block::new() + .with_title(L10n::l("sample_title")) + .add_component(Html::with(|cx| html! { + p { (L10n::l("sample_content").using(cx)) } + })), + ) + .render() +} +``` +*/ + +use pagetop::prelude::*; + +/// El tema usa las mismas regiones predefinidas por [`ThemeRegion`]. +pub type AlinerRegion = ThemeRegion; + +/// Implementa el tema para usar en pruebas que muestran el esquema de páginas HTML. +/// +/// Tema mínimo ideal para **pruebas y demos** que renderiza el **esqueleto HTML** con las mismas +/// regiones básicas definidas por [`ThemeRegion`]. No pretende ser un tema para producción, está +/// pensado para: +/// +/// - Verificar integración de componentes y composiciones (*layouts*) sin estilos complejos. +/// - Realizar pruebas de renderizado rápido con salida estable y predecible. +/// - Preparar ejemplos y documentación, sin dependencias visuales (CSS/JS) innecesarias. +pub struct Aliner; + +impl Extension for Aliner { + fn theme(&self) -> Option<ThemeRef> { + Some(&Self) + } + + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + static_files_service!(scfg, [aliner] => "/aliner"); + } +} + +impl Theme for Aliner { + fn before_render_page_body(&self, page: &mut Page) { + page.alter_param("include_basic_css", true) + .alter_assets(ContextOp::AddStyleSheet( + StyleSheet::from("/aliner/css/styles.css") + .with_version(env!("CARGO_PKG_VERSION")) + .with_weight(-90), + )); + } +} diff --git a/extensions/pagetop-aliner/static/css/styles.css b/extensions/pagetop-aliner/static/css/styles.css new file mode 100644 index 00000000..1cc2f5dc --- /dev/null +++ b/extensions/pagetop-aliner/static/css/styles.css @@ -0,0 +1,356 @@ +html { + background-color: white; + padding: 1px 3px; +} +body { + padding: 1px 3px; +} +div { + padding: 1px 3px; + margin: 5px; +} +h1, h2, h3, h4,h5, h6, p { + background-color: snow; +} +* * { + outline: 5px solid rgba(255,0,0,.1); +} +* * * { + outline: 3px dashed rgba(255,0,0,.4); +} +* * * * { + outline: 2px dotted rgba(255,0,0,.6); +} +* * * * * { + outline: 1px dotted rgba(255,0,0,.9); +} +* * * * * * { + outline-color: gray; +} + +*::before, *::after { + background: #faa; + border-radius: 3px; + font: normal normal 400 10px/1.2 monospace; + vertical-align: middle; + padding: 1px 3px; + margin: 0 3px; +} +*::before { + content: "("; +} +*::after { + content: ")"; +} + +a::before { content: "<a>"; } +a::after { content: "</a>"; } +abbr::before { content: "<abbr>"; } +abbr::after { content: "</abbr>"; } +acronym::before { content: "<acronym>"; } +acronym::after { content: "</acronym>"; } +address::before { content: "<address>"; } +address::after { content: "</address>"; } +applet::before { content: "<applet>"; } +applet::after { content: "</applet>"; } +area::before { content: "<area>"; } +area::after { content: "</area>"; } +article::before { content: "<article>"; } +article::after { content: "</article>"; } +aside::before { content: "<aside>"; } +aside::after { content: "</aside>"; } +audio::before { content: "<audio>"; } +audio::after { content: "</audio>"; } + +b::before { content: "<b>"; } +b::after { content: "</b>"; } +base::before { content: "<base>"; } +base::after { content: "</base>"; } +basefont::before { content: "<basefont>"; } +basefont::after { content: "</basefont>"; } +bdi::before { content: "<bdi>"; } +bdi::after { content: "</bdi>"; } +bdo::before { content: "<bdo>"; } +bdo::after { content: "</bdo>"; } +bgsound::before { content: "<bgsound>"; } +bgsound::after { content: "</bgsound>"; } +big::before { content: "<big>"; } +big::after { content: "</big>"; } +blink::before { content: "<blink>"; } +blink::after { content: "</blink>"; } +blockquote::before { content: "<blockquote>"; } +blockquote::after { content: "</blockquote>"; } +body::before { content: "<body>"; } +body::after { content: "</body>"; } +br::before { content: "<br>"; } +br::after { content: "</br>"; } +button::before { content: "<button>"; } +button::after { content: "</button>"; } + +caption::before { content: "<caption>"; } +caption::after { content: "</caption>"; } +canvas::before { content: "<canvas>"; } +canvas::after { content: "</canvas>"; } +center::before { content: "<center>"; } +center::after { content: "</center>"; } +cite::before { content: "<cite>"; } +cite::after { content: "</cite>"; } +code::before { content: "<code>"; } +code::after { content: "</code>"; } +col::before { content: "<col>"; } +col::after { content: "</col>"; } +colgroup::before { content: "<colgroup>"; } +colgroup::after { content: "</colgroup>"; } +command::before { content: "<command>"; } +command::after { content: "</command>"; } +content::before { content: "<content>"; } +content::after { content: "</content>"; } + +data::before { content: "<data>"; } +data::after { content: "</data>"; } +datalist::before { content: "<datalist>"; } +datalist::after { content: "</datalist>"; } +dd::before { content: "<dd>"; } +dd::after { content: "</dd>"; } +del::before { content: "<del>"; } +del::after { content: "</del>"; } +details::before { content: "<details>"; } +details::after { content: "</details>"; } +dfn::before { content: "<dfn>"; } +dfn::after { content: "</dfn>"; } +dialog::before { content: "<dialog>"; } +dialog::after { content: "</dialog>"; } +dir::before { content: "<dir>"; } +dir::after { content: "</dir>"; } +div::before { content: "<div>"; } +div::after { content: "</div>"; } +dl::before { content: "<dl>"; } +dl::after { content: "</dl>"; } +dt::before { content: "<dt>"; } +dt::after { content: "</dt>"; } + +element::before { content: "<element>"; } +element::after { content: "</element>"; } +em::before { content: "<em>"; } +em::after { content: "</em>"; } +embed::before { content: "<embed>"; } +embed::after { content: "</embed>"; } + +fieldset::before { content: "<fieldset>"; } +fieldset::after { content: "</fieldset>"; } +figcaption::before { content: "<figcaption>"; } +figcaption::after { content: "</figcaption>"; } +figure::before { content: "<figure>"; } +figure::after { content: "</figure>"; } +font::before { content: "<font>"; } +font::after { content: "</font>"; } +footer::before { content: "<footer>"; } +footer::after { content: "</footer>"; } +form::before { content: "<form>"; } +form::after { content: "</form>"; } +frame::before { content: "<frame>"; } +frame::after { content: "</frame>"; } +frameset::before { content: "<frameset>"; } +frameset::after { content: "</frameset>"; } + +h1::before { content: "<h1>"; } +h1::after { content: "</h1>"; } +h2::before { content: "<h2>"; } +h2::after { content: "</h2>"; } +h3::before { content: "<h3>"; } +h3::after { content: "</h3>"; } +h4::before { content: "<h4>"; } +h4::after { content: "</h4>"; } +h5::before { content: "<h5>"; } +h5::after { content: "</h5>"; } +h6::before { content: "<h6>"; } +h6::after { content: "</h6>"; } +head::before { content: "<head>"; } +head::after { content: "</head>"; } +header::before { content: "<header>"; } +header::after { content: "</header>"; } +hgroup::before { content: "<hgroup>"; } +hgroup::after { content: "</hgroup>"; } +hr::before { content: "<hr>"; } +hr::after { content: "</hr>"; } +html::before { content: "<html>"; } +html::after { content: "</html>"; } + +i::before { content: "<i>"; } +i::after { content: "</i>"; } +iframe::before { content: "<iframe>"; } +iframe::after { content: "</iframe>"; } +image::before { content: "<image>"; } +image::after { content: "</image>"; } +img::before { content: "<img>"; } +img::after { content: "</img>"; } +input::before { content: "<input>"; } +input::after { content: "</input>"; } +ins::before { content: "<ins>"; } +ins::after { content: "</ins>"; } +isindex::before { content: "<isindex>"; } +isindex::after { content: "</isindex>"; } + +kbd::before { content: "<kbd>"; } +kbd::after { content: "</kbd>"; } +keygen::before { content: "<keygen>"; } +keygen::after { content: "</keygen>"; } + +label::before { content: "<label>"; } +label::after { content: "</label>"; } +legend::before { content: "<legend>"; } +legend::after { content: "</legend>"; } +li::before { content: "<li>"; } +li::after { content: "</li>"; } +link::before { content: "<link>"; } +link::after { content: "</link>"; } +listing::before { content: "<listing>"; } +listing::after { content: "</listing>"; } + +main::before { content: "<main>"; } +main::after { content: "</main>"; } +map::before { content: "<map>"; } +map::after { content: "</map>"; } +mark::before { content: "<mark>"; } +mark::after { content: "</mark>"; } +marquee::before { content: "<marquee>"; } +marquee::after { content: "</marquee>"; } +menu::before { content: "<menu>"; } +menu::after { content: "</menu>"; } +menuitem::before { content: "<menuitem>"; } +menuitem::after { content: "</menuitem>"; } +meta::before { content: "<meta>"; } +meta::after { content: "</meta>"; } +meter::before { content: "<meter>"; } +meter::after { content: "</meter>"; } +multicol::before { content: "<multicol>"; } +multicol::after { content: "</multicol>"; } + +nav::before { content: "<nav>"; } +nav::after { content: "</nav>"; } +nextid::before { content: "<nextid>"; } +nextid::after { content: "</nextid>"; } +nobr::before { content: "<nobr>"; } +nobr::after { content: "</nobr>"; } +noembed::before { content: "<noembed>"; } +noembed::after { content: "</noembed>"; } +noframes::before { content: "<noframes>"; } +noframes::after { content: "</noframes>"; } +noscript::before { content: "<noscript>"; } +noscript::after { content: "</noscript>"; } + +object::before { content: "<object>"; } +object::after { content: "</object>"; } +ol::before { content: "<ol>"; } +ol::after { content: "</ol>"; } +optgroup::before { content: "<optgroup>"; } +optgroup::after { content: "</optgroup>"; } +option::before { content: "<option>"; } +option::after { content: "</option>"; } +output::before { content: "<output>"; } +output::after { content: "</output>"; } + +p::before { content: "<p>"; } +p::after { content: "</p>"; } +param::before { content: "<param>"; } +param::after { content: "</param>"; } +picture::before { content: "<picture>"; } +picture::after { content: "</picture>"; } +plaintext::before { content: "<plaintext>"; } +plaintext::after { content: "</plaintext>"; } +pre::before { content: "<pre>"; } +pre::after { content: "</pre>"; } +progress::before { content: "<progress>"; } +progress::after { content: "</progress>"; } + +q::before { content: "<q>"; } +q::after { content: "</q>"; } + +rb::before { content: "<rb>"; } +rb::after { content: "</rb>"; } +rp::before { content: "<rp>"; } +rp::after { content: "</rp>"; } +rt::before { content: "<rt>"; } +rt::after { content: "</rt>"; } +rtc::before { content: "<rtc>"; } +rtc::after { content: "</rtc>"; } +ruby::before { content: "<ruby>"; } +ruby::after { content: "</ruby>"; } + +s::before { content: "<s>"; } +s::after { content: "</s>"; } +samp::before { content: "<samp>"; } +samp::after { content: "</samp>"; } +script::before { content: "<script>"; } +script::after { content: "</script>"; } +section::before { content: "<section>"; } +section::after { content: "</section>"; } +select::before { content: "<select>"; } +select::after { content: "</select>"; } +shadow::before { content: "<shadow>"; } +shadow::after { content: "</shadow>"; } +slot::before { content: "<slot>"; } +slot::after { content: "</slot>"; } +small::before { content: "<small>"; } +small::after { content: "</small>"; } +source::before { content: "<source>"; } +source::after { content: "</source>"; } +spacer::before { content: "<spacer>"; } +spacer::after { content: "</spacer>"; } +span::before { content: "<span>"; } +span::after { content: "</span>"; } +strike::before { content: "<strike>"; } +strike::after { content: "</strike>"; } +strong::before { content: "<strong>"; } +strong::after { content: "</strong>"; } +style::before { content: "<style>"; } +style::after { content: "<\/style>"; } +sub::before { content: "<sub>"; } +sub::after { content: "</sub>"; } +summary::before { content: "<summary>"; } +summary::after { content: "</summary>"; } +sup::before { content: "<sup>"; } +sup::after { content: "</sup>"; } + +table::before { content: "<table>"; } +table::after { content: "</table>"; } +tbody::before { content: "<tbody>"; } +tbody::after { content: "</tbody>"; } +td::before { content: "<td>"; } +td::after { content: "</td>"; } +template::before { content: "<template>"; } +template::after { content: "</template>"; } +textarea::before { content: "<textarea>"; } +textarea::after { content: "</textarea>"; } +tfoot::before { content: "<tfoot>"; } +tfoot::after { content: "</tfoot>"; } +th::before { content: "<th>"; } +th::after { content: "</th>"; } +thead::before { content: "<thead>"; } +thead::after { content: "</thead>"; } +time::before { content: "<time>"; } +time::after { content: "</time>"; } +title::before { content: "<title>"; } +title::after { content: "</title>"; } +tr::before { content: "<tr>"; } +tr::after { content: "</tr>"; } +track::before { content: "<track>"; } +track::after { content: "</track>"; } +tt::before { content: "<tt>"; } +tt::after { content: "</tt>"; } + +u::before { content: "<u>"; } +u::after { content: "</u>"; } +ul::before { content: "<ul>"; } +ul::after { content: "</ul>"; } + +var::before { content: "<var>"; } +var::after { content: "</var>"; } +video::before { content: "<video>"; } +video::after { content: "</video>"; } + +wbr::before { content: "<wbr>"; } +wbr::after { content: "</wbr>"; } + +xmp::before { content: "<xmp>"; } +xmp::after { content: "</xmp>"; } From f25f62dd3c5194a2028b6c1af5d6cf3f77b9226d Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 12 Oct 2025 06:57:04 +0200 Subject: [PATCH 203/244] =?UTF-8?q?=F0=9F=93=9D=20Evita=20en=20los=20ejemp?= =?UTF-8?q?los=20`use=20pagetop::prelude::*;`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component/html.rs | 6 ++---- src/base/component/poweredby.rs | 3 +-- src/core.rs | 3 +-- src/core/action.rs | 3 +-- src/core/component/context.rs | 24 ++++++++---------------- src/core/extension/definition.rs | 9 +++------ src/core/theme/definition.rs | 3 +-- src/core/theme/regions.rs | 6 ++---- src/html.rs | 3 +-- src/html/assets/favicon.rs | 3 +-- src/html/assets/javascript.rs | 3 +-- src/html/assets/stylesheet.rs | 3 +-- src/html/attr_classes.rs | 3 +-- src/html/attr_id.rs | 3 +-- src/html/attr_l10n.rs | 3 +-- src/html/attr_name.rs | 3 +-- src/html/attr_value.rs | 3 +-- src/locale.rs | 24 ++++++++---------------- src/response/json.rs | 6 ++---- src/service.rs | 3 +-- src/util.rs | 15 +++++---------- 21 files changed, 44 insertions(+), 88 deletions(-) diff --git a/src/base/component/html.rs b/src/base/component/html.rs index b8c4aaaa..a60d30f9 100644 --- a/src/base/component/html.rs +++ b/src/base/component/html.rs @@ -8,8 +8,7 @@ use crate::prelude::*; /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let component = Html::with(|_| { /// html! { /// div class="example" { @@ -22,8 +21,7 @@ use crate::prelude::*; /// Para renderizar contenido que dependa del contexto, se puede acceder a él dentro del *closure*: /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let component = Html::with(|cx| { /// let user = cx.param::<String>("username").cloned().unwrap_or("visitor".to_string()); /// html! { diff --git a/src/base/component/poweredby.rs b/src/base/component/poweredby.rs index 4b54af36..d77d65c6 100644 --- a/src/base/component/poweredby.rs +++ b/src/base/component/poweredby.rs @@ -47,8 +47,7 @@ impl PoweredBy { /// eliminará, pero en este caso es necesario especificar el tipo explícitamente: /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let p1 = PoweredBy::default().with_copyright(Some("2001 © Foo Inc.")); /// let p2 = PoweredBy::new().with_copyright(None::<String>); /// ``` diff --git a/src/core.rs b/src/core.rs index 79d92074..9ecbd2e9 100644 --- a/src/core.rs +++ b/src/core.rs @@ -122,8 +122,7 @@ impl TypeInfo { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let n = 3u32; /// assert_eq!(n.type_name(), "u32"); /// ``` diff --git a/src/core/action.rs b/src/core/action.rs index cbbe79c0..9f81cd52 100644 --- a/src/core/action.rs +++ b/src/core/action.rs @@ -22,8 +22,7 @@ pub use all::dispatch_actions; /// # Ejemplo /// /// ```rust,ignore -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// impl Extension for MyTheme { /// fn actions(&self) -> Vec<ActionBox> { /// actions_boxed![ diff --git a/src/core/component/context.rs b/src/core/component/context.rs index f58d3816..8c4e47e1 100644 --- a/src/core/component/context.rs +++ b/src/core/component/context.rs @@ -66,8 +66,7 @@ pub enum ContextError { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// fn prepare_context<C: Contextual>(cx: C) -> C { /// cx.with_langid(&LangMatch::resolve("es-ES")) /// .with_theme("aliner") @@ -168,8 +167,7 @@ pub trait Contextual: LangId { /// Crea un nuevo contexto asociado a una solicitud HTTP: /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// fn new_context(request: HttpRequest) -> Context { /// Context::new(Some(request)) /// // Establece el idioma del documento a español. @@ -190,8 +188,7 @@ pub trait Contextual: LangId { /// Y hace operaciones con un contexto dado: /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// fn use_context(cx: &mut Context) { /// // Recupera el tema seleccionado. /// let active_theme = cx.theme(); @@ -310,8 +307,7 @@ impl Context { /// # Ejemplos /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let cx = Context::new(None) /// .with_param("usuario_id", 42_i32) /// .with_param("titulo", "Hola".to_string()); @@ -343,8 +339,7 @@ impl Context { /// # Ejemplos /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let mut cx = Context::new(None) /// .with_param("contador", 7_i32) /// .with_param("titulo", "Hola".to_string()); @@ -374,8 +369,7 @@ impl Context { /// # Ejemplos /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let mut cx = Context::new(None).with_param("temp", 1u8); /// assert!(cx.remove_param("temp")); /// assert!(!cx.remove_param("temp")); // ya no existe @@ -441,8 +435,7 @@ impl Contextual for Context { /// # Ejemplos /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let cx = Context::new(None) /// .with_param("usuario_id", 42_i32) /// .with_param("titulo", "Hola".to_string()) @@ -517,8 +510,7 @@ impl Contextual for Context { /// # Ejemplo /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let cx = Context::new(None).with_param("username", "Alice".to_string()); /// /// // Devuelve Some(&String) si existe y coincide el tipo. diff --git a/src/core/extension/definition.rs b/src/core/extension/definition.rs index 90bdbad2..5699130d 100644 --- a/src/core/extension/definition.rs +++ b/src/core/extension/definition.rs @@ -16,8 +16,7 @@ pub type ExtensionRef = &'static dyn Extension; /// extensión y sobreescribir los métodos que sea necesario. /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// pub struct Blog; /// /// impl Extension for Blog { @@ -45,8 +44,7 @@ pub trait Extension: AnyInfo + Send + Sync { /// la extensión no es un tema, este método devuelve `None` por defecto. /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// pub struct MyTheme; /// /// impl Extension for MyTheme { @@ -88,8 +86,7 @@ pub trait Extension: AnyInfo + Send + Sync { /// estáticos, etc., usando [`ServiceConfig`](crate::service::web::ServiceConfig). /// /// ```rust,ignore - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// pub struct ExtensionSample; /// /// impl Extension for ExtensionSample { diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 7ef95c46..4e7db776 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -155,8 +155,7 @@ pub trait ThemePage { /// **obligatorio** de `Extension` para un tema es [`theme()`](Extension::theme). /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// pub struct MyTheme; /// /// impl Extension for MyTheme { diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index ecb5eb50..8e386f55 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -37,8 +37,7 @@ pub const REGION_CONTENT: &str = "content"; /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// pub enum MyThemeRegion { /// Header, /// Content, @@ -134,8 +133,7 @@ impl InRegion { /// # Ejemplo /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// // Banner global, en la región por defecto de cualquier página. /// InRegion::Content.add(Child::with(Html::with(|_| /// html! { ("🎉 ¡Bienvenido!") } diff --git a/src/html.rs b/src/html.rs index a86c9f76..abc8e8cf 100644 --- a/src/html.rs +++ b/src/html.rs @@ -93,8 +93,7 @@ pub type OptionComponent<C: core::component::Component> = core::component::Typed /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Texto normal, se escapa automáticamente para evitar inyección de HTML. /// let fragment = PrepareMarkup::Escaped("Hola <b>mundo</b>".to_string()); /// assert_eq!(fragment.render().into_string(), "Hola &lt;b&gt;mundo&lt;/b&gt;"); diff --git a/src/html/assets/favicon.rs b/src/html/assets/favicon.rs index c2280aab..dce3e1bd 100644 --- a/src/html/assets/favicon.rs +++ b/src/html/assets/favicon.rs @@ -18,8 +18,7 @@ use crate::AutoDefault; /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let favicon = Favicon::new() /// // Estándar de facto admitido por todos los navegadores. /// .with_icon("/icons/favicon.ico") diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs index dde5f945..6dc9b852 100644 --- a/src/html/assets/javascript.rs +++ b/src/html/assets/javascript.rs @@ -46,8 +46,7 @@ enum Source { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Script externo con carga diferida, versión de caché y prioridad en el renderizado. /// let script = JavaScript::defer("/assets/js/app.js") /// .with_version("1.2.3") diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index 49cb9911..8d1bf29f 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -62,8 +62,7 @@ impl TargetMedia { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Crea una hoja de estilos externa con control de versión y medio específico (`screen`). /// let stylesheet = StyleSheet::from("/assets/css/main.css") /// .with_version("2.0.1") diff --git a/src/html/attr_classes.rs b/src/html/attr_classes.rs index 80fdad79..bb88f587 100644 --- a/src/html/attr_classes.rs +++ b/src/html/attr_classes.rs @@ -31,8 +31,7 @@ pub enum ClassesOp { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let classes = AttrClasses::new("Btn btn-primary") /// .with_value(ClassesOp::Add, "Active") /// .with_value(ClassesOp::Remove, "btn-primary"); diff --git a/src/html/attr_id.rs b/src/html/attr_id.rs index 3d5f3eb4..a1d8a1da 100644 --- a/src/html/attr_id.rs +++ b/src/html/attr_id.rs @@ -12,8 +12,7 @@ use crate::{builder_fn, AutoDefault}; /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let id = AttrId::new(" main Section "); /// assert_eq!(id.as_str(), Some("main_section")); /// diff --git a/src/html/attr_l10n.rs b/src/html/attr_l10n.rs index 37fc80fa..86d1c4a3 100644 --- a/src/html/attr_l10n.rs +++ b/src/html/attr_l10n.rs @@ -9,8 +9,7 @@ use crate::{builder_fn, AutoDefault}; /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Traducción por clave en las locales por defecto de PageTop. /// let hello = AttrL10n::new(L10n::l("test-hello-world")); /// diff --git a/src/html/attr_name.rs b/src/html/attr_name.rs index 9bc9659e..1741695c 100644 --- a/src/html/attr_name.rs +++ b/src/html/attr_name.rs @@ -12,8 +12,7 @@ use crate::{builder_fn, AutoDefault}; /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let name = AttrName::new(" DISplay name "); /// assert_eq!(name.as_str(), Some("display_name")); /// diff --git a/src/html/attr_value.rs b/src/html/attr_value.rs index eff80660..b20dec3d 100644 --- a/src/html/attr_value.rs +++ b/src/html/attr_value.rs @@ -10,8 +10,7 @@ use crate::{builder_fn, AutoDefault}; /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let s = AttrValue::new(" a new string "); /// assert_eq!(s.as_str(), Some("a new string")); /// diff --git a/src/locale.rs b/src/locale.rs index 2bf0da90..7c913ec9 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -76,8 +76,7 @@ //! que declarar: //! //! ```rust -//! use pagetop::prelude::*; -//! +//! # use pagetop::prelude::*; //! include_locales!(LOCALES_SAMPLE); //! ``` //! @@ -149,8 +148,7 @@ pub trait LangId { /// # Ejemplos /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Coincidencia exacta. /// let lang = LangMatch::resolve("es-ES"); /// assert_eq!(lang.langid().to_string(), "es-ES"); @@ -173,8 +171,7 @@ pub trait LangId { /// respaldo ("en-US"): /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Idioma por defecto o de respaldo si no resuelve. /// let lang = LangMatch::resolve("it-IT"); /// let langid = lang.langid(); @@ -236,8 +233,7 @@ impl LangMatch { /// # Ejemplo /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let lang = LangMatch::resolve("es-ES").as_option(); /// assert_eq!(lang.unwrap().to_string(), "es-ES"); /// @@ -327,8 +323,7 @@ enum L10nOp { /// Los argumentos dinámicos se añaden con `with_arg()` o `with_args()`. /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Texto literal sin traducción. /// let raw = L10n::n("© 2025 PageTop").get(); /// @@ -407,8 +402,7 @@ impl L10n { /// # Ejemplo /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let text = L10n::l("greeting").with_arg("name", "Manuel").get(); /// ``` pub fn get(&self) -> Option<String> { @@ -422,8 +416,7 @@ impl L10n { /// # Ejemplo /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// struct ResourceLang; /// /// impl LangId for ResourceLang { @@ -464,8 +457,7 @@ impl L10n { /// # Ejemplo /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let html = L10n::l("welcome.message").using(&LangMatch::resolve("es")); /// ``` pub fn using(&self, language: &impl LangId) -> Markup { diff --git a/src/response/json.rs b/src/response/json.rs index fee4c121..0878999f 100644 --- a/src/response/json.rs +++ b/src/response/json.rs @@ -6,8 +6,7 @@ //! tipo Rust fuertemente tipado, validando el formato y deserializando con *serde*. //! //! ```rust -//! use pagetop::prelude::*; -//! +//! # use pagetop::prelude::*; //! #[derive(serde::Deserialize)] //! struct NuevoUsuario { nombre: String, email: String } //! @@ -25,8 +24,7 @@ //! `application/json; charset=utf-8`, todo con una llamada compacta. //! //! ```rust -//! use pagetop::prelude::*; -//! +//! # use pagetop::prelude::*; //! #[derive(serde::Serialize)] //! struct Usuario { id: u32, nombre: String } //! diff --git a/src/service.rs b/src/service.rs index 09dc6183..9a936fc3 100644 --- a/src/service.rs +++ b/src/service.rs @@ -102,8 +102,7 @@ macro_rules! include_files_service { /// # Ejemplos /// /// ```rust,ignore -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// pub struct MyExtension; /// /// impl Extension for MyExtension { diff --git a/src/util.rs b/src/util.rs index a4daf677..f73cf78a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -50,8 +50,7 @@ macro_rules! hm { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Concatena todos los fragmentos directamente. /// let result = join!("Hello", " ", "World"); /// assert_eq!(result, "Hello World".to_string()); @@ -81,8 +80,7 @@ macro_rules! join { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Concatena los fragmentos no vacíos con un espacio como separador. /// let result_with_separator = join_opt!(["Hello", "", "World"]; " "); /// assert_eq!(result_with_separator, Some("Hello World".to_string())); @@ -121,8 +119,7 @@ macro_rules! join_opt { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let first = "Hello"; /// let separator = "-"; /// let second = "World"; @@ -164,8 +161,7 @@ macro_rules! join_pair { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Concatena los fragmentos. /// let result = join_strict!(["Hello", "World"]); /// assert_eq!(result, Some("HelloWorld".to_string())); @@ -211,8 +207,7 @@ macro_rules! join_strict { /// # Ejemplos /// /// ```rust,no_run -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Ruta relativa, se resuelve respecto a CARGO_MANIFEST_DIR o al directorio actual (`cwd`). /// println!("{:#?}", util::resolve_absolute_dir("documents")); /// From e38d7a3c4fae6d9006a63f076cf5c2bbd0311f09 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 12 Oct 2025 08:43:17 +0200 Subject: [PATCH 204/244] =?UTF-8?q?=F0=9F=94=A8=20A=C3=B1ade=20soporte=20p?= =?UTF-8?q?ara=20el=20tema=20`pagetop-aliner`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +++++ tools/changelog.sh | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/README.md b/README.md index c6c12e0e..0e635189 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,11 @@ El código se organiza en un *workspace* donde actualmente se incluyen los sigui * **[pagetop-macros](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-macros)**, proporciona una colección de macros que mejoran la experiencia de desarrollo con PageTop. +## Extensiones + + * **[pagetop-aliner](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-aliner)**, + es un tema para demos y pruebas que muestra esquemáticamente la composición de las páginas HTML. + # 🧪 Pruebas diff --git a/tools/changelog.sh b/tools/changelog.sh index 722cdb7f..253f22bc 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -55,6 +55,10 @@ case "$CRATE" in --exclude-path "helpers/pagetop-macros/**/*" ) ;; + pagetop-aliner) + CHANGELOG_FILE="extensions/pagetop-aliner/CHANGELOG.md" + PATH_FLAGS=(--include-path "extensions/pagetop-aliner/**/*") + ;; *) echo "Error: unsupported crate '$CRATE'" >&2 exit 1 From ec60c4ce6f50b84a231dbfa3d240dc2107118a5a Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 12 Oct 2025 09:15:50 +0200 Subject: [PATCH 205/244] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactoriza=20p?= =?UTF-8?q?=C3=A1gina=20de=20bienvenida=20y=20tema=20`Basic`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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. --- extensions/pagetop-aliner/src/lib.rs | 2 +- src/base/component.rs | 3 + src/base/component/intro.rs | 343 +++++++++++++++++++++++++++ src/base/extension/welcome.rs | 43 ++-- src/base/theme/basic.rs | 205 +--------------- src/core/theme/definition.rs | 26 +- src/locale/en-US/base.ftl | 6 +- src/locale/en-US/welcome.ftl | 8 +- src/locale/es-ES/base.ftl | 6 +- src/locale/es-ES/welcome.ftl | 8 +- static/css/intro.css | 82 ++++--- static/css/root.css | 19 -- 12 files changed, 455 insertions(+), 296 deletions(-) create mode 100644 src/base/component/intro.rs diff --git a/extensions/pagetop-aliner/src/lib.rs b/extensions/pagetop-aliner/src/lib.rs index 8e9b03ab..084678d7 100644 --- a/extensions/pagetop-aliner/src/lib.rs +++ b/extensions/pagetop-aliner/src/lib.rs @@ -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")) diff --git a/src/base/component.rs b/src/base/component.rs index 4edfc9a9..6c3b028f 100644 --- a/src/base/component.rs +++ b/src/base/component.rs @@ -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; diff --git a/src/base/component/intro.rs b/src/base/component/intro.rs new file mode 100644 index 00000000..5d3440e9 --- /dev/null +++ b/src/base/component/intro.rs @@ -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 + } +} diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs index 5c6fec5a..865807a1 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -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() } diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index b6a982f6..a6711859 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -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) -} diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 4e7db776..1eb7b226 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -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) } diff --git a/src/locale/en-US/base.ftl b/src/locale/en-US/base.ftl index 16b1a3ef..76baa120 100644 --- a/src/locale/en-US/base.ftl +++ b/src/locale/en-US/base.ftl @@ -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 diff --git a/src/locale/en-US/welcome.ftl b/src/locale/en-US/welcome.ftl index 20faf964..34028804 100644 --- a/src/locale/en-US/welcome.ftl +++ b/src/locale/en-US/welcome.ftl @@ -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. diff --git a/src/locale/es-ES/base.ftl b/src/locale/es-ES/base.ftl index fee21a93..09867d13 100644 --- a/src/locale/es-ES/base.ftl +++ b/src/locale/es-ES/base.ftl @@ -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 diff --git a/src/locale/es-ES/welcome.ftl b/src/locale/es-ES/welcome.ftl index 13330dbf..605d1e2c 100644 --- a/src/locale/es-ES/welcome.ftl +++ b/src/locale/es-ES/welcome.ftl @@ -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. diff --git a/static/css/intro.css b/static/css/intro.css index 774bbb2a..17ab5bef 100644 --- a/static/css/intro.css +++ b/static/css/intro.css @@ -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); -} diff --git a/static/css/root.css b/static/css/root.css index 270c1b3f..aeab1c67 100644 --- a/static/css/root.css +++ b/static/css/root.css @@ -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; From 3e3903b2c72d4264cb2a73915c2b8adeb61bc389 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 12 Oct 2025 12:07:02 +0200 Subject: [PATCH 206/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20tema=20`Bootsi?= =?UTF-8?q?er`=20basado=20en=20`Bootstrap`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 9 + Cargo.toml | 3 + extensions/pagetop-aliner/Cargo.toml | 2 +- extensions/pagetop-aliner/README.md | 2 +- extensions/pagetop-aliner/src/lib.rs | 2 +- extensions/pagetop-bootsier/Cargo.toml | 21 + extensions/pagetop-bootsier/README.md | 100 + extensions/pagetop-bootsier/build.rs | 22 + extensions/pagetop-bootsier/src/lib.rs | 121 + .../static/bootstrap-5.3.3/_accordion.scss | 158 + .../static/bootstrap-5.3.3/_alert.scss | 68 + .../static/bootstrap-5.3.3/_badge.scss | 38 + .../static/bootstrap-5.3.3/_breadcrumb.scss | 40 + .../static/bootstrap-5.3.3/_button-group.scss | 142 + .../static/bootstrap-5.3.3/_buttons.scss | 216 + .../static/bootstrap-5.3.3/_card.scss | 239 + .../static/bootstrap-5.3.3/_carousel.scss | 236 + .../static/bootstrap-5.3.3/_close.scss | 63 + .../static/bootstrap-5.3.3/_containers.scss | 41 + .../static/bootstrap-5.3.3/_dropdown.scss | 250 + .../static/bootstrap-5.3.3/_forms.scss | 9 + .../static/bootstrap-5.3.3/_functions.scss | 302 ++ .../static/bootstrap-5.3.3/_grid.scss | 39 + .../static/bootstrap-5.3.3/_helpers.scss | 12 + .../static/bootstrap-5.3.3/_images.scss | 42 + .../static/bootstrap-5.3.3/_list-group.scss | 197 + .../static/bootstrap-5.3.3/_maps.scss | 174 + .../static/bootstrap-5.3.3/_mixins.scss | 42 + .../static/bootstrap-5.3.3/_modal.scss | 236 + .../static/bootstrap-5.3.3/_nav.scss | 197 + .../static/bootstrap-5.3.3/_navbar.scss | 289 ++ .../static/bootstrap-5.3.3/_offcanvas.scss | 143 + .../static/bootstrap-5.3.3/_pagination.scss | 109 + .../static/bootstrap-5.3.3/_placeholders.scss | 51 + .../static/bootstrap-5.3.3/_popover.scss | 196 + .../static/bootstrap-5.3.3/_progress.scss | 68 + .../static/bootstrap-5.3.3/_reboot.scss | 611 +++ .../static/bootstrap-5.3.3/_root.scss | 187 + .../static/bootstrap-5.3.3/_spinners.scss | 85 + .../static/bootstrap-5.3.3/_tables.scss | 171 + .../static/bootstrap-5.3.3/_toasts.scss | 73 + .../static/bootstrap-5.3.3/_tooltip.scss | 119 + .../static/bootstrap-5.3.3/_transitions.scss | 27 + .../static/bootstrap-5.3.3/_type.scss | 106 + .../static/bootstrap-5.3.3/_utilities.scss | 806 +++ .../bootstrap-5.3.3/_variables-dark.scss | 87 + .../static/bootstrap-5.3.3/_variables.scss | 1751 +++++++ .../bootstrap-5.3.3/bootstrap-grid.scss | 62 + .../bootstrap-5.3.3/bootstrap-reboot.scss | 10 + .../bootstrap-5.3.3/bootstrap-utilities.scss | 19 + .../static/bootstrap-5.3.3/bootstrap.scss | 52 + .../forms/_floating-labels.scss | 95 + .../bootstrap-5.3.3/forms/_form-check.scss | 189 + .../bootstrap-5.3.3/forms/_form-control.scss | 214 + .../bootstrap-5.3.3/forms/_form-range.scss | 91 + .../bootstrap-5.3.3/forms/_form-select.scss | 80 + .../bootstrap-5.3.3/forms/_form-text.scss | 11 + .../bootstrap-5.3.3/forms/_input-group.scss | 132 + .../static/bootstrap-5.3.3/forms/_labels.scss | 36 + .../bootstrap-5.3.3/forms/_validation.scss | 12 + .../bootstrap-5.3.3/helpers/_clearfix.scss | 3 + .../bootstrap-5.3.3/helpers/_color-bg.scss | 7 + .../helpers/_colored-links.scss | 30 + .../bootstrap-5.3.3/helpers/_focus-ring.scss | 5 + .../bootstrap-5.3.3/helpers/_icon-link.scss | 25 + .../bootstrap-5.3.3/helpers/_position.scss | 36 + .../bootstrap-5.3.3/helpers/_ratio.scss | 26 + .../bootstrap-5.3.3/helpers/_stacks.scss | 15 + .../helpers/_stretched-link.scss | 15 + .../helpers/_text-truncation.scss | 7 + .../helpers/_visually-hidden.scss | 8 + .../static/bootstrap-5.3.3/helpers/_vr.scss | 8 + .../static/bootstrap-5.3.3/mixins/_alert.scss | 18 + .../bootstrap-5.3.3/mixins/_backdrop.scss | 14 + .../bootstrap-5.3.3/mixins/_banner.scss | 7 + .../mixins/_border-radius.scss | 78 + .../bootstrap-5.3.3/mixins/_box-shadow.scss | 18 + .../bootstrap-5.3.3/mixins/_breakpoints.scss | 127 + .../bootstrap-5.3.3/mixins/_buttons.scss | 70 + .../static/bootstrap-5.3.3/mixins/_caret.scss | 69 + .../bootstrap-5.3.3/mixins/_clearfix.scss | 9 + .../bootstrap-5.3.3/mixins/_color-mode.scss | 21 + .../bootstrap-5.3.3/mixins/_color-scheme.scss | 7 + .../bootstrap-5.3.3/mixins/_container.scss | 11 + .../bootstrap-5.3.3/mixins/_deprecate.scss | 10 + .../static/bootstrap-5.3.3/mixins/_forms.scss | 163 + .../bootstrap-5.3.3/mixins/_gradients.scss | 47 + .../static/bootstrap-5.3.3/mixins/_grid.scss | 151 + .../static/bootstrap-5.3.3/mixins/_image.scss | 16 + .../bootstrap-5.3.3/mixins/_list-group.scss | 26 + .../static/bootstrap-5.3.3/mixins/_lists.scss | 7 + .../bootstrap-5.3.3/mixins/_pagination.scss | 10 + .../bootstrap-5.3.3/mixins/_reset-text.scss | 17 + .../bootstrap-5.3.3/mixins/_resize.scss | 6 + .../mixins/_table-variants.scss | 24 + .../mixins/_text-truncate.scss | 8 + .../bootstrap-5.3.3/mixins/_transition.scss | 26 + .../bootstrap-5.3.3/mixins/_utilities.scss | 97 + .../mixins/_visually-hidden.scss | 33 + .../static/bootstrap-5.3.3/tests/jasmine.js | 16 + .../_auto-import-of-variables-dark.test.scss | 7 + .../tests/mixins/_color-modes.test.scss | 69 + .../_media-query-color-mode-full.test.scss | 8 + .../tests/mixins/_utilities.test.scss | 393 ++ .../tests/sass-true/register.js | 14 + .../bootstrap-5.3.3/tests/sass-true/runner.js | 17 + .../tests/utilities/_api.test.scss | 75 + .../bootstrap-5.3.3/utilities/_api.scss | 47 + .../static/bootstrap-5.3.3/vendor/_rfs.scss | 348 ++ .../pagetop-bootsier/static/js/bootstrap.js | 4494 +++++++++++++++++ .../static/js/bootstrap.js.map | 1 + .../static/js/bootstrap.min.js | 7 + .../static/js/bootstrap.min.js.map | 1 + src/base/extension/welcome.rs | 1 - tools/changelog.sh | 8 + 115 files changed, 15682 insertions(+), 4 deletions(-) create mode 100644 extensions/pagetop-bootsier/Cargo.toml create mode 100644 extensions/pagetop-bootsier/README.md create mode 100644 extensions/pagetop-bootsier/build.rs create mode 100644 extensions/pagetop-bootsier/src/lib.rs create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_accordion.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_alert.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_badge.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_breadcrumb.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_button-group.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_buttons.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_card.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_carousel.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_close.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_containers.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_dropdown.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_forms.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_functions.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_grid.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_helpers.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_images.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_list-group.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_maps.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_mixins.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_modal.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_nav.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_navbar.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_offcanvas.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_pagination.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_placeholders.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_popover.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_progress.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_reboot.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_root.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_spinners.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_tables.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_toasts.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_tooltip.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_transitions.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_type.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_utilities.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables-dark.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-grid.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-reboot.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-utilities.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_floating-labels.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-check.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-control.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-range.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-select.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-text.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_input-group.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_labels.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_validation.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_clearfix.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_color-bg.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_colored-links.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_focus-ring.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_icon-link.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_position.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_ratio.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_stacks.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_stretched-link.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_text-truncation.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_visually-hidden.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_vr.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_alert.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_backdrop.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_banner.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_border-radius.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_box-shadow.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_breakpoints.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_buttons.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_caret.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_clearfix.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_color-mode.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_color-scheme.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_container.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_deprecate.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_forms.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_gradients.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_grid.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_image.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_list-group.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_lists.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_pagination.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_reset-text.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_resize.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_table-variants.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_text-truncate.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_transition.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_utilities.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_visually-hidden.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/jasmine.js create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_auto-import-of-variables-dark.test.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_color-modes.test.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_media-query-color-mode-full.test.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_utilities.test.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/sass-true/register.js create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/sass-true/runner.js create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/utilities/_api.test.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/utilities/_api.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/vendor/_rfs.scss create mode 100644 extensions/pagetop-bootsier/static/js/bootstrap.js create mode 100644 extensions/pagetop-bootsier/static/js/bootstrap.js.map create mode 100644 extensions/pagetop-bootsier/static/js/bootstrap.min.js create mode 100644 extensions/pagetop-bootsier/static/js/bootstrap.min.js.map diff --git a/Cargo.lock b/Cargo.lock index cab741ef..ebcebd39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1561,6 +1561,7 @@ dependencies = [ "indoc", "itoa", "pagetop-aliner", + "pagetop-bootsier", "pagetop-build", "pagetop-macros", "pagetop-statics", @@ -1585,6 +1586,14 @@ dependencies = [ "pagetop-build", ] +[[package]] +name = "pagetop-bootsier" +version = "0.0.18" +dependencies = [ + "pagetop", + "pagetop-build", +] + [[package]] name = "pagetop-build" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index fe101436..103f6a94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ testing = [] [dev-dependencies] tempfile = "3.23" pagetop-aliner.workspace = true +pagetop-bootsier.workspace = true [build-dependencies] pagetop-build.workspace = true @@ -65,6 +66,7 @@ members = [ "helpers/pagetop-statics", # Extensions "extensions/pagetop-aliner", + "extensions/pagetop-bootsier", ] [workspace.package] @@ -81,5 +83,6 @@ pagetop-macros = { version = "0.2", path = "helpers/pagetop-macros" } pagetop-statics = { version = "0.1", path = "helpers/pagetop-statics" } # Extensions pagetop-aliner = { version = "0.0", path = "extensions/pagetop-aliner" } +pagetop-bootsier = { version = "0.0", path = "extensions/pagetop-bootsier" } # PageTop pagetop = { version = "0.4", path = "." } diff --git a/extensions/pagetop-aliner/Cargo.toml b/extensions/pagetop-aliner/Cargo.toml index 1c1101fb..603a6309 100644 --- a/extensions/pagetop-aliner/Cargo.toml +++ b/extensions/pagetop-aliner/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.9" edition = "2021" description = """ - Tema para PageTop que muestra esquemáticamente la composición de las páginas HTML + Tema de PageTop que muestra esquemáticamente la composición de las páginas HTML """ categories = ["web-programming", "gui"] keywords = ["pagetop", "theme", "css"] diff --git a/extensions/pagetop-aliner/README.md b/extensions/pagetop-aliner/README.md index 88e3d782..ac6da910 100644 --- a/extensions/pagetop-aliner/README.md +++ b/extensions/pagetop-aliner/README.md @@ -2,7 +2,7 @@ <h1>PageTop Aliner</h1> -<p>Tema para <strong>PageTop</strong> que muestra esquemáticamente la composición de las páginas HTML.</p> +<p>Tema de <strong>PageTop</strong> que muestra esquemáticamente la composición de las páginas HTML.</p> [![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-aliner?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-aliner) diff --git a/extensions/pagetop-aliner/src/lib.rs b/extensions/pagetop-aliner/src/lib.rs index 084678d7..92f9aa41 100644 --- a/extensions/pagetop-aliner/src/lib.rs +++ b/extensions/pagetop-aliner/src/lib.rs @@ -107,7 +107,7 @@ impl Extension for Aliner { } impl Theme for Aliner { - fn before_render_page_body(&self, page: &mut Page) { + fn after_render_page_body(&self, page: &mut Page) { page.alter_param("include_basic_assets", true) .alter_assets(ContextOp::AddStyleSheet( StyleSheet::from("/aliner/css/styles.css") diff --git a/extensions/pagetop-bootsier/Cargo.toml b/extensions/pagetop-bootsier/Cargo.toml new file mode 100644 index 00000000..8945e5a8 --- /dev/null +++ b/extensions/pagetop-bootsier/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "pagetop-bootsier" +version = "0.0.18" +edition = "2021" + +description = """ + Tema de PageTop basado en Bootstrap para ofrecer su catálogo de estilos y componentes flexibles. +""" +categories = ["web-programming", "gui"] +keywords = ["pagetop", "theme", "bootstrap", "css", "js"] + +repository.workspace = true +homepage.workspace = true +license.workspace = true +authors.workspace = true + +[dependencies] +pagetop.workspace = true + +[build-dependencies] +pagetop-build.workspace = true diff --git a/extensions/pagetop-bootsier/README.md b/extensions/pagetop-bootsier/README.md new file mode 100644 index 00000000..87bd3c7b --- /dev/null +++ b/extensions/pagetop-bootsier/README.md @@ -0,0 +1,100 @@ +<div align="center"> + +<h1>PageTop Bootsier</h1> + +<p>Tema de <strong>PageTop</strong> basado en Bootstrap para ofrecer su catálogo de estilos y componentes flexibles.</p> + +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) +[![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier) +[![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier) +[![Descargas](https://img.shields.io/crates/d/pagetop-bootsier.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-bootsier) + +<br> +</div> + +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + + +# ⚡️ Guía rápida + +Igual que con otras extensiones, **añade la dependencia** a tu `Cargo.toml`: + +```toml +[dependencies] +pagetop-bootsier = "..." +``` + +**Declara la extensión** en tu aplicación (o extensión que la requiera). Recuerda que el orden en +`dependencies()` determina la prioridad relativa frente a las otras extensiones: + +```rust,no_run +use pagetop::prelude::*; + +struct MyApp; + +impl Extension for MyApp { + fn dependencies(&self) -> Vec<ExtensionRef> { + vec![ + // ... + &pagetop_bootsier::Bootsier, + // ... + ] + } +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&MyApp).run()?.await +} +``` + +Y **selecciona el tema en la configuración** de la aplicación: + +```toml +[app] +theme = "Bootsier" +``` + +…o **fuerza el tema por código** en una página concreta: + +```rust,no_run +use pagetop::prelude::*; + +async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { + Page::new(request) + .with_theme("Bootsier") + .add_component( + Block::new() + .with_title(L10n::l("sample_title")) + .add_component(Html::with(|cx| html! { + p { (L10n::l("sample_content").using(cx)) } + })), + ) + .render() +} +``` + + +# 🚧 Advertencia + +**PageTop** es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su +ecosistema. Su API está sujeta a cambios frecuentes. No se recomienda su uso en producción, al menos +hasta que se libere la versión **1.0.0**. + + +# 📜 Licencia + +El código está disponible bajo una doble licencia: + + * **Licencia MIT** + ([LICENSE-MIT](LICENSE-MIT) o también https://opensource.org/licenses/MIT) + + * **Licencia Apache, Versión 2.0** + ([LICENSE-APACHE](LICENSE-APACHE) o también https://www.apache.org/licenses/LICENSE-2.0) + +Puedes elegir la licencia que prefieras. Este enfoque de doble licencia es el estándar de facto en +el ecosistema Rust. diff --git a/extensions/pagetop-bootsier/build.rs b/extensions/pagetop-bootsier/build.rs new file mode 100644 index 00000000..47cb4740 --- /dev/null +++ b/extensions/pagetop-bootsier/build.rs @@ -0,0 +1,22 @@ +use pagetop_build::StaticFilesBundle; + +use std::env; +use std::path::Path; + +fn main() -> std::io::Result<()> { + StaticFilesBundle::from_scss( + "./static/bootstrap-5.3.3/bootstrap.scss", + "bootstrap.min.css", + ) + .with_name("bootsier") + .build()?; + StaticFilesBundle::from_dir("./static/js", Some(bootstrap_js_files)) + .with_name("bootsier_js") + .build() +} + +fn bootstrap_js_files(path: &Path) -> bool { + // No filtering during development, only on "release" compilation. + env::var("PROFILE").unwrap_or_else(|_| "release".to_string()) != "release" + || path.file_name().map_or(false, |n| n == "bootstrap.min.js") +} diff --git a/extensions/pagetop-bootsier/src/lib.rs b/extensions/pagetop-bootsier/src/lib.rs new file mode 100644 index 00000000..8157ec2d --- /dev/null +++ b/extensions/pagetop-bootsier/src/lib.rs @@ -0,0 +1,121 @@ +/*! +<div align="center"> + +<h1>PageTop Bootsier</h1> + +<p>Tema de <strong>PageTop</strong> basado en Bootstrap para ofrecer su catálogo de estilos y componentes flexibles.</p> + +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) +[![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier) +[![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier) +[![Descargas](https://img.shields.io/crates/d/pagetop-bootsier.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-bootsier) + +<br> +</div> + +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + + +# ⚡️ Guía rápida + +Igual que con otras extensiones, **añade la dependencia** a tu `Cargo.toml`: + +```toml +[dependencies] +pagetop-bootsier = "..." +``` + +**Declara la extensión** en tu aplicación (o extensión que la requiera). Recuerda que el orden en +`dependencies()` determina la prioridad relativa frente a las otras extensiones: + +```rust,no_run +use pagetop::prelude::*; + +struct MyApp; + +impl Extension for MyApp { + fn dependencies(&self) -> Vec<ExtensionRef> { + vec![ + // ... + &pagetop_bootsier::Bootsier, + // ... + ] + } +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&MyApp).run()?.await +} +``` + +Y **selecciona el tema en la configuración** de la aplicación: + +```toml +[app] +theme = "Bootsier" +``` + +…o **fuerza el tema por código** en una página concreta: + +```rust,no_run +use pagetop::prelude::*; + +async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { + Page::new(request) + .with_theme("Bootsier") + .add_component( + Block::new() + .with_title(L10n::l("sample_title")) + .add_component(Html::with(|cx| html! { + p { (L10n::l("sample_content").using(cx)) } + })), + ) + .render() +} +``` +*/ + +use pagetop::prelude::*; + +/// El tema usa las mismas regiones predefinidas por [`ThemeRegion`]. +pub type BootsierRegion = ThemeRegion; + +// Versión de la librería Bootstrap. +const BOOTSTRAP_VERSION: &str = "5.3.3"; + +/// Tema basado en [Bootstrap](https://getbootstrap.com/) para los componentes base de PageTop. +/// +/// Ofrece composición de páginas *responsive*, utilidades y componentes listos para usar, con +/// estilos coherentes y enfoque en accesibilidad. +pub struct Bootsier; + +impl Extension for Bootsier { + fn theme(&self) -> Option<ThemeRef> { + Some(&Self) + } + + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + static_files_service!(scfg, [bootsier] => "/bootsier/css"); + static_files_service!(scfg, [bootsier_js] => "/bootsier/js"); + } +} + +impl Theme for Bootsier { + fn after_render_page_body(&self, page: &mut Page) { + page.alter_assets(ContextOp::AddStyleSheet( + StyleSheet::from("/bootsier/css/bootstrap.min.css") + .with_version(BOOTSTRAP_VERSION) + .with_weight(-90), + )) + .alter_assets(ContextOp::AddJavaScript( + JavaScript::defer("/bootsier/js/bootstrap.min.js") + .with_version(BOOTSTRAP_VERSION) + .with_weight(-90), + )); + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_accordion.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_accordion.scss new file mode 100644 index 00000000..17e5436e --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_accordion.scss @@ -0,0 +1,158 @@ +// +// Base styles +// + +.accordion { + // scss-docs-start accordion-css-vars + --#{$prefix}accordion-color: #{$accordion-color}; + --#{$prefix}accordion-bg: #{$accordion-bg}; + --#{$prefix}accordion-transition: #{$accordion-transition}; + --#{$prefix}accordion-border-color: #{$accordion-border-color}; + --#{$prefix}accordion-border-width: #{$accordion-border-width}; + --#{$prefix}accordion-border-radius: #{$accordion-border-radius}; + --#{$prefix}accordion-inner-border-radius: #{$accordion-inner-border-radius}; + --#{$prefix}accordion-btn-padding-x: #{$accordion-button-padding-x}; + --#{$prefix}accordion-btn-padding-y: #{$accordion-button-padding-y}; + --#{$prefix}accordion-btn-color: #{$accordion-button-color}; + --#{$prefix}accordion-btn-bg: #{$accordion-button-bg}; + --#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon)}; + --#{$prefix}accordion-btn-icon-width: #{$accordion-icon-width}; + --#{$prefix}accordion-btn-icon-transform: #{$accordion-icon-transform}; + --#{$prefix}accordion-btn-icon-transition: #{$accordion-icon-transition}; + --#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon)}; + --#{$prefix}accordion-btn-focus-box-shadow: #{$accordion-button-focus-box-shadow}; + --#{$prefix}accordion-body-padding-x: #{$accordion-body-padding-x}; + --#{$prefix}accordion-body-padding-y: #{$accordion-body-padding-y}; + --#{$prefix}accordion-active-color: #{$accordion-button-active-color}; + --#{$prefix}accordion-active-bg: #{$accordion-button-active-bg}; + // scss-docs-end accordion-css-vars +} + +.accordion-button { + position: relative; + display: flex; + align-items: center; + width: 100%; + padding: var(--#{$prefix}accordion-btn-padding-y) var(--#{$prefix}accordion-btn-padding-x); + @include font-size($font-size-base); + color: var(--#{$prefix}accordion-btn-color); + text-align: left; // Reset button style + background-color: var(--#{$prefix}accordion-btn-bg); + border: 0; + @include border-radius(0); + overflow-anchor: none; + @include transition(var(--#{$prefix}accordion-transition)); + + &:not(.collapsed) { + color: var(--#{$prefix}accordion-active-color); + background-color: var(--#{$prefix}accordion-active-bg); + box-shadow: inset 0 calc(-1 * var(--#{$prefix}accordion-border-width)) 0 var(--#{$prefix}accordion-border-color); // stylelint-disable-line function-disallowed-list + + &::after { + background-image: var(--#{$prefix}accordion-btn-active-icon); + transform: var(--#{$prefix}accordion-btn-icon-transform); + } + } + + // Accordion icon + &::after { + flex-shrink: 0; + width: var(--#{$prefix}accordion-btn-icon-width); + height: var(--#{$prefix}accordion-btn-icon-width); + margin-left: auto; + content: ""; + background-image: var(--#{$prefix}accordion-btn-icon); + background-repeat: no-repeat; + background-size: var(--#{$prefix}accordion-btn-icon-width); + @include transition(var(--#{$prefix}accordion-btn-icon-transition)); + } + + &:hover { + z-index: 2; + } + + &:focus { + z-index: 3; + outline: 0; + box-shadow: var(--#{$prefix}accordion-btn-focus-box-shadow); + } +} + +.accordion-header { + margin-bottom: 0; +} + +.accordion-item { + color: var(--#{$prefix}accordion-color); + background-color: var(--#{$prefix}accordion-bg); + border: var(--#{$prefix}accordion-border-width) solid var(--#{$prefix}accordion-border-color); + + &:first-of-type { + @include border-top-radius(var(--#{$prefix}accordion-border-radius)); + + > .accordion-header .accordion-button { + @include border-top-radius(var(--#{$prefix}accordion-inner-border-radius)); + } + } + + &:not(:first-of-type) { + border-top: 0; + } + + // Only set a border-radius on the last item if the accordion is collapsed + &:last-of-type { + @include border-bottom-radius(var(--#{$prefix}accordion-border-radius)); + + > .accordion-header .accordion-button { + &.collapsed { + @include border-bottom-radius(var(--#{$prefix}accordion-inner-border-radius)); + } + } + + > .accordion-collapse { + @include border-bottom-radius(var(--#{$prefix}accordion-border-radius)); + } + } +} + +.accordion-body { + padding: var(--#{$prefix}accordion-body-padding-y) var(--#{$prefix}accordion-body-padding-x); +} + + +// Flush accordion items +// +// Remove borders and border-radius to keep accordion items edge-to-edge. + +.accordion-flush { + > .accordion-item { + border-right: 0; + border-left: 0; + @include border-radius(0); + + &:first-child { border-top: 0; } + &:last-child { border-bottom: 0; } + + // stylelint-disable selector-max-class + > .accordion-header .accordion-button { + &, + &.collapsed { + @include border-radius(0); + } + } + // stylelint-enable selector-max-class + + > .accordion-collapse { + @include border-radius(0); + } + } +} + +@if $enable-dark-mode { + @include color-mode(dark) { + .accordion-button::after { + --#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon-dark)}; + --#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon-dark)}; + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_alert.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_alert.scss new file mode 100644 index 00000000..b8cff9b7 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_alert.scss @@ -0,0 +1,68 @@ +// +// Base styles +// + +.alert { + // scss-docs-start alert-css-vars + --#{$prefix}alert-bg: transparent; + --#{$prefix}alert-padding-x: #{$alert-padding-x}; + --#{$prefix}alert-padding-y: #{$alert-padding-y}; + --#{$prefix}alert-margin-bottom: #{$alert-margin-bottom}; + --#{$prefix}alert-color: inherit; + --#{$prefix}alert-border-color: transparent; + --#{$prefix}alert-border: #{$alert-border-width} solid var(--#{$prefix}alert-border-color); + --#{$prefix}alert-border-radius: #{$alert-border-radius}; + --#{$prefix}alert-link-color: inherit; + // scss-docs-end alert-css-vars + + position: relative; + padding: var(--#{$prefix}alert-padding-y) var(--#{$prefix}alert-padding-x); + margin-bottom: var(--#{$prefix}alert-margin-bottom); + color: var(--#{$prefix}alert-color); + background-color: var(--#{$prefix}alert-bg); + border: var(--#{$prefix}alert-border); + @include border-radius(var(--#{$prefix}alert-border-radius)); +} + +// Headings for larger alerts +.alert-heading { + // Specified to prevent conflicts of changing $headings-color + color: inherit; +} + +// Provide class for links that match alerts +.alert-link { + font-weight: $alert-link-font-weight; + color: var(--#{$prefix}alert-link-color); +} + + +// Dismissible alerts +// +// Expand the right padding and account for the close button's positioning. + +.alert-dismissible { + padding-right: $alert-dismissible-padding-r; + + // Adjust close link position + .btn-close { + position: absolute; + top: 0; + right: 0; + z-index: $stretched-link-z-index + 1; + padding: $alert-padding-y * 1.25 $alert-padding-x; + } +} + + +// scss-docs-start alert-modifiers +// Generate contextual modifier classes for colorizing the alert +@each $state in map-keys($theme-colors) { + .alert-#{$state} { + --#{$prefix}alert-color: var(--#{$prefix}#{$state}-text-emphasis); + --#{$prefix}alert-bg: var(--#{$prefix}#{$state}-bg-subtle); + --#{$prefix}alert-border-color: var(--#{$prefix}#{$state}-border-subtle); + --#{$prefix}alert-link-color: var(--#{$prefix}#{$state}-text-emphasis); + } +} +// scss-docs-end alert-modifiers diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_badge.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_badge.scss new file mode 100644 index 00000000..cc3d2695 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_badge.scss @@ -0,0 +1,38 @@ +// Base class +// +// Requires one of the contextual, color modifier classes for `color` and +// `background-color`. + +.badge { + // scss-docs-start badge-css-vars + --#{$prefix}badge-padding-x: #{$badge-padding-x}; + --#{$prefix}badge-padding-y: #{$badge-padding-y}; + @include rfs($badge-font-size, --#{$prefix}badge-font-size); + --#{$prefix}badge-font-weight: #{$badge-font-weight}; + --#{$prefix}badge-color: #{$badge-color}; + --#{$prefix}badge-border-radius: #{$badge-border-radius}; + // scss-docs-end badge-css-vars + + display: inline-block; + padding: var(--#{$prefix}badge-padding-y) var(--#{$prefix}badge-padding-x); + @include font-size(var(--#{$prefix}badge-font-size)); + font-weight: var(--#{$prefix}badge-font-weight); + line-height: 1; + color: var(--#{$prefix}badge-color); + text-align: center; + white-space: nowrap; + vertical-align: baseline; + @include border-radius(var(--#{$prefix}badge-border-radius)); + @include gradient-bg(); + + // Empty badges collapse automatically + &:empty { + display: none; + } +} + +// Quick fix for badges in buttons +.btn .badge { + position: relative; + top: -1px; +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_breadcrumb.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_breadcrumb.scss new file mode 100644 index 00000000..b8252ff2 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_breadcrumb.scss @@ -0,0 +1,40 @@ +.breadcrumb { + // scss-docs-start breadcrumb-css-vars + --#{$prefix}breadcrumb-padding-x: #{$breadcrumb-padding-x}; + --#{$prefix}breadcrumb-padding-y: #{$breadcrumb-padding-y}; + --#{$prefix}breadcrumb-margin-bottom: #{$breadcrumb-margin-bottom}; + @include rfs($breadcrumb-font-size, --#{$prefix}breadcrumb-font-size); + --#{$prefix}breadcrumb-bg: #{$breadcrumb-bg}; + --#{$prefix}breadcrumb-border-radius: #{$breadcrumb-border-radius}; + --#{$prefix}breadcrumb-divider-color: #{$breadcrumb-divider-color}; + --#{$prefix}breadcrumb-item-padding-x: #{$breadcrumb-item-padding-x}; + --#{$prefix}breadcrumb-item-active-color: #{$breadcrumb-active-color}; + // scss-docs-end breadcrumb-css-vars + + display: flex; + flex-wrap: wrap; + padding: var(--#{$prefix}breadcrumb-padding-y) var(--#{$prefix}breadcrumb-padding-x); + margin-bottom: var(--#{$prefix}breadcrumb-margin-bottom); + @include font-size(var(--#{$prefix}breadcrumb-font-size)); + list-style: none; + background-color: var(--#{$prefix}breadcrumb-bg); + @include border-radius(var(--#{$prefix}breadcrumb-border-radius)); +} + +.breadcrumb-item { + // The separator between breadcrumbs (by default, a forward-slash: "/") + + .breadcrumb-item { + padding-left: var(--#{$prefix}breadcrumb-item-padding-x); + + &::before { + float: left; // Suppress inline spacings and underlining of the separator + padding-right: var(--#{$prefix}breadcrumb-item-padding-x); + color: var(--#{$prefix}breadcrumb-divider-color); + content: var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{"/* rtl:"} var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{"*/"}; + } + } + + &.active { + color: var(--#{$prefix}breadcrumb-item-active-color); + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_button-group.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_button-group.scss new file mode 100644 index 00000000..55ae3f65 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_button-group.scss @@ -0,0 +1,142 @@ +// Make the div behave like a button +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-flex; + vertical-align: middle; // match .btn alignment given font-size hack above + + > .btn { + position: relative; + flex: 1 1 auto; + } + + // Bring the hover, focused, and "active" buttons to the front to overlay + // the borders properly + > .btn-check:checked + .btn, + > .btn-check:focus + .btn, + > .btn:hover, + > .btn:focus, + > .btn:active, + > .btn.active { + z-index: 1; + } +} + +// Optional: Group multiple button groups together for a toolbar +.btn-toolbar { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + + .input-group { + width: auto; + } +} + +.btn-group { + @include border-radius($btn-border-radius); + + // Prevent double borders when buttons are next to each other + > :not(.btn-check:first-child) + .btn, + > .btn-group:not(:first-child) { + margin-left: calc(#{$btn-border-width} * -1); // stylelint-disable-line function-disallowed-list + } + + // Reset rounded corners + > .btn:not(:last-child):not(.dropdown-toggle), + > .btn.dropdown-toggle-split:first-child, + > .btn-group:not(:last-child) > .btn { + @include border-end-radius(0); + } + + // The left radius should be 0 if the button is: + // - the "third or more" child + // - the second child and the previous element isn't `.btn-check` (making it the first child visually) + // - part of a btn-group which isn't the first child + > .btn:nth-child(n + 3), + > :not(.btn-check) + .btn, + > .btn-group:not(:first-child) > .btn { + @include border-start-radius(0); + } +} + +// Sizing +// +// Remix the default button sizing classes into new ones for easier manipulation. + +.btn-group-sm > .btn { @extend .btn-sm; } +.btn-group-lg > .btn { @extend .btn-lg; } + + +// +// Split button dropdowns +// + +.dropdown-toggle-split { + padding-right: $btn-padding-x * .75; + padding-left: $btn-padding-x * .75; + + &::after, + .dropup &::after, + .dropend &::after { + margin-left: 0; + } + + .dropstart &::before { + margin-right: 0; + } +} + +.btn-sm + .dropdown-toggle-split { + padding-right: $btn-padding-x-sm * .75; + padding-left: $btn-padding-x-sm * .75; +} + +.btn-lg + .dropdown-toggle-split { + padding-right: $btn-padding-x-lg * .75; + padding-left: $btn-padding-x-lg * .75; +} + + +// The clickable button for toggling the menu +// Set the same inset shadow as the :active state +.btn-group.show .dropdown-toggle { + @include box-shadow($btn-active-box-shadow); + + // Show no shadow for `.btn-link` since it has no other button styles. + &.btn-link { + @include box-shadow(none); + } +} + + +// +// Vertical button groups +// + +.btn-group-vertical { + flex-direction: column; + align-items: flex-start; + justify-content: center; + + > .btn, + > .btn-group { + width: 100%; + } + + > .btn:not(:first-child), + > .btn-group:not(:first-child) { + margin-top: calc(#{$btn-border-width} * -1); // stylelint-disable-line function-disallowed-list + } + + // Reset rounded corners + > .btn:not(:last-child):not(.dropdown-toggle), + > .btn-group:not(:last-child) > .btn { + @include border-bottom-radius(0); + } + + > .btn ~ .btn, + > .btn-group:not(:first-child) > .btn { + @include border-top-radius(0); + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_buttons.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_buttons.scss new file mode 100644 index 00000000..caa4518a --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_buttons.scss @@ -0,0 +1,216 @@ +// +// Base styles +// + +.btn { + // scss-docs-start btn-css-vars + --#{$prefix}btn-padding-x: #{$btn-padding-x}; + --#{$prefix}btn-padding-y: #{$btn-padding-y}; + --#{$prefix}btn-font-family: #{$btn-font-family}; + @include rfs($btn-font-size, --#{$prefix}btn-font-size); + --#{$prefix}btn-font-weight: #{$btn-font-weight}; + --#{$prefix}btn-line-height: #{$btn-line-height}; + --#{$prefix}btn-color: #{$btn-color}; + --#{$prefix}btn-bg: transparent; + --#{$prefix}btn-border-width: #{$btn-border-width}; + --#{$prefix}btn-border-color: transparent; + --#{$prefix}btn-border-radius: #{$btn-border-radius}; + --#{$prefix}btn-hover-border-color: transparent; + --#{$prefix}btn-box-shadow: #{$btn-box-shadow}; + --#{$prefix}btn-disabled-opacity: #{$btn-disabled-opacity}; + --#{$prefix}btn-focus-box-shadow: 0 0 0 #{$btn-focus-width} rgba(var(--#{$prefix}btn-focus-shadow-rgb), .5); + // scss-docs-end btn-css-vars + + display: inline-block; + padding: var(--#{$prefix}btn-padding-y) var(--#{$prefix}btn-padding-x); + font-family: var(--#{$prefix}btn-font-family); + @include font-size(var(--#{$prefix}btn-font-size)); + font-weight: var(--#{$prefix}btn-font-weight); + line-height: var(--#{$prefix}btn-line-height); + color: var(--#{$prefix}btn-color); + text-align: center; + text-decoration: if($link-decoration == none, null, none); + white-space: $btn-white-space; + vertical-align: middle; + cursor: if($enable-button-pointers, pointer, null); + user-select: none; + border: var(--#{$prefix}btn-border-width) solid var(--#{$prefix}btn-border-color); + @include border-radius(var(--#{$prefix}btn-border-radius)); + @include gradient-bg(var(--#{$prefix}btn-bg)); + @include box-shadow(var(--#{$prefix}btn-box-shadow)); + @include transition($btn-transition); + + &:hover { + color: var(--#{$prefix}btn-hover-color); + text-decoration: if($link-hover-decoration == underline, none, null); + background-color: var(--#{$prefix}btn-hover-bg); + border-color: var(--#{$prefix}btn-hover-border-color); + } + + .btn-check + &:hover { + // override for the checkbox/radio buttons + color: var(--#{$prefix}btn-color); + background-color: var(--#{$prefix}btn-bg); + border-color: var(--#{$prefix}btn-border-color); + } + + &:focus-visible { + color: var(--#{$prefix}btn-hover-color); + @include gradient-bg(var(--#{$prefix}btn-hover-bg)); + border-color: var(--#{$prefix}btn-hover-border-color); + outline: 0; + // Avoid using mixin so we can pass custom focus shadow properly + @if $enable-shadows { + box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow); + } @else { + box-shadow: var(--#{$prefix}btn-focus-box-shadow); + } + } + + .btn-check:focus-visible + & { + border-color: var(--#{$prefix}btn-hover-border-color); + outline: 0; + // Avoid using mixin so we can pass custom focus shadow properly + @if $enable-shadows { + box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow); + } @else { + box-shadow: var(--#{$prefix}btn-focus-box-shadow); + } + } + + .btn-check:checked + &, + :not(.btn-check) + &:active, + &:first-child:active, + &.active, + &.show { + color: var(--#{$prefix}btn-active-color); + background-color: var(--#{$prefix}btn-active-bg); + // Remove CSS gradients if they're enabled + background-image: if($enable-gradients, none, null); + border-color: var(--#{$prefix}btn-active-border-color); + @include box-shadow(var(--#{$prefix}btn-active-shadow)); + + &:focus-visible { + // Avoid using mixin so we can pass custom focus shadow properly + @if $enable-shadows { + box-shadow: var(--#{$prefix}btn-active-shadow), var(--#{$prefix}btn-focus-box-shadow); + } @else { + box-shadow: var(--#{$prefix}btn-focus-box-shadow); + } + } + } + + .btn-check:checked:focus-visible + & { + // Avoid using mixin so we can pass custom focus shadow properly + @if $enable-shadows { + box-shadow: var(--#{$prefix}btn-active-shadow), var(--#{$prefix}btn-focus-box-shadow); + } @else { + box-shadow: var(--#{$prefix}btn-focus-box-shadow); + } + } + + &:disabled, + &.disabled, + fieldset:disabled & { + color: var(--#{$prefix}btn-disabled-color); + pointer-events: none; + background-color: var(--#{$prefix}btn-disabled-bg); + background-image: if($enable-gradients, none, null); + border-color: var(--#{$prefix}btn-disabled-border-color); + opacity: var(--#{$prefix}btn-disabled-opacity); + @include box-shadow(none); + } +} + + +// +// Alternate buttons +// + +// scss-docs-start btn-variant-loops +@each $color, $value in $theme-colors { + .btn-#{$color} { + @if $color == "light" { + @include button-variant( + $value, + $value, + $hover-background: shade-color($value, $btn-hover-bg-shade-amount), + $hover-border: shade-color($value, $btn-hover-border-shade-amount), + $active-background: shade-color($value, $btn-active-bg-shade-amount), + $active-border: shade-color($value, $btn-active-border-shade-amount) + ); + } @else if $color == "dark" { + @include button-variant( + $value, + $value, + $hover-background: tint-color($value, $btn-hover-bg-tint-amount), + $hover-border: tint-color($value, $btn-hover-border-tint-amount), + $active-background: tint-color($value, $btn-active-bg-tint-amount), + $active-border: tint-color($value, $btn-active-border-tint-amount) + ); + } @else { + @include button-variant($value, $value); + } + } +} + +@each $color, $value in $theme-colors { + .btn-outline-#{$color} { + @include button-outline-variant($value); + } +} +// scss-docs-end btn-variant-loops + + +// +// Link buttons +// + +// Make a button look and behave like a link +.btn-link { + --#{$prefix}btn-font-weight: #{$font-weight-normal}; + --#{$prefix}btn-color: #{$btn-link-color}; + --#{$prefix}btn-bg: transparent; + --#{$prefix}btn-border-color: transparent; + --#{$prefix}btn-hover-color: #{$btn-link-hover-color}; + --#{$prefix}btn-hover-border-color: transparent; + --#{$prefix}btn-active-color: #{$btn-link-hover-color}; + --#{$prefix}btn-active-border-color: transparent; + --#{$prefix}btn-disabled-color: #{$btn-link-disabled-color}; + --#{$prefix}btn-disabled-border-color: transparent; + --#{$prefix}btn-box-shadow: 0 0 0 #000; // Can't use `none` as keyword negates all values when used with multiple shadows + --#{$prefix}btn-focus-shadow-rgb: #{$btn-link-focus-shadow-rgb}; + + text-decoration: $link-decoration; + @if $enable-gradients { + background-image: none; + } + + &:hover, + &:focus-visible { + text-decoration: $link-hover-decoration; + } + + &:focus-visible { + color: var(--#{$prefix}btn-color); + } + + &:hover { + color: var(--#{$prefix}btn-hover-color); + } + + // No need for an active state here +} + + +// +// Button Sizes +// + +.btn-lg { + @include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg); +} + +.btn-sm { + @include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm); +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_card.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_card.scss new file mode 100644 index 00000000..d3535a98 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_card.scss @@ -0,0 +1,239 @@ +// +// Base styles +// + +.card { + // scss-docs-start card-css-vars + --#{$prefix}card-spacer-y: #{$card-spacer-y}; + --#{$prefix}card-spacer-x: #{$card-spacer-x}; + --#{$prefix}card-title-spacer-y: #{$card-title-spacer-y}; + --#{$prefix}card-title-color: #{$card-title-color}; + --#{$prefix}card-subtitle-color: #{$card-subtitle-color}; + --#{$prefix}card-border-width: #{$card-border-width}; + --#{$prefix}card-border-color: #{$card-border-color}; + --#{$prefix}card-border-radius: #{$card-border-radius}; + --#{$prefix}card-box-shadow: #{$card-box-shadow}; + --#{$prefix}card-inner-border-radius: #{$card-inner-border-radius}; + --#{$prefix}card-cap-padding-y: #{$card-cap-padding-y}; + --#{$prefix}card-cap-padding-x: #{$card-cap-padding-x}; + --#{$prefix}card-cap-bg: #{$card-cap-bg}; + --#{$prefix}card-cap-color: #{$card-cap-color}; + --#{$prefix}card-height: #{$card-height}; + --#{$prefix}card-color: #{$card-color}; + --#{$prefix}card-bg: #{$card-bg}; + --#{$prefix}card-img-overlay-padding: #{$card-img-overlay-padding}; + --#{$prefix}card-group-margin: #{$card-group-margin}; + // scss-docs-end card-css-vars + + position: relative; + display: flex; + flex-direction: column; + min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106 + height: var(--#{$prefix}card-height); + color: var(--#{$prefix}body-color); + word-wrap: break-word; + background-color: var(--#{$prefix}card-bg); + background-clip: border-box; + border: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color); + @include border-radius(var(--#{$prefix}card-border-radius)); + @include box-shadow(var(--#{$prefix}card-box-shadow)); + + > hr { + margin-right: 0; + margin-left: 0; + } + + > .list-group { + border-top: inherit; + border-bottom: inherit; + + &:first-child { + border-top-width: 0; + @include border-top-radius(var(--#{$prefix}card-inner-border-radius)); + } + + &:last-child { + border-bottom-width: 0; + @include border-bottom-radius(var(--#{$prefix}card-inner-border-radius)); + } + } + + // Due to specificity of the above selector (`.card > .list-group`), we must + // use a child selector here to prevent double borders. + > .card-header + .list-group, + > .list-group + .card-footer { + border-top: 0; + } +} + +.card-body { + // Enable `flex-grow: 1` for decks and groups so that card blocks take up + // as much space as possible, ensuring footers are aligned to the bottom. + flex: 1 1 auto; + padding: var(--#{$prefix}card-spacer-y) var(--#{$prefix}card-spacer-x); + color: var(--#{$prefix}card-color); +} + +.card-title { + margin-bottom: var(--#{$prefix}card-title-spacer-y); + color: var(--#{$prefix}card-title-color); +} + +.card-subtitle { + margin-top: calc(-.5 * var(--#{$prefix}card-title-spacer-y)); // stylelint-disable-line function-disallowed-list + margin-bottom: 0; + color: var(--#{$prefix}card-subtitle-color); +} + +.card-text:last-child { + margin-bottom: 0; +} + +.card-link { + &:hover { + text-decoration: if($link-hover-decoration == underline, none, null); + } + + + .card-link { + margin-left: var(--#{$prefix}card-spacer-x); + } +} + +// +// Optional textual caps +// + +.card-header { + padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x); + margin-bottom: 0; // Removes the default margin-bottom of <hN> + color: var(--#{$prefix}card-cap-color); + background-color: var(--#{$prefix}card-cap-bg); + border-bottom: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color); + + &:first-child { + @include border-radius(var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius) 0 0); + } +} + +.card-footer { + padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x); + color: var(--#{$prefix}card-cap-color); + background-color: var(--#{$prefix}card-cap-bg); + border-top: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color); + + &:last-child { + @include border-radius(0 0 var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius)); + } +} + + +// +// Header navs +// + +.card-header-tabs { + margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list + margin-bottom: calc(-1 * var(--#{$prefix}card-cap-padding-y)); // stylelint-disable-line function-disallowed-list + margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list + border-bottom: 0; + + .nav-link.active { + background-color: var(--#{$prefix}card-bg); + border-bottom-color: var(--#{$prefix}card-bg); + } +} + +.card-header-pills { + margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list + margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list +} + +// Card image +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: var(--#{$prefix}card-img-overlay-padding); + @include border-radius(var(--#{$prefix}card-inner-border-radius)); +} + +.card-img, +.card-img-top, +.card-img-bottom { + width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch +} + +.card-img, +.card-img-top { + @include border-top-radius(var(--#{$prefix}card-inner-border-radius)); +} + +.card-img, +.card-img-bottom { + @include border-bottom-radius(var(--#{$prefix}card-inner-border-radius)); +} + + +// +// Card groups +// + +.card-group { + // The child selector allows nested `.card` within `.card-group` + // to display properly. + > .card { + margin-bottom: var(--#{$prefix}card-group-margin); + } + + @include media-breakpoint-up(sm) { + display: flex; + flex-flow: row wrap; + // The child selector allows nested `.card` within `.card-group` + // to display properly. + > .card { + // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4 + flex: 1 0 0%; + margin-bottom: 0; + + + .card { + margin-left: 0; + border-left: 0; + } + + // Handle rounded corners + @if $enable-rounded { + &:not(:last-child) { + @include border-end-radius(0); + + .card-img-top, + .card-header { + // stylelint-disable-next-line property-disallowed-list + border-top-right-radius: 0; + } + .card-img-bottom, + .card-footer { + // stylelint-disable-next-line property-disallowed-list + border-bottom-right-radius: 0; + } + } + + &:not(:first-child) { + @include border-start-radius(0); + + .card-img-top, + .card-header { + // stylelint-disable-next-line property-disallowed-list + border-top-left-radius: 0; + } + .card-img-bottom, + .card-footer { + // stylelint-disable-next-line property-disallowed-list + border-bottom-left-radius: 0; + } + } + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_carousel.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_carousel.scss new file mode 100644 index 00000000..3a135220 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_carousel.scss @@ -0,0 +1,236 @@ +// Notes on the classes: +// +// 1. .carousel.pointer-event should ideally be pan-y (to allow for users to scroll vertically) +// even when their scroll action started on a carousel, but for compatibility (with Firefox) +// we're preventing all actions instead +// 2. The .carousel-item-start and .carousel-item-end is used to indicate where +// the active slide is heading. +// 3. .active.carousel-item is the current slide. +// 4. .active.carousel-item-start and .active.carousel-item-end is the current +// slide in its in-transition state. Only one of these occurs at a time. +// 5. .carousel-item-next.carousel-item-start and .carousel-item-prev.carousel-item-end +// is the upcoming slide in transition. + +.carousel { + position: relative; +} + +.carousel.pointer-event { + touch-action: pan-y; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; + @include clearfix(); +} + +.carousel-item { + position: relative; + display: none; + float: left; + width: 100%; + margin-right: -100%; + backface-visibility: hidden; + @include transition($carousel-transition); +} + +.carousel-item.active, +.carousel-item-next, +.carousel-item-prev { + display: block; +} + +.carousel-item-next:not(.carousel-item-start), +.active.carousel-item-end { + transform: translateX(100%); +} + +.carousel-item-prev:not(.carousel-item-end), +.active.carousel-item-start { + transform: translateX(-100%); +} + + +// +// Alternate transitions +// + +.carousel-fade { + .carousel-item { + opacity: 0; + transition-property: opacity; + transform: none; + } + + .carousel-item.active, + .carousel-item-next.carousel-item-start, + .carousel-item-prev.carousel-item-end { + z-index: 1; + opacity: 1; + } + + .active.carousel-item-start, + .active.carousel-item-end { + z-index: 0; + opacity: 0; + @include transition(opacity 0s $carousel-transition-duration); + } +} + + +// +// Left/right controls for nav +// + +.carousel-control-prev, +.carousel-control-next { + position: absolute; + top: 0; + bottom: 0; + z-index: 1; + // Use flex for alignment (1-3) + display: flex; // 1. allow flex styles + align-items: center; // 2. vertically center contents + justify-content: center; // 3. horizontally center contents + width: $carousel-control-width; + padding: 0; + color: $carousel-control-color; + text-align: center; + background: none; + border: 0; + opacity: $carousel-control-opacity; + @include transition($carousel-control-transition); + + // Hover/focus state + &:hover, + &:focus { + color: $carousel-control-color; + text-decoration: none; + outline: 0; + opacity: $carousel-control-hover-opacity; + } +} +.carousel-control-prev { + left: 0; + background-image: if($enable-gradients, linear-gradient(90deg, rgba($black, .25), rgba($black, .001)), null); +} +.carousel-control-next { + right: 0; + background-image: if($enable-gradients, linear-gradient(270deg, rgba($black, .25), rgba($black, .001)), null); +} + +// Icons for within +.carousel-control-prev-icon, +.carousel-control-next-icon { + display: inline-block; + width: $carousel-control-icon-width; + height: $carousel-control-icon-width; + background-repeat: no-repeat; + background-position: 50%; + background-size: 100% 100%; +} + +.carousel-control-prev-icon { + background-image: escape-svg($carousel-control-prev-icon-bg) #{"/*rtl:" + escape-svg($carousel-control-next-icon-bg) + "*/"}; +} +.carousel-control-next-icon { + background-image: escape-svg($carousel-control-next-icon-bg) #{"/*rtl:" + escape-svg($carousel-control-prev-icon-bg) + "*/"}; +} + +// Optional indicator pips/controls +// +// Add a container (such as a list) with the following class and add an item (ideally a focusable control, +// like a button) with data-bs-target for each slide your carousel holds. + +.carousel-indicators { + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 2; + display: flex; + justify-content: center; + padding: 0; + // Use the .carousel-control's width as margin so we don't overlay those + margin-right: $carousel-control-width; + margin-bottom: 1rem; + margin-left: $carousel-control-width; + + [data-bs-target] { + box-sizing: content-box; + flex: 0 1 auto; + width: $carousel-indicator-width; + height: $carousel-indicator-height; + padding: 0; + margin-right: $carousel-indicator-spacer; + margin-left: $carousel-indicator-spacer; + text-indent: -999px; + cursor: pointer; + background-color: $carousel-indicator-active-bg; + background-clip: padding-box; + border: 0; + // Use transparent borders to increase the hit area by 10px on top and bottom. + border-top: $carousel-indicator-hit-area-height solid transparent; + border-bottom: $carousel-indicator-hit-area-height solid transparent; + opacity: $carousel-indicator-opacity; + @include transition($carousel-indicator-transition); + } + + .active { + opacity: $carousel-indicator-active-opacity; + } +} + + +// Optional captions +// +// + +.carousel-caption { + position: absolute; + right: (100% - $carousel-caption-width) * .5; + bottom: $carousel-caption-spacer; + left: (100% - $carousel-caption-width) * .5; + padding-top: $carousel-caption-padding-y; + padding-bottom: $carousel-caption-padding-y; + color: $carousel-caption-color; + text-align: center; +} + +// Dark mode carousel + +@mixin carousel-dark() { + .carousel-control-prev-icon, + .carousel-control-next-icon { + filter: $carousel-dark-control-icon-filter; + } + + .carousel-indicators [data-bs-target] { + background-color: $carousel-dark-indicator-active-bg; + } + + .carousel-caption { + color: $carousel-dark-caption-color; + } +} + +.carousel-dark { + @include carousel-dark(); +} + +@if $enable-dark-mode { + @include color-mode(dark) { + @if $color-mode-type == "media-query" { + .carousel { + @include carousel-dark(); + } + } @else { + .carousel, + &.carousel { + @include carousel-dark(); + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_close.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_close.scss new file mode 100644 index 00000000..4d6e73c1 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_close.scss @@ -0,0 +1,63 @@ +// Transparent background and border properties included for button version. +// iOS requires the button element instead of an anchor tag. +// If you want the anchor version, it requires `href="#"`. +// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile + +.btn-close { + // scss-docs-start close-css-vars + --#{$prefix}btn-close-color: #{$btn-close-color}; + --#{$prefix}btn-close-bg: #{ escape-svg($btn-close-bg) }; + --#{$prefix}btn-close-opacity: #{$btn-close-opacity}; + --#{$prefix}btn-close-hover-opacity: #{$btn-close-hover-opacity}; + --#{$prefix}btn-close-focus-shadow: #{$btn-close-focus-shadow}; + --#{$prefix}btn-close-focus-opacity: #{$btn-close-focus-opacity}; + --#{$prefix}btn-close-disabled-opacity: #{$btn-close-disabled-opacity}; + --#{$prefix}btn-close-white-filter: #{$btn-close-white-filter}; + // scss-docs-end close-css-vars + + box-sizing: content-box; + width: $btn-close-width; + height: $btn-close-height; + padding: $btn-close-padding-y $btn-close-padding-x; + color: var(--#{$prefix}btn-close-color); + background: transparent var(--#{$prefix}btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements + border: 0; // for button elements + @include border-radius(); + opacity: var(--#{$prefix}btn-close-opacity); + + // Override <a>'s hover style + &:hover { + color: var(--#{$prefix}btn-close-color); + text-decoration: none; + opacity: var(--#{$prefix}btn-close-hover-opacity); + } + + &:focus { + outline: 0; + box-shadow: var(--#{$prefix}btn-close-focus-shadow); + opacity: var(--#{$prefix}btn-close-focus-opacity); + } + + &:disabled, + &.disabled { + pointer-events: none; + user-select: none; + opacity: var(--#{$prefix}btn-close-disabled-opacity); + } +} + +@mixin btn-close-white() { + filter: var(--#{$prefix}btn-close-white-filter); +} + +.btn-close-white { + @include btn-close-white(); +} + +@if $enable-dark-mode { + @include color-mode(dark) { + .btn-close { + @include btn-close-white(); + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_containers.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_containers.scss new file mode 100644 index 00000000..83b31381 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_containers.scss @@ -0,0 +1,41 @@ +// Container widths +// +// Set the container width, and override it for fixed navbars in media queries. + +@if $enable-container-classes { + // Single container class with breakpoint max-widths + .container, + // 100% wide container at all breakpoints + .container-fluid { + @include make-container(); + } + + // Responsive containers that are 100% wide until a breakpoint + @each $breakpoint, $container-max-width in $container-max-widths { + .container-#{$breakpoint} { + @extend .container-fluid; + } + + @include media-breakpoint-up($breakpoint, $grid-breakpoints) { + %responsive-container-#{$breakpoint} { + max-width: $container-max-width; + } + + // Extend each breakpoint which is smaller or equal to the current breakpoint + $extend-breakpoint: true; + + @each $name, $width in $grid-breakpoints { + @if ($extend-breakpoint) { + .container#{breakpoint-infix($name, $grid-breakpoints)} { + @extend %responsive-container-#{$breakpoint}; + } + + // Once the current breakpoint is reached, stop extending + @if ($breakpoint == $name) { + $extend-breakpoint: false; + } + } + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_dropdown.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_dropdown.scss new file mode 100644 index 00000000..587ebb48 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_dropdown.scss @@ -0,0 +1,250 @@ +// The dropdown wrapper (`<div>`) +.dropup, +.dropend, +.dropdown, +.dropstart, +.dropup-center, +.dropdown-center { + position: relative; +} + +.dropdown-toggle { + white-space: nowrap; + + // Generate the caret automatically + @include caret(); +} + +// The dropdown menu +.dropdown-menu { + // scss-docs-start dropdown-css-vars + --#{$prefix}dropdown-zindex: #{$zindex-dropdown}; + --#{$prefix}dropdown-min-width: #{$dropdown-min-width}; + --#{$prefix}dropdown-padding-x: #{$dropdown-padding-x}; + --#{$prefix}dropdown-padding-y: #{$dropdown-padding-y}; + --#{$prefix}dropdown-spacer: #{$dropdown-spacer}; + @include rfs($dropdown-font-size, --#{$prefix}dropdown-font-size); + --#{$prefix}dropdown-color: #{$dropdown-color}; + --#{$prefix}dropdown-bg: #{$dropdown-bg}; + --#{$prefix}dropdown-border-color: #{$dropdown-border-color}; + --#{$prefix}dropdown-border-radius: #{$dropdown-border-radius}; + --#{$prefix}dropdown-border-width: #{$dropdown-border-width}; + --#{$prefix}dropdown-inner-border-radius: #{$dropdown-inner-border-radius}; + --#{$prefix}dropdown-divider-bg: #{$dropdown-divider-bg}; + --#{$prefix}dropdown-divider-margin-y: #{$dropdown-divider-margin-y}; + --#{$prefix}dropdown-box-shadow: #{$dropdown-box-shadow}; + --#{$prefix}dropdown-link-color: #{$dropdown-link-color}; + --#{$prefix}dropdown-link-hover-color: #{$dropdown-link-hover-color}; + --#{$prefix}dropdown-link-hover-bg: #{$dropdown-link-hover-bg}; + --#{$prefix}dropdown-link-active-color: #{$dropdown-link-active-color}; + --#{$prefix}dropdown-link-active-bg: #{$dropdown-link-active-bg}; + --#{$prefix}dropdown-link-disabled-color: #{$dropdown-link-disabled-color}; + --#{$prefix}dropdown-item-padding-x: #{$dropdown-item-padding-x}; + --#{$prefix}dropdown-item-padding-y: #{$dropdown-item-padding-y}; + --#{$prefix}dropdown-header-color: #{$dropdown-header-color}; + --#{$prefix}dropdown-header-padding-x: #{$dropdown-header-padding-x}; + --#{$prefix}dropdown-header-padding-y: #{$dropdown-header-padding-y}; + // scss-docs-end dropdown-css-vars + + position: absolute; + z-index: var(--#{$prefix}dropdown-zindex); + display: none; // none by default, but block on "open" of the menu + min-width: var(--#{$prefix}dropdown-min-width); + padding: var(--#{$prefix}dropdown-padding-y) var(--#{$prefix}dropdown-padding-x); + margin: 0; // Override default margin of ul + @include font-size(var(--#{$prefix}dropdown-font-size)); + color: var(--#{$prefix}dropdown-color); + text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer) + list-style: none; + background-color: var(--#{$prefix}dropdown-bg); + background-clip: padding-box; + border: var(--#{$prefix}dropdown-border-width) solid var(--#{$prefix}dropdown-border-color); + @include border-radius(var(--#{$prefix}dropdown-border-radius)); + @include box-shadow(var(--#{$prefix}dropdown-box-shadow)); + + &[data-bs-popper] { + top: 100%; + left: 0; + margin-top: var(--#{$prefix}dropdown-spacer); + } + + @if $dropdown-padding-y == 0 { + > .dropdown-item:first-child, + > li:first-child .dropdown-item { + @include border-top-radius(var(--#{$prefix}dropdown-inner-border-radius)); + } + > .dropdown-item:last-child, + > li:last-child .dropdown-item { + @include border-bottom-radius(var(--#{$prefix}dropdown-inner-border-radius)); + } + + } +} + +// scss-docs-start responsive-breakpoints +// We deliberately hardcode the `bs-` prefix because we check +// this custom property in JS to determine Popper's positioning + +@each $breakpoint in map-keys($grid-breakpoints) { + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + .dropdown-menu#{$infix}-start { + --bs-position: start; + + &[data-bs-popper] { + right: auto; + left: 0; + } + } + + .dropdown-menu#{$infix}-end { + --bs-position: end; + + &[data-bs-popper] { + right: 0; + left: auto; + } + } + } +} +// scss-docs-end responsive-breakpoints + +// Allow for dropdowns to go bottom up (aka, dropup-menu) +// Just add .dropup after the standard .dropdown class and you're set. +.dropup { + .dropdown-menu[data-bs-popper] { + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: var(--#{$prefix}dropdown-spacer); + } + + .dropdown-toggle { + @include caret(up); + } +} + +.dropend { + .dropdown-menu[data-bs-popper] { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: var(--#{$prefix}dropdown-spacer); + } + + .dropdown-toggle { + @include caret(end); + &::after { + vertical-align: 0; + } + } +} + +.dropstart { + .dropdown-menu[data-bs-popper] { + top: 0; + right: 100%; + left: auto; + margin-top: 0; + margin-right: var(--#{$prefix}dropdown-spacer); + } + + .dropdown-toggle { + @include caret(start); + &::before { + vertical-align: 0; + } + } +} + + +// Dividers (basically an `<hr>`) within the dropdown +.dropdown-divider { + height: 0; + margin: var(--#{$prefix}dropdown-divider-margin-y) 0; + overflow: hidden; + border-top: 1px solid var(--#{$prefix}dropdown-divider-bg); + opacity: 1; // Revisit in v6 to de-dupe styles that conflict with <hr> element +} + +// Links, buttons, and more within the dropdown menu +// +// `<button>`-specific styles are denoted with `// For <button>s` +.dropdown-item { + display: block; + width: 100%; // For `<button>`s + padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x); + clear: both; + font-weight: $font-weight-normal; + color: var(--#{$prefix}dropdown-link-color); + text-align: inherit; // For `<button>`s + text-decoration: if($link-decoration == none, null, none); + white-space: nowrap; // prevent links from randomly breaking onto new lines + background-color: transparent; // For `<button>`s + border: 0; // For `<button>`s + @include border-radius(var(--#{$prefix}dropdown-item-border-radius, 0)); + + &:hover, + &:focus { + color: var(--#{$prefix}dropdown-link-hover-color); + text-decoration: if($link-hover-decoration == underline, none, null); + @include gradient-bg(var(--#{$prefix}dropdown-link-hover-bg)); + } + + &.active, + &:active { + color: var(--#{$prefix}dropdown-link-active-color); + text-decoration: none; + @include gradient-bg(var(--#{$prefix}dropdown-link-active-bg)); + } + + &.disabled, + &:disabled { + color: var(--#{$prefix}dropdown-link-disabled-color); + pointer-events: none; + background-color: transparent; + // Remove CSS gradients if they're enabled + background-image: if($enable-gradients, none, null); + } +} + +.dropdown-menu.show { + display: block; +} + +// Dropdown section headers +.dropdown-header { + display: block; + padding: var(--#{$prefix}dropdown-header-padding-y) var(--#{$prefix}dropdown-header-padding-x); + margin-bottom: 0; // for use with heading elements + @include font-size($font-size-sm); + color: var(--#{$prefix}dropdown-header-color); + white-space: nowrap; // as with > li > a +} + +// Dropdown text +.dropdown-item-text { + display: block; + padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x); + color: var(--#{$prefix}dropdown-link-color); +} + +// Dark dropdowns +.dropdown-menu-dark { + // scss-docs-start dropdown-dark-css-vars + --#{$prefix}dropdown-color: #{$dropdown-dark-color}; + --#{$prefix}dropdown-bg: #{$dropdown-dark-bg}; + --#{$prefix}dropdown-border-color: #{$dropdown-dark-border-color}; + --#{$prefix}dropdown-box-shadow: #{$dropdown-dark-box-shadow}; + --#{$prefix}dropdown-link-color: #{$dropdown-dark-link-color}; + --#{$prefix}dropdown-link-hover-color: #{$dropdown-dark-link-hover-color}; + --#{$prefix}dropdown-divider-bg: #{$dropdown-dark-divider-bg}; + --#{$prefix}dropdown-link-hover-bg: #{$dropdown-dark-link-hover-bg}; + --#{$prefix}dropdown-link-active-color: #{$dropdown-dark-link-active-color}; + --#{$prefix}dropdown-link-active-bg: #{$dropdown-dark-link-active-bg}; + --#{$prefix}dropdown-link-disabled-color: #{$dropdown-dark-link-disabled-color}; + --#{$prefix}dropdown-header-color: #{$dropdown-dark-header-color}; + // scss-docs-end dropdown-dark-css-vars +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_forms.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_forms.scss new file mode 100644 index 00000000..7b17d849 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_forms.scss @@ -0,0 +1,9 @@ +@import "forms/labels"; +@import "forms/form-text"; +@import "forms/form-control"; +@import "forms/form-select"; +@import "forms/form-check"; +@import "forms/form-range"; +@import "forms/floating-labels"; +@import "forms/input-group"; +@import "forms/validation"; diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_functions.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_functions.scss new file mode 100644 index 00000000..90296586 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_functions.scss @@ -0,0 +1,302 @@ +// Bootstrap functions +// +// Utility mixins and functions for evaluating source code across our variables, maps, and mixins. + +// Ascending +// Used to evaluate Sass maps like our grid breakpoints. +@mixin _assert-ascending($map, $map-name) { + $prev-key: null; + $prev-num: null; + @each $key, $num in $map { + @if $prev-num == null or unit($num) == "%" or unit($prev-num) == "%" { + // Do nothing + } @else if not comparable($prev-num, $num) { + @warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !"; + } @else if $prev-num >= $num { + @warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !"; + } + $prev-key: $key; + $prev-num: $num; + } +} + +// Starts at zero +// Used to ensure the min-width of the lowest breakpoint starts at 0. +@mixin _assert-starts-at-zero($map, $map-name: "$grid-breakpoints") { + @if length($map) > 0 { + $values: map-values($map); + $first-value: nth($values, 1); + @if $first-value != 0 { + @warn "First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}."; + } + } +} + +// Colors +@function to-rgb($value) { + @return red($value), green($value), blue($value); +} + +// stylelint-disable scss/dollar-variable-pattern +@function rgba-css-var($identifier, $target) { + @if $identifier == "body" and $target == "bg" { + @return rgba(var(--#{$prefix}#{$identifier}-bg-rgb), var(--#{$prefix}#{$target}-opacity)); + } @if $identifier == "body" and $target == "text" { + @return rgba(var(--#{$prefix}#{$identifier}-color-rgb), var(--#{$prefix}#{$target}-opacity)); + } @else { + @return rgba(var(--#{$prefix}#{$identifier}-rgb), var(--#{$prefix}#{$target}-opacity)); + } +} + +@function map-loop($map, $func, $args...) { + $_map: (); + + @each $key, $value in $map { + // allow to pass the $key and $value of the map as an function argument + $_args: (); + @each $arg in $args { + $_args: append($_args, if($arg == "$key", $key, if($arg == "$value", $value, $arg))); + } + + $_map: map-merge($_map, ($key: call(get-function($func), $_args...))); + } + + @return $_map; +} +// stylelint-enable scss/dollar-variable-pattern + +@function varify($list) { + $result: null; + @each $entry in $list { + $result: append($result, var(--#{$prefix}#{$entry}), space); + } + @return $result; +} + +// Internal Bootstrap function to turn maps into its negative variant. +// It prefixes the keys with `n` and makes the value negative. +@function negativify-map($map) { + $result: (); + @each $key, $value in $map { + @if $key != 0 { + $result: map-merge($result, ("n" + $key: (-$value))); + } + } + @return $result; +} + +// Get multiple keys from a sass map +@function map-get-multiple($map, $values) { + $result: (); + @each $key, $value in $map { + @if (index($values, $key) != null) { + $result: map-merge($result, ($key: $value)); + } + } + @return $result; +} + +// Merge multiple maps +@function map-merge-multiple($maps...) { + $merged-maps: (); + + @each $map in $maps { + $merged-maps: map-merge($merged-maps, $map); + } + @return $merged-maps; +} + +// Replace `$search` with `$replace` in `$string` +// Used on our SVG icon backgrounds for custom forms. +// +// @author Kitty Giraudel +// @param {String} $string - Initial string +// @param {String} $search - Substring to replace +// @param {String} $replace ('') - New value +// @return {String} - Updated string +@function str-replace($string, $search, $replace: "") { + $index: str-index($string, $search); + + @if $index { + @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); + } + + @return $string; +} + +// See https://codepen.io/kevinweber/pen/dXWoRw +// +// Requires the use of quotes around data URIs. + +@function escape-svg($string) { + @if str-index($string, "data:image/svg+xml") { + @each $char, $encoded in $escaped-characters { + // Do not escape the url brackets + @if str-index($string, "url(") == 1 { + $string: url("#{str-replace(str-slice($string, 6, -3), $char, $encoded)}"); + } @else { + $string: str-replace($string, $char, $encoded); + } + } + } + + @return $string; +} + +// Color contrast +// See https://github.com/twbs/bootstrap/pull/30168 + +// A list of pre-calculated numbers of pow(divide((divide($value, 255) + .055), 1.055), 2.4). (from 0 to 255) +// stylelint-disable-next-line scss/dollar-variable-default, scss/dollar-variable-pattern +$_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003 .0033 .0037 .004 .0044 .0048 .0052 .0056 .006 .0065 .007 .0075 .008 .0086 .0091 .0097 .0103 .011 .0116 .0123 .013 .0137 .0144 .0152 .016 .0168 .0176 .0185 .0194 .0203 .0212 .0222 .0232 .0242 .0252 .0262 .0273 .0284 .0296 .0307 .0319 .0331 .0343 .0356 .0369 .0382 .0395 .0409 .0423 .0437 .0452 .0467 .0482 .0497 .0513 .0529 .0545 .0561 .0578 .0595 .0612 .063 .0648 .0666 .0685 .0704 .0723 .0742 .0762 .0782 .0802 .0823 .0844 .0865 .0887 .0908 .0931 .0953 .0976 .0999 .1022 .1046 .107 .1095 .1119 .1144 .117 .1195 .1221 .1248 .1274 .1301 .1329 .1356 .1384 .1413 .1441 .147 .15 .1529 .1559 .159 .162 .1651 .1683 .1714 .1746 .1779 .1812 .1845 .1878 .1912 .1946 .1981 .2016 .2051 .2086 .2122 .2159 .2195 .2232 .227 .2307 .2346 .2384 .2423 .2462 .2502 .2542 .2582 .2623 .2664 .2705 .2747 .2789 .2831 .2874 .2918 .2961 .3005 .305 .3095 .314 .3185 .3231 .3278 .3325 .3372 .3419 .3467 .3515 .3564 .3613 .3663 .3712 .3763 .3813 .3864 .3916 .3968 .402 .4072 .4125 .4179 .4233 .4287 .4342 .4397 .4452 .4508 .4564 .4621 .4678 .4735 .4793 .4851 .491 .4969 .5029 .5089 .5149 .521 .5271 .5333 .5395 .5457 .552 .5583 .5647 .5711 .5776 .5841 .5906 .5972 .6038 .6105 .6172 .624 .6308 .6376 .6445 .6514 .6584 .6654 .6724 .6795 .6867 .6939 .7011 .7084 .7157 .7231 .7305 .7379 .7454 .7529 .7605 .7682 .7758 .7835 .7913 .7991 .807 .8148 .8228 .8308 .8388 .8469 .855 .8632 .8714 .8796 .8879 .8963 .9047 .9131 .9216 .9301 .9387 .9473 .956 .9647 .9734 .9823 .9911 1; + +@function color-contrast($background, $color-contrast-dark: $color-contrast-dark, $color-contrast-light: $color-contrast-light, $min-contrast-ratio: $min-contrast-ratio) { + $foregrounds: $color-contrast-light, $color-contrast-dark, $white, $black; + $max-ratio: 0; + $max-ratio-color: null; + + @each $color in $foregrounds { + $contrast-ratio: contrast-ratio($background, $color); + @if $contrast-ratio > $min-contrast-ratio { + @return $color; + } @else if $contrast-ratio > $max-ratio { + $max-ratio: $contrast-ratio; + $max-ratio-color: $color; + } + } + + @warn "Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$background}..."; + + @return $max-ratio-color; +} + +@function contrast-ratio($background, $foreground: $color-contrast-light) { + $l1: luminance($background); + $l2: luminance(opaque($background, $foreground)); + + @return if($l1 > $l2, divide($l1 + .05, $l2 + .05), divide($l2 + .05, $l1 + .05)); +} + +// Return WCAG2.1 relative luminance +// See https://www.w3.org/TR/WCAG/#dfn-relative-luminance +// See https://www.w3.org/TR/WCAG/#dfn-contrast-ratio +@function luminance($color) { + $rgb: ( + "r": red($color), + "g": green($color), + "b": blue($color) + ); + + @each $name, $value in $rgb { + $value: if(divide($value, 255) < .04045, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1)); + $rgb: map-merge($rgb, ($name: $value)); + } + + @return (map-get($rgb, "r") * .2126) + (map-get($rgb, "g") * .7152) + (map-get($rgb, "b") * .0722); +} + +// Return opaque color +// opaque(#fff, rgba(0, 0, 0, .5)) => #808080 +@function opaque($background, $foreground) { + @return mix(rgba($foreground, 1), $background, opacity($foreground) * 100%); +} + +// scss-docs-start color-functions +// Tint a color: mix a color with white +@function tint-color($color, $weight) { + @return mix(white, $color, $weight); +} + +// Shade a color: mix a color with black +@function shade-color($color, $weight) { + @return mix(black, $color, $weight); +} + +// Shade the color if the weight is positive, else tint it +@function shift-color($color, $weight) { + @return if($weight > 0, shade-color($color, $weight), tint-color($color, -$weight)); +} +// scss-docs-end color-functions + +// Return valid calc +@function add($value1, $value2, $return-calc: true) { + @if $value1 == null { + @return $value2; + } + + @if $value2 == null { + @return $value1; + } + + @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) { + @return $value1 + $value2; + } + + @return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(" + ") + $value2); +} + +@function subtract($value1, $value2, $return-calc: true) { + @if $value1 == null and $value2 == null { + @return null; + } + + @if $value1 == null { + @return -$value2; + } + + @if $value2 == null { + @return $value1; + } + + @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) { + @return $value1 - $value2; + } + + @if type-of($value2) != number { + $value2: unquote("(") + $value2 + unquote(")"); + } + + @return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(" - ") + $value2); +} + +@function divide($dividend, $divisor, $precision: 10) { + $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1); + $dividend: abs($dividend); + $divisor: abs($divisor); + @if $dividend == 0 { + @return 0; + } + @if $divisor == 0 { + @error "Cannot divide by 0"; + } + $remainder: $dividend; + $result: 0; + $factor: 10; + @while ($remainder > 0 and $precision >= 0) { + $quotient: 0; + @while ($remainder >= $divisor) { + $remainder: $remainder - $divisor; + $quotient: $quotient + 1; + } + $result: $result * 10 + $quotient; + $factor: $factor * .1; + $remainder: $remainder * 10; + $precision: $precision - 1; + @if ($precision < 0 and $remainder >= $divisor * 5) { + $result: $result + 1; + } + } + $result: $result * $factor * $sign; + $dividend-unit: unit($dividend); + $divisor-unit: unit($divisor); + $unit-map: ( + "px": 1px, + "rem": 1rem, + "em": 1em, + "%": 1% + ); + @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) { + $result: $result * map-get($unit-map, $dividend-unit); + } + @return $result; +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_grid.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_grid.scss new file mode 100644 index 00000000..048f8009 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_grid.scss @@ -0,0 +1,39 @@ +// Row +// +// Rows contain your columns. + +:root { + @each $name, $value in $grid-breakpoints { + --#{$prefix}breakpoint-#{$name}: #{$value}; + } +} + +@if $enable-grid-classes { + .row { + @include make-row(); + + > * { + @include make-col-ready(); + } + } +} + +@if $enable-cssgrid { + .grid { + display: grid; + grid-template-rows: repeat(var(--#{$prefix}rows, 1), 1fr); + grid-template-columns: repeat(var(--#{$prefix}columns, #{$grid-columns}), 1fr); + gap: var(--#{$prefix}gap, #{$grid-gutter-width}); + + @include make-cssgrid(); + } +} + + +// Columns +// +// Common styles for small and large grid columns + +@if $enable-grid-classes { + @include make-grid-columns(); +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_helpers.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_helpers.scss new file mode 100644 index 00000000..13f2752c --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_helpers.scss @@ -0,0 +1,12 @@ +@import "helpers/clearfix"; +@import "helpers/color-bg"; +@import "helpers/colored-links"; +@import "helpers/focus-ring"; +@import "helpers/icon-link"; +@import "helpers/ratio"; +@import "helpers/position"; +@import "helpers/stacks"; +@import "helpers/visually-hidden"; +@import "helpers/stretched-link"; +@import "helpers/text-truncation"; +@import "helpers/vr"; diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_images.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_images.scss new file mode 100644 index 00000000..3d6a1014 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_images.scss @@ -0,0 +1,42 @@ +// Responsive images (ensure images don't scale beyond their parents) +// +// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s. +// We previously tried the "images are responsive by default" approach in Bootstrap v2, +// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps) +// which weren't expecting the images within themselves to be involuntarily resized. +// See also https://github.com/twbs/bootstrap/issues/18178 +.img-fluid { + @include img-fluid(); +} + + +// Image thumbnails +.img-thumbnail { + padding: $thumbnail-padding; + background-color: $thumbnail-bg; + border: $thumbnail-border-width solid $thumbnail-border-color; + @include border-radius($thumbnail-border-radius); + @include box-shadow($thumbnail-box-shadow); + + // Keep them at most 100% wide + @include img-fluid(); +} + +// +// Figures +// + +.figure { + // Ensures the caption's text aligns with the image. + display: inline-block; +} + +.figure-img { + margin-bottom: $spacer * .5; + line-height: 1; +} + +.figure-caption { + @include font-size($figure-caption-font-size); + color: $figure-caption-color; +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_list-group.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_list-group.scss new file mode 100644 index 00000000..455531ee --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_list-group.scss @@ -0,0 +1,197 @@ +// Base class +// +// Easily usable on <ul>, <ol>, or <div>. + +.list-group { + // scss-docs-start list-group-css-vars + --#{$prefix}list-group-color: #{$list-group-color}; + --#{$prefix}list-group-bg: #{$list-group-bg}; + --#{$prefix}list-group-border-color: #{$list-group-border-color}; + --#{$prefix}list-group-border-width: #{$list-group-border-width}; + --#{$prefix}list-group-border-radius: #{$list-group-border-radius}; + --#{$prefix}list-group-item-padding-x: #{$list-group-item-padding-x}; + --#{$prefix}list-group-item-padding-y: #{$list-group-item-padding-y}; + --#{$prefix}list-group-action-color: #{$list-group-action-color}; + --#{$prefix}list-group-action-hover-color: #{$list-group-action-hover-color}; + --#{$prefix}list-group-action-hover-bg: #{$list-group-hover-bg}; + --#{$prefix}list-group-action-active-color: #{$list-group-action-active-color}; + --#{$prefix}list-group-action-active-bg: #{$list-group-action-active-bg}; + --#{$prefix}list-group-disabled-color: #{$list-group-disabled-color}; + --#{$prefix}list-group-disabled-bg: #{$list-group-disabled-bg}; + --#{$prefix}list-group-active-color: #{$list-group-active-color}; + --#{$prefix}list-group-active-bg: #{$list-group-active-bg}; + --#{$prefix}list-group-active-border-color: #{$list-group-active-border-color}; + // scss-docs-end list-group-css-vars + + display: flex; + flex-direction: column; + + // No need to set list-style: none; since .list-group-item is block level + padding-left: 0; // reset padding because ul and ol + margin-bottom: 0; + @include border-radius(var(--#{$prefix}list-group-border-radius)); +} + +.list-group-numbered { + list-style-type: none; + counter-reset: section; + + > .list-group-item::before { + // Increments only this instance of the section counter + content: counters(section, ".") ". "; + counter-increment: section; + } +} + +// Interactive list items +// +// Use anchor or button elements instead of `li`s or `div`s to create interactive +// list items. Includes an extra `.active` modifier class for selected items. + +.list-group-item-action { + width: 100%; // For `<button>`s (anchors become 100% by default though) + color: var(--#{$prefix}list-group-action-color); + text-align: inherit; // For `<button>`s (anchors inherit) + + // Hover state + &:hover, + &:focus { + z-index: 1; // Place hover/focus items above their siblings for proper border styling + color: var(--#{$prefix}list-group-action-hover-color); + text-decoration: none; + background-color: var(--#{$prefix}list-group-action-hover-bg); + } + + &:active { + color: var(--#{$prefix}list-group-action-active-color); + background-color: var(--#{$prefix}list-group-action-active-bg); + } +} + +// Individual list items +// +// Use on `li`s or `div`s within the `.list-group` parent. + +.list-group-item { + position: relative; + display: block; + padding: var(--#{$prefix}list-group-item-padding-y) var(--#{$prefix}list-group-item-padding-x); + color: var(--#{$prefix}list-group-color); + text-decoration: if($link-decoration == none, null, none); + background-color: var(--#{$prefix}list-group-bg); + border: var(--#{$prefix}list-group-border-width) solid var(--#{$prefix}list-group-border-color); + + &:first-child { + @include border-top-radius(inherit); + } + + &:last-child { + @include border-bottom-radius(inherit); + } + + &.disabled, + &:disabled { + color: var(--#{$prefix}list-group-disabled-color); + pointer-events: none; + background-color: var(--#{$prefix}list-group-disabled-bg); + } + + // Include both here for `<a>`s and `<button>`s + &.active { + z-index: 2; // Place active items above their siblings for proper border styling + color: var(--#{$prefix}list-group-active-color); + background-color: var(--#{$prefix}list-group-active-bg); + border-color: var(--#{$prefix}list-group-active-border-color); + } + + // stylelint-disable-next-line scss/selector-no-redundant-nesting-selector + & + .list-group-item { + border-top-width: 0; + + &.active { + margin-top: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list + border-top-width: var(--#{$prefix}list-group-border-width); + } + } +} + +// Horizontal +// +// Change the layout of list group items from vertical (default) to horizontal. + +@each $breakpoint in map-keys($grid-breakpoints) { + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + .list-group-horizontal#{$infix} { + flex-direction: row; + + > .list-group-item { + &:first-child:not(:last-child) { + @include border-bottom-start-radius(var(--#{$prefix}list-group-border-radius)); + @include border-top-end-radius(0); + } + + &:last-child:not(:first-child) { + @include border-top-end-radius(var(--#{$prefix}list-group-border-radius)); + @include border-bottom-start-radius(0); + } + + &.active { + margin-top: 0; + } + + + .list-group-item { + border-top-width: var(--#{$prefix}list-group-border-width); + border-left-width: 0; + + &.active { + margin-left: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list + border-left-width: var(--#{$prefix}list-group-border-width); + } + } + } + } + } +} + + +// Flush list items +// +// Remove borders and border-radius to keep list group items edge-to-edge. Most +// useful within other components (e.g., cards). + +.list-group-flush { + @include border-radius(0); + + > .list-group-item { + border-width: 0 0 var(--#{$prefix}list-group-border-width); + + &:last-child { + border-bottom-width: 0; + } + } +} + + +// scss-docs-start list-group-modifiers +// List group contextual variants +// +// Add modifier classes to change text and background color on individual items. +// Organizationally, this must come after the `:hover` states. + +@each $state in map-keys($theme-colors) { + .list-group-item-#{$state} { + --#{$prefix}list-group-color: var(--#{$prefix}#{$state}-text-emphasis); + --#{$prefix}list-group-bg: var(--#{$prefix}#{$state}-bg-subtle); + --#{$prefix}list-group-border-color: var(--#{$prefix}#{$state}-border-subtle); + --#{$prefix}list-group-action-hover-color: var(--#{$prefix}emphasis-color); + --#{$prefix}list-group-action-hover-bg: var(--#{$prefix}#{$state}-border-subtle); + --#{$prefix}list-group-action-active-color: var(--#{$prefix}emphasis-color); + --#{$prefix}list-group-action-active-bg: var(--#{$prefix}#{$state}-border-subtle); + --#{$prefix}list-group-active-color: var(--#{$prefix}#{$state}-bg-subtle); + --#{$prefix}list-group-active-bg: var(--#{$prefix}#{$state}-text-emphasis); + --#{$prefix}list-group-active-border-color: var(--#{$prefix}#{$state}-text-emphasis); + } +} +// scss-docs-end list-group-modifiers diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_maps.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_maps.scss new file mode 100644 index 00000000..68ee421c --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_maps.scss @@ -0,0 +1,174 @@ +// Re-assigned maps +// +// Placed here so that others can override the default Sass maps and see automatic updates to utilities and more. + +// scss-docs-start theme-colors-rgb +$theme-colors-rgb: map-loop($theme-colors, to-rgb, "$value") !default; +// scss-docs-end theme-colors-rgb + +// scss-docs-start theme-text-map +$theme-colors-text: ( + "primary": $primary-text-emphasis, + "secondary": $secondary-text-emphasis, + "success": $success-text-emphasis, + "info": $info-text-emphasis, + "warning": $warning-text-emphasis, + "danger": $danger-text-emphasis, + "light": $light-text-emphasis, + "dark": $dark-text-emphasis, +) !default; +// scss-docs-end theme-text-map + +// scss-docs-start theme-bg-subtle-map +$theme-colors-bg-subtle: ( + "primary": $primary-bg-subtle, + "secondary": $secondary-bg-subtle, + "success": $success-bg-subtle, + "info": $info-bg-subtle, + "warning": $warning-bg-subtle, + "danger": $danger-bg-subtle, + "light": $light-bg-subtle, + "dark": $dark-bg-subtle, +) !default; +// scss-docs-end theme-bg-subtle-map + +// scss-docs-start theme-border-subtle-map +$theme-colors-border-subtle: ( + "primary": $primary-border-subtle, + "secondary": $secondary-border-subtle, + "success": $success-border-subtle, + "info": $info-border-subtle, + "warning": $warning-border-subtle, + "danger": $danger-border-subtle, + "light": $light-border-subtle, + "dark": $dark-border-subtle, +) !default; +// scss-docs-end theme-border-subtle-map + +$theme-colors-text-dark: null !default; +$theme-colors-bg-subtle-dark: null !default; +$theme-colors-border-subtle-dark: null !default; + +@if $enable-dark-mode { + // scss-docs-start theme-text-dark-map + $theme-colors-text-dark: ( + "primary": $primary-text-emphasis-dark, + "secondary": $secondary-text-emphasis-dark, + "success": $success-text-emphasis-dark, + "info": $info-text-emphasis-dark, + "warning": $warning-text-emphasis-dark, + "danger": $danger-text-emphasis-dark, + "light": $light-text-emphasis-dark, + "dark": $dark-text-emphasis-dark, + ) !default; + // scss-docs-end theme-text-dark-map + + // scss-docs-start theme-bg-subtle-dark-map + $theme-colors-bg-subtle-dark: ( + "primary": $primary-bg-subtle-dark, + "secondary": $secondary-bg-subtle-dark, + "success": $success-bg-subtle-dark, + "info": $info-bg-subtle-dark, + "warning": $warning-bg-subtle-dark, + "danger": $danger-bg-subtle-dark, + "light": $light-bg-subtle-dark, + "dark": $dark-bg-subtle-dark, + ) !default; + // scss-docs-end theme-bg-subtle-dark-map + + // scss-docs-start theme-border-subtle-dark-map + $theme-colors-border-subtle-dark: ( + "primary": $primary-border-subtle-dark, + "secondary": $secondary-border-subtle-dark, + "success": $success-border-subtle-dark, + "info": $info-border-subtle-dark, + "warning": $warning-border-subtle-dark, + "danger": $danger-border-subtle-dark, + "light": $light-border-subtle-dark, + "dark": $dark-border-subtle-dark, + ) !default; + // scss-docs-end theme-border-subtle-dark-map +} + +// Utilities maps +// +// Extends the default `$theme-colors` maps to help create our utilities. + +// Come v6, we'll de-dupe these variables. Until then, for backward compatibility, we keep them to reassign. +// scss-docs-start utilities-colors +$utilities-colors: $theme-colors-rgb !default; +// scss-docs-end utilities-colors + +// scss-docs-start utilities-text-colors +$utilities-text: map-merge( + $utilities-colors, + ( + "black": to-rgb($black), + "white": to-rgb($white), + "body": to-rgb($body-color) + ) +) !default; +$utilities-text-colors: map-loop($utilities-text, rgba-css-var, "$key", "text") !default; + +$utilities-text-emphasis-colors: ( + "primary-emphasis": var(--#{$prefix}primary-text-emphasis), + "secondary-emphasis": var(--#{$prefix}secondary-text-emphasis), + "success-emphasis": var(--#{$prefix}success-text-emphasis), + "info-emphasis": var(--#{$prefix}info-text-emphasis), + "warning-emphasis": var(--#{$prefix}warning-text-emphasis), + "danger-emphasis": var(--#{$prefix}danger-text-emphasis), + "light-emphasis": var(--#{$prefix}light-text-emphasis), + "dark-emphasis": var(--#{$prefix}dark-text-emphasis) +) !default; +// scss-docs-end utilities-text-colors + +// scss-docs-start utilities-bg-colors +$utilities-bg: map-merge( + $utilities-colors, + ( + "black": to-rgb($black), + "white": to-rgb($white), + "body": to-rgb($body-bg) + ) +) !default; +$utilities-bg-colors: map-loop($utilities-bg, rgba-css-var, "$key", "bg") !default; + +$utilities-bg-subtle: ( + "primary-subtle": var(--#{$prefix}primary-bg-subtle), + "secondary-subtle": var(--#{$prefix}secondary-bg-subtle), + "success-subtle": var(--#{$prefix}success-bg-subtle), + "info-subtle": var(--#{$prefix}info-bg-subtle), + "warning-subtle": var(--#{$prefix}warning-bg-subtle), + "danger-subtle": var(--#{$prefix}danger-bg-subtle), + "light-subtle": var(--#{$prefix}light-bg-subtle), + "dark-subtle": var(--#{$prefix}dark-bg-subtle) +) !default; +// scss-docs-end utilities-bg-colors + +// scss-docs-start utilities-border-colors +$utilities-border: map-merge( + $utilities-colors, + ( + "black": to-rgb($black), + "white": to-rgb($white) + ) +) !default; +$utilities-border-colors: map-loop($utilities-border, rgba-css-var, "$key", "border") !default; + +$utilities-border-subtle: ( + "primary-subtle": var(--#{$prefix}primary-border-subtle), + "secondary-subtle": var(--#{$prefix}secondary-border-subtle), + "success-subtle": var(--#{$prefix}success-border-subtle), + "info-subtle": var(--#{$prefix}info-border-subtle), + "warning-subtle": var(--#{$prefix}warning-border-subtle), + "danger-subtle": var(--#{$prefix}danger-border-subtle), + "light-subtle": var(--#{$prefix}light-border-subtle), + "dark-subtle": var(--#{$prefix}dark-border-subtle) +) !default; +// scss-docs-end utilities-border-colors + +$utilities-links-underline: map-loop($utilities-colors, rgba-css-var, "$key", "link-underline") !default; + +$negative-spacers: if($enable-negative-margins, negativify-map($spacers), null) !default; + +$gutters: $spacers !default; diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_mixins.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_mixins.scss new file mode 100644 index 00000000..e1e130b1 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_mixins.scss @@ -0,0 +1,42 @@ +// Toggles +// +// Used in conjunction with global variables to enable certain theme features. + +// Vendor +@import "vendor/rfs"; + +// Deprecate +@import "mixins/deprecate"; + +// Helpers +@import "mixins/breakpoints"; +@import "mixins/color-mode"; +@import "mixins/color-scheme"; +@import "mixins/image"; +@import "mixins/resize"; +@import "mixins/visually-hidden"; +@import "mixins/reset-text"; +@import "mixins/text-truncate"; + +// Utilities +@import "mixins/utilities"; + +// Components +@import "mixins/backdrop"; +@import "mixins/buttons"; +@import "mixins/caret"; +@import "mixins/pagination"; +@import "mixins/lists"; +@import "mixins/forms"; +@import "mixins/table-variants"; + +// Skins +@import "mixins/border-radius"; +@import "mixins/box-shadow"; +@import "mixins/gradients"; +@import "mixins/transition"; + +// Layout +@import "mixins/clearfix"; +@import "mixins/container"; +@import "mixins/grid"; diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_modal.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_modal.scss new file mode 100644 index 00000000..494db94e --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_modal.scss @@ -0,0 +1,236 @@ +// stylelint-disable function-disallowed-list + +// .modal-open - body class for killing the scroll +// .modal - container to scroll within +// .modal-dialog - positioning shell for the actual modal +// .modal-content - actual modal w/ bg and corners and stuff + + +// Container that the modal scrolls within +.modal { + // scss-docs-start modal-css-vars + --#{$prefix}modal-zindex: #{$zindex-modal}; + --#{$prefix}modal-width: #{$modal-md}; + --#{$prefix}modal-padding: #{$modal-inner-padding}; + --#{$prefix}modal-margin: #{$modal-dialog-margin}; + --#{$prefix}modal-color: #{$modal-content-color}; + --#{$prefix}modal-bg: #{$modal-content-bg}; + --#{$prefix}modal-border-color: #{$modal-content-border-color}; + --#{$prefix}modal-border-width: #{$modal-content-border-width}; + --#{$prefix}modal-border-radius: #{$modal-content-border-radius}; + --#{$prefix}modal-box-shadow: #{$modal-content-box-shadow-xs}; + --#{$prefix}modal-inner-border-radius: #{$modal-content-inner-border-radius}; + --#{$prefix}modal-header-padding-x: #{$modal-header-padding-x}; + --#{$prefix}modal-header-padding-y: #{$modal-header-padding-y}; + --#{$prefix}modal-header-padding: #{$modal-header-padding}; // Todo in v6: Split this padding into x and y + --#{$prefix}modal-header-border-color: #{$modal-header-border-color}; + --#{$prefix}modal-header-border-width: #{$modal-header-border-width}; + --#{$prefix}modal-title-line-height: #{$modal-title-line-height}; + --#{$prefix}modal-footer-gap: #{$modal-footer-margin-between}; + --#{$prefix}modal-footer-bg: #{$modal-footer-bg}; + --#{$prefix}modal-footer-border-color: #{$modal-footer-border-color}; + --#{$prefix}modal-footer-border-width: #{$modal-footer-border-width}; + // scss-docs-end modal-css-vars + + position: fixed; + top: 0; + left: 0; + z-index: var(--#{$prefix}modal-zindex); + display: none; + width: 100%; + height: 100%; + overflow-x: hidden; + overflow-y: auto; + // Prevent Chrome on Windows from adding a focus outline. For details, see + // https://github.com/twbs/bootstrap/pull/10951. + outline: 0; + // We deliberately don't use `-webkit-overflow-scrolling: touch;` due to a + // gnarly iOS Safari bug: https://bugs.webkit.org/show_bug.cgi?id=158342 + // See also https://github.com/twbs/bootstrap/issues/17695 +} + +// Shell div to position the modal with bottom padding +.modal-dialog { + position: relative; + width: auto; + margin: var(--#{$prefix}modal-margin); + // allow clicks to pass through for custom click handling to close modal + pointer-events: none; + + // When fading in the modal, animate it to slide down + .modal.fade & { + @include transition($modal-transition); + transform: $modal-fade-transform; + } + .modal.show & { + transform: $modal-show-transform; + } + + // When trying to close, animate focus to scale + .modal.modal-static & { + transform: $modal-scale-transform; + } +} + +.modal-dialog-scrollable { + height: calc(100% - var(--#{$prefix}modal-margin) * 2); + + .modal-content { + max-height: 100%; + overflow: hidden; + } + + .modal-body { + overflow-y: auto; + } +} + +.modal-dialog-centered { + display: flex; + align-items: center; + min-height: calc(100% - var(--#{$prefix}modal-margin) * 2); +} + +// Actual modal +.modal-content { + position: relative; + display: flex; + flex-direction: column; + width: 100%; // Ensure `.modal-content` extends the full width of the parent `.modal-dialog` + // counteract the pointer-events: none; in the .modal-dialog + color: var(--#{$prefix}modal-color); + pointer-events: auto; + background-color: var(--#{$prefix}modal-bg); + background-clip: padding-box; + border: var(--#{$prefix}modal-border-width) solid var(--#{$prefix}modal-border-color); + @include border-radius(var(--#{$prefix}modal-border-radius)); + @include box-shadow(var(--#{$prefix}modal-box-shadow)); + // Remove focus outline from opened modal + outline: 0; +} + +// Modal background +.modal-backdrop { + // scss-docs-start modal-backdrop-css-vars + --#{$prefix}backdrop-zindex: #{$zindex-modal-backdrop}; + --#{$prefix}backdrop-bg: #{$modal-backdrop-bg}; + --#{$prefix}backdrop-opacity: #{$modal-backdrop-opacity}; + // scss-docs-end modal-backdrop-css-vars + + @include overlay-backdrop(var(--#{$prefix}backdrop-zindex), var(--#{$prefix}backdrop-bg), var(--#{$prefix}backdrop-opacity)); +} + +// Modal header +// Top section of the modal w/ title and dismiss +.modal-header { + display: flex; + flex-shrink: 0; + align-items: center; + padding: var(--#{$prefix}modal-header-padding); + border-bottom: var(--#{$prefix}modal-header-border-width) solid var(--#{$prefix}modal-header-border-color); + @include border-top-radius(var(--#{$prefix}modal-inner-border-radius)); + + .btn-close { + padding: calc(var(--#{$prefix}modal-header-padding-y) * .5) calc(var(--#{$prefix}modal-header-padding-x) * .5); + margin: calc(-.5 * var(--#{$prefix}modal-header-padding-y)) calc(-.5 * var(--#{$prefix}modal-header-padding-x)) calc(-.5 * var(--#{$prefix}modal-header-padding-y)) auto; + } +} + +// Title text within header +.modal-title { + margin-bottom: 0; + line-height: var(--#{$prefix}modal-title-line-height); +} + +// Modal body +// Where all modal content resides (sibling of .modal-header and .modal-footer) +.modal-body { + position: relative; + // Enable `flex-grow: 1` so that the body take up as much space as possible + // when there should be a fixed height on `.modal-dialog`. + flex: 1 1 auto; + padding: var(--#{$prefix}modal-padding); +} + +// Footer (for actions) +.modal-footer { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + align-items: center; // vertically center + justify-content: flex-end; // Right align buttons with flex property because text-align doesn't work on flex items + padding: calc(var(--#{$prefix}modal-padding) - var(--#{$prefix}modal-footer-gap) * .5); + background-color: var(--#{$prefix}modal-footer-bg); + border-top: var(--#{$prefix}modal-footer-border-width) solid var(--#{$prefix}modal-footer-border-color); + @include border-bottom-radius(var(--#{$prefix}modal-inner-border-radius)); + + // Place margin between footer elements + // This solution is far from ideal because of the universal selector usage, + // but is needed to fix https://github.com/twbs/bootstrap/issues/24800 + > * { + margin: calc(var(--#{$prefix}modal-footer-gap) * .5); // Todo in v6: replace with gap on parent class + } +} + +// Scale up the modal +@include media-breakpoint-up(sm) { + .modal { + --#{$prefix}modal-margin: #{$modal-dialog-margin-y-sm-up}; + --#{$prefix}modal-box-shadow: #{$modal-content-box-shadow-sm-up}; + } + + // Automatically set modal's width for larger viewports + .modal-dialog { + max-width: var(--#{$prefix}modal-width); + margin-right: auto; + margin-left: auto; + } + + .modal-sm { + --#{$prefix}modal-width: #{$modal-sm}; + } +} + +@include media-breakpoint-up(lg) { + .modal-lg, + .modal-xl { + --#{$prefix}modal-width: #{$modal-lg}; + } +} + +@include media-breakpoint-up(xl) { + .modal-xl { + --#{$prefix}modal-width: #{$modal-xl}; + } +} + +// scss-docs-start modal-fullscreen-loop +@each $breakpoint in map-keys($grid-breakpoints) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + $postfix: if($infix != "", $infix + "-down", ""); + + @include media-breakpoint-down($breakpoint) { + .modal-fullscreen#{$postfix} { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + + .modal-content { + height: 100%; + border: 0; + @include border-radius(0); + } + + .modal-header, + .modal-footer { + @include border-radius(0); + } + + .modal-body { + overflow-y: auto; + } + } + } +} +// scss-docs-end modal-fullscreen-loop diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_nav.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_nav.scss new file mode 100644 index 00000000..ff073d36 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_nav.scss @@ -0,0 +1,197 @@ +// Base class +// +// Kickstart any navigation component with a set of style resets. Works with +// `<nav>`s, `<ul>`s or `<ol>`s. + +.nav { + // scss-docs-start nav-css-vars + --#{$prefix}nav-link-padding-x: #{$nav-link-padding-x}; + --#{$prefix}nav-link-padding-y: #{$nav-link-padding-y}; + @include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size); + --#{$prefix}nav-link-font-weight: #{$nav-link-font-weight}; + --#{$prefix}nav-link-color: #{$nav-link-color}; + --#{$prefix}nav-link-hover-color: #{$nav-link-hover-color}; + --#{$prefix}nav-link-disabled-color: #{$nav-link-disabled-color}; + // scss-docs-end nav-css-vars + + display: flex; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav-link { + display: block; + padding: var(--#{$prefix}nav-link-padding-y) var(--#{$prefix}nav-link-padding-x); + @include font-size(var(--#{$prefix}nav-link-font-size)); + font-weight: var(--#{$prefix}nav-link-font-weight); + color: var(--#{$prefix}nav-link-color); + text-decoration: if($link-decoration == none, null, none); + background: none; + border: 0; + @include transition($nav-link-transition); + + &:hover, + &:focus { + color: var(--#{$prefix}nav-link-hover-color); + text-decoration: if($link-hover-decoration == underline, none, null); + } + + &:focus-visible { + outline: 0; + box-shadow: $nav-link-focus-box-shadow; + } + + // Disabled state lightens text + &.disabled, + &:disabled { + color: var(--#{$prefix}nav-link-disabled-color); + pointer-events: none; + cursor: default; + } +} + +// +// Tabs +// + +.nav-tabs { + // scss-docs-start nav-tabs-css-vars + --#{$prefix}nav-tabs-border-width: #{$nav-tabs-border-width}; + --#{$prefix}nav-tabs-border-color: #{$nav-tabs-border-color}; + --#{$prefix}nav-tabs-border-radius: #{$nav-tabs-border-radius}; + --#{$prefix}nav-tabs-link-hover-border-color: #{$nav-tabs-link-hover-border-color}; + --#{$prefix}nav-tabs-link-active-color: #{$nav-tabs-link-active-color}; + --#{$prefix}nav-tabs-link-active-bg: #{$nav-tabs-link-active-bg}; + --#{$prefix}nav-tabs-link-active-border-color: #{$nav-tabs-link-active-border-color}; + // scss-docs-end nav-tabs-css-vars + + border-bottom: var(--#{$prefix}nav-tabs-border-width) solid var(--#{$prefix}nav-tabs-border-color); + + .nav-link { + margin-bottom: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list + border: var(--#{$prefix}nav-tabs-border-width) solid transparent; + @include border-top-radius(var(--#{$prefix}nav-tabs-border-radius)); + + &:hover, + &:focus { + // Prevents active .nav-link tab overlapping focus outline of previous/next .nav-link + isolation: isolate; + border-color: var(--#{$prefix}nav-tabs-link-hover-border-color); + } + } + + .nav-link.active, + .nav-item.show .nav-link { + color: var(--#{$prefix}nav-tabs-link-active-color); + background-color: var(--#{$prefix}nav-tabs-link-active-bg); + border-color: var(--#{$prefix}nav-tabs-link-active-border-color); + } + + .dropdown-menu { + // Make dropdown border overlap tab border + margin-top: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list + // Remove the top rounded corners here since there is a hard edge above the menu + @include border-top-radius(0); + } +} + + +// +// Pills +// + +.nav-pills { + // scss-docs-start nav-pills-css-vars + --#{$prefix}nav-pills-border-radius: #{$nav-pills-border-radius}; + --#{$prefix}nav-pills-link-active-color: #{$nav-pills-link-active-color}; + --#{$prefix}nav-pills-link-active-bg: #{$nav-pills-link-active-bg}; + // scss-docs-end nav-pills-css-vars + + .nav-link { + @include border-radius(var(--#{$prefix}nav-pills-border-radius)); + } + + .nav-link.active, + .show > .nav-link { + color: var(--#{$prefix}nav-pills-link-active-color); + @include gradient-bg(var(--#{$prefix}nav-pills-link-active-bg)); + } +} + + +// +// Underline +// + +.nav-underline { + // scss-docs-start nav-underline-css-vars + --#{$prefix}nav-underline-gap: #{$nav-underline-gap}; + --#{$prefix}nav-underline-border-width: #{$nav-underline-border-width}; + --#{$prefix}nav-underline-link-active-color: #{$nav-underline-link-active-color}; + // scss-docs-end nav-underline-css-vars + + gap: var(--#{$prefix}nav-underline-gap); + + .nav-link { + padding-right: 0; + padding-left: 0; + border-bottom: var(--#{$prefix}nav-underline-border-width) solid transparent; + + &:hover, + &:focus { + border-bottom-color: currentcolor; + } + } + + .nav-link.active, + .show > .nav-link { + font-weight: $font-weight-bold; + color: var(--#{$prefix}nav-underline-link-active-color); + border-bottom-color: currentcolor; + } +} + + +// +// Justified variants +// + +.nav-fill { + > .nav-link, + .nav-item { + flex: 1 1 auto; + text-align: center; + } +} + +.nav-justified { + > .nav-link, + .nav-item { + flex-basis: 0; + flex-grow: 1; + text-align: center; + } +} + +.nav-fill, +.nav-justified { + .nav-item .nav-link { + width: 100%; // Make sure button will grow + } +} + + +// Tabbable tabs +// +// Hide tabbable panes to start, show them when `.active` + +.tab-content { + > .tab-pane { + display: none; + } + > .active { + display: block; + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_navbar.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_navbar.scss new file mode 100644 index 00000000..71619382 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_navbar.scss @@ -0,0 +1,289 @@ +// Navbar +// +// Provide a static navbar from which we expand to create full-width, fixed, and +// other navbar variations. + +.navbar { + // scss-docs-start navbar-css-vars + --#{$prefix}navbar-padding-x: #{if($navbar-padding-x == null, 0, $navbar-padding-x)}; + --#{$prefix}navbar-padding-y: #{$navbar-padding-y}; + --#{$prefix}navbar-color: #{$navbar-light-color}; + --#{$prefix}navbar-hover-color: #{$navbar-light-hover-color}; + --#{$prefix}navbar-disabled-color: #{$navbar-light-disabled-color}; + --#{$prefix}navbar-active-color: #{$navbar-light-active-color}; + --#{$prefix}navbar-brand-padding-y: #{$navbar-brand-padding-y}; + --#{$prefix}navbar-brand-margin-end: #{$navbar-brand-margin-end}; + --#{$prefix}navbar-brand-font-size: #{$navbar-brand-font-size}; + --#{$prefix}navbar-brand-color: #{$navbar-light-brand-color}; + --#{$prefix}navbar-brand-hover-color: #{$navbar-light-brand-hover-color}; + --#{$prefix}navbar-nav-link-padding-x: #{$navbar-nav-link-padding-x}; + --#{$prefix}navbar-toggler-padding-y: #{$navbar-toggler-padding-y}; + --#{$prefix}navbar-toggler-padding-x: #{$navbar-toggler-padding-x}; + --#{$prefix}navbar-toggler-font-size: #{$navbar-toggler-font-size}; + --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-light-toggler-icon-bg)}; + --#{$prefix}navbar-toggler-border-color: #{$navbar-light-toggler-border-color}; + --#{$prefix}navbar-toggler-border-radius: #{$navbar-toggler-border-radius}; + --#{$prefix}navbar-toggler-focus-width: #{$navbar-toggler-focus-width}; + --#{$prefix}navbar-toggler-transition: #{$navbar-toggler-transition}; + // scss-docs-end navbar-css-vars + + position: relative; + display: flex; + flex-wrap: wrap; // allow us to do the line break for collapsing content + align-items: center; + justify-content: space-between; // space out brand from logo + padding: var(--#{$prefix}navbar-padding-y) var(--#{$prefix}navbar-padding-x); + @include gradient-bg(); + + // Because flex properties aren't inherited, we need to redeclare these first + // few properties so that content nested within behave properly. + // The `flex-wrap` property is inherited to simplify the expanded navbars + %container-flex-properties { + display: flex; + flex-wrap: inherit; + align-items: center; + justify-content: space-between; + } + + > .container, + > .container-fluid { + @extend %container-flex-properties; + } + + @each $breakpoint, $container-max-width in $container-max-widths { + > .container#{breakpoint-infix($breakpoint, $container-max-widths)} { + @extend %container-flex-properties; + } + } +} + + +// Navbar brand +// +// Used for brand, project, or site names. + +.navbar-brand { + padding-top: var(--#{$prefix}navbar-brand-padding-y); + padding-bottom: var(--#{$prefix}navbar-brand-padding-y); + margin-right: var(--#{$prefix}navbar-brand-margin-end); + @include font-size(var(--#{$prefix}navbar-brand-font-size)); + color: var(--#{$prefix}navbar-brand-color); + text-decoration: if($link-decoration == none, null, none); + white-space: nowrap; + + &:hover, + &:focus { + color: var(--#{$prefix}navbar-brand-hover-color); + text-decoration: if($link-hover-decoration == underline, none, null); + } +} + + +// Navbar nav +// +// Custom navbar navigation (doesn't require `.nav`, but does make use of `.nav-link`). + +.navbar-nav { + // scss-docs-start navbar-nav-css-vars + --#{$prefix}nav-link-padding-x: 0; + --#{$prefix}nav-link-padding-y: #{$nav-link-padding-y}; + @include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size); + --#{$prefix}nav-link-font-weight: #{$nav-link-font-weight}; + --#{$prefix}nav-link-color: var(--#{$prefix}navbar-color); + --#{$prefix}nav-link-hover-color: var(--#{$prefix}navbar-hover-color); + --#{$prefix}nav-link-disabled-color: var(--#{$prefix}navbar-disabled-color); + // scss-docs-end navbar-nav-css-vars + + display: flex; + flex-direction: column; // cannot use `inherit` to get the `.navbar`s value + padding-left: 0; + margin-bottom: 0; + list-style: none; + + .nav-link { + &.active, + &.show { + color: var(--#{$prefix}navbar-active-color); + } + } + + .dropdown-menu { + position: static; + } +} + + +// Navbar text +// +// + +.navbar-text { + padding-top: $nav-link-padding-y; + padding-bottom: $nav-link-padding-y; + color: var(--#{$prefix}navbar-color); + + a, + a:hover, + a:focus { + color: var(--#{$prefix}navbar-active-color); + } +} + + +// Responsive navbar +// +// Custom styles for responsive collapsing and toggling of navbar contents. +// Powered by the collapse Bootstrap JavaScript plugin. + +// When collapsed, prevent the toggleable navbar contents from appearing in +// the default flexbox row orientation. Requires the use of `flex-wrap: wrap` +// on the `.navbar` parent. +.navbar-collapse { + flex-basis: 100%; + flex-grow: 1; + // For always expanded or extra full navbars, ensure content aligns itself + // properly vertically. Can be easily overridden with flex utilities. + align-items: center; +} + +// Button for toggling the navbar when in its collapsed state +.navbar-toggler { + padding: var(--#{$prefix}navbar-toggler-padding-y) var(--#{$prefix}navbar-toggler-padding-x); + @include font-size(var(--#{$prefix}navbar-toggler-font-size)); + line-height: 1; + color: var(--#{$prefix}navbar-color); + background-color: transparent; // remove default button style + border: var(--#{$prefix}border-width) solid var(--#{$prefix}navbar-toggler-border-color); // remove default button style + @include border-radius(var(--#{$prefix}navbar-toggler-border-radius)); + @include transition(var(--#{$prefix}navbar-toggler-transition)); + + &:hover { + text-decoration: none; + } + + &:focus { + text-decoration: none; + outline: 0; + box-shadow: 0 0 0 var(--#{$prefix}navbar-toggler-focus-width); + } +} + +// Keep as a separate element so folks can easily override it with another icon +// or image file as needed. +.navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + background-image: var(--#{$prefix}navbar-toggler-icon-bg); + background-repeat: no-repeat; + background-position: center; + background-size: 100%; +} + +.navbar-nav-scroll { + max-height: var(--#{$prefix}scroll-height, 75vh); + overflow-y: auto; +} + +// scss-docs-start navbar-expand-loop +// Generate series of `.navbar-expand-*` responsive classes for configuring +// where your navbar collapses. +.navbar-expand { + @each $breakpoint in map-keys($grid-breakpoints) { + $next: breakpoint-next($breakpoint, $grid-breakpoints); + $infix: breakpoint-infix($next, $grid-breakpoints); + + // stylelint-disable-next-line scss/selector-no-union-class-name + &#{$infix} { + @include media-breakpoint-up($next) { + flex-wrap: nowrap; + justify-content: flex-start; + + .navbar-nav { + flex-direction: row; + + .dropdown-menu { + position: absolute; + } + + .nav-link { + padding-right: var(--#{$prefix}navbar-nav-link-padding-x); + padding-left: var(--#{$prefix}navbar-nav-link-padding-x); + } + } + + .navbar-nav-scroll { + overflow: visible; + } + + .navbar-collapse { + display: flex !important; // stylelint-disable-line declaration-no-important + flex-basis: auto; + } + + .navbar-toggler { + display: none; + } + + .offcanvas { + // stylelint-disable declaration-no-important + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + @include box-shadow(none); + @include transition(none); + // stylelint-enable declaration-no-important + + .offcanvas-header { + display: none; + } + + .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } + } + } + } + } +} +// scss-docs-end navbar-expand-loop + +// Navbar themes +// +// Styles for switching between navbars with light or dark background. + +.navbar-light { + @include deprecate("`.navbar-light`", "v5.2.0", "v6.0.0", true); +} + +.navbar-dark, +.navbar[data-bs-theme="dark"] { + // scss-docs-start navbar-dark-css-vars + --#{$prefix}navbar-color: #{$navbar-dark-color}; + --#{$prefix}navbar-hover-color: #{$navbar-dark-hover-color}; + --#{$prefix}navbar-disabled-color: #{$navbar-dark-disabled-color}; + --#{$prefix}navbar-active-color: #{$navbar-dark-active-color}; + --#{$prefix}navbar-brand-color: #{$navbar-dark-brand-color}; + --#{$prefix}navbar-brand-hover-color: #{$navbar-dark-brand-hover-color}; + --#{$prefix}navbar-toggler-border-color: #{$navbar-dark-toggler-border-color}; + --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)}; + // scss-docs-end navbar-dark-css-vars +} + +@if $enable-dark-mode { + @include color-mode(dark) { + .navbar-toggler-icon { + --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)}; + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_offcanvas.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_offcanvas.scss new file mode 100644 index 00000000..eb2c97ab --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_offcanvas.scss @@ -0,0 +1,143 @@ +// stylelint-disable function-disallowed-list + +%offcanvas-css-vars { + // scss-docs-start offcanvas-css-vars + --#{$prefix}offcanvas-zindex: #{$zindex-offcanvas}; + --#{$prefix}offcanvas-width: #{$offcanvas-horizontal-width}; + --#{$prefix}offcanvas-height: #{$offcanvas-vertical-height}; + --#{$prefix}offcanvas-padding-x: #{$offcanvas-padding-x}; + --#{$prefix}offcanvas-padding-y: #{$offcanvas-padding-y}; + --#{$prefix}offcanvas-color: #{$offcanvas-color}; + --#{$prefix}offcanvas-bg: #{$offcanvas-bg-color}; + --#{$prefix}offcanvas-border-width: #{$offcanvas-border-width}; + --#{$prefix}offcanvas-border-color: #{$offcanvas-border-color}; + --#{$prefix}offcanvas-box-shadow: #{$offcanvas-box-shadow}; + --#{$prefix}offcanvas-transition: #{transform $offcanvas-transition-duration ease-in-out}; + --#{$prefix}offcanvas-title-line-height: #{$offcanvas-title-line-height}; + // scss-docs-end offcanvas-css-vars +} + +@each $breakpoint in map-keys($grid-breakpoints) { + $next: breakpoint-next($breakpoint, $grid-breakpoints); + $infix: breakpoint-infix($next, $grid-breakpoints); + + .offcanvas#{$infix} { + @extend %offcanvas-css-vars; + } +} + +@each $breakpoint in map-keys($grid-breakpoints) { + $next: breakpoint-next($breakpoint, $grid-breakpoints); + $infix: breakpoint-infix($next, $grid-breakpoints); + + .offcanvas#{$infix} { + @include media-breakpoint-down($next) { + position: fixed; + bottom: 0; + z-index: var(--#{$prefix}offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--#{$prefix}offcanvas-color); + visibility: hidden; + background-color: var(--#{$prefix}offcanvas-bg); + background-clip: padding-box; + outline: 0; + @include box-shadow(var(--#{$prefix}offcanvas-box-shadow)); + @include transition(var(--#{$prefix}offcanvas-transition)); + + &.offcanvas-start { + top: 0; + left: 0; + width: var(--#{$prefix}offcanvas-width); + border-right: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color); + transform: translateX(-100%); + } + + &.offcanvas-end { + top: 0; + right: 0; + width: var(--#{$prefix}offcanvas-width); + border-left: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color); + transform: translateX(100%); + } + + &.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--#{$prefix}offcanvas-height); + max-height: 100%; + border-bottom: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color); + transform: translateY(-100%); + } + + &.offcanvas-bottom { + right: 0; + left: 0; + height: var(--#{$prefix}offcanvas-height); + max-height: 100%; + border-top: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color); + transform: translateY(100%); + } + + &.showing, + &.show:not(.hiding) { + transform: none; + } + + &.showing, + &.hiding, + &.show { + visibility: visible; + } + } + + @if not ($infix == "") { + @include media-breakpoint-up($next) { + --#{$prefix}offcanvas-height: auto; + --#{$prefix}offcanvas-border-width: 0; + background-color: transparent !important; // stylelint-disable-line declaration-no-important + + .offcanvas-header { + display: none; + } + + .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + // Reset `background-color` in case `.bg-*` classes are used in offcanvas + background-color: transparent !important; // stylelint-disable-line declaration-no-important + } + } + } + } +} + +.offcanvas-backdrop { + @include overlay-backdrop($zindex-offcanvas-backdrop, $offcanvas-backdrop-bg, $offcanvas-backdrop-opacity); +} + +.offcanvas-header { + display: flex; + align-items: center; + padding: var(--#{$prefix}offcanvas-padding-y) var(--#{$prefix}offcanvas-padding-x); + + .btn-close { + padding: calc(var(--#{$prefix}offcanvas-padding-y) * .5) calc(var(--#{$prefix}offcanvas-padding-x) * .5); + margin: calc(-.5 * var(--#{$prefix}offcanvas-padding-y)) calc(-.5 * var(--#{$prefix}offcanvas-padding-x)) calc(-.5 * var(--#{$prefix}offcanvas-padding-y)) auto; + } +} + +.offcanvas-title { + margin-bottom: 0; + line-height: var(--#{$prefix}offcanvas-title-line-height); +} + +.offcanvas-body { + flex-grow: 1; + padding: var(--#{$prefix}offcanvas-padding-y) var(--#{$prefix}offcanvas-padding-x); + overflow-y: auto; +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_pagination.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_pagination.scss new file mode 100644 index 00000000..f275a62e --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_pagination.scss @@ -0,0 +1,109 @@ +.pagination { + // scss-docs-start pagination-css-vars + --#{$prefix}pagination-padding-x: #{$pagination-padding-x}; + --#{$prefix}pagination-padding-y: #{$pagination-padding-y}; + @include rfs($pagination-font-size, --#{$prefix}pagination-font-size); + --#{$prefix}pagination-color: #{$pagination-color}; + --#{$prefix}pagination-bg: #{$pagination-bg}; + --#{$prefix}pagination-border-width: #{$pagination-border-width}; + --#{$prefix}pagination-border-color: #{$pagination-border-color}; + --#{$prefix}pagination-border-radius: #{$pagination-border-radius}; + --#{$prefix}pagination-hover-color: #{$pagination-hover-color}; + --#{$prefix}pagination-hover-bg: #{$pagination-hover-bg}; + --#{$prefix}pagination-hover-border-color: #{$pagination-hover-border-color}; + --#{$prefix}pagination-focus-color: #{$pagination-focus-color}; + --#{$prefix}pagination-focus-bg: #{$pagination-focus-bg}; + --#{$prefix}pagination-focus-box-shadow: #{$pagination-focus-box-shadow}; + --#{$prefix}pagination-active-color: #{$pagination-active-color}; + --#{$prefix}pagination-active-bg: #{$pagination-active-bg}; + --#{$prefix}pagination-active-border-color: #{$pagination-active-border-color}; + --#{$prefix}pagination-disabled-color: #{$pagination-disabled-color}; + --#{$prefix}pagination-disabled-bg: #{$pagination-disabled-bg}; + --#{$prefix}pagination-disabled-border-color: #{$pagination-disabled-border-color}; + // scss-docs-end pagination-css-vars + + display: flex; + @include list-unstyled(); +} + +.page-link { + position: relative; + display: block; + padding: var(--#{$prefix}pagination-padding-y) var(--#{$prefix}pagination-padding-x); + @include font-size(var(--#{$prefix}pagination-font-size)); + color: var(--#{$prefix}pagination-color); + text-decoration: if($link-decoration == none, null, none); + background-color: var(--#{$prefix}pagination-bg); + border: var(--#{$prefix}pagination-border-width) solid var(--#{$prefix}pagination-border-color); + @include transition($pagination-transition); + + &:hover { + z-index: 2; + color: var(--#{$prefix}pagination-hover-color); + text-decoration: if($link-hover-decoration == underline, none, null); + background-color: var(--#{$prefix}pagination-hover-bg); + border-color: var(--#{$prefix}pagination-hover-border-color); + } + + &:focus { + z-index: 3; + color: var(--#{$prefix}pagination-focus-color); + background-color: var(--#{$prefix}pagination-focus-bg); + outline: $pagination-focus-outline; + box-shadow: var(--#{$prefix}pagination-focus-box-shadow); + } + + &.active, + .active > & { + z-index: 3; + color: var(--#{$prefix}pagination-active-color); + @include gradient-bg(var(--#{$prefix}pagination-active-bg)); + border-color: var(--#{$prefix}pagination-active-border-color); + } + + &.disabled, + .disabled > & { + color: var(--#{$prefix}pagination-disabled-color); + pointer-events: none; + background-color: var(--#{$prefix}pagination-disabled-bg); + border-color: var(--#{$prefix}pagination-disabled-border-color); + } +} + +.page-item { + &:not(:first-child) .page-link { + margin-left: $pagination-margin-start; + } + + @if $pagination-margin-start == calc(#{$pagination-border-width} * -1) { + &:first-child { + .page-link { + @include border-start-radius(var(--#{$prefix}pagination-border-radius)); + } + } + + &:last-child { + .page-link { + @include border-end-radius(var(--#{$prefix}pagination-border-radius)); + } + } + } @else { + // Add border-radius to all pageLinks in case they have left margin + .page-link { + @include border-radius(var(--#{$prefix}pagination-border-radius)); + } + } +} + + +// +// Sizing +// + +.pagination-lg { + @include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $pagination-border-radius-lg); +} + +.pagination-sm { + @include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $pagination-border-radius-sm); +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_placeholders.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_placeholders.scss new file mode 100644 index 00000000..6e32e1cd --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_placeholders.scss @@ -0,0 +1,51 @@ +.placeholder { + display: inline-block; + min-height: 1em; + vertical-align: middle; + cursor: wait; + background-color: currentcolor; + opacity: $placeholder-opacity-max; + + &.btn::before { + display: inline-block; + content: ""; + } +} + +// Sizing +.placeholder-xs { + min-height: .6em; +} + +.placeholder-sm { + min-height: .8em; +} + +.placeholder-lg { + min-height: 1.2em; +} + +// Animation +.placeholder-glow { + .placeholder { + animation: placeholder-glow 2s ease-in-out infinite; + } +} + +@keyframes placeholder-glow { + 50% { + opacity: $placeholder-opacity-min; + } +} + +.placeholder-wave { + mask-image: linear-gradient(130deg, $black 55%, rgba(0, 0, 0, (1 - $placeholder-opacity-min)) 75%, $black 95%); + mask-size: 200% 100%; + animation: placeholder-wave 2s linear infinite; +} + +@keyframes placeholder-wave { + 100% { + mask-position: -200% 0%; + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_popover.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_popover.scss new file mode 100644 index 00000000..7b69f623 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_popover.scss @@ -0,0 +1,196 @@ +.popover { + // scss-docs-start popover-css-vars + --#{$prefix}popover-zindex: #{$zindex-popover}; + --#{$prefix}popover-max-width: #{$popover-max-width}; + @include rfs($popover-font-size, --#{$prefix}popover-font-size); + --#{$prefix}popover-bg: #{$popover-bg}; + --#{$prefix}popover-border-width: #{$popover-border-width}; + --#{$prefix}popover-border-color: #{$popover-border-color}; + --#{$prefix}popover-border-radius: #{$popover-border-radius}; + --#{$prefix}popover-inner-border-radius: #{$popover-inner-border-radius}; + --#{$prefix}popover-box-shadow: #{$popover-box-shadow}; + --#{$prefix}popover-header-padding-x: #{$popover-header-padding-x}; + --#{$prefix}popover-header-padding-y: #{$popover-header-padding-y}; + @include rfs($popover-header-font-size, --#{$prefix}popover-header-font-size); + --#{$prefix}popover-header-color: #{$popover-header-color}; + --#{$prefix}popover-header-bg: #{$popover-header-bg}; + --#{$prefix}popover-body-padding-x: #{$popover-body-padding-x}; + --#{$prefix}popover-body-padding-y: #{$popover-body-padding-y}; + --#{$prefix}popover-body-color: #{$popover-body-color}; + --#{$prefix}popover-arrow-width: #{$popover-arrow-width}; + --#{$prefix}popover-arrow-height: #{$popover-arrow-height}; + --#{$prefix}popover-arrow-border: var(--#{$prefix}popover-border-color); + // scss-docs-end popover-css-vars + + z-index: var(--#{$prefix}popover-zindex); + display: block; + max-width: var(--#{$prefix}popover-max-width); + // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element. + // So reset our font and text properties to avoid inheriting weird values. + @include reset-text(); + @include font-size(var(--#{$prefix}popover-font-size)); + // Allow breaking very long words so they don't overflow the popover's bounds + word-wrap: break-word; + background-color: var(--#{$prefix}popover-bg); + background-clip: padding-box; + border: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color); + @include border-radius(var(--#{$prefix}popover-border-radius)); + @include box-shadow(var(--#{$prefix}popover-box-shadow)); + + .popover-arrow { + display: block; + width: var(--#{$prefix}popover-arrow-width); + height: var(--#{$prefix}popover-arrow-height); + + &::before, + &::after { + position: absolute; + display: block; + content: ""; + border-color: transparent; + border-style: solid; + border-width: 0; + } + } +} + +.bs-popover-top { + > .popover-arrow { + bottom: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list + + &::before, + &::after { + border-width: var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list + } + + &::before { + bottom: 0; + border-top-color: var(--#{$prefix}popover-arrow-border); + } + + &::after { + bottom: var(--#{$prefix}popover-border-width); + border-top-color: var(--#{$prefix}popover-bg); + } + } +} + +/* rtl:begin:ignore */ +.bs-popover-end { + > .popover-arrow { + left: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list + width: var(--#{$prefix}popover-arrow-height); + height: var(--#{$prefix}popover-arrow-width); + + &::before, + &::after { + border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list + } + + &::before { + left: 0; + border-right-color: var(--#{$prefix}popover-arrow-border); + } + + &::after { + left: var(--#{$prefix}popover-border-width); + border-right-color: var(--#{$prefix}popover-bg); + } + } +} + +/* rtl:end:ignore */ + +.bs-popover-bottom { + > .popover-arrow { + top: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list + + &::before, + &::after { + border-width: 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list + } + + &::before { + top: 0; + border-bottom-color: var(--#{$prefix}popover-arrow-border); + } + + &::after { + top: var(--#{$prefix}popover-border-width); + border-bottom-color: var(--#{$prefix}popover-bg); + } + } + + // This will remove the popover-header's border just below the arrow + .popover-header::before { + position: absolute; + top: 0; + left: 50%; + display: block; + width: var(--#{$prefix}popover-arrow-width); + margin-left: calc(-.5 * var(--#{$prefix}popover-arrow-width)); // stylelint-disable-line function-disallowed-list + content: ""; + border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-header-bg); + } +} + +/* rtl:begin:ignore */ +.bs-popover-start { + > .popover-arrow { + right: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list + width: var(--#{$prefix}popover-arrow-height); + height: var(--#{$prefix}popover-arrow-width); + + &::before, + &::after { + border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list + } + + &::before { + right: 0; + border-left-color: var(--#{$prefix}popover-arrow-border); + } + + &::after { + right: var(--#{$prefix}popover-border-width); + border-left-color: var(--#{$prefix}popover-bg); + } + } +} + +/* rtl:end:ignore */ + +.bs-popover-auto { + &[data-popper-placement^="top"] { + @extend .bs-popover-top; + } + &[data-popper-placement^="right"] { + @extend .bs-popover-end; + } + &[data-popper-placement^="bottom"] { + @extend .bs-popover-bottom; + } + &[data-popper-placement^="left"] { + @extend .bs-popover-start; + } +} + +// Offset the popover to account for the popover arrow +.popover-header { + padding: var(--#{$prefix}popover-header-padding-y) var(--#{$prefix}popover-header-padding-x); + margin-bottom: 0; // Reset the default from Reboot + @include font-size(var(--#{$prefix}popover-header-font-size)); + color: var(--#{$prefix}popover-header-color); + background-color: var(--#{$prefix}popover-header-bg); + border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color); + @include border-top-radius(var(--#{$prefix}popover-inner-border-radius)); + + &:empty { + display: none; + } +} + +.popover-body { + padding: var(--#{$prefix}popover-body-padding-y) var(--#{$prefix}popover-body-padding-x); + color: var(--#{$prefix}popover-body-color); +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_progress.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_progress.scss new file mode 100644 index 00000000..148c3815 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_progress.scss @@ -0,0 +1,68 @@ +// Disable animation if transitions are disabled + +// scss-docs-start progress-keyframes +@if $enable-transitions { + @keyframes progress-bar-stripes { + 0% { background-position-x: $progress-height; } + } +} +// scss-docs-end progress-keyframes + +.progress, +.progress-stacked { + // scss-docs-start progress-css-vars + --#{$prefix}progress-height: #{$progress-height}; + @include rfs($progress-font-size, --#{$prefix}progress-font-size); + --#{$prefix}progress-bg: #{$progress-bg}; + --#{$prefix}progress-border-radius: #{$progress-border-radius}; + --#{$prefix}progress-box-shadow: #{$progress-box-shadow}; + --#{$prefix}progress-bar-color: #{$progress-bar-color}; + --#{$prefix}progress-bar-bg: #{$progress-bar-bg}; + --#{$prefix}progress-bar-transition: #{$progress-bar-transition}; + // scss-docs-end progress-css-vars + + display: flex; + height: var(--#{$prefix}progress-height); + overflow: hidden; // force rounded corners by cropping it + @include font-size(var(--#{$prefix}progress-font-size)); + background-color: var(--#{$prefix}progress-bg); + @include border-radius(var(--#{$prefix}progress-border-radius)); + @include box-shadow(var(--#{$prefix}progress-box-shadow)); +} + +.progress-bar { + display: flex; + flex-direction: column; + justify-content: center; + overflow: hidden; + color: var(--#{$prefix}progress-bar-color); + text-align: center; + white-space: nowrap; + background-color: var(--#{$prefix}progress-bar-bg); + @include transition(var(--#{$prefix}progress-bar-transition)); +} + +.progress-bar-striped { + @include gradient-striped(); + background-size: var(--#{$prefix}progress-height) var(--#{$prefix}progress-height); +} + +.progress-stacked > .progress { + overflow: visible; +} + +.progress-stacked > .progress > .progress-bar { + width: 100%; +} + +@if $enable-transitions { + .progress-bar-animated { + animation: $progress-bar-animation-timing progress-bar-stripes; + + @if $enable-reduced-motion { + @media (prefers-reduced-motion: reduce) { + animation: none; + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_reboot.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_reboot.scss new file mode 100644 index 00000000..18791753 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_reboot.scss @@ -0,0 +1,611 @@ +// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix + + +// Reboot +// +// Normalization of HTML elements, manually forked from Normalize.css to remove +// styles targeting irrelevant browsers while applying new styles. +// +// Normalize is licensed MIT. https://github.com/necolas/normalize.css + + +// Document +// +// Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`. + +*, +*::before, +*::after { + box-sizing: border-box; +} + + +// Root +// +// Ability to the value of the root font sizes, affecting the value of `rem`. +// null by default, thus nothing is generated. + +:root { + @if $font-size-root != null { + @include font-size(var(--#{$prefix}root-font-size)); + } + + @if $enable-smooth-scroll { + @media (prefers-reduced-motion: no-preference) { + scroll-behavior: smooth; + } + } +} + + +// Body +// +// 1. Remove the margin in all browsers. +// 2. As a best practice, apply a default `background-color`. +// 3. Prevent adjustments of font size after orientation changes in iOS. +// 4. Change the default tap highlight to be completely transparent in iOS. + +// scss-docs-start reboot-body-rules +body { + margin: 0; // 1 + font-family: var(--#{$prefix}body-font-family); + @include font-size(var(--#{$prefix}body-font-size)); + font-weight: var(--#{$prefix}body-font-weight); + line-height: var(--#{$prefix}body-line-height); + color: var(--#{$prefix}body-color); + text-align: var(--#{$prefix}body-text-align); + background-color: var(--#{$prefix}body-bg); // 2 + -webkit-text-size-adjust: 100%; // 3 + -webkit-tap-highlight-color: rgba($black, 0); // 4 +} +// scss-docs-end reboot-body-rules + + +// Content grouping +// +// 1. Reset Firefox's gray color + +hr { + margin: $hr-margin-y 0; + color: $hr-color; // 1 + border: 0; + border-top: $hr-border-width solid $hr-border-color; + opacity: $hr-opacity; +} + + +// Typography +// +// 1. Remove top margins from headings +// By default, `<h1>`-`<h6>` all receive top and bottom margins. We nuke the top +// margin for easier control within type scales as it avoids margin collapsing. + +%heading { + margin-top: 0; // 1 + margin-bottom: $headings-margin-bottom; + font-family: $headings-font-family; + font-style: $headings-font-style; + font-weight: $headings-font-weight; + line-height: $headings-line-height; + color: var(--#{$prefix}heading-color); +} + +h1 { + @extend %heading; + @include font-size($h1-font-size); +} + +h2 { + @extend %heading; + @include font-size($h2-font-size); +} + +h3 { + @extend %heading; + @include font-size($h3-font-size); +} + +h4 { + @extend %heading; + @include font-size($h4-font-size); +} + +h5 { + @extend %heading; + @include font-size($h5-font-size); +} + +h6 { + @extend %heading; + @include font-size($h6-font-size); +} + + +// Reset margins on paragraphs +// +// Similarly, the top margin on `<p>`s get reset. However, we also reset the +// bottom margin to use `rem` units instead of `em`. + +p { + margin-top: 0; + margin-bottom: $paragraph-margin-bottom; +} + + +// Abbreviations +// +// 1. Add the correct text decoration in Chrome, Edge, Opera, and Safari. +// 2. Add explicit cursor to indicate changed behavior. +// 3. Prevent the text-decoration to be skipped. + +abbr[title] { + text-decoration: underline dotted; // 1 + cursor: help; // 2 + text-decoration-skip-ink: none; // 3 +} + + +// Address + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit; +} + + +// Lists + +ol, +ul { + padding-left: 2rem; +} + +ol, +ul, +dl { + margin-top: 0; + margin-bottom: 1rem; +} + +ol ol, +ul ul, +ol ul, +ul ol { + margin-bottom: 0; +} + +dt { + font-weight: $dt-font-weight; +} + +// 1. Undo browser default + +dd { + margin-bottom: .5rem; + margin-left: 0; // 1 +} + + +// Blockquote + +blockquote { + margin: 0 0 1rem; +} + + +// Strong +// +// Add the correct font weight in Chrome, Edge, and Safari + +b, +strong { + font-weight: $font-weight-bolder; +} + + +// Small +// +// Add the correct font size in all browsers + +small { + @include font-size($small-font-size); +} + + +// Mark + +mark { + padding: $mark-padding; + color: var(--#{$prefix}highlight-color); + background-color: var(--#{$prefix}highlight-bg); +} + + +// Sub and Sup +// +// Prevent `sub` and `sup` elements from affecting the line height in +// all browsers. + +sub, +sup { + position: relative; + @include font-size($sub-sup-font-size); + line-height: 0; + vertical-align: baseline; +} + +sub { bottom: -.25em; } +sup { top: -.5em; } + + +// Links + +a { + color: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-opacity, 1)); + text-decoration: $link-decoration; + + &:hover { + --#{$prefix}link-color-rgb: var(--#{$prefix}link-hover-color-rgb); + text-decoration: $link-hover-decoration; + } +} + +// And undo these styles for placeholder links/named anchors (without href). +// It would be more straightforward to just use a[href] in previous block, but that +// causes specificity issues in many other styles that are too complex to fix. +// See https://github.com/twbs/bootstrap/issues/19402 + +a:not([href]):not([class]) { + &, + &:hover { + color: inherit; + text-decoration: none; + } +} + + +// Code + +pre, +code, +kbd, +samp { + font-family: $font-family-code; + @include font-size(1em); // Correct the odd `em` font sizing in all browsers. +} + +// 1. Remove browser default top margin +// 2. Reset browser default of `1em` to use `rem`s +// 3. Don't allow content to break outside + +pre { + display: block; + margin-top: 0; // 1 + margin-bottom: 1rem; // 2 + overflow: auto; // 3 + @include font-size($code-font-size); + color: $pre-color; + + // Account for some code outputs that place code tags in pre tags + code { + @include font-size(inherit); + color: inherit; + word-break: normal; + } +} + +code { + @include font-size($code-font-size); + color: var(--#{$prefix}code-color); + word-wrap: break-word; + + // Streamline the style when inside anchors to avoid broken underline and more + a > & { + color: inherit; + } +} + +kbd { + padding: $kbd-padding-y $kbd-padding-x; + @include font-size($kbd-font-size); + color: $kbd-color; + background-color: $kbd-bg; + @include border-radius($border-radius-sm); + + kbd { + padding: 0; + @include font-size(1em); + font-weight: $nested-kbd-font-weight; + } +} + + +// Figures +// +// Apply a consistent margin strategy (matches our type styles). + +figure { + margin: 0 0 1rem; +} + + +// Images and content + +img, +svg { + vertical-align: middle; +} + + +// Tables +// +// Prevent double borders + +table { + caption-side: bottom; + border-collapse: collapse; +} + +caption { + padding-top: $table-cell-padding-y; + padding-bottom: $table-cell-padding-y; + color: $table-caption-color; + text-align: left; +} + +// 1. Removes font-weight bold by inheriting +// 2. Matches default `<td>` alignment by inheriting `text-align`. +// 3. Fix alignment for Safari + +th { + font-weight: $table-th-font-weight; // 1 + text-align: inherit; // 2 + text-align: -webkit-match-parent; // 3 +} + +thead, +tbody, +tfoot, +tr, +td, +th { + border-color: inherit; + border-style: solid; + border-width: 0; +} + + +// Forms +// +// 1. Allow labels to use `margin` for spacing. + +label { + display: inline-block; // 1 +} + +// Remove the default `border-radius` that macOS Chrome adds. +// See https://github.com/twbs/bootstrap/issues/24093 + +button { + // stylelint-disable-next-line property-disallowed-list + border-radius: 0; +} + +// Explicitly remove focus outline in Chromium when it shouldn't be +// visible (e.g. as result of mouse click or touch tap). It already +// should be doing this automatically, but seems to currently be +// confused and applies its very visible two-tone outline anyway. + +button:focus:not(:focus-visible) { + outline: 0; +} + +// 1. Remove the margin in Firefox and Safari + +input, +button, +select, +optgroup, +textarea { + margin: 0; // 1 + font-family: inherit; + @include font-size(inherit); + line-height: inherit; +} + +// Remove the inheritance of text transform in Firefox +button, +select { + text-transform: none; +} +// Set the cursor for non-`<button>` buttons +// +// Details at https://github.com/twbs/bootstrap/pull/30562 +[role="button"] { + cursor: pointer; +} + +select { + // Remove the inheritance of word-wrap in Safari. + // See https://github.com/twbs/bootstrap/issues/24990 + word-wrap: normal; + + // Undo the opacity change from Chrome + &:disabled { + opacity: 1; + } +} + +// Remove the dropdown arrow only from text type inputs built with datalists in Chrome. +// See https://stackoverflow.com/a/54997118 + +[list]:not([type="date"]):not([type="datetime-local"]):not([type="month"]):not([type="week"]):not([type="time"])::-webkit-calendar-picker-indicator { + display: none !important; +} + +// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` +// controls in Android 4. +// 2. Correct the inability to style clickable types in iOS and Safari. +// 3. Opinionated: add "hand" cursor to non-disabled button elements. + +button, +[type="button"], // 1 +[type="reset"], +[type="submit"] { + -webkit-appearance: button; // 2 + + @if $enable-button-pointers { + &:not(:disabled) { + cursor: pointer; // 3 + } + } +} + +// Remove inner border and padding from Firefox, but don't restore the outline like Normalize. + +::-moz-focus-inner { + padding: 0; + border-style: none; +} + +// 1. Textareas should really only resize vertically so they don't break their (horizontal) containers. + +textarea { + resize: vertical; // 1 +} + +// 1. Browsers set a default `min-width: min-content;` on fieldsets, +// unlike e.g. `<div>`s, which have `min-width: 0;` by default. +// So we reset that to ensure fieldsets behave more like a standard block element. +// See https://github.com/twbs/bootstrap/issues/12359 +// and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements +// 2. Reset the default outline behavior of fieldsets so they don't affect page layout. + +fieldset { + min-width: 0; // 1 + padding: 0; // 2 + margin: 0; // 2 + border: 0; // 2 +} + +// 1. By using `float: left`, the legend will behave like a block element. +// This way the border of a fieldset wraps around the legend if present. +// 2. Fix wrapping bug. +// See https://github.com/twbs/bootstrap/issues/29712 + +legend { + float: left; // 1 + width: 100%; + padding: 0; + margin-bottom: $legend-margin-bottom; + @include font-size($legend-font-size); + font-weight: $legend-font-weight; + line-height: inherit; + + + * { + clear: left; // 2 + } +} + +// Fix height of inputs with a type of datetime-local, date, month, week, or time +// See https://github.com/twbs/bootstrap/issues/18842 + +::-webkit-datetime-edit-fields-wrapper, +::-webkit-datetime-edit-text, +::-webkit-datetime-edit-minute, +::-webkit-datetime-edit-hour-field, +::-webkit-datetime-edit-day-field, +::-webkit-datetime-edit-month-field, +::-webkit-datetime-edit-year-field { + padding: 0; +} + +::-webkit-inner-spin-button { + height: auto; +} + +// 1. This overrides the extra rounded corners on search inputs in iOS so that our +// `.form-control` class can properly style them. Note that this cannot simply +// be added to `.form-control` as it's not specific enough. For details, see +// https://github.com/twbs/bootstrap/issues/11586. +// 2. Correct the outline style in Safari. + +[type="search"] { + -webkit-appearance: textfield; // 1 + outline-offset: -2px; // 2 +} + +// 1. A few input types should stay LTR +// See https://rtlstyling.com/posts/rtl-styling#form-inputs +// 2. RTL only output +// See https://rtlcss.com/learn/usage-guide/control-directives/#raw + +/* rtl:raw: +[type="tel"], +[type="url"], +[type="email"], +[type="number"] { + direction: ltr; +} +*/ + +// Remove the inner padding in Chrome and Safari on macOS. + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +// Remove padding around color pickers in webkit browsers + +::-webkit-color-swatch-wrapper { + padding: 0; +} + + +// 1. Inherit font family and line height for file input buttons +// 2. Correct the inability to style clickable types in iOS and Safari. + +::file-selector-button { + font: inherit; // 1 + -webkit-appearance: button; // 2 +} + +// Correct element displays + +output { + display: inline-block; +} + +// Remove border from iframe + +iframe { + border: 0; +} + +// Summary +// +// 1. Add the correct display in all browsers + +summary { + display: list-item; // 1 + cursor: pointer; +} + + +// Progress +// +// Add the correct vertical alignment in Chrome, Firefox, and Opera. + +progress { + vertical-align: baseline; +} + + +// Hidden attribute +// +// Always hide an element with the `hidden` HTML attribute. + +[hidden] { + display: none !important; +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_root.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_root.scss new file mode 100644 index 00000000..becddf14 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_root.scss @@ -0,0 +1,187 @@ +:root, +[data-bs-theme="light"] { + // Note: Custom variable values only support SassScript inside `#{}`. + + // Colors + // + // Generate palettes for full colors, grays, and theme colors. + + @each $color, $value in $colors { + --#{$prefix}#{$color}: #{$value}; + } + + @each $color, $value in $grays { + --#{$prefix}gray-#{$color}: #{$value}; + } + + @each $color, $value in $theme-colors { + --#{$prefix}#{$color}: #{$value}; + } + + @each $color, $value in $theme-colors-rgb { + --#{$prefix}#{$color}-rgb: #{$value}; + } + + @each $color, $value in $theme-colors-text { + --#{$prefix}#{$color}-text-emphasis: #{$value}; + } + + @each $color, $value in $theme-colors-bg-subtle { + --#{$prefix}#{$color}-bg-subtle: #{$value}; + } + + @each $color, $value in $theme-colors-border-subtle { + --#{$prefix}#{$color}-border-subtle: #{$value}; + } + + --#{$prefix}white-rgb: #{to-rgb($white)}; + --#{$prefix}black-rgb: #{to-rgb($black)}; + + // Fonts + + // Note: Use `inspect` for lists so that quoted items keep the quotes. + // See https://github.com/sass/sass/issues/2383#issuecomment-336349172 + --#{$prefix}font-sans-serif: #{inspect($font-family-sans-serif)}; + --#{$prefix}font-monospace: #{inspect($font-family-monospace)}; + --#{$prefix}gradient: #{$gradient}; + + // Root and body + // scss-docs-start root-body-variables + @if $font-size-root != null { + --#{$prefix}root-font-size: #{$font-size-root}; + } + --#{$prefix}body-font-family: #{inspect($font-family-base)}; + @include rfs($font-size-base, --#{$prefix}body-font-size); + --#{$prefix}body-font-weight: #{$font-weight-base}; + --#{$prefix}body-line-height: #{$line-height-base}; + @if $body-text-align != null { + --#{$prefix}body-text-align: #{$body-text-align}; + } + + --#{$prefix}body-color: #{$body-color}; + --#{$prefix}body-color-rgb: #{to-rgb($body-color)}; + --#{$prefix}body-bg: #{$body-bg}; + --#{$prefix}body-bg-rgb: #{to-rgb($body-bg)}; + + --#{$prefix}emphasis-color: #{$body-emphasis-color}; + --#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color)}; + + --#{$prefix}secondary-color: #{$body-secondary-color}; + --#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color)}; + --#{$prefix}secondary-bg: #{$body-secondary-bg}; + --#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg)}; + + --#{$prefix}tertiary-color: #{$body-tertiary-color}; + --#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color)}; + --#{$prefix}tertiary-bg: #{$body-tertiary-bg}; + --#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg)}; + // scss-docs-end root-body-variables + + --#{$prefix}heading-color: #{$headings-color}; + + --#{$prefix}link-color: #{$link-color}; + --#{$prefix}link-color-rgb: #{to-rgb($link-color)}; + --#{$prefix}link-decoration: #{$link-decoration}; + + --#{$prefix}link-hover-color: #{$link-hover-color}; + --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color)}; + + @if $link-hover-decoration != null { + --#{$prefix}link-hover-decoration: #{$link-hover-decoration}; + } + + --#{$prefix}code-color: #{$code-color}; + --#{$prefix}highlight-color: #{$mark-color}; + --#{$prefix}highlight-bg: #{$mark-bg}; + + // scss-docs-start root-border-var + --#{$prefix}border-width: #{$border-width}; + --#{$prefix}border-style: #{$border-style}; + --#{$prefix}border-color: #{$border-color}; + --#{$prefix}border-color-translucent: #{$border-color-translucent}; + + --#{$prefix}border-radius: #{$border-radius}; + --#{$prefix}border-radius-sm: #{$border-radius-sm}; + --#{$prefix}border-radius-lg: #{$border-radius-lg}; + --#{$prefix}border-radius-xl: #{$border-radius-xl}; + --#{$prefix}border-radius-xxl: #{$border-radius-xxl}; + --#{$prefix}border-radius-2xl: var(--#{$prefix}border-radius-xxl); // Deprecated in v5.3.0 for consistency + --#{$prefix}border-radius-pill: #{$border-radius-pill}; + // scss-docs-end root-border-var + + --#{$prefix}box-shadow: #{$box-shadow}; + --#{$prefix}box-shadow-sm: #{$box-shadow-sm}; + --#{$prefix}box-shadow-lg: #{$box-shadow-lg}; + --#{$prefix}box-shadow-inset: #{$box-shadow-inset}; + + // Focus styles + // scss-docs-start root-focus-variables + --#{$prefix}focus-ring-width: #{$focus-ring-width}; + --#{$prefix}focus-ring-opacity: #{$focus-ring-opacity}; + --#{$prefix}focus-ring-color: #{$focus-ring-color}; + // scss-docs-end root-focus-variables + + // scss-docs-start root-form-validation-variables + --#{$prefix}form-valid-color: #{$form-valid-color}; + --#{$prefix}form-valid-border-color: #{$form-valid-border-color}; + --#{$prefix}form-invalid-color: #{$form-invalid-color}; + --#{$prefix}form-invalid-border-color: #{$form-invalid-border-color}; + // scss-docs-end root-form-validation-variables +} + +@if $enable-dark-mode { + @include color-mode(dark, true) { + color-scheme: dark; + + // scss-docs-start root-dark-mode-vars + --#{$prefix}body-color: #{$body-color-dark}; + --#{$prefix}body-color-rgb: #{to-rgb($body-color-dark)}; + --#{$prefix}body-bg: #{$body-bg-dark}; + --#{$prefix}body-bg-rgb: #{to-rgb($body-bg-dark)}; + + --#{$prefix}emphasis-color: #{$body-emphasis-color-dark}; + --#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color-dark)}; + + --#{$prefix}secondary-color: #{$body-secondary-color-dark}; + --#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color-dark)}; + --#{$prefix}secondary-bg: #{$body-secondary-bg-dark}; + --#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg-dark)}; + + --#{$prefix}tertiary-color: #{$body-tertiary-color-dark}; + --#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color-dark)}; + --#{$prefix}tertiary-bg: #{$body-tertiary-bg-dark}; + --#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg-dark)}; + + @each $color, $value in $theme-colors-text-dark { + --#{$prefix}#{$color}-text-emphasis: #{$value}; + } + + @each $color, $value in $theme-colors-bg-subtle-dark { + --#{$prefix}#{$color}-bg-subtle: #{$value}; + } + + @each $color, $value in $theme-colors-border-subtle-dark { + --#{$prefix}#{$color}-border-subtle: #{$value}; + } + + --#{$prefix}heading-color: #{$headings-color-dark}; + + --#{$prefix}link-color: #{$link-color-dark}; + --#{$prefix}link-hover-color: #{$link-hover-color-dark}; + --#{$prefix}link-color-rgb: #{to-rgb($link-color-dark)}; + --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color-dark)}; + + --#{$prefix}code-color: #{$code-color-dark}; + --#{$prefix}highlight-color: #{$mark-color-dark}; + --#{$prefix}highlight-bg: #{$mark-bg-dark}; + + --#{$prefix}border-color: #{$border-color-dark}; + --#{$prefix}border-color-translucent: #{$border-color-translucent-dark}; + + --#{$prefix}form-valid-color: #{$form-valid-color-dark}; + --#{$prefix}form-valid-border-color: #{$form-valid-border-color-dark}; + --#{$prefix}form-invalid-color: #{$form-invalid-color-dark}; + --#{$prefix}form-invalid-border-color: #{$form-invalid-border-color-dark}; + // scss-docs-end root-dark-mode-vars + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_spinners.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_spinners.scss new file mode 100644 index 00000000..ec847320 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_spinners.scss @@ -0,0 +1,85 @@ +// +// Rotating border +// + +.spinner-grow, +.spinner-border { + display: inline-block; + width: var(--#{$prefix}spinner-width); + height: var(--#{$prefix}spinner-height); + vertical-align: var(--#{$prefix}spinner-vertical-align); + // stylelint-disable-next-line property-disallowed-list + border-radius: 50%; + animation: var(--#{$prefix}spinner-animation-speed) linear infinite var(--#{$prefix}spinner-animation-name); +} + +// scss-docs-start spinner-border-keyframes +@keyframes spinner-border { + to { transform: rotate(360deg) #{"/* rtl:ignore */"}; } +} +// scss-docs-end spinner-border-keyframes + +.spinner-border { + // scss-docs-start spinner-border-css-vars + --#{$prefix}spinner-width: #{$spinner-width}; + --#{$prefix}spinner-height: #{$spinner-height}; + --#{$prefix}spinner-vertical-align: #{$spinner-vertical-align}; + --#{$prefix}spinner-border-width: #{$spinner-border-width}; + --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed}; + --#{$prefix}spinner-animation-name: spinner-border; + // scss-docs-end spinner-border-css-vars + + border: var(--#{$prefix}spinner-border-width) solid currentcolor; + border-right-color: transparent; +} + +.spinner-border-sm { + // scss-docs-start spinner-border-sm-css-vars + --#{$prefix}spinner-width: #{$spinner-width-sm}; + --#{$prefix}spinner-height: #{$spinner-height-sm}; + --#{$prefix}spinner-border-width: #{$spinner-border-width-sm}; + // scss-docs-end spinner-border-sm-css-vars +} + +// +// Growing circle +// + +// scss-docs-start spinner-grow-keyframes +@keyframes spinner-grow { + 0% { + transform: scale(0); + } + 50% { + opacity: 1; + transform: none; + } +} +// scss-docs-end spinner-grow-keyframes + +.spinner-grow { + // scss-docs-start spinner-grow-css-vars + --#{$prefix}spinner-width: #{$spinner-width}; + --#{$prefix}spinner-height: #{$spinner-height}; + --#{$prefix}spinner-vertical-align: #{$spinner-vertical-align}; + --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed}; + --#{$prefix}spinner-animation-name: spinner-grow; + // scss-docs-end spinner-grow-css-vars + + background-color: currentcolor; + opacity: 0; +} + +.spinner-grow-sm { + --#{$prefix}spinner-width: #{$spinner-width-sm}; + --#{$prefix}spinner-height: #{$spinner-height-sm}; +} + +@if $enable-reduced-motion { + @media (prefers-reduced-motion: reduce) { + .spinner-border, + .spinner-grow { + --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed * 2}; + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_tables.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_tables.scss new file mode 100644 index 00000000..276521a3 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_tables.scss @@ -0,0 +1,171 @@ +// +// Basic Bootstrap table +// + +.table { + // Reset needed for nesting tables + --#{$prefix}table-color-type: initial; + --#{$prefix}table-bg-type: initial; + --#{$prefix}table-color-state: initial; + --#{$prefix}table-bg-state: initial; + // End of reset + --#{$prefix}table-color: #{$table-color}; + --#{$prefix}table-bg: #{$table-bg}; + --#{$prefix}table-border-color: #{$table-border-color}; + --#{$prefix}table-accent-bg: #{$table-accent-bg}; + --#{$prefix}table-striped-color: #{$table-striped-color}; + --#{$prefix}table-striped-bg: #{$table-striped-bg}; + --#{$prefix}table-active-color: #{$table-active-color}; + --#{$prefix}table-active-bg: #{$table-active-bg}; + --#{$prefix}table-hover-color: #{$table-hover-color}; + --#{$prefix}table-hover-bg: #{$table-hover-bg}; + + width: 100%; + margin-bottom: $spacer; + vertical-align: $table-cell-vertical-align; + border-color: var(--#{$prefix}table-border-color); + + // Target th & td + // We need the child combinator to prevent styles leaking to nested tables which doesn't have a `.table` class. + // We use the universal selectors here to simplify the selector (else we would need 6 different selectors). + // Another advantage is that this generates less code and makes the selector less specific making it easier to override. + // stylelint-disable-next-line selector-max-universal + > :not(caption) > * > * { + padding: $table-cell-padding-y $table-cell-padding-x; + // Following the precept of cascades: https://codepen.io/miriamsuzanne/full/vYNgodb + color: var(--#{$prefix}table-color-state, var(--#{$prefix}table-color-type, var(--#{$prefix}table-color))); + background-color: var(--#{$prefix}table-bg); + border-bottom-width: $table-border-width; + box-shadow: inset 0 0 0 9999px var(--#{$prefix}table-bg-state, var(--#{$prefix}table-bg-type, var(--#{$prefix}table-accent-bg))); + } + + > tbody { + vertical-align: inherit; + } + + > thead { + vertical-align: bottom; + } +} + +.table-group-divider { + border-top: calc(#{$table-border-width} * 2) solid $table-group-separator-color; // stylelint-disable-line function-disallowed-list +} + +// +// Change placement of captions with a class +// + +.caption-top { + caption-side: top; +} + + +// +// Condensed table w/ half padding +// + +.table-sm { + // stylelint-disable-next-line selector-max-universal + > :not(caption) > * > * { + padding: $table-cell-padding-y-sm $table-cell-padding-x-sm; + } +} + + +// Border versions +// +// Add or remove borders all around the table and between all the columns. +// +// When borders are added on all sides of the cells, the corners can render odd when +// these borders do not have the same color or if they are semi-transparent. +// Therefore we add top and border bottoms to the `tr`s and left and right borders +// to the `td`s or `th`s + +.table-bordered { + > :not(caption) > * { + border-width: $table-border-width 0; + + // stylelint-disable-next-line selector-max-universal + > * { + border-width: 0 $table-border-width; + } + } +} + +.table-borderless { + // stylelint-disable-next-line selector-max-universal + > :not(caption) > * > * { + border-bottom-width: 0; + } + + > :not(:first-child) { + border-top-width: 0; + } +} + +// Zebra-striping +// +// Default zebra-stripe styles (alternating gray and transparent backgrounds) + +// For rows +.table-striped { + > tbody > tr:nth-of-type(#{$table-striped-order}) > * { + --#{$prefix}table-color-type: var(--#{$prefix}table-striped-color); + --#{$prefix}table-bg-type: var(--#{$prefix}table-striped-bg); + } +} + +// For columns +.table-striped-columns { + > :not(caption) > tr > :nth-child(#{$table-striped-columns-order}) { + --#{$prefix}table-color-type: var(--#{$prefix}table-striped-color); + --#{$prefix}table-bg-type: var(--#{$prefix}table-striped-bg); + } +} + +// Active table +// +// The `.table-active` class can be added to highlight rows or cells + +.table-active { + --#{$prefix}table-color-state: var(--#{$prefix}table-active-color); + --#{$prefix}table-bg-state: var(--#{$prefix}table-active-bg); +} + +// Hover effect +// +// Placed here since it has to come after the potential zebra striping + +.table-hover { + > tbody > tr:hover > * { + --#{$prefix}table-color-state: var(--#{$prefix}table-hover-color); + --#{$prefix}table-bg-state: var(--#{$prefix}table-hover-bg); + } +} + + +// Table variants +// +// Table variants set the table cell backgrounds, border colors +// and the colors of the striped, hovered & active tables + +@each $color, $value in $table-variants { + @include table-variant($color, $value); +} + +// Responsive tables +// +// Generate series of `.table-responsive-*` classes for configuring the screen +// size of where your table will overflow. + +@each $breakpoint in map-keys($grid-breakpoints) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + @include media-breakpoint-down($breakpoint) { + .table-responsive#{$infix} { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_toasts.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_toasts.scss new file mode 100644 index 00000000..2ce378d5 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_toasts.scss @@ -0,0 +1,73 @@ +.toast { + // scss-docs-start toast-css-vars + --#{$prefix}toast-zindex: #{$zindex-toast}; + --#{$prefix}toast-padding-x: #{$toast-padding-x}; + --#{$prefix}toast-padding-y: #{$toast-padding-y}; + --#{$prefix}toast-spacing: #{$toast-spacing}; + --#{$prefix}toast-max-width: #{$toast-max-width}; + @include rfs($toast-font-size, --#{$prefix}toast-font-size); + --#{$prefix}toast-color: #{$toast-color}; + --#{$prefix}toast-bg: #{$toast-background-color}; + --#{$prefix}toast-border-width: #{$toast-border-width}; + --#{$prefix}toast-border-color: #{$toast-border-color}; + --#{$prefix}toast-border-radius: #{$toast-border-radius}; + --#{$prefix}toast-box-shadow: #{$toast-box-shadow}; + --#{$prefix}toast-header-color: #{$toast-header-color}; + --#{$prefix}toast-header-bg: #{$toast-header-background-color}; + --#{$prefix}toast-header-border-color: #{$toast-header-border-color}; + // scss-docs-end toast-css-vars + + width: var(--#{$prefix}toast-max-width); + max-width: 100%; + @include font-size(var(--#{$prefix}toast-font-size)); + color: var(--#{$prefix}toast-color); + pointer-events: auto; + background-color: var(--#{$prefix}toast-bg); + background-clip: padding-box; + border: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-border-color); + box-shadow: var(--#{$prefix}toast-box-shadow); + @include border-radius(var(--#{$prefix}toast-border-radius)); + + &.showing { + opacity: 0; + } + + &:not(.show) { + display: none; + } +} + +.toast-container { + --#{$prefix}toast-zindex: #{$zindex-toast}; + + position: absolute; + z-index: var(--#{$prefix}toast-zindex); + width: max-content; + max-width: 100%; + pointer-events: none; + + > :not(:last-child) { + margin-bottom: var(--#{$prefix}toast-spacing); + } +} + +.toast-header { + display: flex; + align-items: center; + padding: var(--#{$prefix}toast-padding-y) var(--#{$prefix}toast-padding-x); + color: var(--#{$prefix}toast-header-color); + background-color: var(--#{$prefix}toast-header-bg); + background-clip: padding-box; + border-bottom: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-header-border-color); + @include border-top-radius(calc(var(--#{$prefix}toast-border-radius) - var(--#{$prefix}toast-border-width))); + + .btn-close { + margin-right: calc(-.5 * var(--#{$prefix}toast-padding-x)); // stylelint-disable-line function-disallowed-list + margin-left: var(--#{$prefix}toast-padding-x); + } +} + +.toast-body { + padding: var(--#{$prefix}toast-padding-x); + word-wrap: break-word; +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_tooltip.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_tooltip.scss new file mode 100644 index 00000000..85de90f5 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_tooltip.scss @@ -0,0 +1,119 @@ +// Base class +.tooltip { + // scss-docs-start tooltip-css-vars + --#{$prefix}tooltip-zindex: #{$zindex-tooltip}; + --#{$prefix}tooltip-max-width: #{$tooltip-max-width}; + --#{$prefix}tooltip-padding-x: #{$tooltip-padding-x}; + --#{$prefix}tooltip-padding-y: #{$tooltip-padding-y}; + --#{$prefix}tooltip-margin: #{$tooltip-margin}; + @include rfs($tooltip-font-size, --#{$prefix}tooltip-font-size); + --#{$prefix}tooltip-color: #{$tooltip-color}; + --#{$prefix}tooltip-bg: #{$tooltip-bg}; + --#{$prefix}tooltip-border-radius: #{$tooltip-border-radius}; + --#{$prefix}tooltip-opacity: #{$tooltip-opacity}; + --#{$prefix}tooltip-arrow-width: #{$tooltip-arrow-width}; + --#{$prefix}tooltip-arrow-height: #{$tooltip-arrow-height}; + // scss-docs-end tooltip-css-vars + + z-index: var(--#{$prefix}tooltip-zindex); + display: block; + margin: var(--#{$prefix}tooltip-margin); + @include deprecate("`$tooltip-margin`", "v5", "v5.x", true); + // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element. + // So reset our font and text properties to avoid inheriting weird values. + @include reset-text(); + @include font-size(var(--#{$prefix}tooltip-font-size)); + // Allow breaking very long words so they don't overflow the tooltip's bounds + word-wrap: break-word; + opacity: 0; + + &.show { opacity: var(--#{$prefix}tooltip-opacity); } + + .tooltip-arrow { + display: block; + width: var(--#{$prefix}tooltip-arrow-width); + height: var(--#{$prefix}tooltip-arrow-height); + + &::before { + position: absolute; + content: ""; + border-color: transparent; + border-style: solid; + } + } +} + +.bs-tooltip-top .tooltip-arrow { + bottom: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list + + &::before { + top: -1px; + border-width: var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list + border-top-color: var(--#{$prefix}tooltip-bg); + } +} + +/* rtl:begin:ignore */ +.bs-tooltip-end .tooltip-arrow { + left: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list + width: var(--#{$prefix}tooltip-arrow-height); + height: var(--#{$prefix}tooltip-arrow-width); + + &::before { + right: -1px; + border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list + border-right-color: var(--#{$prefix}tooltip-bg); + } +} + +/* rtl:end:ignore */ + +.bs-tooltip-bottom .tooltip-arrow { + top: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list + + &::before { + bottom: -1px; + border-width: 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list + border-bottom-color: var(--#{$prefix}tooltip-bg); + } +} + +/* rtl:begin:ignore */ +.bs-tooltip-start .tooltip-arrow { + right: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list + width: var(--#{$prefix}tooltip-arrow-height); + height: var(--#{$prefix}tooltip-arrow-width); + + &::before { + left: -1px; + border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list + border-left-color: var(--#{$prefix}tooltip-bg); + } +} + +/* rtl:end:ignore */ + +.bs-tooltip-auto { + &[data-popper-placement^="top"] { + @extend .bs-tooltip-top; + } + &[data-popper-placement^="right"] { + @extend .bs-tooltip-end; + } + &[data-popper-placement^="bottom"] { + @extend .bs-tooltip-bottom; + } + &[data-popper-placement^="left"] { + @extend .bs-tooltip-start; + } +} + +// Wrapper for the tooltip content +.tooltip-inner { + max-width: var(--#{$prefix}tooltip-max-width); + padding: var(--#{$prefix}tooltip-padding-y) var(--#{$prefix}tooltip-padding-x); + color: var(--#{$prefix}tooltip-color); + text-align: center; + background-color: var(--#{$prefix}tooltip-bg); + @include border-radius(var(--#{$prefix}tooltip-border-radius)); +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_transitions.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_transitions.scss new file mode 100644 index 00000000..bfb26aa8 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_transitions.scss @@ -0,0 +1,27 @@ +.fade { + @include transition($transition-fade); + + &:not(.show) { + opacity: 0; + } +} + +// scss-docs-start collapse-classes +.collapse { + &:not(.show) { + display: none; + } +} + +.collapsing { + height: 0; + overflow: hidden; + @include transition($transition-collapse); + + &.collapse-horizontal { + width: 0; + height: auto; + @include transition($transition-collapse-width); + } +} +// scss-docs-end collapse-classes diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_type.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_type.scss new file mode 100644 index 00000000..37d64bf8 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_type.scss @@ -0,0 +1,106 @@ +// +// Headings +// +.h1 { + @extend h1; +} + +.h2 { + @extend h2; +} + +.h3 { + @extend h3; +} + +.h4 { + @extend h4; +} + +.h5 { + @extend h5; +} + +.h6 { + @extend h6; +} + + +.lead { + @include font-size($lead-font-size); + font-weight: $lead-font-weight; +} + +// Type display classes +@each $display, $font-size in $display-font-sizes { + .display-#{$display} { + @include font-size($font-size); + font-family: $display-font-family; + font-style: $display-font-style; + font-weight: $display-font-weight; + line-height: $display-line-height; + } +} + +// +// Emphasis +// +.small { + @extend small; +} + +.mark { + @extend mark; +} + +// +// Lists +// + +.list-unstyled { + @include list-unstyled(); +} + +// Inline turns list items into inline-block +.list-inline { + @include list-unstyled(); +} +.list-inline-item { + display: inline-block; + + &:not(:last-child) { + margin-right: $list-inline-padding; + } +} + + +// +// Misc +// + +// Builds on `abbr` +.initialism { + @include font-size($initialism-font-size); + text-transform: uppercase; +} + +// Blockquotes +.blockquote { + margin-bottom: $blockquote-margin-y; + @include font-size($blockquote-font-size); + + > :last-child { + margin-bottom: 0; + } +} + +.blockquote-footer { + margin-top: -$blockquote-margin-y; + margin-bottom: $blockquote-margin-y; + @include font-size($blockquote-footer-font-size); + color: $blockquote-footer-color; + + &::before { + content: "\2014\00A0"; // em dash, nbsp + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_utilities.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_utilities.scss new file mode 100644 index 00000000..696f906e --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_utilities.scss @@ -0,0 +1,806 @@ +// Utilities + +$utilities: () !default; +// stylelint-disable-next-line scss/dollar-variable-default +$utilities: map-merge( + ( + // scss-docs-start utils-vertical-align + "align": ( + property: vertical-align, + class: align, + values: baseline top middle bottom text-bottom text-top + ), + // scss-docs-end utils-vertical-align + // scss-docs-start utils-float + "float": ( + responsive: true, + property: float, + values: ( + start: left, + end: right, + none: none, + ) + ), + // scss-docs-end utils-float + // Object Fit utilities + // scss-docs-start utils-object-fit + "object-fit": ( + responsive: true, + property: object-fit, + values: ( + contain: contain, + cover: cover, + fill: fill, + scale: scale-down, + none: none, + ) + ), + // scss-docs-end utils-object-fit + // Opacity utilities + // scss-docs-start utils-opacity + "opacity": ( + property: opacity, + values: ( + 0: 0, + 25: .25, + 50: .5, + 75: .75, + 100: 1, + ) + ), + // scss-docs-end utils-opacity + // scss-docs-start utils-overflow + "overflow": ( + property: overflow, + values: auto hidden visible scroll, + ), + "overflow-x": ( + property: overflow-x, + values: auto hidden visible scroll, + ), + "overflow-y": ( + property: overflow-y, + values: auto hidden visible scroll, + ), + // scss-docs-end utils-overflow + // scss-docs-start utils-display + "display": ( + responsive: true, + print: true, + property: display, + class: d, + values: inline inline-block block grid inline-grid table table-row table-cell flex inline-flex none + ), + // scss-docs-end utils-display + // scss-docs-start utils-shadow + "shadow": ( + property: box-shadow, + class: shadow, + values: ( + null: var(--#{$prefix}box-shadow), + sm: var(--#{$prefix}box-shadow-sm), + lg: var(--#{$prefix}box-shadow-lg), + none: none, + ) + ), + // scss-docs-end utils-shadow + // scss-docs-start utils-focus-ring + "focus-ring": ( + css-var: true, + css-variable-name: focus-ring-color, + class: focus-ring, + values: map-loop($theme-colors-rgb, rgba-css-var, "$key", "focus-ring") + ), + // scss-docs-end utils-focus-ring + // scss-docs-start utils-position + "position": ( + property: position, + values: static relative absolute fixed sticky + ), + "top": ( + property: top, + values: $position-values + ), + "bottom": ( + property: bottom, + values: $position-values + ), + "start": ( + property: left, + class: start, + values: $position-values + ), + "end": ( + property: right, + class: end, + values: $position-values + ), + "translate-middle": ( + property: transform, + class: translate-middle, + values: ( + null: translate(-50%, -50%), + x: translateX(-50%), + y: translateY(-50%), + ) + ), + // scss-docs-end utils-position + // scss-docs-start utils-borders + "border": ( + property: border, + values: ( + null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color), + 0: 0, + ) + ), + "border-top": ( + property: border-top, + values: ( + null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color), + 0: 0, + ) + ), + "border-end": ( + property: border-right, + class: border-end, + values: ( + null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color), + 0: 0, + ) + ), + "border-bottom": ( + property: border-bottom, + values: ( + null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color), + 0: 0, + ) + ), + "border-start": ( + property: border-left, + class: border-start, + values: ( + null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color), + 0: 0, + ) + ), + "border-color": ( + property: border-color, + class: border, + local-vars: ( + "border-opacity": 1 + ), + values: $utilities-border-colors + ), + "subtle-border-color": ( + property: border-color, + class: border, + values: $utilities-border-subtle + ), + "border-width": ( + property: border-width, + class: border, + values: $border-widths + ), + "border-opacity": ( + css-var: true, + class: border-opacity, + values: ( + 10: .1, + 25: .25, + 50: .5, + 75: .75, + 100: 1 + ) + ), + // scss-docs-end utils-borders + // Sizing utilities + // scss-docs-start utils-sizing + "width": ( + property: width, + class: w, + values: ( + 25: 25%, + 50: 50%, + 75: 75%, + 100: 100%, + auto: auto + ) + ), + "max-width": ( + property: max-width, + class: mw, + values: (100: 100%) + ), + "viewport-width": ( + property: width, + class: vw, + values: (100: 100vw) + ), + "min-viewport-width": ( + property: min-width, + class: min-vw, + values: (100: 100vw) + ), + "height": ( + property: height, + class: h, + values: ( + 25: 25%, + 50: 50%, + 75: 75%, + 100: 100%, + auto: auto + ) + ), + "max-height": ( + property: max-height, + class: mh, + values: (100: 100%) + ), + "viewport-height": ( + property: height, + class: vh, + values: (100: 100vh) + ), + "min-viewport-height": ( + property: min-height, + class: min-vh, + values: (100: 100vh) + ), + // scss-docs-end utils-sizing + // Flex utilities + // scss-docs-start utils-flex + "flex": ( + responsive: true, + property: flex, + values: (fill: 1 1 auto) + ), + "flex-direction": ( + responsive: true, + property: flex-direction, + class: flex, + values: row column row-reverse column-reverse + ), + "flex-grow": ( + responsive: true, + property: flex-grow, + class: flex, + values: ( + grow-0: 0, + grow-1: 1, + ) + ), + "flex-shrink": ( + responsive: true, + property: flex-shrink, + class: flex, + values: ( + shrink-0: 0, + shrink-1: 1, + ) + ), + "flex-wrap": ( + responsive: true, + property: flex-wrap, + class: flex, + values: wrap nowrap wrap-reverse + ), + "justify-content": ( + responsive: true, + property: justify-content, + values: ( + start: flex-start, + end: flex-end, + center: center, + between: space-between, + around: space-around, + evenly: space-evenly, + ) + ), + "align-items": ( + responsive: true, + property: align-items, + values: ( + start: flex-start, + end: flex-end, + center: center, + baseline: baseline, + stretch: stretch, + ) + ), + "align-content": ( + responsive: true, + property: align-content, + values: ( + start: flex-start, + end: flex-end, + center: center, + between: space-between, + around: space-around, + stretch: stretch, + ) + ), + "align-self": ( + responsive: true, + property: align-self, + values: ( + auto: auto, + start: flex-start, + end: flex-end, + center: center, + baseline: baseline, + stretch: stretch, + ) + ), + "order": ( + responsive: true, + property: order, + values: ( + first: -1, + 0: 0, + 1: 1, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + last: 6, + ), + ), + // scss-docs-end utils-flex + // Margin utilities + // scss-docs-start utils-spacing + "margin": ( + responsive: true, + property: margin, + class: m, + values: map-merge($spacers, (auto: auto)) + ), + "margin-x": ( + responsive: true, + property: margin-right margin-left, + class: mx, + values: map-merge($spacers, (auto: auto)) + ), + "margin-y": ( + responsive: true, + property: margin-top margin-bottom, + class: my, + values: map-merge($spacers, (auto: auto)) + ), + "margin-top": ( + responsive: true, + property: margin-top, + class: mt, + values: map-merge($spacers, (auto: auto)) + ), + "margin-end": ( + responsive: true, + property: margin-right, + class: me, + values: map-merge($spacers, (auto: auto)) + ), + "margin-bottom": ( + responsive: true, + property: margin-bottom, + class: mb, + values: map-merge($spacers, (auto: auto)) + ), + "margin-start": ( + responsive: true, + property: margin-left, + class: ms, + values: map-merge($spacers, (auto: auto)) + ), + // Negative margin utilities + "negative-margin": ( + responsive: true, + property: margin, + class: m, + values: $negative-spacers + ), + "negative-margin-x": ( + responsive: true, + property: margin-right margin-left, + class: mx, + values: $negative-spacers + ), + "negative-margin-y": ( + responsive: true, + property: margin-top margin-bottom, + class: my, + values: $negative-spacers + ), + "negative-margin-top": ( + responsive: true, + property: margin-top, + class: mt, + values: $negative-spacers + ), + "negative-margin-end": ( + responsive: true, + property: margin-right, + class: me, + values: $negative-spacers + ), + "negative-margin-bottom": ( + responsive: true, + property: margin-bottom, + class: mb, + values: $negative-spacers + ), + "negative-margin-start": ( + responsive: true, + property: margin-left, + class: ms, + values: $negative-spacers + ), + // Padding utilities + "padding": ( + responsive: true, + property: padding, + class: p, + values: $spacers + ), + "padding-x": ( + responsive: true, + property: padding-right padding-left, + class: px, + values: $spacers + ), + "padding-y": ( + responsive: true, + property: padding-top padding-bottom, + class: py, + values: $spacers + ), + "padding-top": ( + responsive: true, + property: padding-top, + class: pt, + values: $spacers + ), + "padding-end": ( + responsive: true, + property: padding-right, + class: pe, + values: $spacers + ), + "padding-bottom": ( + responsive: true, + property: padding-bottom, + class: pb, + values: $spacers + ), + "padding-start": ( + responsive: true, + property: padding-left, + class: ps, + values: $spacers + ), + // Gap utility + "gap": ( + responsive: true, + property: gap, + class: gap, + values: $spacers + ), + "row-gap": ( + responsive: true, + property: row-gap, + class: row-gap, + values: $spacers + ), + "column-gap": ( + responsive: true, + property: column-gap, + class: column-gap, + values: $spacers + ), + // scss-docs-end utils-spacing + // Text + // scss-docs-start utils-text + "font-family": ( + property: font-family, + class: font, + values: (monospace: var(--#{$prefix}font-monospace)) + ), + "font-size": ( + rfs: true, + property: font-size, + class: fs, + values: $font-sizes + ), + "font-style": ( + property: font-style, + class: fst, + values: italic normal + ), + "font-weight": ( + property: font-weight, + class: fw, + values: ( + lighter: $font-weight-lighter, + light: $font-weight-light, + normal: $font-weight-normal, + medium: $font-weight-medium, + semibold: $font-weight-semibold, + bold: $font-weight-bold, + bolder: $font-weight-bolder + ) + ), + "line-height": ( + property: line-height, + class: lh, + values: ( + 1: 1, + sm: $line-height-sm, + base: $line-height-base, + lg: $line-height-lg, + ) + ), + "text-align": ( + responsive: true, + property: text-align, + class: text, + values: ( + start: left, + end: right, + center: center, + ) + ), + "text-decoration": ( + property: text-decoration, + values: none underline line-through + ), + "text-transform": ( + property: text-transform, + class: text, + values: lowercase uppercase capitalize + ), + "white-space": ( + property: white-space, + class: text, + values: ( + wrap: normal, + nowrap: nowrap, + ) + ), + "word-wrap": ( + property: word-wrap word-break, + class: text, + values: (break: break-word), + rtl: false + ), + // scss-docs-end utils-text + // scss-docs-start utils-color + "color": ( + property: color, + class: text, + local-vars: ( + "text-opacity": 1 + ), + values: map-merge( + $utilities-text-colors, + ( + "muted": var(--#{$prefix}secondary-color), // deprecated + "black-50": rgba($black, .5), // deprecated + "white-50": rgba($white, .5), // deprecated + "body-secondary": var(--#{$prefix}secondary-color), + "body-tertiary": var(--#{$prefix}tertiary-color), + "body-emphasis": var(--#{$prefix}emphasis-color), + "reset": inherit, + ) + ) + ), + "text-opacity": ( + css-var: true, + class: text-opacity, + values: ( + 25: .25, + 50: .5, + 75: .75, + 100: 1 + ) + ), + "text-color": ( + property: color, + class: text, + values: $utilities-text-emphasis-colors + ), + // scss-docs-end utils-color + // scss-docs-start utils-links + "link-opacity": ( + css-var: true, + class: link-opacity, + state: hover, + values: ( + 10: .1, + 25: .25, + 50: .5, + 75: .75, + 100: 1 + ) + ), + "link-offset": ( + property: text-underline-offset, + class: link-offset, + state: hover, + values: ( + 1: .125em, + 2: .25em, + 3: .375em, + ) + ), + "link-underline": ( + property: text-decoration-color, + class: link-underline, + local-vars: ( + "link-underline-opacity": 1 + ), + values: map-merge( + $utilities-links-underline, + ( + null: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-underline-opacity, 1)), + ) + ) + ), + "link-underline-opacity": ( + css-var: true, + class: link-underline-opacity, + state: hover, + values: ( + 0: 0, + 10: .1, + 25: .25, + 50: .5, + 75: .75, + 100: 1 + ), + ), + // scss-docs-end utils-links + // scss-docs-start utils-bg-color + "background-color": ( + property: background-color, + class: bg, + local-vars: ( + "bg-opacity": 1 + ), + values: map-merge( + $utilities-bg-colors, + ( + "transparent": transparent, + "body-secondary": rgba(var(--#{$prefix}secondary-bg-rgb), var(--#{$prefix}bg-opacity)), + "body-tertiary": rgba(var(--#{$prefix}tertiary-bg-rgb), var(--#{$prefix}bg-opacity)), + ) + ) + ), + "bg-opacity": ( + css-var: true, + class: bg-opacity, + values: ( + 10: .1, + 25: .25, + 50: .5, + 75: .75, + 100: 1 + ) + ), + "subtle-background-color": ( + property: background-color, + class: bg, + values: $utilities-bg-subtle + ), + // scss-docs-end utils-bg-color + "gradient": ( + property: background-image, + class: bg, + values: (gradient: var(--#{$prefix}gradient)) + ), + // scss-docs-start utils-interaction + "user-select": ( + property: user-select, + values: all auto none + ), + "pointer-events": ( + property: pointer-events, + class: pe, + values: none auto, + ), + // scss-docs-end utils-interaction + // scss-docs-start utils-border-radius + "rounded": ( + property: border-radius, + class: rounded, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-top": ( + property: border-top-left-radius border-top-right-radius, + class: rounded-top, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-end": ( + property: border-top-right-radius border-bottom-right-radius, + class: rounded-end, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-bottom": ( + property: border-bottom-right-radius border-bottom-left-radius, + class: rounded-bottom, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-start": ( + property: border-bottom-left-radius border-top-left-radius, + class: rounded-start, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + // scss-docs-end utils-border-radius + // scss-docs-start utils-visibility + "visibility": ( + property: visibility, + class: null, + values: ( + visible: visible, + invisible: hidden, + ) + ), + // scss-docs-end utils-visibility + // scss-docs-start utils-zindex + "z-index": ( + property: z-index, + class: z, + values: $zindex-levels, + ) + // scss-docs-end utils-zindex + ), + $utilities +); diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables-dark.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables-dark.scss new file mode 100644 index 00000000..6422b387 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables-dark.scss @@ -0,0 +1,87 @@ +// Dark color mode variables +// +// Custom variables for the `[data-bs-theme="dark"]` theme. Use this as a starting point for your own custom color modes by creating a new theme-specific file like `_variables-dark.scss` and adding the variables you need. + +// +// Global colors +// + +// scss-docs-start sass-dark-mode-vars +// scss-docs-start theme-text-dark-variables +$primary-text-emphasis-dark: tint-color($primary, 40%) !default; +$secondary-text-emphasis-dark: tint-color($secondary, 40%) !default; +$success-text-emphasis-dark: tint-color($success, 40%) !default; +$info-text-emphasis-dark: tint-color($info, 40%) !default; +$warning-text-emphasis-dark: tint-color($warning, 40%) !default; +$danger-text-emphasis-dark: tint-color($danger, 40%) !default; +$light-text-emphasis-dark: $gray-100 !default; +$dark-text-emphasis-dark: $gray-300 !default; +// scss-docs-end theme-text-dark-variables + +// scss-docs-start theme-bg-subtle-dark-variables +$primary-bg-subtle-dark: shade-color($primary, 80%) !default; +$secondary-bg-subtle-dark: shade-color($secondary, 80%) !default; +$success-bg-subtle-dark: shade-color($success, 80%) !default; +$info-bg-subtle-dark: shade-color($info, 80%) !default; +$warning-bg-subtle-dark: shade-color($warning, 80%) !default; +$danger-bg-subtle-dark: shade-color($danger, 80%) !default; +$light-bg-subtle-dark: $gray-800 !default; +$dark-bg-subtle-dark: mix($gray-800, $black) !default; +// scss-docs-end theme-bg-subtle-dark-variables + +// scss-docs-start theme-border-subtle-dark-variables +$primary-border-subtle-dark: shade-color($primary, 40%) !default; +$secondary-border-subtle-dark: shade-color($secondary, 40%) !default; +$success-border-subtle-dark: shade-color($success, 40%) !default; +$info-border-subtle-dark: shade-color($info, 40%) !default; +$warning-border-subtle-dark: shade-color($warning, 40%) !default; +$danger-border-subtle-dark: shade-color($danger, 40%) !default; +$light-border-subtle-dark: $gray-700 !default; +$dark-border-subtle-dark: $gray-800 !default; +// scss-docs-end theme-border-subtle-dark-variables + +$body-color-dark: $gray-300 !default; +$body-bg-dark: $gray-900 !default; +$body-secondary-color-dark: rgba($body-color-dark, .75) !default; +$body-secondary-bg-dark: $gray-800 !default; +$body-tertiary-color-dark: rgba($body-color-dark, .5) !default; +$body-tertiary-bg-dark: mix($gray-800, $gray-900, 50%) !default; +$body-emphasis-color-dark: $white !default; +$border-color-dark: $gray-700 !default; +$border-color-translucent-dark: rgba($white, .15) !default; +$headings-color-dark: inherit !default; +$link-color-dark: tint-color($primary, 40%) !default; +$link-hover-color-dark: shift-color($link-color-dark, -$link-shade-percentage) !default; +$code-color-dark: tint-color($code-color, 40%) !default; +$mark-color-dark: $body-color-dark !default; +$mark-bg-dark: $yellow-800 !default; + + +// +// Forms +// + +$form-select-indicator-color-dark: $body-color-dark !default; +$form-select-indicator-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='#{$form-select-indicator-color-dark}' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/></svg>") !default; + +$form-switch-color-dark: rgba($white, .25) !default; +$form-switch-bg-image-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-color-dark}'/></svg>") !default; + +// scss-docs-start form-validation-colors-dark +$form-valid-color-dark: $green-300 !default; +$form-valid-border-color-dark: $green-300 !default; +$form-invalid-color-dark: $red-300 !default; +$form-invalid-border-color-dark: $red-300 !default; +// scss-docs-end form-validation-colors-dark + + +// +// Accordion +// + +$accordion-icon-color-dark: $primary-text-emphasis-dark !default; +$accordion-icon-active-color-dark: $primary-text-emphasis-dark !default; + +$accordion-button-icon-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-color-dark}'><path fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/></svg>") !default; +$accordion-button-active-icon-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-active-color-dark}'><path fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/></svg>") !default; +// scss-docs-end sass-dark-mode-vars diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables.scss new file mode 100644 index 00000000..06531395 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables.scss @@ -0,0 +1,1751 @@ +// Variables +// +// Variables should follow the `$component-state-property-size` formula for +// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs. + +// Color system + +// scss-docs-start gray-color-variables +$white: #fff !default; +$gray-100: #f8f9fa !default; +$gray-200: #e9ecef !default; +$gray-300: #dee2e6 !default; +$gray-400: #ced4da !default; +$gray-500: #adb5bd !default; +$gray-600: #6c757d !default; +$gray-700: #495057 !default; +$gray-800: #343a40 !default; +$gray-900: #212529 !default; +$black: #000 !default; +// scss-docs-end gray-color-variables + +// fusv-disable +// scss-docs-start gray-colors-map +$grays: ( + "100": $gray-100, + "200": $gray-200, + "300": $gray-300, + "400": $gray-400, + "500": $gray-500, + "600": $gray-600, + "700": $gray-700, + "800": $gray-800, + "900": $gray-900 +) !default; +// scss-docs-end gray-colors-map +// fusv-enable + +// scss-docs-start color-variables +$blue: #0d6efd !default; +$indigo: #6610f2 !default; +$purple: #6f42c1 !default; +$pink: #d63384 !default; +$red: #dc3545 !default; +$orange: #fd7e14 !default; +$yellow: #ffc107 !default; +$green: #198754 !default; +$teal: #20c997 !default; +$cyan: #0dcaf0 !default; +// scss-docs-end color-variables + +// scss-docs-start colors-map +$colors: ( + "blue": $blue, + "indigo": $indigo, + "purple": $purple, + "pink": $pink, + "red": $red, + "orange": $orange, + "yellow": $yellow, + "green": $green, + "teal": $teal, + "cyan": $cyan, + "black": $black, + "white": $white, + "gray": $gray-600, + "gray-dark": $gray-800 +) !default; +// scss-docs-end colors-map + +// The contrast ratio to reach against white, to determine if color changes from "light" to "dark". Acceptable values for WCAG 2.0 are 3, 4.5 and 7. +// See https://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast +$min-contrast-ratio: 4.5 !default; + +// Customize the light and dark text colors for use in our color contrast function. +$color-contrast-dark: $black !default; +$color-contrast-light: $white !default; + +// fusv-disable +$blue-100: tint-color($blue, 80%) !default; +$blue-200: tint-color($blue, 60%) !default; +$blue-300: tint-color($blue, 40%) !default; +$blue-400: tint-color($blue, 20%) !default; +$blue-500: $blue !default; +$blue-600: shade-color($blue, 20%) !default; +$blue-700: shade-color($blue, 40%) !default; +$blue-800: shade-color($blue, 60%) !default; +$blue-900: shade-color($blue, 80%) !default; + +$indigo-100: tint-color($indigo, 80%) !default; +$indigo-200: tint-color($indigo, 60%) !default; +$indigo-300: tint-color($indigo, 40%) !default; +$indigo-400: tint-color($indigo, 20%) !default; +$indigo-500: $indigo !default; +$indigo-600: shade-color($indigo, 20%) !default; +$indigo-700: shade-color($indigo, 40%) !default; +$indigo-800: shade-color($indigo, 60%) !default; +$indigo-900: shade-color($indigo, 80%) !default; + +$purple-100: tint-color($purple, 80%) !default; +$purple-200: tint-color($purple, 60%) !default; +$purple-300: tint-color($purple, 40%) !default; +$purple-400: tint-color($purple, 20%) !default; +$purple-500: $purple !default; +$purple-600: shade-color($purple, 20%) !default; +$purple-700: shade-color($purple, 40%) !default; +$purple-800: shade-color($purple, 60%) !default; +$purple-900: shade-color($purple, 80%) !default; + +$pink-100: tint-color($pink, 80%) !default; +$pink-200: tint-color($pink, 60%) !default; +$pink-300: tint-color($pink, 40%) !default; +$pink-400: tint-color($pink, 20%) !default; +$pink-500: $pink !default; +$pink-600: shade-color($pink, 20%) !default; +$pink-700: shade-color($pink, 40%) !default; +$pink-800: shade-color($pink, 60%) !default; +$pink-900: shade-color($pink, 80%) !default; + +$red-100: tint-color($red, 80%) !default; +$red-200: tint-color($red, 60%) !default; +$red-300: tint-color($red, 40%) !default; +$red-400: tint-color($red, 20%) !default; +$red-500: $red !default; +$red-600: shade-color($red, 20%) !default; +$red-700: shade-color($red, 40%) !default; +$red-800: shade-color($red, 60%) !default; +$red-900: shade-color($red, 80%) !default; + +$orange-100: tint-color($orange, 80%) !default; +$orange-200: tint-color($orange, 60%) !default; +$orange-300: tint-color($orange, 40%) !default; +$orange-400: tint-color($orange, 20%) !default; +$orange-500: $orange !default; +$orange-600: shade-color($orange, 20%) !default; +$orange-700: shade-color($orange, 40%) !default; +$orange-800: shade-color($orange, 60%) !default; +$orange-900: shade-color($orange, 80%) !default; + +$yellow-100: tint-color($yellow, 80%) !default; +$yellow-200: tint-color($yellow, 60%) !default; +$yellow-300: tint-color($yellow, 40%) !default; +$yellow-400: tint-color($yellow, 20%) !default; +$yellow-500: $yellow !default; +$yellow-600: shade-color($yellow, 20%) !default; +$yellow-700: shade-color($yellow, 40%) !default; +$yellow-800: shade-color($yellow, 60%) !default; +$yellow-900: shade-color($yellow, 80%) !default; + +$green-100: tint-color($green, 80%) !default; +$green-200: tint-color($green, 60%) !default; +$green-300: tint-color($green, 40%) !default; +$green-400: tint-color($green, 20%) !default; +$green-500: $green !default; +$green-600: shade-color($green, 20%) !default; +$green-700: shade-color($green, 40%) !default; +$green-800: shade-color($green, 60%) !default; +$green-900: shade-color($green, 80%) !default; + +$teal-100: tint-color($teal, 80%) !default; +$teal-200: tint-color($teal, 60%) !default; +$teal-300: tint-color($teal, 40%) !default; +$teal-400: tint-color($teal, 20%) !default; +$teal-500: $teal !default; +$teal-600: shade-color($teal, 20%) !default; +$teal-700: shade-color($teal, 40%) !default; +$teal-800: shade-color($teal, 60%) !default; +$teal-900: shade-color($teal, 80%) !default; + +$cyan-100: tint-color($cyan, 80%) !default; +$cyan-200: tint-color($cyan, 60%) !default; +$cyan-300: tint-color($cyan, 40%) !default; +$cyan-400: tint-color($cyan, 20%) !default; +$cyan-500: $cyan !default; +$cyan-600: shade-color($cyan, 20%) !default; +$cyan-700: shade-color($cyan, 40%) !default; +$cyan-800: shade-color($cyan, 60%) !default; +$cyan-900: shade-color($cyan, 80%) !default; + +$blues: ( + "blue-100": $blue-100, + "blue-200": $blue-200, + "blue-300": $blue-300, + "blue-400": $blue-400, + "blue-500": $blue-500, + "blue-600": $blue-600, + "blue-700": $blue-700, + "blue-800": $blue-800, + "blue-900": $blue-900 +) !default; + +$indigos: ( + "indigo-100": $indigo-100, + "indigo-200": $indigo-200, + "indigo-300": $indigo-300, + "indigo-400": $indigo-400, + "indigo-500": $indigo-500, + "indigo-600": $indigo-600, + "indigo-700": $indigo-700, + "indigo-800": $indigo-800, + "indigo-900": $indigo-900 +) !default; + +$purples: ( + "purple-100": $purple-100, + "purple-200": $purple-200, + "purple-300": $purple-300, + "purple-400": $purple-400, + "purple-500": $purple-500, + "purple-600": $purple-600, + "purple-700": $purple-700, + "purple-800": $purple-800, + "purple-900": $purple-900 +) !default; + +$pinks: ( + "pink-100": $pink-100, + "pink-200": $pink-200, + "pink-300": $pink-300, + "pink-400": $pink-400, + "pink-500": $pink-500, + "pink-600": $pink-600, + "pink-700": $pink-700, + "pink-800": $pink-800, + "pink-900": $pink-900 +) !default; + +$reds: ( + "red-100": $red-100, + "red-200": $red-200, + "red-300": $red-300, + "red-400": $red-400, + "red-500": $red-500, + "red-600": $red-600, + "red-700": $red-700, + "red-800": $red-800, + "red-900": $red-900 +) !default; + +$oranges: ( + "orange-100": $orange-100, + "orange-200": $orange-200, + "orange-300": $orange-300, + "orange-400": $orange-400, + "orange-500": $orange-500, + "orange-600": $orange-600, + "orange-700": $orange-700, + "orange-800": $orange-800, + "orange-900": $orange-900 +) !default; + +$yellows: ( + "yellow-100": $yellow-100, + "yellow-200": $yellow-200, + "yellow-300": $yellow-300, + "yellow-400": $yellow-400, + "yellow-500": $yellow-500, + "yellow-600": $yellow-600, + "yellow-700": $yellow-700, + "yellow-800": $yellow-800, + "yellow-900": $yellow-900 +) !default; + +$greens: ( + "green-100": $green-100, + "green-200": $green-200, + "green-300": $green-300, + "green-400": $green-400, + "green-500": $green-500, + "green-600": $green-600, + "green-700": $green-700, + "green-800": $green-800, + "green-900": $green-900 +) !default; + +$teals: ( + "teal-100": $teal-100, + "teal-200": $teal-200, + "teal-300": $teal-300, + "teal-400": $teal-400, + "teal-500": $teal-500, + "teal-600": $teal-600, + "teal-700": $teal-700, + "teal-800": $teal-800, + "teal-900": $teal-900 +) !default; + +$cyans: ( + "cyan-100": $cyan-100, + "cyan-200": $cyan-200, + "cyan-300": $cyan-300, + "cyan-400": $cyan-400, + "cyan-500": $cyan-500, + "cyan-600": $cyan-600, + "cyan-700": $cyan-700, + "cyan-800": $cyan-800, + "cyan-900": $cyan-900 +) !default; +// fusv-enable + +// scss-docs-start theme-color-variables +$primary: $blue !default; +$secondary: $gray-600 !default; +$success: $green !default; +$info: $cyan !default; +$warning: $yellow !default; +$danger: $red !default; +$light: $gray-100 !default; +$dark: $gray-900 !default; +// scss-docs-end theme-color-variables + +// scss-docs-start theme-colors-map +$theme-colors: ( + "primary": $primary, + "secondary": $secondary, + "success": $success, + "info": $info, + "warning": $warning, + "danger": $danger, + "light": $light, + "dark": $dark +) !default; +// scss-docs-end theme-colors-map + +// scss-docs-start theme-text-variables +$primary-text-emphasis: shade-color($primary, 60%) !default; +$secondary-text-emphasis: shade-color($secondary, 60%) !default; +$success-text-emphasis: shade-color($success, 60%) !default; +$info-text-emphasis: shade-color($info, 60%) !default; +$warning-text-emphasis: shade-color($warning, 60%) !default; +$danger-text-emphasis: shade-color($danger, 60%) !default; +$light-text-emphasis: $gray-700 !default; +$dark-text-emphasis: $gray-700 !default; +// scss-docs-end theme-text-variables + +// scss-docs-start theme-bg-subtle-variables +$primary-bg-subtle: tint-color($primary, 80%) !default; +$secondary-bg-subtle: tint-color($secondary, 80%) !default; +$success-bg-subtle: tint-color($success, 80%) !default; +$info-bg-subtle: tint-color($info, 80%) !default; +$warning-bg-subtle: tint-color($warning, 80%) !default; +$danger-bg-subtle: tint-color($danger, 80%) !default; +$light-bg-subtle: mix($gray-100, $white) !default; +$dark-bg-subtle: $gray-400 !default; +// scss-docs-end theme-bg-subtle-variables + +// scss-docs-start theme-border-subtle-variables +$primary-border-subtle: tint-color($primary, 60%) !default; +$secondary-border-subtle: tint-color($secondary, 60%) !default; +$success-border-subtle: tint-color($success, 60%) !default; +$info-border-subtle: tint-color($info, 60%) !default; +$warning-border-subtle: tint-color($warning, 60%) !default; +$danger-border-subtle: tint-color($danger, 60%) !default; +$light-border-subtle: $gray-200 !default; +$dark-border-subtle: $gray-500 !default; +// scss-docs-end theme-border-subtle-variables + +// Characters which are escaped by the escape-svg function +$escaped-characters: ( + ("<", "%3c"), + (">", "%3e"), + ("#", "%23"), + ("(", "%28"), + (")", "%29"), +) !default; + +// Options +// +// Quickly modify global styling by enabling or disabling optional features. + +$enable-caret: true !default; +$enable-rounded: true !default; +$enable-shadows: false !default; +$enable-gradients: false !default; +$enable-transitions: true !default; +$enable-reduced-motion: true !default; +$enable-smooth-scroll: true !default; +$enable-grid-classes: true !default; +$enable-container-classes: true !default; +$enable-cssgrid: false !default; +$enable-button-pointers: true !default; +$enable-rfs: true !default; +$enable-validation-icons: true !default; +$enable-negative-margins: false !default; +$enable-deprecation-messages: true !default; +$enable-important-utilities: true !default; + +$enable-dark-mode: true !default; +$color-mode-type: data !default; // `data` or `media-query` + +// Prefix for :root CSS variables + +$variable-prefix: bs- !default; // Deprecated in v5.2.0 for the shorter `$prefix` +$prefix: $variable-prefix !default; + +// Gradient +// +// The gradient which is added to components if `$enable-gradients` is `true` +// This gradient is also added to elements with `.bg-gradient` +// scss-docs-start variable-gradient +$gradient: linear-gradient(180deg, rgba($white, .15), rgba($white, 0)) !default; +// scss-docs-end variable-gradient + +// Spacing +// +// Control the default styling of most Bootstrap elements by modifying these +// variables. Mostly focused on spacing. +// You can add more entries to the $spacers map, should you need more variation. + +// scss-docs-start spacer-variables-maps +$spacer: 1rem !default; +$spacers: ( + 0: 0, + 1: $spacer * .25, + 2: $spacer * .5, + 3: $spacer, + 4: $spacer * 1.5, + 5: $spacer * 3, +) !default; +// scss-docs-end spacer-variables-maps + +// Position +// +// Define the edge positioning anchors of the position utilities. + +// scss-docs-start position-map +$position-values: ( + 0: 0, + 50: 50%, + 100: 100% +) !default; +// scss-docs-end position-map + +// Body +// +// Settings for the `<body>` element. + +$body-text-align: null !default; +$body-color: $gray-900 !default; +$body-bg: $white !default; + +$body-secondary-color: rgba($body-color, .75) !default; +$body-secondary-bg: $gray-200 !default; + +$body-tertiary-color: rgba($body-color, .5) !default; +$body-tertiary-bg: $gray-100 !default; + +$body-emphasis-color: $black !default; + +// Links +// +// Style anchor elements. + +$link-color: $primary !default; +$link-decoration: underline !default; +$link-shade-percentage: 20% !default; +$link-hover-color: shift-color($link-color, $link-shade-percentage) !default; +$link-hover-decoration: null !default; + +$stretched-link-pseudo-element: after !default; +$stretched-link-z-index: 1 !default; + +// Icon links +// scss-docs-start icon-link-variables +$icon-link-gap: .375rem !default; +$icon-link-underline-offset: .25em !default; +$icon-link-icon-size: 1em !default; +$icon-link-icon-transition: .2s ease-in-out transform !default; +$icon-link-icon-transform: translate3d(.25em, 0, 0) !default; +// scss-docs-end icon-link-variables + +// Paragraphs +// +// Style p element. + +$paragraph-margin-bottom: 1rem !default; + + +// Grid breakpoints +// +// Define the minimum dimensions at which your layout will change, +// adapting to different screen sizes, for use in media queries. + +// scss-docs-start grid-breakpoints +$grid-breakpoints: ( + xs: 0, + sm: 576px, + md: 768px, + lg: 992px, + xl: 1200px, + xxl: 1400px +) !default; +// scss-docs-end grid-breakpoints + +@include _assert-ascending($grid-breakpoints, "$grid-breakpoints"); +@include _assert-starts-at-zero($grid-breakpoints, "$grid-breakpoints"); + + +// Grid containers +// +// Define the maximum width of `.container` for different screen sizes. + +// scss-docs-start container-max-widths +$container-max-widths: ( + sm: 540px, + md: 720px, + lg: 960px, + xl: 1140px, + xxl: 1320px +) !default; +// scss-docs-end container-max-widths + +@include _assert-ascending($container-max-widths, "$container-max-widths"); + + +// Grid columns +// +// Set the number of columns and specify the width of the gutters. + +$grid-columns: 12 !default; +$grid-gutter-width: 1.5rem !default; +$grid-row-columns: 6 !default; + +// Container padding + +$container-padding-x: $grid-gutter-width !default; + + +// Components +// +// Define common padding and border radius sizes and more. + +// scss-docs-start border-variables +$border-width: 1px !default; +$border-widths: ( + 1: 1px, + 2: 2px, + 3: 3px, + 4: 4px, + 5: 5px +) !default; +$border-style: solid !default; +$border-color: $gray-300 !default; +$border-color-translucent: rgba($black, .175) !default; +// scss-docs-end border-variables + +// scss-docs-start border-radius-variables +$border-radius: .375rem !default; +$border-radius-sm: .25rem !default; +$border-radius-lg: .5rem !default; +$border-radius-xl: 1rem !default; +$border-radius-xxl: 2rem !default; +$border-radius-pill: 50rem !default; +// scss-docs-end border-radius-variables +// fusv-disable +$border-radius-2xl: $border-radius-xxl !default; // Deprecated in v5.3.0 +// fusv-enable + +// scss-docs-start box-shadow-variables +$box-shadow: 0 .5rem 1rem rgba($black, .15) !default; +$box-shadow-sm: 0 .125rem .25rem rgba($black, .075) !default; +$box-shadow-lg: 0 1rem 3rem rgba($black, .175) !default; +$box-shadow-inset: inset 0 1px 2px rgba($black, .075) !default; +// scss-docs-end box-shadow-variables + +$component-active-color: $white !default; +$component-active-bg: $primary !default; + +// scss-docs-start focus-ring-variables +$focus-ring-width: .25rem !default; +$focus-ring-opacity: .25 !default; +$focus-ring-color: rgba($primary, $focus-ring-opacity) !default; +$focus-ring-blur: 0 !default; +$focus-ring-box-shadow: 0 0 $focus-ring-blur $focus-ring-width $focus-ring-color !default; +// scss-docs-end focus-ring-variables + +// scss-docs-start caret-variables +$caret-width: .3em !default; +$caret-vertical-align: $caret-width * .85 !default; +$caret-spacing: $caret-width * .85 !default; +// scss-docs-end caret-variables + +$transition-base: all .2s ease-in-out !default; +$transition-fade: opacity .15s linear !default; +// scss-docs-start collapse-transition +$transition-collapse: height .35s ease !default; +$transition-collapse-width: width .35s ease !default; +// scss-docs-end collapse-transition + +// stylelint-disable function-disallowed-list +// scss-docs-start aspect-ratios +$aspect-ratios: ( + "1x1": 100%, + "4x3": calc(3 / 4 * 100%), + "16x9": calc(9 / 16 * 100%), + "21x9": calc(9 / 21 * 100%) +) !default; +// scss-docs-end aspect-ratios +// stylelint-enable function-disallowed-list + +// Typography +// +// Font, line-height, and color for body text, headings, and more. + +// scss-docs-start font-variables +// stylelint-disable value-keyword-case +$font-family-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; +$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; +// stylelint-enable value-keyword-case +$font-family-base: var(--#{$prefix}font-sans-serif) !default; +$font-family-code: var(--#{$prefix}font-monospace) !default; + +// $font-size-root affects the value of `rem`, which is used for as well font sizes, paddings, and margins +// $font-size-base affects the font size of the body text +$font-size-root: null !default; +$font-size-base: 1rem !default; // Assumes the browser default, typically `16px` +$font-size-sm: $font-size-base * .875 !default; +$font-size-lg: $font-size-base * 1.25 !default; + +$font-weight-lighter: lighter !default; +$font-weight-light: 300 !default; +$font-weight-normal: 400 !default; +$font-weight-medium: 500 !default; +$font-weight-semibold: 600 !default; +$font-weight-bold: 700 !default; +$font-weight-bolder: bolder !default; + +$font-weight-base: $font-weight-normal !default; + +$line-height-base: 1.5 !default; +$line-height-sm: 1.25 !default; +$line-height-lg: 2 !default; + +$h1-font-size: $font-size-base * 2.5 !default; +$h2-font-size: $font-size-base * 2 !default; +$h3-font-size: $font-size-base * 1.75 !default; +$h4-font-size: $font-size-base * 1.5 !default; +$h5-font-size: $font-size-base * 1.25 !default; +$h6-font-size: $font-size-base !default; +// scss-docs-end font-variables + +// scss-docs-start font-sizes +$font-sizes: ( + 1: $h1-font-size, + 2: $h2-font-size, + 3: $h3-font-size, + 4: $h4-font-size, + 5: $h5-font-size, + 6: $h6-font-size +) !default; +// scss-docs-end font-sizes + +// scss-docs-start headings-variables +$headings-margin-bottom: $spacer * .5 !default; +$headings-font-family: null !default; +$headings-font-style: null !default; +$headings-font-weight: 500 !default; +$headings-line-height: 1.2 !default; +$headings-color: inherit !default; +// scss-docs-end headings-variables + +// scss-docs-start display-headings +$display-font-sizes: ( + 1: 5rem, + 2: 4.5rem, + 3: 4rem, + 4: 3.5rem, + 5: 3rem, + 6: 2.5rem +) !default; + +$display-font-family: null !default; +$display-font-style: null !default; +$display-font-weight: 300 !default; +$display-line-height: $headings-line-height !default; +// scss-docs-end display-headings + +// scss-docs-start type-variables +$lead-font-size: $font-size-base * 1.25 !default; +$lead-font-weight: 300 !default; + +$small-font-size: .875em !default; + +$sub-sup-font-size: .75em !default; + +// fusv-disable +$text-muted: var(--#{$prefix}secondary-color) !default; // Deprecated in 5.3.0 +// fusv-enable + +$initialism-font-size: $small-font-size !default; + +$blockquote-margin-y: $spacer !default; +$blockquote-font-size: $font-size-base * 1.25 !default; +$blockquote-footer-color: $gray-600 !default; +$blockquote-footer-font-size: $small-font-size !default; + +$hr-margin-y: $spacer !default; +$hr-color: inherit !default; + +// fusv-disable +$hr-bg-color: null !default; // Deprecated in v5.2.0 +$hr-height: null !default; // Deprecated in v5.2.0 +// fusv-enable + +$hr-border-color: null !default; // Allows for inherited colors +$hr-border-width: var(--#{$prefix}border-width) !default; +$hr-opacity: .25 !default; + +// scss-docs-start vr-variables +$vr-border-width: var(--#{$prefix}border-width) !default; +// scss-docs-end vr-variables + +$legend-margin-bottom: .5rem !default; +$legend-font-size: 1.5rem !default; +$legend-font-weight: null !default; + +$dt-font-weight: $font-weight-bold !default; + +$list-inline-padding: .5rem !default; + +$mark-padding: .1875em !default; +$mark-color: $body-color !default; +$mark-bg: $yellow-100 !default; +// scss-docs-end type-variables + + +// Tables +// +// Customizes the `.table` component with basic values, each used across all table variations. + +// scss-docs-start table-variables +$table-cell-padding-y: .5rem !default; +$table-cell-padding-x: .5rem !default; +$table-cell-padding-y-sm: .25rem !default; +$table-cell-padding-x-sm: .25rem !default; + +$table-cell-vertical-align: top !default; + +$table-color: var(--#{$prefix}emphasis-color) !default; +$table-bg: var(--#{$prefix}body-bg) !default; +$table-accent-bg: transparent !default; + +$table-th-font-weight: null !default; + +$table-striped-color: $table-color !default; +$table-striped-bg-factor: .05 !default; +$table-striped-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-striped-bg-factor) !default; + +$table-active-color: $table-color !default; +$table-active-bg-factor: .1 !default; +$table-active-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-active-bg-factor) !default; + +$table-hover-color: $table-color !default; +$table-hover-bg-factor: .075 !default; +$table-hover-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-hover-bg-factor) !default; + +$table-border-factor: .2 !default; +$table-border-width: var(--#{$prefix}border-width) !default; +$table-border-color: var(--#{$prefix}border-color) !default; + +$table-striped-order: odd !default; +$table-striped-columns-order: even !default; + +$table-group-separator-color: currentcolor !default; + +$table-caption-color: var(--#{$prefix}secondary-color) !default; + +$table-bg-scale: -80% !default; +// scss-docs-end table-variables + +// scss-docs-start table-loop +$table-variants: ( + "primary": shift-color($primary, $table-bg-scale), + "secondary": shift-color($secondary, $table-bg-scale), + "success": shift-color($success, $table-bg-scale), + "info": shift-color($info, $table-bg-scale), + "warning": shift-color($warning, $table-bg-scale), + "danger": shift-color($danger, $table-bg-scale), + "light": $light, + "dark": $dark, +) !default; +// scss-docs-end table-loop + + +// Buttons + Forms +// +// Shared variables that are reassigned to `$input-` and `$btn-` specific variables. + +// scss-docs-start input-btn-variables +$input-btn-padding-y: .375rem !default; +$input-btn-padding-x: .75rem !default; +$input-btn-font-family: null !default; +$input-btn-font-size: $font-size-base !default; +$input-btn-line-height: $line-height-base !default; + +$input-btn-focus-width: $focus-ring-width !default; +$input-btn-focus-color-opacity: $focus-ring-opacity !default; +$input-btn-focus-color: $focus-ring-color !default; +$input-btn-focus-blur: $focus-ring-blur !default; +$input-btn-focus-box-shadow: $focus-ring-box-shadow !default; + +$input-btn-padding-y-sm: .25rem !default; +$input-btn-padding-x-sm: .5rem !default; +$input-btn-font-size-sm: $font-size-sm !default; + +$input-btn-padding-y-lg: .5rem !default; +$input-btn-padding-x-lg: 1rem !default; +$input-btn-font-size-lg: $font-size-lg !default; + +$input-btn-border-width: var(--#{$prefix}border-width) !default; +// scss-docs-end input-btn-variables + + +// Buttons +// +// For each of Bootstrap's buttons, define text, background, and border color. + +// scss-docs-start btn-variables +$btn-color: var(--#{$prefix}body-color) !default; +$btn-padding-y: $input-btn-padding-y !default; +$btn-padding-x: $input-btn-padding-x !default; +$btn-font-family: $input-btn-font-family !default; +$btn-font-size: $input-btn-font-size !default; +$btn-line-height: $input-btn-line-height !default; +$btn-white-space: null !default; // Set to `nowrap` to prevent text wrapping + +$btn-padding-y-sm: $input-btn-padding-y-sm !default; +$btn-padding-x-sm: $input-btn-padding-x-sm !default; +$btn-font-size-sm: $input-btn-font-size-sm !default; + +$btn-padding-y-lg: $input-btn-padding-y-lg !default; +$btn-padding-x-lg: $input-btn-padding-x-lg !default; +$btn-font-size-lg: $input-btn-font-size-lg !default; + +$btn-border-width: $input-btn-border-width !default; + +$btn-font-weight: $font-weight-normal !default; +$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default; +$btn-focus-width: $input-btn-focus-width !default; +$btn-focus-box-shadow: $input-btn-focus-box-shadow !default; +$btn-disabled-opacity: .65 !default; +$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default; + +$btn-link-color: var(--#{$prefix}link-color) !default; +$btn-link-hover-color: var(--#{$prefix}link-hover-color) !default; +$btn-link-disabled-color: $gray-600 !default; +$btn-link-focus-shadow-rgb: to-rgb(mix(color-contrast($link-color), $link-color, 15%)) !default; + +// Allows for customizing button radius independently from global border radius +$btn-border-radius: var(--#{$prefix}border-radius) !default; +$btn-border-radius-sm: var(--#{$prefix}border-radius-sm) !default; +$btn-border-radius-lg: var(--#{$prefix}border-radius-lg) !default; + +$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$btn-hover-bg-shade-amount: 15% !default; +$btn-hover-bg-tint-amount: 15% !default; +$btn-hover-border-shade-amount: 20% !default; +$btn-hover-border-tint-amount: 10% !default; +$btn-active-bg-shade-amount: 20% !default; +$btn-active-bg-tint-amount: 20% !default; +$btn-active-border-shade-amount: 25% !default; +$btn-active-border-tint-amount: 10% !default; +// scss-docs-end btn-variables + + +// Forms + +// scss-docs-start form-text-variables +$form-text-margin-top: .25rem !default; +$form-text-font-size: $small-font-size !default; +$form-text-font-style: null !default; +$form-text-font-weight: null !default; +$form-text-color: var(--#{$prefix}secondary-color) !default; +// scss-docs-end form-text-variables + +// scss-docs-start form-label-variables +$form-label-margin-bottom: .5rem !default; +$form-label-font-size: null !default; +$form-label-font-style: null !default; +$form-label-font-weight: null !default; +$form-label-color: null !default; +// scss-docs-end form-label-variables + +// scss-docs-start form-input-variables +$input-padding-y: $input-btn-padding-y !default; +$input-padding-x: $input-btn-padding-x !default; +$input-font-family: $input-btn-font-family !default; +$input-font-size: $input-btn-font-size !default; +$input-font-weight: $font-weight-base !default; +$input-line-height: $input-btn-line-height !default; + +$input-padding-y-sm: $input-btn-padding-y-sm !default; +$input-padding-x-sm: $input-btn-padding-x-sm !default; +$input-font-size-sm: $input-btn-font-size-sm !default; + +$input-padding-y-lg: $input-btn-padding-y-lg !default; +$input-padding-x-lg: $input-btn-padding-x-lg !default; +$input-font-size-lg: $input-btn-font-size-lg !default; + +$input-bg: var(--#{$prefix}body-bg) !default; +$input-disabled-color: null !default; +$input-disabled-bg: var(--#{$prefix}secondary-bg) !default; +$input-disabled-border-color: null !default; + +$input-color: var(--#{$prefix}body-color) !default; +$input-border-color: var(--#{$prefix}border-color) !default; +$input-border-width: $input-btn-border-width !default; +$input-box-shadow: var(--#{$prefix}box-shadow-inset) !default; + +$input-border-radius: var(--#{$prefix}border-radius) !default; +$input-border-radius-sm: var(--#{$prefix}border-radius-sm) !default; +$input-border-radius-lg: var(--#{$prefix}border-radius-lg) !default; + +$input-focus-bg: $input-bg !default; +$input-focus-border-color: tint-color($component-active-bg, 50%) !default; +$input-focus-color: $input-color !default; +$input-focus-width: $input-btn-focus-width !default; +$input-focus-box-shadow: $input-btn-focus-box-shadow !default; + +$input-placeholder-color: var(--#{$prefix}secondary-color) !default; +$input-plaintext-color: var(--#{$prefix}body-color) !default; + +$input-height-border: calc(#{$input-border-width} * 2) !default; // stylelint-disable-line function-disallowed-list + +$input-height-inner: add($input-line-height * 1em, $input-padding-y * 2) !default; +$input-height-inner-half: add($input-line-height * .5em, $input-padding-y) !default; +$input-height-inner-quarter: add($input-line-height * .25em, $input-padding-y * .5) !default; + +$input-height: add($input-line-height * 1em, add($input-padding-y * 2, $input-height-border, false)) !default; +$input-height-sm: add($input-line-height * 1em, add($input-padding-y-sm * 2, $input-height-border, false)) !default; +$input-height-lg: add($input-line-height * 1em, add($input-padding-y-lg * 2, $input-height-border, false)) !default; + +$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$form-color-width: 3rem !default; +// scss-docs-end form-input-variables + +// scss-docs-start form-check-variables +$form-check-input-width: 1em !default; +$form-check-min-height: $font-size-base * $line-height-base !default; +$form-check-padding-start: $form-check-input-width + .5em !default; +$form-check-margin-bottom: .125rem !default; +$form-check-label-color: null !default; +$form-check-label-cursor: null !default; +$form-check-transition: null !default; + +$form-check-input-active-filter: brightness(90%) !default; + +$form-check-input-bg: $input-bg !default; +$form-check-input-border: var(--#{$prefix}border-width) solid var(--#{$prefix}border-color) !default; +$form-check-input-border-radius: .25em !default; +$form-check-radio-border-radius: 50% !default; +$form-check-input-focus-border: $input-focus-border-color !default; +$form-check-input-focus-box-shadow: $focus-ring-box-shadow !default; + +$form-check-input-checked-color: $component-active-color !default; +$form-check-input-checked-bg-color: $component-active-bg !default; +$form-check-input-checked-border-color: $form-check-input-checked-bg-color !default; +$form-check-input-checked-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='none' stroke='#{$form-check-input-checked-color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/></svg>") !default; +$form-check-radio-checked-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='2' fill='#{$form-check-input-checked-color}'/></svg>") !default; + +$form-check-input-indeterminate-color: $component-active-color !default; +$form-check-input-indeterminate-bg-color: $component-active-bg !default; +$form-check-input-indeterminate-border-color: $form-check-input-indeterminate-bg-color !default; +$form-check-input-indeterminate-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='none' stroke='#{$form-check-input-indeterminate-color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/></svg>") !default; + +$form-check-input-disabled-opacity: .5 !default; +$form-check-label-disabled-opacity: $form-check-input-disabled-opacity !default; +$form-check-btn-check-disabled-opacity: $btn-disabled-opacity !default; + +$form-check-inline-margin-end: 1rem !default; +// scss-docs-end form-check-variables + +// scss-docs-start form-switch-variables +$form-switch-color: rgba($black, .25) !default; +$form-switch-width: 2em !default; +$form-switch-padding-start: $form-switch-width + .5em !default; +$form-switch-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-color}'/></svg>") !default; +$form-switch-border-radius: $form-switch-width !default; +$form-switch-transition: background-position .15s ease-in-out !default; + +$form-switch-focus-color: $input-focus-border-color !default; +$form-switch-focus-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-focus-color}'/></svg>") !default; + +$form-switch-checked-color: $component-active-color !default; +$form-switch-checked-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-checked-color}'/></svg>") !default; +$form-switch-checked-bg-position: right center !default; +// scss-docs-end form-switch-variables + +// scss-docs-start input-group-variables +$input-group-addon-padding-y: $input-padding-y !default; +$input-group-addon-padding-x: $input-padding-x !default; +$input-group-addon-font-weight: $input-font-weight !default; +$input-group-addon-color: $input-color !default; +$input-group-addon-bg: var(--#{$prefix}tertiary-bg) !default; +$input-group-addon-border-color: $input-border-color !default; +// scss-docs-end input-group-variables + +// scss-docs-start form-select-variables +$form-select-padding-y: $input-padding-y !default; +$form-select-padding-x: $input-padding-x !default; +$form-select-font-family: $input-font-family !default; +$form-select-font-size: $input-font-size !default; +$form-select-indicator-padding: $form-select-padding-x * 3 !default; // Extra padding for background-image +$form-select-font-weight: $input-font-weight !default; +$form-select-line-height: $input-line-height !default; +$form-select-color: $input-color !default; +$form-select-bg: $input-bg !default; +$form-select-disabled-color: null !default; +$form-select-disabled-bg: $input-disabled-bg !default; +$form-select-disabled-border-color: $input-disabled-border-color !default; +$form-select-bg-position: right $form-select-padding-x center !default; +$form-select-bg-size: 16px 12px !default; // In pixels because image dimensions +$form-select-indicator-color: $gray-800 !default; +$form-select-indicator: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='#{$form-select-indicator-color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/></svg>") !default; + +$form-select-feedback-icon-padding-end: $form-select-padding-x * 2.5 + $form-select-indicator-padding !default; +$form-select-feedback-icon-position: center right $form-select-indicator-padding !default; +$form-select-feedback-icon-size: $input-height-inner-half $input-height-inner-half !default; + +$form-select-border-width: $input-border-width !default; +$form-select-border-color: $input-border-color !default; +$form-select-border-radius: $input-border-radius !default; +$form-select-box-shadow: var(--#{$prefix}box-shadow-inset) !default; + +$form-select-focus-border-color: $input-focus-border-color !default; +$form-select-focus-width: $input-focus-width !default; +$form-select-focus-box-shadow: 0 0 0 $form-select-focus-width $input-btn-focus-color !default; + +$form-select-padding-y-sm: $input-padding-y-sm !default; +$form-select-padding-x-sm: $input-padding-x-sm !default; +$form-select-font-size-sm: $input-font-size-sm !default; +$form-select-border-radius-sm: $input-border-radius-sm !default; + +$form-select-padding-y-lg: $input-padding-y-lg !default; +$form-select-padding-x-lg: $input-padding-x-lg !default; +$form-select-font-size-lg: $input-font-size-lg !default; +$form-select-border-radius-lg: $input-border-radius-lg !default; + +$form-select-transition: $input-transition !default; +// scss-docs-end form-select-variables + +// scss-docs-start form-range-variables +$form-range-track-width: 100% !default; +$form-range-track-height: .5rem !default; +$form-range-track-cursor: pointer !default; +$form-range-track-bg: var(--#{$prefix}secondary-bg) !default; +$form-range-track-border-radius: 1rem !default; +$form-range-track-box-shadow: var(--#{$prefix}box-shadow-inset) !default; + +$form-range-thumb-width: 1rem !default; +$form-range-thumb-height: $form-range-thumb-width !default; +$form-range-thumb-bg: $component-active-bg !default; +$form-range-thumb-border: 0 !default; +$form-range-thumb-border-radius: 1rem !default; +$form-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default; +$form-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default; +$form-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in Edge +$form-range-thumb-active-bg: tint-color($component-active-bg, 70%) !default; +$form-range-thumb-disabled-bg: var(--#{$prefix}secondary-color) !default; +$form-range-thumb-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; +// scss-docs-end form-range-variables + +// scss-docs-start form-file-variables +$form-file-button-color: $input-color !default; +$form-file-button-bg: var(--#{$prefix}tertiary-bg) !default; +$form-file-button-hover-bg: var(--#{$prefix}secondary-bg) !default; +// scss-docs-end form-file-variables + +// scss-docs-start form-floating-variables +$form-floating-height: add(3.5rem, $input-height-border) !default; +$form-floating-line-height: 1.25 !default; +$form-floating-padding-x: $input-padding-x !default; +$form-floating-padding-y: 1rem !default; +$form-floating-input-padding-t: 1.625rem !default; +$form-floating-input-padding-b: .625rem !default; +$form-floating-label-height: 1.5em !default; +$form-floating-label-opacity: .65 !default; +$form-floating-label-transform: scale(.85) translateY(-.5rem) translateX(.15rem) !default; +$form-floating-label-disabled-color: $gray-600 !default; +$form-floating-transition: opacity .1s ease-in-out, transform .1s ease-in-out !default; +// scss-docs-end form-floating-variables + +// Form validation + +// scss-docs-start form-feedback-variables +$form-feedback-margin-top: $form-text-margin-top !default; +$form-feedback-font-size: $form-text-font-size !default; +$form-feedback-font-style: $form-text-font-style !default; +$form-feedback-valid-color: $success !default; +$form-feedback-invalid-color: $danger !default; + +$form-feedback-icon-valid-color: $form-feedback-valid-color !default; +$form-feedback-icon-valid: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/></svg>") !default; +$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default; +$form-feedback-icon-invalid: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='#{$form-feedback-icon-invalid-color}'><circle cx='6' cy='6' r='4.5'/><path stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/><circle cx='6' cy='8.2' r='.6' fill='#{$form-feedback-icon-invalid-color}' stroke='none'/></svg>") !default; +// scss-docs-end form-feedback-variables + +// scss-docs-start form-validation-colors +$form-valid-color: $form-feedback-valid-color !default; +$form-valid-border-color: $form-feedback-valid-color !default; +$form-invalid-color: $form-feedback-invalid-color !default; +$form-invalid-border-color: $form-feedback-invalid-color !default; +// scss-docs-end form-validation-colors + +// scss-docs-start form-validation-states +$form-validation-states: ( + "valid": ( + "color": var(--#{$prefix}form-valid-color), + "icon": $form-feedback-icon-valid, + "tooltip-color": #fff, + "tooltip-bg-color": var(--#{$prefix}success), + "focus-box-shadow": 0 0 $input-btn-focus-blur $input-focus-width rgba(var(--#{$prefix}success-rgb), $input-btn-focus-color-opacity), + "border-color": var(--#{$prefix}form-valid-border-color), + ), + "invalid": ( + "color": var(--#{$prefix}form-invalid-color), + "icon": $form-feedback-icon-invalid, + "tooltip-color": #fff, + "tooltip-bg-color": var(--#{$prefix}danger), + "focus-box-shadow": 0 0 $input-btn-focus-blur $input-focus-width rgba(var(--#{$prefix}danger-rgb), $input-btn-focus-color-opacity), + "border-color": var(--#{$prefix}form-invalid-border-color), + ) +) !default; +// scss-docs-end form-validation-states + +// Z-index master list +// +// Warning: Avoid customizing these values. They're used for a bird's eye view +// of components dependent on the z-axis and are designed to all work together. + +// scss-docs-start zindex-stack +$zindex-dropdown: 1000 !default; +$zindex-sticky: 1020 !default; +$zindex-fixed: 1030 !default; +$zindex-offcanvas-backdrop: 1040 !default; +$zindex-offcanvas: 1045 !default; +$zindex-modal-backdrop: 1050 !default; +$zindex-modal: 1055 !default; +$zindex-popover: 1070 !default; +$zindex-tooltip: 1080 !default; +$zindex-toast: 1090 !default; +// scss-docs-end zindex-stack + +// scss-docs-start zindex-levels-map +$zindex-levels: ( + n1: -1, + 0: 0, + 1: 1, + 2: 2, + 3: 3 +) !default; +// scss-docs-end zindex-levels-map + + +// Navs + +// scss-docs-start nav-variables +$nav-link-padding-y: .5rem !default; +$nav-link-padding-x: 1rem !default; +$nav-link-font-size: null !default; +$nav-link-font-weight: null !default; +$nav-link-color: var(--#{$prefix}link-color) !default; +$nav-link-hover-color: var(--#{$prefix}link-hover-color) !default; +$nav-link-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out !default; +$nav-link-disabled-color: var(--#{$prefix}secondary-color) !default; +$nav-link-focus-box-shadow: $focus-ring-box-shadow !default; + +$nav-tabs-border-color: var(--#{$prefix}border-color) !default; +$nav-tabs-border-width: var(--#{$prefix}border-width) !default; +$nav-tabs-border-radius: var(--#{$prefix}border-radius) !default; +$nav-tabs-link-hover-border-color: var(--#{$prefix}secondary-bg) var(--#{$prefix}secondary-bg) $nav-tabs-border-color !default; +$nav-tabs-link-active-color: var(--#{$prefix}emphasis-color) !default; +$nav-tabs-link-active-bg: var(--#{$prefix}body-bg) !default; +$nav-tabs-link-active-border-color: var(--#{$prefix}border-color) var(--#{$prefix}border-color) $nav-tabs-link-active-bg !default; + +$nav-pills-border-radius: var(--#{$prefix}border-radius) !default; +$nav-pills-link-active-color: $component-active-color !default; +$nav-pills-link-active-bg: $component-active-bg !default; + +$nav-underline-gap: 1rem !default; +$nav-underline-border-width: .125rem !default; +$nav-underline-link-active-color: var(--#{$prefix}emphasis-color) !default; +// scss-docs-end nav-variables + + +// Navbar + +// scss-docs-start navbar-variables +$navbar-padding-y: $spacer * .5 !default; +$navbar-padding-x: null !default; + +$navbar-nav-link-padding-x: .5rem !default; + +$navbar-brand-font-size: $font-size-lg !default; +// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link +$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default; +$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default; +$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) * .5 !default; +$navbar-brand-margin-end: 1rem !default; + +$navbar-toggler-padding-y: .25rem !default; +$navbar-toggler-padding-x: .75rem !default; +$navbar-toggler-font-size: $font-size-lg !default; +$navbar-toggler-border-radius: $btn-border-radius !default; +$navbar-toggler-focus-width: $btn-focus-width !default; +$navbar-toggler-transition: box-shadow .15s ease-in-out !default; + +$navbar-light-color: rgba(var(--#{$prefix}emphasis-color-rgb), .65) !default; +$navbar-light-hover-color: rgba(var(--#{$prefix}emphasis-color-rgb), .8) !default; +$navbar-light-active-color: rgba(var(--#{$prefix}emphasis-color-rgb), 1) !default; +$navbar-light-disabled-color: rgba(var(--#{$prefix}emphasis-color-rgb), .3) !default; +$navbar-light-icon-color: rgba($body-color, .75) !default; +$navbar-light-toggler-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke='#{$navbar-light-icon-color}' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg>") !default; +$navbar-light-toggler-border-color: rgba(var(--#{$prefix}emphasis-color-rgb), .15) !default; +$navbar-light-brand-color: $navbar-light-active-color !default; +$navbar-light-brand-hover-color: $navbar-light-active-color !default; +// scss-docs-end navbar-variables + +// scss-docs-start navbar-dark-variables +$navbar-dark-color: rgba($white, .55) !default; +$navbar-dark-hover-color: rgba($white, .75) !default; +$navbar-dark-active-color: $white !default; +$navbar-dark-disabled-color: rgba($white, .25) !default; +$navbar-dark-icon-color: $navbar-dark-color !default; +$navbar-dark-toggler-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke='#{$navbar-dark-icon-color}' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg>") !default; +$navbar-dark-toggler-border-color: rgba($white, .1) !default; +$navbar-dark-brand-color: $navbar-dark-active-color !default; +$navbar-dark-brand-hover-color: $navbar-dark-active-color !default; +// scss-docs-end navbar-dark-variables + + +// Dropdowns +// +// Dropdown menu container and contents. + +// scss-docs-start dropdown-variables +$dropdown-min-width: 10rem !default; +$dropdown-padding-x: 0 !default; +$dropdown-padding-y: .5rem !default; +$dropdown-spacer: .125rem !default; +$dropdown-font-size: $font-size-base !default; +$dropdown-color: var(--#{$prefix}body-color) !default; +$dropdown-bg: var(--#{$prefix}body-bg) !default; +$dropdown-border-color: var(--#{$prefix}border-color-translucent) !default; +$dropdown-border-radius: var(--#{$prefix}border-radius) !default; +$dropdown-border-width: var(--#{$prefix}border-width) !default; +$dropdown-inner-border-radius: calc(#{$dropdown-border-radius} - #{$dropdown-border-width}) !default; // stylelint-disable-line function-disallowed-list +$dropdown-divider-bg: $dropdown-border-color !default; +$dropdown-divider-margin-y: $spacer * .5 !default; +$dropdown-box-shadow: var(--#{$prefix}box-shadow) !default; + +$dropdown-link-color: var(--#{$prefix}body-color) !default; +$dropdown-link-hover-color: $dropdown-link-color !default; +$dropdown-link-hover-bg: var(--#{$prefix}tertiary-bg) !default; + +$dropdown-link-active-color: $component-active-color !default; +$dropdown-link-active-bg: $component-active-bg !default; + +$dropdown-link-disabled-color: var(--#{$prefix}tertiary-color) !default; + +$dropdown-item-padding-y: $spacer * .25 !default; +$dropdown-item-padding-x: $spacer !default; + +$dropdown-header-color: $gray-600 !default; +$dropdown-header-padding-x: $dropdown-item-padding-x !default; +$dropdown-header-padding-y: $dropdown-padding-y !default; +// fusv-disable +$dropdown-header-padding: $dropdown-header-padding-y $dropdown-header-padding-x !default; // Deprecated in v5.2.0 +// fusv-enable +// scss-docs-end dropdown-variables + +// scss-docs-start dropdown-dark-variables +$dropdown-dark-color: $gray-300 !default; +$dropdown-dark-bg: $gray-800 !default; +$dropdown-dark-border-color: $dropdown-border-color !default; +$dropdown-dark-divider-bg: $dropdown-divider-bg !default; +$dropdown-dark-box-shadow: null !default; +$dropdown-dark-link-color: $dropdown-dark-color !default; +$dropdown-dark-link-hover-color: $white !default; +$dropdown-dark-link-hover-bg: rgba($white, .15) !default; +$dropdown-dark-link-active-color: $dropdown-link-active-color !default; +$dropdown-dark-link-active-bg: $dropdown-link-active-bg !default; +$dropdown-dark-link-disabled-color: $gray-500 !default; +$dropdown-dark-header-color: $gray-500 !default; +// scss-docs-end dropdown-dark-variables + + +// Pagination + +// scss-docs-start pagination-variables +$pagination-padding-y: .375rem !default; +$pagination-padding-x: .75rem !default; +$pagination-padding-y-sm: .25rem !default; +$pagination-padding-x-sm: .5rem !default; +$pagination-padding-y-lg: .75rem !default; +$pagination-padding-x-lg: 1.5rem !default; + +$pagination-font-size: $font-size-base !default; + +$pagination-color: var(--#{$prefix}link-color) !default; +$pagination-bg: var(--#{$prefix}body-bg) !default; +$pagination-border-radius: var(--#{$prefix}border-radius) !default; +$pagination-border-width: var(--#{$prefix}border-width) !default; +$pagination-margin-start: calc(#{$pagination-border-width} * -1) !default; // stylelint-disable-line function-disallowed-list +$pagination-border-color: var(--#{$prefix}border-color) !default; + +$pagination-focus-color: var(--#{$prefix}link-hover-color) !default; +$pagination-focus-bg: var(--#{$prefix}secondary-bg) !default; +$pagination-focus-box-shadow: $focus-ring-box-shadow !default; +$pagination-focus-outline: 0 !default; + +$pagination-hover-color: var(--#{$prefix}link-hover-color) !default; +$pagination-hover-bg: var(--#{$prefix}tertiary-bg) !default; +$pagination-hover-border-color: var(--#{$prefix}border-color) !default; // Todo in v6: remove this? + +$pagination-active-color: $component-active-color !default; +$pagination-active-bg: $component-active-bg !default; +$pagination-active-border-color: $component-active-bg !default; + +$pagination-disabled-color: var(--#{$prefix}secondary-color) !default; +$pagination-disabled-bg: var(--#{$prefix}secondary-bg) !default; +$pagination-disabled-border-color: var(--#{$prefix}border-color) !default; + +$pagination-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$pagination-border-radius-sm: var(--#{$prefix}border-radius-sm) !default; +$pagination-border-radius-lg: var(--#{$prefix}border-radius-lg) !default; +// scss-docs-end pagination-variables + + +// Placeholders + +// scss-docs-start placeholders +$placeholder-opacity-max: .5 !default; +$placeholder-opacity-min: .2 !default; +// scss-docs-end placeholders + +// Cards + +// scss-docs-start card-variables +$card-spacer-y: $spacer !default; +$card-spacer-x: $spacer !default; +$card-title-spacer-y: $spacer * .5 !default; +$card-title-color: null !default; +$card-subtitle-color: null !default; +$card-border-width: var(--#{$prefix}border-width) !default; +$card-border-color: var(--#{$prefix}border-color-translucent) !default; +$card-border-radius: var(--#{$prefix}border-radius) !default; +$card-box-shadow: null !default; +$card-inner-border-radius: subtract($card-border-radius, $card-border-width) !default; +$card-cap-padding-y: $card-spacer-y * .5 !default; +$card-cap-padding-x: $card-spacer-x !default; +$card-cap-bg: rgba(var(--#{$prefix}body-color-rgb), .03) !default; +$card-cap-color: null !default; +$card-height: null !default; +$card-color: null !default; +$card-bg: var(--#{$prefix}body-bg) !default; +$card-img-overlay-padding: $spacer !default; +$card-group-margin: $grid-gutter-width * .5 !default; +// scss-docs-end card-variables + +// Accordion + +// scss-docs-start accordion-variables +$accordion-padding-y: 1rem !default; +$accordion-padding-x: 1.25rem !default; +$accordion-color: var(--#{$prefix}body-color) !default; +$accordion-bg: var(--#{$prefix}body-bg) !default; +$accordion-border-width: var(--#{$prefix}border-width) !default; +$accordion-border-color: var(--#{$prefix}border-color) !default; +$accordion-border-radius: var(--#{$prefix}border-radius) !default; +$accordion-inner-border-radius: subtract($accordion-border-radius, $accordion-border-width) !default; + +$accordion-body-padding-y: $accordion-padding-y !default; +$accordion-body-padding-x: $accordion-padding-x !default; + +$accordion-button-padding-y: $accordion-padding-y !default; +$accordion-button-padding-x: $accordion-padding-x !default; +$accordion-button-color: var(--#{$prefix}body-color) !default; +$accordion-button-bg: var(--#{$prefix}accordion-bg) !default; +$accordion-transition: $btn-transition, border-radius .15s ease !default; +$accordion-button-active-bg: var(--#{$prefix}primary-bg-subtle) !default; +$accordion-button-active-color: var(--#{$prefix}primary-text-emphasis) !default; + +// fusv-disable +$accordion-button-focus-border-color: $input-focus-border-color !default; // Deprecated in v5.3.3 +// fusv-enable +$accordion-button-focus-box-shadow: $btn-focus-box-shadow !default; + +$accordion-icon-width: 1.25rem !default; +$accordion-icon-color: $body-color !default; +$accordion-icon-active-color: $primary-text-emphasis !default; +$accordion-icon-transition: transform .2s ease-in-out !default; +$accordion-icon-transform: rotate(-180deg) !default; + +$accordion-button-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='#{$accordion-icon-color}' stroke-linecap='round' stroke-linejoin='round'><path d='M2 5L8 11L14 5'/></svg>") !default; +$accordion-button-active-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='#{$accordion-icon-active-color}' stroke-linecap='round' stroke-linejoin='round'><path d='M2 5L8 11L14 5'/></svg>") !default; +// scss-docs-end accordion-variables + +// Tooltips + +// scss-docs-start tooltip-variables +$tooltip-font-size: $font-size-sm !default; +$tooltip-max-width: 200px !default; +$tooltip-color: var(--#{$prefix}body-bg) !default; +$tooltip-bg: var(--#{$prefix}emphasis-color) !default; +$tooltip-border-radius: var(--#{$prefix}border-radius) !default; +$tooltip-opacity: .9 !default; +$tooltip-padding-y: $spacer * .25 !default; +$tooltip-padding-x: $spacer * .5 !default; +$tooltip-margin: null !default; // TODO: remove this in v6 + +$tooltip-arrow-width: .8rem !default; +$tooltip-arrow-height: .4rem !default; +// fusv-disable +$tooltip-arrow-color: null !default; // Deprecated in Bootstrap 5.2.0 for CSS variables +// fusv-enable +// scss-docs-end tooltip-variables + +// Form tooltips must come after regular tooltips +// scss-docs-start tooltip-feedback-variables +$form-feedback-tooltip-padding-y: $tooltip-padding-y !default; +$form-feedback-tooltip-padding-x: $tooltip-padding-x !default; +$form-feedback-tooltip-font-size: $tooltip-font-size !default; +$form-feedback-tooltip-line-height: null !default; +$form-feedback-tooltip-opacity: $tooltip-opacity !default; +$form-feedback-tooltip-border-radius: $tooltip-border-radius !default; +// scss-docs-end tooltip-feedback-variables + + +// Popovers + +// scss-docs-start popover-variables +$popover-font-size: $font-size-sm !default; +$popover-bg: var(--#{$prefix}body-bg) !default; +$popover-max-width: 276px !default; +$popover-border-width: var(--#{$prefix}border-width) !default; +$popover-border-color: var(--#{$prefix}border-color-translucent) !default; +$popover-border-radius: var(--#{$prefix}border-radius-lg) !default; +$popover-inner-border-radius: calc(#{$popover-border-radius} - #{$popover-border-width}) !default; // stylelint-disable-line function-disallowed-list +$popover-box-shadow: var(--#{$prefix}box-shadow) !default; + +$popover-header-font-size: $font-size-base !default; +$popover-header-bg: var(--#{$prefix}secondary-bg) !default; +$popover-header-color: $headings-color !default; +$popover-header-padding-y: .5rem !default; +$popover-header-padding-x: $spacer !default; + +$popover-body-color: var(--#{$prefix}body-color) !default; +$popover-body-padding-y: $spacer !default; +$popover-body-padding-x: $spacer !default; + +$popover-arrow-width: 1rem !default; +$popover-arrow-height: .5rem !default; +// scss-docs-end popover-variables + +// fusv-disable +// Deprecated in Bootstrap 5.2.0 for CSS variables +$popover-arrow-color: $popover-bg !default; +$popover-arrow-outer-color: var(--#{$prefix}border-color-translucent) !default; +// fusv-enable + + +// Toasts + +// scss-docs-start toast-variables +$toast-max-width: 350px !default; +$toast-padding-x: .75rem !default; +$toast-padding-y: .5rem !default; +$toast-font-size: .875rem !default; +$toast-color: null !default; +$toast-background-color: rgba(var(--#{$prefix}body-bg-rgb), .85) !default; +$toast-border-width: var(--#{$prefix}border-width) !default; +$toast-border-color: var(--#{$prefix}border-color-translucent) !default; +$toast-border-radius: var(--#{$prefix}border-radius) !default; +$toast-box-shadow: var(--#{$prefix}box-shadow) !default; +$toast-spacing: $container-padding-x !default; + +$toast-header-color: var(--#{$prefix}secondary-color) !default; +$toast-header-background-color: rgba(var(--#{$prefix}body-bg-rgb), .85) !default; +$toast-header-border-color: $toast-border-color !default; +// scss-docs-end toast-variables + + +// Badges + +// scss-docs-start badge-variables +$badge-font-size: .75em !default; +$badge-font-weight: $font-weight-bold !default; +$badge-color: $white !default; +$badge-padding-y: .35em !default; +$badge-padding-x: .65em !default; +$badge-border-radius: var(--#{$prefix}border-radius) !default; +// scss-docs-end badge-variables + + +// Modals + +// scss-docs-start modal-variables +$modal-inner-padding: $spacer !default; + +$modal-footer-margin-between: .5rem !default; + +$modal-dialog-margin: .5rem !default; +$modal-dialog-margin-y-sm-up: 1.75rem !default; + +$modal-title-line-height: $line-height-base !default; + +$modal-content-color: null !default; +$modal-content-bg: var(--#{$prefix}body-bg) !default; +$modal-content-border-color: var(--#{$prefix}border-color-translucent) !default; +$modal-content-border-width: var(--#{$prefix}border-width) !default; +$modal-content-border-radius: var(--#{$prefix}border-radius-lg) !default; +$modal-content-inner-border-radius: subtract($modal-content-border-radius, $modal-content-border-width) !default; +$modal-content-box-shadow-xs: var(--#{$prefix}box-shadow-sm) !default; +$modal-content-box-shadow-sm-up: var(--#{$prefix}box-shadow) !default; + +$modal-backdrop-bg: $black !default; +$modal-backdrop-opacity: .5 !default; + +$modal-header-border-color: var(--#{$prefix}border-color) !default; +$modal-header-border-width: $modal-content-border-width !default; +$modal-header-padding-y: $modal-inner-padding !default; +$modal-header-padding-x: $modal-inner-padding !default; +$modal-header-padding: $modal-header-padding-y $modal-header-padding-x !default; // Keep this for backwards compatibility + +$modal-footer-bg: null !default; +$modal-footer-border-color: $modal-header-border-color !default; +$modal-footer-border-width: $modal-header-border-width !default; + +$modal-sm: 300px !default; +$modal-md: 500px !default; +$modal-lg: 800px !default; +$modal-xl: 1140px !default; + +$modal-fade-transform: translate(0, -50px) !default; +$modal-show-transform: none !default; +$modal-transition: transform .3s ease-out !default; +$modal-scale-transform: scale(1.02) !default; +// scss-docs-end modal-variables + + +// Alerts +// +// Define alert colors, border radius, and padding. + +// scss-docs-start alert-variables +$alert-padding-y: $spacer !default; +$alert-padding-x: $spacer !default; +$alert-margin-bottom: 1rem !default; +$alert-border-radius: var(--#{$prefix}border-radius) !default; +$alert-link-font-weight: $font-weight-bold !default; +$alert-border-width: var(--#{$prefix}border-width) !default; +$alert-dismissible-padding-r: $alert-padding-x * 3 !default; // 3x covers width of x plus default padding on either side +// scss-docs-end alert-variables + +// fusv-disable +$alert-bg-scale: -80% !default; // Deprecated in v5.2.0, to be removed in v6 +$alert-border-scale: -70% !default; // Deprecated in v5.2.0, to be removed in v6 +$alert-color-scale: 40% !default; // Deprecated in v5.2.0, to be removed in v6 +// fusv-enable + +// Progress bars + +// scss-docs-start progress-variables +$progress-height: 1rem !default; +$progress-font-size: $font-size-base * .75 !default; +$progress-bg: var(--#{$prefix}secondary-bg) !default; +$progress-border-radius: var(--#{$prefix}border-radius) !default; +$progress-box-shadow: var(--#{$prefix}box-shadow-inset) !default; +$progress-bar-color: $white !default; +$progress-bar-bg: $primary !default; +$progress-bar-animation-timing: 1s linear infinite !default; +$progress-bar-transition: width .6s ease !default; +// scss-docs-end progress-variables + + +// List group + +// scss-docs-start list-group-variables +$list-group-color: var(--#{$prefix}body-color) !default; +$list-group-bg: var(--#{$prefix}body-bg) !default; +$list-group-border-color: var(--#{$prefix}border-color) !default; +$list-group-border-width: var(--#{$prefix}border-width) !default; +$list-group-border-radius: var(--#{$prefix}border-radius) !default; + +$list-group-item-padding-y: $spacer * .5 !default; +$list-group-item-padding-x: $spacer !default; +// fusv-disable +$list-group-item-bg-scale: -80% !default; // Deprecated in v5.3.0 +$list-group-item-color-scale: 40% !default; // Deprecated in v5.3.0 +// fusv-enable + +$list-group-hover-bg: var(--#{$prefix}tertiary-bg) !default; +$list-group-active-color: $component-active-color !default; +$list-group-active-bg: $component-active-bg !default; +$list-group-active-border-color: $list-group-active-bg !default; + +$list-group-disabled-color: var(--#{$prefix}secondary-color) !default; +$list-group-disabled-bg: $list-group-bg !default; + +$list-group-action-color: var(--#{$prefix}secondary-color) !default; +$list-group-action-hover-color: var(--#{$prefix}emphasis-color) !default; + +$list-group-action-active-color: var(--#{$prefix}body-color) !default; +$list-group-action-active-bg: var(--#{$prefix}secondary-bg) !default; +// scss-docs-end list-group-variables + + +// Image thumbnails + +// scss-docs-start thumbnail-variables +$thumbnail-padding: .25rem !default; +$thumbnail-bg: var(--#{$prefix}body-bg) !default; +$thumbnail-border-width: var(--#{$prefix}border-width) !default; +$thumbnail-border-color: var(--#{$prefix}border-color) !default; +$thumbnail-border-radius: var(--#{$prefix}border-radius) !default; +$thumbnail-box-shadow: var(--#{$prefix}box-shadow-sm) !default; +// scss-docs-end thumbnail-variables + + +// Figures + +// scss-docs-start figure-variables +$figure-caption-font-size: $small-font-size !default; +$figure-caption-color: var(--#{$prefix}secondary-color) !default; +// scss-docs-end figure-variables + + +// Breadcrumbs + +// scss-docs-start breadcrumb-variables +$breadcrumb-font-size: null !default; +$breadcrumb-padding-y: 0 !default; +$breadcrumb-padding-x: 0 !default; +$breadcrumb-item-padding-x: .5rem !default; +$breadcrumb-margin-bottom: 1rem !default; +$breadcrumb-bg: null !default; +$breadcrumb-divider-color: var(--#{$prefix}secondary-color) !default; +$breadcrumb-active-color: var(--#{$prefix}secondary-color) !default; +$breadcrumb-divider: quote("/") !default; +$breadcrumb-divider-flipped: $breadcrumb-divider !default; +$breadcrumb-border-radius: null !default; +// scss-docs-end breadcrumb-variables + +// Carousel + +// scss-docs-start carousel-variables +$carousel-control-color: $white !default; +$carousel-control-width: 15% !default; +$carousel-control-opacity: .5 !default; +$carousel-control-hover-opacity: .9 !default; +$carousel-control-transition: opacity .15s ease !default; + +$carousel-indicator-width: 30px !default; +$carousel-indicator-height: 3px !default; +$carousel-indicator-hit-area-height: 10px !default; +$carousel-indicator-spacer: 3px !default; +$carousel-indicator-opacity: .5 !default; +$carousel-indicator-active-bg: $white !default; +$carousel-indicator-active-opacity: 1 !default; +$carousel-indicator-transition: opacity .6s ease !default; + +$carousel-caption-width: 70% !default; +$carousel-caption-color: $white !default; +$carousel-caption-padding-y: 1.25rem !default; +$carousel-caption-spacer: 1.25rem !default; + +$carousel-control-icon-width: 2rem !default; + +$carousel-control-prev-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$carousel-control-color}'><path d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/></svg>") !default; +$carousel-control-next-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$carousel-control-color}'><path d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/></svg>") !default; + +$carousel-transition-duration: .6s !default; +$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`) +// scss-docs-end carousel-variables + +// scss-docs-start carousel-dark-variables +$carousel-dark-indicator-active-bg: $black !default; +$carousel-dark-caption-color: $black !default; +$carousel-dark-control-icon-filter: invert(1) grayscale(100) !default; +// scss-docs-end carousel-dark-variables + + +// Spinners + +// scss-docs-start spinner-variables +$spinner-width: 2rem !default; +$spinner-height: $spinner-width !default; +$spinner-vertical-align: -.125em !default; +$spinner-border-width: .25em !default; +$spinner-animation-speed: .75s !default; + +$spinner-width-sm: 1rem !default; +$spinner-height-sm: $spinner-width-sm !default; +$spinner-border-width-sm: .2em !default; +// scss-docs-end spinner-variables + + +// Close + +// scss-docs-start close-variables +$btn-close-width: 1em !default; +$btn-close-height: $btn-close-width !default; +$btn-close-padding-x: .25em !default; +$btn-close-padding-y: $btn-close-padding-x !default; +$btn-close-color: $black !default; +$btn-close-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$btn-close-color}'><path d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/></svg>") !default; +$btn-close-focus-shadow: $focus-ring-box-shadow !default; +$btn-close-opacity: .5 !default; +$btn-close-hover-opacity: .75 !default; +$btn-close-focus-opacity: 1 !default; +$btn-close-disabled-opacity: .25 !default; +$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%) !default; +// scss-docs-end close-variables + + +// Offcanvas + +// scss-docs-start offcanvas-variables +$offcanvas-padding-y: $modal-inner-padding !default; +$offcanvas-padding-x: $modal-inner-padding !default; +$offcanvas-horizontal-width: 400px !default; +$offcanvas-vertical-height: 30vh !default; +$offcanvas-transition-duration: .3s !default; +$offcanvas-border-color: $modal-content-border-color !default; +$offcanvas-border-width: $modal-content-border-width !default; +$offcanvas-title-line-height: $modal-title-line-height !default; +$offcanvas-bg-color: var(--#{$prefix}body-bg) !default; +$offcanvas-color: var(--#{$prefix}body-color) !default; +$offcanvas-box-shadow: $modal-content-box-shadow-xs !default; +$offcanvas-backdrop-bg: $modal-backdrop-bg !default; +$offcanvas-backdrop-opacity: $modal-backdrop-opacity !default; +// scss-docs-end offcanvas-variables + +// Code + +$code-font-size: $small-font-size !default; +$code-color: $pink !default; + +$kbd-padding-y: .1875rem !default; +$kbd-padding-x: .375rem !default; +$kbd-font-size: $code-font-size !default; +$kbd-color: var(--#{$prefix}body-bg) !default; +$kbd-bg: var(--#{$prefix}body-color) !default; +$nested-kbd-font-weight: null !default; // Deprecated in v5.2.0, removing in v6 + +$pre-color: null !default; + +@import "variables-dark"; // TODO: can be removed safely in v6, only here to avoid breaking changes in v5.3 diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-grid.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-grid.scss new file mode 100644 index 00000000..52bd577e --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-grid.scss @@ -0,0 +1,62 @@ +@import "mixins/banner"; +@include bsBanner(Grid); + +$include-column-box-sizing: true !default; + +@import "functions"; +@import "variables"; +@import "variables-dark"; +@import "maps"; + +@import "mixins/breakpoints"; +@import "mixins/container"; +@import "mixins/grid"; +@import "mixins/utilities"; + +@import "vendor/rfs"; + +@import "containers"; +@import "grid"; + +@import "utilities"; +// Only use the utilities we need +// stylelint-disable-next-line scss/dollar-variable-default +$utilities: map-get-multiple( + $utilities, + ( + "display", + "order", + "flex", + "flex-direction", + "flex-grow", + "flex-shrink", + "flex-wrap", + "justify-content", + "align-items", + "align-content", + "align-self", + "margin", + "margin-x", + "margin-y", + "margin-top", + "margin-end", + "margin-bottom", + "margin-start", + "negative-margin", + "negative-margin-x", + "negative-margin-y", + "negative-margin-top", + "negative-margin-end", + "negative-margin-bottom", + "negative-margin-start", + "padding", + "padding-x", + "padding-y", + "padding-top", + "padding-end", + "padding-bottom", + "padding-start", + ) +); + +@import "utilities/api"; diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-reboot.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-reboot.scss new file mode 100644 index 00000000..5b69b955 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-reboot.scss @@ -0,0 +1,10 @@ +@import "mixins/banner"; +@include bsBanner(Reboot); + +@import "functions"; +@import "variables"; +@import "variables-dark"; +@import "maps"; +@import "mixins"; +@import "root"; +@import "reboot"; diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-utilities.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-utilities.scss new file mode 100644 index 00000000..99c4a359 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-utilities.scss @@ -0,0 +1,19 @@ +@import "mixins/banner"; +@include bsBanner(Utilities); + +// Configuration +@import "functions"; +@import "variables"; +@import "variables-dark"; +@import "maps"; +@import "mixins"; +@import "utilities"; + +// Layout & components +@import "root"; + +// Helpers +@import "helpers"; + +// Utilities +@import "utilities/api"; diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap.scss new file mode 100644 index 00000000..449d7048 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap.scss @@ -0,0 +1,52 @@ +@import "mixins/banner"; +@include bsBanner(""); + + +// scss-docs-start import-stack +// Configuration +@import "functions"; +@import "variables"; +@import "variables-dark"; +@import "maps"; +@import "mixins"; +@import "utilities"; + +// Layout & components +@import "root"; +@import "reboot"; +@import "type"; +@import "images"; +@import "containers"; +@import "grid"; +@import "tables"; +@import "forms"; +@import "buttons"; +@import "transitions"; +@import "dropdown"; +@import "button-group"; +@import "nav"; +@import "navbar"; +@import "card"; +@import "accordion"; +@import "breadcrumb"; +@import "pagination"; +@import "badge"; +@import "alert"; +@import "progress"; +@import "list-group"; +@import "close"; +@import "toasts"; +@import "modal"; +@import "tooltip"; +@import "popover"; +@import "carousel"; +@import "spinners"; +@import "offcanvas"; +@import "placeholders"; + +// Helpers +@import "helpers"; + +// Utilities +@import "utilities/api"; +// scss-docs-end import-stack diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_floating-labels.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_floating-labels.scss new file mode 100644 index 00000000..2cf04704 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_floating-labels.scss @@ -0,0 +1,95 @@ +.form-floating { + position: relative; + + > .form-control, + > .form-control-plaintext, + > .form-select { + height: $form-floating-height; + min-height: $form-floating-height; + line-height: $form-floating-line-height; + } + + > label { + position: absolute; + top: 0; + left: 0; + z-index: 2; + height: 100%; // allow textareas + padding: $form-floating-padding-y $form-floating-padding-x; + overflow: hidden; + text-align: start; + text-overflow: ellipsis; + white-space: nowrap; + pointer-events: none; + border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model + transform-origin: 0 0; + @include transition($form-floating-transition); + } + + > .form-control, + > .form-control-plaintext { + padding: $form-floating-padding-y $form-floating-padding-x; + + &::placeholder { + color: transparent; + } + + &:focus, + &:not(:placeholder-shown) { + padding-top: $form-floating-input-padding-t; + padding-bottom: $form-floating-input-padding-b; + } + // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped + &:-webkit-autofill { + padding-top: $form-floating-input-padding-t; + padding-bottom: $form-floating-input-padding-b; + } + } + + > .form-select { + padding-top: $form-floating-input-padding-t; + padding-bottom: $form-floating-input-padding-b; + } + + > .form-control:focus, + > .form-control:not(:placeholder-shown), + > .form-control-plaintext, + > .form-select { + ~ label { + color: rgba(var(--#{$prefix}body-color-rgb), #{$form-floating-label-opacity}); + transform: $form-floating-label-transform; + + &::after { + position: absolute; + inset: $form-floating-padding-y ($form-floating-padding-x * .5); + z-index: -1; + height: $form-floating-label-height; + content: ""; + background-color: $input-bg; + @include border-radius($input-border-radius); + } + } + } + // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped + > .form-control:-webkit-autofill { + ~ label { + color: rgba(var(--#{$prefix}body-color-rgb), #{$form-floating-label-opacity}); + transform: $form-floating-label-transform; + } + } + + > .form-control-plaintext { + ~ label { + border-width: $input-border-width 0; // Required to properly position label text - as explained above + } + } + + > :disabled ~ label, + > .form-control:disabled ~ label { // Required for `.form-control`s because of specificity + color: $form-floating-label-disabled-color; + + &::after { + background-color: $input-disabled-bg; + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-check.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-check.scss new file mode 100644 index 00000000..8a1b639d --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-check.scss @@ -0,0 +1,189 @@ +// +// Check/radio +// + +.form-check { + display: block; + min-height: $form-check-min-height; + padding-left: $form-check-padding-start; + margin-bottom: $form-check-margin-bottom; + + .form-check-input { + float: left; + margin-left: $form-check-padding-start * -1; + } +} + +.form-check-reverse { + padding-right: $form-check-padding-start; + padding-left: 0; + text-align: right; + + .form-check-input { + float: right; + margin-right: $form-check-padding-start * -1; + margin-left: 0; + } +} + +.form-check-input { + --#{$prefix}form-check-bg: #{$form-check-input-bg}; + + flex-shrink: 0; + width: $form-check-input-width; + height: $form-check-input-width; + margin-top: ($line-height-base - $form-check-input-width) * .5; // line-height minus check height + vertical-align: top; + appearance: none; + background-color: var(--#{$prefix}form-check-bg); + background-image: var(--#{$prefix}form-check-bg-image); + background-repeat: no-repeat; + background-position: center; + background-size: contain; + border: $form-check-input-border; + print-color-adjust: exact; // Keep themed appearance for print + @include transition($form-check-transition); + + &[type="checkbox"] { + @include border-radius($form-check-input-border-radius); + } + + &[type="radio"] { + // stylelint-disable-next-line property-disallowed-list + border-radius: $form-check-radio-border-radius; + } + + &:active { + filter: $form-check-input-active-filter; + } + + &:focus { + border-color: $form-check-input-focus-border; + outline: 0; + box-shadow: $form-check-input-focus-box-shadow; + } + + &:checked { + background-color: $form-check-input-checked-bg-color; + border-color: $form-check-input-checked-border-color; + + &[type="checkbox"] { + @if $enable-gradients { + --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-checked-bg-image)}, var(--#{$prefix}gradient); + } @else { + --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-checked-bg-image)}; + } + } + + &[type="radio"] { + @if $enable-gradients { + --#{$prefix}form-check-bg-image: #{escape-svg($form-check-radio-checked-bg-image)}, var(--#{$prefix}gradient); + } @else { + --#{$prefix}form-check-bg-image: #{escape-svg($form-check-radio-checked-bg-image)}; + } + } + } + + &[type="checkbox"]:indeterminate { + background-color: $form-check-input-indeterminate-bg-color; + border-color: $form-check-input-indeterminate-border-color; + + @if $enable-gradients { + --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-indeterminate-bg-image)}, var(--#{$prefix}gradient); + } @else { + --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-indeterminate-bg-image)}; + } + } + + &:disabled { + pointer-events: none; + filter: none; + opacity: $form-check-input-disabled-opacity; + } + + // Use disabled attribute in addition of :disabled pseudo-class + // See: https://github.com/twbs/bootstrap/issues/28247 + &[disabled], + &:disabled { + ~ .form-check-label { + cursor: default; + opacity: $form-check-label-disabled-opacity; + } + } +} + +.form-check-label { + color: $form-check-label-color; + cursor: $form-check-label-cursor; +} + +// +// Switch +// + +.form-switch { + padding-left: $form-switch-padding-start; + + .form-check-input { + --#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image)}; + + width: $form-switch-width; + margin-left: $form-switch-padding-start * -1; + background-image: var(--#{$prefix}form-switch-bg); + background-position: left center; + @include border-radius($form-switch-border-radius, 0); + @include transition($form-switch-transition); + + &:focus { + --#{$prefix}form-switch-bg: #{escape-svg($form-switch-focus-bg-image)}; + } + + &:checked { + background-position: $form-switch-checked-bg-position; + + @if $enable-gradients { + --#{$prefix}form-switch-bg: #{escape-svg($form-switch-checked-bg-image)}, var(--#{$prefix}gradient); + } @else { + --#{$prefix}form-switch-bg: #{escape-svg($form-switch-checked-bg-image)}; + } + } + } + + &.form-check-reverse { + padding-right: $form-switch-padding-start; + padding-left: 0; + + .form-check-input { + margin-right: $form-switch-padding-start * -1; + margin-left: 0; + } + } +} + +.form-check-inline { + display: inline-block; + margin-right: $form-check-inline-margin-end; +} + +.btn-check { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; + + &[disabled], + &:disabled { + + .btn { + pointer-events: none; + filter: none; + opacity: $form-check-btn-check-disabled-opacity; + } + } +} + +@if $enable-dark-mode { + @include color-mode(dark) { + .form-switch .form-check-input:not(:checked):not(:focus) { + --#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image-dark)}; + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-control.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-control.scss new file mode 100644 index 00000000..67ae5f4f --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-control.scss @@ -0,0 +1,214 @@ +// +// General form controls (plus a few specific high-level interventions) +// + +.form-control { + display: block; + width: 100%; + padding: $input-padding-y $input-padding-x; + font-family: $input-font-family; + @include font-size($input-font-size); + font-weight: $input-font-weight; + line-height: $input-line-height; + color: $input-color; + appearance: none; // Fix appearance for date inputs in Safari + background-color: $input-bg; + background-clip: padding-box; + border: $input-border-width solid $input-border-color; + + // Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS. + @include border-radius($input-border-radius, 0); + + @include box-shadow($input-box-shadow); + @include transition($input-transition); + + &[type="file"] { + overflow: hidden; // prevent pseudo element button overlap + + &:not(:disabled):not([readonly]) { + cursor: pointer; + } + } + + // Customize the `:focus` state to imitate native WebKit styles. + &:focus { + color: $input-focus-color; + background-color: $input-focus-bg; + border-color: $input-focus-border-color; + outline: 0; + @if $enable-shadows { + @include box-shadow($input-box-shadow, $input-focus-box-shadow); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: $input-focus-box-shadow; + } + } + + &::-webkit-date-and-time-value { + // On Android Chrome, form-control's "width: 100%" makes the input width too small + // Tested under Android 11 / Chrome 89, Android 12 / Chrome 100, Android 13 / Chrome 109 + // + // On iOS Safari, form-control's "appearance: none" + "width: 100%" makes the input width too small + // Tested under iOS 16.2 / Safari 16.2 + min-width: 85px; // Seems to be a good minimum safe width + + // Add some height to date inputs on iOS + // https://github.com/twbs/bootstrap/issues/23307 + // TODO: we can remove this workaround once https://bugs.webkit.org/show_bug.cgi?id=198959 is resolved + // Multiply line-height by 1em if it has no unit + height: if(unit($input-line-height) == "", $input-line-height * 1em, $input-line-height); + + // Android Chrome type="date" is taller than the other inputs + // because of "margin: 1px 24px 1px 4px" inside the shadow DOM + // Tested under Android 11 / Chrome 89, Android 12 / Chrome 100, Android 13 / Chrome 109 + margin: 0; + } + + // Prevent excessive date input height in Webkit + // https://github.com/twbs/bootstrap/issues/34433 + &::-webkit-datetime-edit { + display: block; + padding: 0; + } + + // Placeholder + &::placeholder { + color: $input-placeholder-color; + // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526. + opacity: 1; + } + + // Disabled inputs + // + // HTML5 says that controls under a fieldset > legend:first-child won't be + // disabled if the fieldset is disabled. Due to implementation difficulty, we + // don't honor that edge case; we style them as disabled anyway. + &:disabled { + color: $input-disabled-color; + background-color: $input-disabled-bg; + border-color: $input-disabled-border-color; + // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655. + opacity: 1; + } + + // File input buttons theming + &::file-selector-button { + padding: $input-padding-y $input-padding-x; + margin: (-$input-padding-y) (-$input-padding-x); + margin-inline-end: $input-padding-x; + color: $form-file-button-color; + @include gradient-bg($form-file-button-bg); + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: $input-border-width; + border-radius: 0; // stylelint-disable-line property-disallowed-list + @include transition($btn-transition); + } + + &:hover:not(:disabled):not([readonly])::file-selector-button { + background-color: $form-file-button-hover-bg; + } +} + +// Readonly controls as plain text +// +// Apply class to a readonly input to make it appear like regular plain +// text (without any border, background color, focus indicator) + +.form-control-plaintext { + display: block; + width: 100%; + padding: $input-padding-y 0; + margin-bottom: 0; // match inputs if this class comes on inputs with default margins + line-height: $input-line-height; + color: $input-plaintext-color; + background-color: transparent; + border: solid transparent; + border-width: $input-border-width 0; + + &:focus { + outline: 0; + } + + &.form-control-sm, + &.form-control-lg { + padding-right: 0; + padding-left: 0; + } +} + +// Form control sizing +// +// Build on `.form-control` with modifier classes to decrease or increase the +// height and font-size of form controls. +// +// Repeated in `_input_group.scss` to avoid Sass extend issues. + +.form-control-sm { + min-height: $input-height-sm; + padding: $input-padding-y-sm $input-padding-x-sm; + @include font-size($input-font-size-sm); + @include border-radius($input-border-radius-sm); + + &::file-selector-button { + padding: $input-padding-y-sm $input-padding-x-sm; + margin: (-$input-padding-y-sm) (-$input-padding-x-sm); + margin-inline-end: $input-padding-x-sm; + } +} + +.form-control-lg { + min-height: $input-height-lg; + padding: $input-padding-y-lg $input-padding-x-lg; + @include font-size($input-font-size-lg); + @include border-radius($input-border-radius-lg); + + &::file-selector-button { + padding: $input-padding-y-lg $input-padding-x-lg; + margin: (-$input-padding-y-lg) (-$input-padding-x-lg); + margin-inline-end: $input-padding-x-lg; + } +} + +// Make sure textareas don't shrink too much when resized +// https://github.com/twbs/bootstrap/pull/29124 +// stylelint-disable selector-no-qualifying-type +textarea { + &.form-control { + min-height: $input-height; + } + + &.form-control-sm { + min-height: $input-height-sm; + } + + &.form-control-lg { + min-height: $input-height-lg; + } +} +// stylelint-enable selector-no-qualifying-type + +.form-control-color { + width: $form-color-width; + height: $input-height; + padding: $input-padding-y; + + &:not(:disabled):not([readonly]) { + cursor: pointer; + } + + &::-moz-color-swatch { + border: 0 !important; // stylelint-disable-line declaration-no-important + @include border-radius($input-border-radius); + } + + &::-webkit-color-swatch { + border: 0 !important; // stylelint-disable-line declaration-no-important + @include border-radius($input-border-radius); + } + + &.form-control-sm { height: $input-height-sm; } + &.form-control-lg { height: $input-height-lg; } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-range.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-range.scss new file mode 100644 index 00000000..4732213e --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-range.scss @@ -0,0 +1,91 @@ +// Range +// +// Style range inputs the same across browsers. Vendor-specific rules for pseudo +// elements cannot be mixed. As such, there are no shared styles for focus or +// active states on prefixed selectors. + +.form-range { + width: 100%; + height: add($form-range-thumb-height, $form-range-thumb-focus-box-shadow-width * 2); + padding: 0; // Need to reset padding + appearance: none; + background-color: transparent; + + &:focus { + outline: 0; + + // Pseudo-elements must be split across multiple rulesets to have an effect. + // No box-shadow() mixin for focus accessibility. + &::-webkit-slider-thumb { box-shadow: $form-range-thumb-focus-box-shadow; } + &::-moz-range-thumb { box-shadow: $form-range-thumb-focus-box-shadow; } + } + + &::-moz-focus-outer { + border: 0; + } + + &::-webkit-slider-thumb { + width: $form-range-thumb-width; + height: $form-range-thumb-height; + margin-top: ($form-range-track-height - $form-range-thumb-height) * .5; // Webkit specific + appearance: none; + @include gradient-bg($form-range-thumb-bg); + border: $form-range-thumb-border; + @include border-radius($form-range-thumb-border-radius); + @include box-shadow($form-range-thumb-box-shadow); + @include transition($form-range-thumb-transition); + + &:active { + @include gradient-bg($form-range-thumb-active-bg); + } + } + + &::-webkit-slider-runnable-track { + width: $form-range-track-width; + height: $form-range-track-height; + color: transparent; // Why? + cursor: $form-range-track-cursor; + background-color: $form-range-track-bg; + border-color: transparent; + @include border-radius($form-range-track-border-radius); + @include box-shadow($form-range-track-box-shadow); + } + + &::-moz-range-thumb { + width: $form-range-thumb-width; + height: $form-range-thumb-height; + appearance: none; + @include gradient-bg($form-range-thumb-bg); + border: $form-range-thumb-border; + @include border-radius($form-range-thumb-border-radius); + @include box-shadow($form-range-thumb-box-shadow); + @include transition($form-range-thumb-transition); + + &:active { + @include gradient-bg($form-range-thumb-active-bg); + } + } + + &::-moz-range-track { + width: $form-range-track-width; + height: $form-range-track-height; + color: transparent; + cursor: $form-range-track-cursor; + background-color: $form-range-track-bg; + border-color: transparent; // Firefox specific? + @include border-radius($form-range-track-border-radius); + @include box-shadow($form-range-track-box-shadow); + } + + &:disabled { + pointer-events: none; + + &::-webkit-slider-thumb { + background-color: $form-range-thumb-disabled-bg; + } + + &::-moz-range-thumb { + background-color: $form-range-thumb-disabled-bg; + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-select.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-select.scss new file mode 100644 index 00000000..69ace529 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-select.scss @@ -0,0 +1,80 @@ +// Select +// +// Replaces the browser default select with a custom one, mostly pulled from +// https://primer.github.io/. + +.form-select { + --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator)}; + + display: block; + width: 100%; + padding: $form-select-padding-y $form-select-indicator-padding $form-select-padding-y $form-select-padding-x; + font-family: $form-select-font-family; + @include font-size($form-select-font-size); + font-weight: $form-select-font-weight; + line-height: $form-select-line-height; + color: $form-select-color; + appearance: none; + background-color: $form-select-bg; + background-image: var(--#{$prefix}form-select-bg-img), var(--#{$prefix}form-select-bg-icon, none); + background-repeat: no-repeat; + background-position: $form-select-bg-position; + background-size: $form-select-bg-size; + border: $form-select-border-width solid $form-select-border-color; + @include border-radius($form-select-border-radius, 0); + @include box-shadow($form-select-box-shadow); + @include transition($form-select-transition); + + &:focus { + border-color: $form-select-focus-border-color; + outline: 0; + @if $enable-shadows { + @include box-shadow($form-select-box-shadow, $form-select-focus-box-shadow); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: $form-select-focus-box-shadow; + } + } + + &[multiple], + &[size]:not([size="1"]) { + padding-right: $form-select-padding-x; + background-image: none; + } + + &:disabled { + color: $form-select-disabled-color; + background-color: $form-select-disabled-bg; + border-color: $form-select-disabled-border-color; + } + + // Remove outline from select box in FF + &:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 $form-select-color; + } +} + +.form-select-sm { + padding-top: $form-select-padding-y-sm; + padding-bottom: $form-select-padding-y-sm; + padding-left: $form-select-padding-x-sm; + @include font-size($form-select-font-size-sm); + @include border-radius($form-select-border-radius-sm); +} + +.form-select-lg { + padding-top: $form-select-padding-y-lg; + padding-bottom: $form-select-padding-y-lg; + padding-left: $form-select-padding-x-lg; + @include font-size($form-select-font-size-lg); + @include border-radius($form-select-border-radius-lg); +} + +@if $enable-dark-mode { + @include color-mode(dark) { + .form-select { + --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator-dark)}; + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-text.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-text.scss new file mode 100644 index 00000000..f080d1a2 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-text.scss @@ -0,0 +1,11 @@ +// +// Form text +// + +.form-text { + margin-top: $form-text-margin-top; + @include font-size($form-text-font-size); + font-style: $form-text-font-style; + font-weight: $form-text-font-weight; + color: $form-text-color; +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_input-group.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_input-group.scss new file mode 100644 index 00000000..58e4d409 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_input-group.scss @@ -0,0 +1,132 @@ +// +// Base styles +// + +.input-group { + position: relative; + display: flex; + flex-wrap: wrap; // For form validation feedback + align-items: stretch; + width: 100%; + + > .form-control, + > .form-select, + > .form-floating { + position: relative; // For focus state's z-index + flex: 1 1 auto; + width: 1%; + min-width: 0; // https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size + } + + // Bring the "active" form control to the top of surrounding elements + > .form-control:focus, + > .form-select:focus, + > .form-floating:focus-within { + z-index: 5; + } + + // Ensure buttons are always above inputs for more visually pleasing borders. + // This isn't needed for `.input-group-text` since it shares the same border-color + // as our inputs. + .btn { + position: relative; + z-index: 2; + + &:focus { + z-index: 5; + } + } +} + + +// Textual addons +// +// Serves as a catch-all element for any text or radio/checkbox input you wish +// to prepend or append to an input. + +.input-group-text { + display: flex; + align-items: center; + padding: $input-group-addon-padding-y $input-group-addon-padding-x; + @include font-size($input-font-size); // Match inputs + font-weight: $input-group-addon-font-weight; + line-height: $input-line-height; + color: $input-group-addon-color; + text-align: center; + white-space: nowrap; + background-color: $input-group-addon-bg; + border: $input-border-width solid $input-group-addon-border-color; + @include border-radius($input-border-radius); +} + + +// Sizing +// +// Remix the default form control sizing classes into new ones for easier +// manipulation. + +.input-group-lg > .form-control, +.input-group-lg > .form-select, +.input-group-lg > .input-group-text, +.input-group-lg > .btn { + padding: $input-padding-y-lg $input-padding-x-lg; + @include font-size($input-font-size-lg); + @include border-radius($input-border-radius-lg); +} + +.input-group-sm > .form-control, +.input-group-sm > .form-select, +.input-group-sm > .input-group-text, +.input-group-sm > .btn { + padding: $input-padding-y-sm $input-padding-x-sm; + @include font-size($input-font-size-sm); + @include border-radius($input-border-radius-sm); +} + +.input-group-lg > .form-select, +.input-group-sm > .form-select { + padding-right: $form-select-padding-x + $form-select-indicator-padding; +} + + +// Rounded corners +// +// These rulesets must come after the sizing ones to properly override sm and lg +// border-radius values when extending. They're more specific than we'd like +// with the `.input-group >` part, but without it, we cannot override the sizing. + +// stylelint-disable-next-line no-duplicate-selectors +.input-group { + &:not(.has-validation) { + > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), + > .dropdown-toggle:nth-last-child(n + 3), + > .form-floating:not(:last-child) > .form-control, + > .form-floating:not(:last-child) > .form-select { + @include border-end-radius(0); + } + } + + &.has-validation { + > :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), + > .dropdown-toggle:nth-last-child(n + 4), + > .form-floating:nth-last-child(n + 3) > .form-control, + > .form-floating:nth-last-child(n + 3) > .form-select { + @include border-end-radius(0); + } + } + + $validation-messages: ""; + @each $state in map-keys($form-validation-states) { + $validation-messages: $validation-messages + ":not(." + unquote($state) + "-tooltip)" + ":not(." + unquote($state) + "-feedback)"; + } + + > :not(:first-child):not(.dropdown-menu)#{$validation-messages} { + margin-left: calc(#{$input-border-width} * -1); // stylelint-disable-line function-disallowed-list + @include border-start-radius(0); + } + + > .form-floating:not(:first-child) > .form-control, + > .form-floating:not(:first-child) > .form-select { + @include border-start-radius(0); + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_labels.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_labels.scss new file mode 100644 index 00000000..39ecafcd --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_labels.scss @@ -0,0 +1,36 @@ +// +// Labels +// + +.form-label { + margin-bottom: $form-label-margin-bottom; + @include font-size($form-label-font-size); + font-style: $form-label-font-style; + font-weight: $form-label-font-weight; + color: $form-label-color; +} + +// For use with horizontal and inline forms, when you need the label (or legend) +// text to align with the form controls. +.col-form-label { + padding-top: add($input-padding-y, $input-border-width); + padding-bottom: add($input-padding-y, $input-border-width); + margin-bottom: 0; // Override the `<legend>` default + @include font-size(inherit); // Override the `<legend>` default + font-style: $form-label-font-style; + font-weight: $form-label-font-weight; + line-height: $input-line-height; + color: $form-label-color; +} + +.col-form-label-lg { + padding-top: add($input-padding-y-lg, $input-border-width); + padding-bottom: add($input-padding-y-lg, $input-border-width); + @include font-size($input-font-size-lg); +} + +.col-form-label-sm { + padding-top: add($input-padding-y-sm, $input-border-width); + padding-bottom: add($input-padding-y-sm, $input-border-width); + @include font-size($input-font-size-sm); +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_validation.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_validation.scss new file mode 100644 index 00000000..c48123a7 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_validation.scss @@ -0,0 +1,12 @@ +// Form validation +// +// Provide feedback to users when form field values are valid or invalid. Works +// primarily for client-side validation via scoped `:invalid` and `:valid` +// pseudo-classes but also includes `.is-invalid` and `.is-valid` classes for +// server-side validation. + +// scss-docs-start form-validation-states-loop +@each $state, $data in $form-validation-states { + @include form-validation-state($state, $data...); +} +// scss-docs-end form-validation-states-loop diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_clearfix.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_clearfix.scss new file mode 100644 index 00000000..e92522a9 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_clearfix.scss @@ -0,0 +1,3 @@ +.clearfix { + @include clearfix(); +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_color-bg.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_color-bg.scss new file mode 100644 index 00000000..1a3a4cff --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_color-bg.scss @@ -0,0 +1,7 @@ +// All-caps `RGBA()` function used because of this Sass bug: https://github.com/sass/node-sass/issues/2251 +@each $color, $value in $theme-colors { + .text-bg-#{$color} { + color: color-contrast($value) if($enable-important-utilities, !important, null); + background-color: RGBA(var(--#{$prefix}#{$color}-rgb), var(--#{$prefix}bg-opacity, 1)) if($enable-important-utilities, !important, null); + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_colored-links.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_colored-links.scss new file mode 100644 index 00000000..5f868578 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_colored-links.scss @@ -0,0 +1,30 @@ +// All-caps `RGBA()` function used because of this Sass bug: https://github.com/sass/node-sass/issues/2251 +@each $color, $value in $theme-colors { + .link-#{$color} { + color: RGBA(var(--#{$prefix}#{$color}-rgb), var(--#{$prefix}link-opacity, 1)) if($enable-important-utilities, !important, null); + text-decoration-color: RGBA(var(--#{$prefix}#{$color}-rgb), var(--#{$prefix}link-underline-opacity, 1)) if($enable-important-utilities, !important, null); + + @if $link-shade-percentage != 0 { + &:hover, + &:focus { + $hover-color: if(color-contrast($value) == $color-contrast-light, shade-color($value, $link-shade-percentage), tint-color($value, $link-shade-percentage)); + color: RGBA(#{to-rgb($hover-color)}, var(--#{$prefix}link-opacity, 1)) if($enable-important-utilities, !important, null); + text-decoration-color: RGBA(to-rgb($hover-color), var(--#{$prefix}link-underline-opacity, 1)) if($enable-important-utilities, !important, null); + } + } + } +} + +// One-off special link helper as a bridge until v6 +.link-body-emphasis { + color: RGBA(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}link-opacity, 1)) if($enable-important-utilities, !important, null); + text-decoration-color: RGBA(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}link-underline-opacity, 1)) if($enable-important-utilities, !important, null); + + @if $link-shade-percentage != 0 { + &:hover, + &:focus { + color: RGBA(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}link-opacity, .75)) if($enable-important-utilities, !important, null); + text-decoration-color: RGBA(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}link-underline-opacity, .75)) if($enable-important-utilities, !important, null); + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_focus-ring.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_focus-ring.scss new file mode 100644 index 00000000..26508a8d --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_focus-ring.scss @@ -0,0 +1,5 @@ +.focus-ring:focus { + outline: 0; + // By default, there is no `--bs-focus-ring-x`, `--bs-focus-ring-y`, or `--bs-focus-ring-blur`, but we provide CSS variables with fallbacks to initial `0` values + box-shadow: var(--#{$prefix}focus-ring-x, 0) var(--#{$prefix}focus-ring-y, 0) var(--#{$prefix}focus-ring-blur, 0) var(--#{$prefix}focus-ring-width) var(--#{$prefix}focus-ring-color); +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_icon-link.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_icon-link.scss new file mode 100644 index 00000000..3f8bcb33 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_icon-link.scss @@ -0,0 +1,25 @@ +.icon-link { + display: inline-flex; + gap: $icon-link-gap; + align-items: center; + text-decoration-color: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-opacity, .5)); + text-underline-offset: $icon-link-underline-offset; + backface-visibility: hidden; + + > .bi { + flex-shrink: 0; + width: $icon-link-icon-size; + height: $icon-link-icon-size; + fill: currentcolor; + @include transition($icon-link-icon-transition); + } +} + +.icon-link-hover { + &:hover, + &:focus-visible { + > .bi { + transform: var(--#{$prefix}icon-link-transform, $icon-link-icon-transform); + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_position.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_position.scss new file mode 100644 index 00000000..59103d94 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_position.scss @@ -0,0 +1,36 @@ +// Shorthand + +.fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: $zindex-fixed; +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: $zindex-fixed; +} + +// Responsive sticky top and bottom +@each $breakpoint in map-keys($grid-breakpoints) { + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + .sticky#{$infix}-top { + position: sticky; + top: 0; + z-index: $zindex-sticky; + } + + .sticky#{$infix}-bottom { + position: sticky; + bottom: 0; + z-index: $zindex-sticky; + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_ratio.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_ratio.scss new file mode 100644 index 00000000..b6a7654c --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_ratio.scss @@ -0,0 +1,26 @@ +// Credit: Nicolas Gallagher and SUIT CSS. + +.ratio { + position: relative; + width: 100%; + + &::before { + display: block; + padding-top: var(--#{$prefix}aspect-ratio); + content: ""; + } + + > * { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } +} + +@each $key, $ratio in $aspect-ratios { + .ratio-#{$key} { + --#{$prefix}aspect-ratio: #{$ratio}; + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_stacks.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_stacks.scss new file mode 100644 index 00000000..6cd237ae --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_stacks.scss @@ -0,0 +1,15 @@ +// scss-docs-start stacks +.hstack { + display: flex; + flex-direction: row; + align-items: center; + align-self: stretch; +} + +.vstack { + display: flex; + flex: 1 1 auto; + flex-direction: column; + align-self: stretch; +} +// scss-docs-end stacks diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_stretched-link.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_stretched-link.scss new file mode 100644 index 00000000..71a1c755 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_stretched-link.scss @@ -0,0 +1,15 @@ +// +// Stretched link +// + +.stretched-link { + &::#{$stretched-link-pseudo-element} { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: $stretched-link-z-index; + content: ""; + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_text-truncation.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_text-truncation.scss new file mode 100644 index 00000000..6421dac9 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_text-truncation.scss @@ -0,0 +1,7 @@ +// +// Text truncation +// + +.text-truncate { + @include text-truncate(); +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_visually-hidden.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_visually-hidden.scss new file mode 100644 index 00000000..4760ff03 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_visually-hidden.scss @@ -0,0 +1,8 @@ +// +// Visually hidden +// + +.visually-hidden, +.visually-hidden-focusable:not(:focus):not(:focus-within) { + @include visually-hidden(); +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_vr.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_vr.scss new file mode 100644 index 00000000..b6f9d42c --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_vr.scss @@ -0,0 +1,8 @@ +.vr { + display: inline-block; + align-self: stretch; + width: $vr-border-width; + min-height: 1em; + background-color: currentcolor; + opacity: $hr-opacity; +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_alert.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_alert.scss new file mode 100644 index 00000000..fb524af1 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_alert.scss @@ -0,0 +1,18 @@ +@include deprecate("`alert-variant()`", "v5.3.0", "v6.0.0"); + +// scss-docs-start alert-variant-mixin +@mixin alert-variant($background, $border, $color) { + --#{$prefix}alert-color: #{$color}; + --#{$prefix}alert-bg: #{$background}; + --#{$prefix}alert-border-color: #{$border}; + --#{$prefix}alert-link-color: #{shade-color($color, 20%)}; + + @if $enable-gradients { + background-image: var(--#{$prefix}gradient); + } + + .alert-link { + color: var(--#{$prefix}alert-link-color); + } +} +// scss-docs-end alert-variant-mixin diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_backdrop.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_backdrop.scss new file mode 100644 index 00000000..9705ae9e --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_backdrop.scss @@ -0,0 +1,14 @@ +// Shared between modals and offcanvases +@mixin overlay-backdrop($zindex, $backdrop-bg, $backdrop-opacity) { + position: fixed; + top: 0; + left: 0; + z-index: $zindex; + width: 100vw; + height: 100vh; + background-color: $backdrop-bg; + + // Fade for backdrop + &.fade { opacity: 0; } + &.show { opacity: $backdrop-opacity; } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_banner.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_banner.scss new file mode 100644 index 00000000..20c2fd12 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_banner.scss @@ -0,0 +1,7 @@ +@mixin bsBanner($file) { + /*! + * Bootstrap #{$file} v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_border-radius.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_border-radius.scss new file mode 100644 index 00000000..616decbc --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_border-radius.scss @@ -0,0 +1,78 @@ +// stylelint-disable property-disallowed-list +// Single side border-radius + +// Helper function to replace negative values with 0 +@function valid-radius($radius) { + $return: (); + @each $value in $radius { + @if type-of($value) == number { + $return: append($return, max($value, 0)); + } @else { + $return: append($return, $value); + } + } + @return $return; +} + +// scss-docs-start border-radius-mixins +@mixin border-radius($radius: $border-radius, $fallback-border-radius: false) { + @if $enable-rounded { + border-radius: valid-radius($radius); + } + @else if $fallback-border-radius != false { + border-radius: $fallback-border-radius; + } +} + +@mixin border-top-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-left-radius: valid-radius($radius); + border-top-right-radius: valid-radius($radius); + } +} + +@mixin border-end-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-right-radius: valid-radius($radius); + border-bottom-right-radius: valid-radius($radius); + } +} + +@mixin border-bottom-radius($radius: $border-radius) { + @if $enable-rounded { + border-bottom-right-radius: valid-radius($radius); + border-bottom-left-radius: valid-radius($radius); + } +} + +@mixin border-start-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-left-radius: valid-radius($radius); + border-bottom-left-radius: valid-radius($radius); + } +} + +@mixin border-top-start-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-left-radius: valid-radius($radius); + } +} + +@mixin border-top-end-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-right-radius: valid-radius($radius); + } +} + +@mixin border-bottom-end-radius($radius: $border-radius) { + @if $enable-rounded { + border-bottom-right-radius: valid-radius($radius); + } +} + +@mixin border-bottom-start-radius($radius: $border-radius) { + @if $enable-rounded { + border-bottom-left-radius: valid-radius($radius); + } +} +// scss-docs-end border-radius-mixins diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_box-shadow.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_box-shadow.scss new file mode 100644 index 00000000..4172541f --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_box-shadow.scss @@ -0,0 +1,18 @@ +@mixin box-shadow($shadow...) { + @if $enable-shadows { + $result: (); + + @each $value in $shadow { + @if $value != null { + $result: append($result, $value, "comma"); + } + @if $value == none and length($shadow) > 1 { + @warn "The keyword 'none' must be used as a single argument."; + } + } + + @if (length($result) > 0) { + box-shadow: $result; + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_breakpoints.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_breakpoints.scss new file mode 100644 index 00000000..286be893 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_breakpoints.scss @@ -0,0 +1,127 @@ +// Breakpoint viewport sizes and media queries. +// +// Breakpoints are defined as a map of (name: minimum width), order from small to large: +// +// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px) +// +// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default. + +// Name of the next breakpoint, or null for the last breakpoint. +// +// >> breakpoint-next(sm) +// md +// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// md +// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl xxl)) +// md +@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) { + $n: index($breakpoint-names, $name); + @if not $n { + @error "breakpoint `#{$name}` not found in `#{$breakpoints}`"; + } + @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null); +} + +// Minimum breakpoint width. Null for the smallest (first) breakpoint. +// +// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// 576px +@function breakpoint-min($name, $breakpoints: $grid-breakpoints) { + $min: map-get($breakpoints, $name); + @return if($min != 0, $min, null); +} + +// Maximum breakpoint width. +// The maximum value is reduced by 0.02px to work around the limitations of +// `min-` and `max-` prefixes and viewports with fractional widths. +// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max +// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari. +// See https://bugs.webkit.org/show_bug.cgi?id=178261 +// +// >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// 767.98px +@function breakpoint-max($name, $breakpoints: $grid-breakpoints) { + $max: map-get($breakpoints, $name); + @return if($max and $max > 0, $max - .02, null); +} + +// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front. +// Useful for making responsive utilities. +// +// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// "" (Returns a blank string) +// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// "-sm" +@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) { + @return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}"); +} + +// Media of at least the minimum breakpoint width. No query for the smallest breakpoint. +// Makes the @content apply to the given breakpoint and wider. +@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($name, $breakpoints); + @if $min { + @media (min-width: $min) { + @content; + } + } @else { + @content; + } +} + +// Media of at most the maximum breakpoint width. No query for the largest breakpoint. +// Makes the @content apply to the given breakpoint and narrower. +@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) { + $max: breakpoint-max($name, $breakpoints); + @if $max { + @media (max-width: $max) { + @content; + } + } @else { + @content; + } +} + +// Media that spans multiple breakpoint widths. +// Makes the @content apply between the min and max breakpoints +@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($lower, $breakpoints); + $max: breakpoint-max($upper, $breakpoints); + + @if $min != null and $max != null { + @media (min-width: $min) and (max-width: $max) { + @content; + } + } @else if $max == null { + @include media-breakpoint-up($lower, $breakpoints) { + @content; + } + } @else if $min == null { + @include media-breakpoint-down($upper, $breakpoints) { + @content; + } + } +} + +// Media between the breakpoint's minimum and maximum widths. +// No minimum for the smallest breakpoint, and no maximum for the largest one. +// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower. +@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($name, $breakpoints); + $next: breakpoint-next($name, $breakpoints); + $max: breakpoint-max($next, $breakpoints); + + @if $min != null and $max != null { + @media (min-width: $min) and (max-width: $max) { + @content; + } + } @else if $max == null { + @include media-breakpoint-up($name, $breakpoints) { + @content; + } + } @else if $min == null { + @include media-breakpoint-down($next, $breakpoints) { + @content; + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_buttons.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_buttons.scss new file mode 100644 index 00000000..cf087fda --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_buttons.scss @@ -0,0 +1,70 @@ +// Button variants +// +// Easily pump out default styles, as well as :hover, :focus, :active, +// and disabled options for all buttons + +// scss-docs-start btn-variant-mixin +@mixin button-variant( + $background, + $border, + $color: color-contrast($background), + $hover-background: if($color == $color-contrast-light, shade-color($background, $btn-hover-bg-shade-amount), tint-color($background, $btn-hover-bg-tint-amount)), + $hover-border: if($color == $color-contrast-light, shade-color($border, $btn-hover-border-shade-amount), tint-color($border, $btn-hover-border-tint-amount)), + $hover-color: color-contrast($hover-background), + $active-background: if($color == $color-contrast-light, shade-color($background, $btn-active-bg-shade-amount), tint-color($background, $btn-active-bg-tint-amount)), + $active-border: if($color == $color-contrast-light, shade-color($border, $btn-active-border-shade-amount), tint-color($border, $btn-active-border-tint-amount)), + $active-color: color-contrast($active-background), + $disabled-background: $background, + $disabled-border: $border, + $disabled-color: color-contrast($disabled-background) +) { + --#{$prefix}btn-color: #{$color}; + --#{$prefix}btn-bg: #{$background}; + --#{$prefix}btn-border-color: #{$border}; + --#{$prefix}btn-hover-color: #{$hover-color}; + --#{$prefix}btn-hover-bg: #{$hover-background}; + --#{$prefix}btn-hover-border-color: #{$hover-border}; + --#{$prefix}btn-focus-shadow-rgb: #{to-rgb(mix($color, $border, 15%))}; + --#{$prefix}btn-active-color: #{$active-color}; + --#{$prefix}btn-active-bg: #{$active-background}; + --#{$prefix}btn-active-border-color: #{$active-border}; + --#{$prefix}btn-active-shadow: #{$btn-active-box-shadow}; + --#{$prefix}btn-disabled-color: #{$disabled-color}; + --#{$prefix}btn-disabled-bg: #{$disabled-background}; + --#{$prefix}btn-disabled-border-color: #{$disabled-border}; +} +// scss-docs-end btn-variant-mixin + +// scss-docs-start btn-outline-variant-mixin +@mixin button-outline-variant( + $color, + $color-hover: color-contrast($color), + $active-background: $color, + $active-border: $color, + $active-color: color-contrast($active-background) +) { + --#{$prefix}btn-color: #{$color}; + --#{$prefix}btn-border-color: #{$color}; + --#{$prefix}btn-hover-color: #{$color-hover}; + --#{$prefix}btn-hover-bg: #{$active-background}; + --#{$prefix}btn-hover-border-color: #{$active-border}; + --#{$prefix}btn-focus-shadow-rgb: #{to-rgb($color)}; + --#{$prefix}btn-active-color: #{$active-color}; + --#{$prefix}btn-active-bg: #{$active-background}; + --#{$prefix}btn-active-border-color: #{$active-border}; + --#{$prefix}btn-active-shadow: #{$btn-active-box-shadow}; + --#{$prefix}btn-disabled-color: #{$color}; + --#{$prefix}btn-disabled-bg: transparent; + --#{$prefix}btn-disabled-border-color: #{$color}; + --#{$prefix}gradient: none; +} +// scss-docs-end btn-outline-variant-mixin + +// scss-docs-start btn-size-mixin +@mixin button-size($padding-y, $padding-x, $font-size, $border-radius) { + --#{$prefix}btn-padding-y: #{$padding-y}; + --#{$prefix}btn-padding-x: #{$padding-x}; + @include rfs($font-size, --#{$prefix}btn-font-size); + --#{$prefix}btn-border-radius: #{$border-radius}; +} +// scss-docs-end btn-size-mixin diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_caret.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_caret.scss new file mode 100644 index 00000000..be731165 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_caret.scss @@ -0,0 +1,69 @@ +// scss-docs-start caret-mixins +@mixin caret-down($width: $caret-width) { + border-top: $width solid; + border-right: $width solid transparent; + border-bottom: 0; + border-left: $width solid transparent; +} + +@mixin caret-up($width: $caret-width) { + border-top: 0; + border-right: $width solid transparent; + border-bottom: $width solid; + border-left: $width solid transparent; +} + +@mixin caret-end($width: $caret-width) { + border-top: $width solid transparent; + border-right: 0; + border-bottom: $width solid transparent; + border-left: $width solid; +} + +@mixin caret-start($width: $caret-width) { + border-top: $width solid transparent; + border-right: $width solid; + border-bottom: $width solid transparent; +} + +@mixin caret( + $direction: down, + $width: $caret-width, + $spacing: $caret-spacing, + $vertical-align: $caret-vertical-align +) { + @if $enable-caret { + &::after { + display: inline-block; + margin-left: $spacing; + vertical-align: $vertical-align; + content: ""; + @if $direction == down { + @include caret-down($width); + } @else if $direction == up { + @include caret-up($width); + } @else if $direction == end { + @include caret-end($width); + } + } + + @if $direction == start { + &::after { + display: none; + } + + &::before { + display: inline-block; + margin-right: $spacing; + vertical-align: $vertical-align; + content: ""; + @include caret-start($width); + } + } + + &:empty::after { + margin-left: 0; + } + } +} +// scss-docs-end caret-mixins diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_clearfix.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_clearfix.scss new file mode 100644 index 00000000..ffc62bb2 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_clearfix.scss @@ -0,0 +1,9 @@ +// scss-docs-start clearfix +@mixin clearfix() { + &::after { + display: block; + clear: both; + content: ""; + } +} +// scss-docs-end clearfix diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_color-mode.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_color-mode.scss new file mode 100644 index 00000000..03338b02 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_color-mode.scss @@ -0,0 +1,21 @@ +// scss-docs-start color-mode-mixin +@mixin color-mode($mode: light, $root: false) { + @if $color-mode-type == "media-query" { + @if $root == true { + @media (prefers-color-scheme: $mode) { + :root { + @content; + } + } + } @else { + @media (prefers-color-scheme: $mode) { + @content; + } + } + } @else { + [data-bs-theme="#{$mode}"] { + @content; + } + } +} +// scss-docs-end color-mode-mixin diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_color-scheme.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_color-scheme.scss new file mode 100644 index 00000000..90497aa0 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_color-scheme.scss @@ -0,0 +1,7 @@ +// scss-docs-start mixin-color-scheme +@mixin color-scheme($name) { + @media (prefers-color-scheme: #{$name}) { + @content; + } +} +// scss-docs-end mixin-color-scheme diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_container.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_container.scss new file mode 100644 index 00000000..b9f33519 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_container.scss @@ -0,0 +1,11 @@ +// Container mixins + +@mixin make-container($gutter: $container-padding-x) { + --#{$prefix}gutter-x: #{$gutter}; + --#{$prefix}gutter-y: 0; + width: 100%; + padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list + padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list + margin-right: auto; + margin-left: auto; +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_deprecate.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_deprecate.scss new file mode 100644 index 00000000..df070bc5 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_deprecate.scss @@ -0,0 +1,10 @@ +// Deprecate mixin +// +// This mixin can be used to deprecate mixins or functions. +// `$enable-deprecation-messages` is a global variable, `$ignore-warning` is a variable that can be passed to +// some deprecated mixins to suppress the warning (for example if the mixin is still be used in the current version of Bootstrap) +@mixin deprecate($name, $deprecate-version, $remove-version, $ignore-warning: false) { + @if ($enable-deprecation-messages != false and $ignore-warning != true) { + @warn "#{$name} has been deprecated as of #{$deprecate-version}. It will be removed entirely in #{$remove-version}."; + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_forms.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_forms.scss new file mode 100644 index 00000000..00b47641 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_forms.scss @@ -0,0 +1,163 @@ +// This mixin uses an `if()` technique to be compatible with Dart Sass +// See https://github.com/sass/sass/issues/1873#issuecomment-152293725 for more details + +// scss-docs-start form-validation-mixins +@mixin form-validation-state-selector($state) { + @if ($state == "valid" or $state == "invalid") { + .was-validated #{if(&, "&", "")}:#{$state}, + #{if(&, "&", "")}.is-#{$state} { + @content; + } + } @else { + #{if(&, "&", "")}.is-#{$state} { + @content; + } + } +} + +@mixin form-validation-state( + $state, + $color, + $icon, + $tooltip-color: color-contrast($color), + $tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity), + $focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity), + $border-color: $color +) { + .#{$state}-feedback { + display: none; + width: 100%; + margin-top: $form-feedback-margin-top; + @include font-size($form-feedback-font-size); + font-style: $form-feedback-font-style; + color: $color; + } + + .#{$state}-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; // Contain to parent when possible + padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x; + margin-top: .1rem; + @include font-size($form-feedback-tooltip-font-size); + line-height: $form-feedback-tooltip-line-height; + color: $tooltip-color; + background-color: $tooltip-bg-color; + @include border-radius($form-feedback-tooltip-border-radius); + } + + @include form-validation-state-selector($state) { + ~ .#{$state}-feedback, + ~ .#{$state}-tooltip { + display: block; + } + } + + .form-control { + @include form-validation-state-selector($state) { + border-color: $border-color; + + @if $enable-validation-icons { + padding-right: $input-height-inner; + background-image: escape-svg($icon); + background-repeat: no-repeat; + background-position: right $input-height-inner-quarter center; + background-size: $input-height-inner-half $input-height-inner-half; + } + + &:focus { + border-color: $border-color; + @if $enable-shadows { + @include box-shadow($input-box-shadow, $focus-box-shadow); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: $focus-box-shadow; + } + } + } + } + + // stylelint-disable-next-line selector-no-qualifying-type + textarea.form-control { + @include form-validation-state-selector($state) { + @if $enable-validation-icons { + padding-right: $input-height-inner; + background-position: top $input-height-inner-quarter right $input-height-inner-quarter; + } + } + } + + .form-select { + @include form-validation-state-selector($state) { + border-color: $border-color; + + @if $enable-validation-icons { + &:not([multiple]):not([size]), + &:not([multiple])[size="1"] { + --#{$prefix}form-select-bg-icon: #{escape-svg($icon)}; + padding-right: $form-select-feedback-icon-padding-end; + background-position: $form-select-bg-position, $form-select-feedback-icon-position; + background-size: $form-select-bg-size, $form-select-feedback-icon-size; + } + } + + &:focus { + border-color: $border-color; + @if $enable-shadows { + @include box-shadow($form-select-box-shadow, $focus-box-shadow); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: $focus-box-shadow; + } + } + } + } + + .form-control-color { + @include form-validation-state-selector($state) { + @if $enable-validation-icons { + width: add($form-color-width, $input-height-inner); + } + } + } + + .form-check-input { + @include form-validation-state-selector($state) { + border-color: $border-color; + + &:checked { + background-color: $color; + } + + &:focus { + box-shadow: $focus-box-shadow; + } + + ~ .form-check-label { + color: $color; + } + } + } + .form-check-inline .form-check-input { + ~ .#{$state}-feedback { + margin-left: .5em; + } + } + + .input-group { + > .form-control:not(:focus), + > .form-select:not(:focus), + > .form-floating:not(:focus-within) { + @include form-validation-state-selector($state) { + @if $state == "valid" { + z-index: 3; + } @else if $state == "invalid" { + z-index: 4; + } + } + } + } +} +// scss-docs-end form-validation-mixins diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_gradients.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_gradients.scss new file mode 100644 index 00000000..608e18df --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_gradients.scss @@ -0,0 +1,47 @@ +// Gradients + +// scss-docs-start gradient-bg-mixin +@mixin gradient-bg($color: null) { + background-color: $color; + + @if $enable-gradients { + background-image: var(--#{$prefix}gradient); + } +} +// scss-docs-end gradient-bg-mixin + +// scss-docs-start gradient-mixins +// Horizontal gradient, from left to right +// +// Creates two color stops, start and end, by specifying a color and position for each color stop. +@mixin gradient-x($start-color: $gray-700, $end-color: $gray-800, $start-percent: 0%, $end-percent: 100%) { + background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent); +} + +// Vertical gradient, from top to bottom +// +// Creates two color stops, start and end, by specifying a color and position for each color stop. +@mixin gradient-y($start-color: $gray-700, $end-color: $gray-800, $start-percent: null, $end-percent: null) { + background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent); +} + +@mixin gradient-directional($start-color: $gray-700, $end-color: $gray-800, $deg: 45deg) { + background-image: linear-gradient($deg, $start-color, $end-color); +} + +@mixin gradient-x-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) { + background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color); +} + +@mixin gradient-y-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) { + background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color); +} + +@mixin gradient-radial($inner-color: $gray-700, $outer-color: $gray-800) { + background-image: radial-gradient(circle, $inner-color, $outer-color); +} + +@mixin gradient-striped($color: rgba($white, .15), $angle: 45deg) { + background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent); +} +// scss-docs-end gradient-mixins diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_grid.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_grid.scss new file mode 100644 index 00000000..ea307399 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_grid.scss @@ -0,0 +1,151 @@ +// Grid system +// +// Generate semantic grid columns with these mixins. + +@mixin make-row($gutter: $grid-gutter-width) { + --#{$prefix}gutter-x: #{$gutter}; + --#{$prefix}gutter-y: 0; + display: flex; + flex-wrap: wrap; + // TODO: Revisit calc order after https://github.com/react-bootstrap/react-bootstrap/issues/6039 is fixed + margin-top: calc(-1 * var(--#{$prefix}gutter-y)); // stylelint-disable-line function-disallowed-list + margin-right: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list + margin-left: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list +} + +@mixin make-col-ready() { + // Add box sizing if only the grid is loaded + box-sizing: if(variable-exists(include-column-box-sizing) and $include-column-box-sizing, border-box, null); + // Prevent columns from becoming too narrow when at smaller grid tiers by + // always setting `width: 100%;`. This works because we set the width + // later on to override this initial width. + flex-shrink: 0; + width: 100%; + max-width: 100%; // Prevent `.col-auto`, `.col` (& responsive variants) from breaking out the grid + padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list + padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list + margin-top: var(--#{$prefix}gutter-y); +} + +@mixin make-col($size: false, $columns: $grid-columns) { + @if $size { + flex: 0 0 auto; + width: percentage(divide($size, $columns)); + + } @else { + flex: 1 1 0; + max-width: 100%; + } +} + +@mixin make-col-auto() { + flex: 0 0 auto; + width: auto; +} + +@mixin make-col-offset($size, $columns: $grid-columns) { + $num: divide($size, $columns); + margin-left: if($num == 0, 0, percentage($num)); +} + +// Row columns +// +// Specify on a parent element(e.g., .row) to force immediate children into NN +// number of columns. Supports wrapping to new lines, but does not do a Masonry +// style grid. +@mixin row-cols($count) { + > * { + flex: 0 0 auto; + width: percentage(divide(1, $count)); + } +} + +// Framework grid generation +// +// Used only by Bootstrap to generate the correct number of grid classes given +// any value of `$grid-columns`. + +@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) { + @each $breakpoint in map-keys($breakpoints) { + $infix: breakpoint-infix($breakpoint, $breakpoints); + + @include media-breakpoint-up($breakpoint, $breakpoints) { + // Provide basic `.col-{bp}` classes for equal-width flexbox columns + .col#{$infix} { + flex: 1 0 0%; // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4 + } + + .row-cols#{$infix}-auto > * { + @include make-col-auto(); + } + + @if $grid-row-columns > 0 { + @for $i from 1 through $grid-row-columns { + .row-cols#{$infix}-#{$i} { + @include row-cols($i); + } + } + } + + .col#{$infix}-auto { + @include make-col-auto(); + } + + @if $columns > 0 { + @for $i from 1 through $columns { + .col#{$infix}-#{$i} { + @include make-col($i, $columns); + } + } + + // `$columns - 1` because offsetting by the width of an entire row isn't possible + @for $i from 0 through ($columns - 1) { + @if not ($infix == "" and $i == 0) { // Avoid emitting useless .offset-0 + .offset#{$infix}-#{$i} { + @include make-col-offset($i, $columns); + } + } + } + } + + // Gutters + // + // Make use of `.g-*`, `.gx-*` or `.gy-*` utilities to change spacing between the columns. + @each $key, $value in $gutters { + .g#{$infix}-#{$key}, + .gx#{$infix}-#{$key} { + --#{$prefix}gutter-x: #{$value}; + } + + .g#{$infix}-#{$key}, + .gy#{$infix}-#{$key} { + --#{$prefix}gutter-y: #{$value}; + } + } + } + } +} + +@mixin make-cssgrid($columns: $grid-columns, $breakpoints: $grid-breakpoints) { + @each $breakpoint in map-keys($breakpoints) { + $infix: breakpoint-infix($breakpoint, $breakpoints); + + @include media-breakpoint-up($breakpoint, $breakpoints) { + @if $columns > 0 { + @for $i from 1 through $columns { + .g-col#{$infix}-#{$i} { + grid-column: auto / span $i; + } + } + + // Start with `1` because `0` is an invalid value. + // Ends with `$columns - 1` because offsetting by the width of an entire row isn't possible. + @for $i from 1 through ($columns - 1) { + .g-start#{$infix}-#{$i} { + grid-column-start: $i; + } + } + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_image.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_image.scss new file mode 100644 index 00000000..e1df779f --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_image.scss @@ -0,0 +1,16 @@ +// Image Mixins +// - Responsive image +// - Retina image + + +// Responsive image +// +// Keep images from scaling beyond the width of their parents. + +@mixin img-fluid { + // Part 1: Set a maximum relative to the parent + max-width: 100%; + // Part 2: Override the height to auto, otherwise images will be stretched + // when setting a width and height attribute on the img element. + height: auto; +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_list-group.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_list-group.scss new file mode 100644 index 00000000..6274f343 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_list-group.scss @@ -0,0 +1,26 @@ +@include deprecate("`list-group-item-variant()`", "v5.3.0", "v6.0.0"); + +// List Groups + +// scss-docs-start list-group-mixin +@mixin list-group-item-variant($state, $background, $color) { + .list-group-item-#{$state} { + color: $color; + background-color: $background; + + &.list-group-item-action { + &:hover, + &:focus { + color: $color; + background-color: shade-color($background, 10%); + } + + &.active { + color: $white; + background-color: $color; + border-color: $color; + } + } + } +} +// scss-docs-end list-group-mixin diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_lists.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_lists.scss new file mode 100644 index 00000000..25185626 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_lists.scss @@ -0,0 +1,7 @@ +// Lists + +// Unstyled keeps list items block level, just removes default browser padding and list-style +@mixin list-unstyled { + padding-left: 0; + list-style: none; +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_pagination.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_pagination.scss new file mode 100644 index 00000000..0d657964 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_pagination.scss @@ -0,0 +1,10 @@ +// Pagination + +// scss-docs-start pagination-mixin +@mixin pagination-size($padding-y, $padding-x, $font-size, $border-radius) { + --#{$prefix}pagination-padding-x: #{$padding-x}; + --#{$prefix}pagination-padding-y: #{$padding-y}; + @include rfs($font-size, --#{$prefix}pagination-font-size); + --#{$prefix}pagination-border-radius: #{$border-radius}; +} +// scss-docs-end pagination-mixin diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_reset-text.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_reset-text.scss new file mode 100644 index 00000000..f5bd1afe --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_reset-text.scss @@ -0,0 +1,17 @@ +@mixin reset-text { + font-family: $font-family-base; + // We deliberately do NOT reset font-size or overflow-wrap / word-wrap. + font-style: normal; + font-weight: $font-weight-normal; + line-height: $line-height-base; + text-align: left; // Fallback for where `start` is not supported + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + white-space: normal; + word-spacing: normal; + line-break: auto; +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_resize.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_resize.scss new file mode 100644 index 00000000..66f233a6 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_resize.scss @@ -0,0 +1,6 @@ +// Resize anything + +@mixin resizable($direction) { + overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible` + resize: $direction; // Options: horizontal, vertical, both +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_table-variants.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_table-variants.scss new file mode 100644 index 00000000..5fe1b9b2 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_table-variants.scss @@ -0,0 +1,24 @@ +// scss-docs-start table-variant +@mixin table-variant($state, $background) { + .table-#{$state} { + $color: color-contrast(opaque($body-bg, $background)); + $hover-bg: mix($color, $background, percentage($table-hover-bg-factor)); + $striped-bg: mix($color, $background, percentage($table-striped-bg-factor)); + $active-bg: mix($color, $background, percentage($table-active-bg-factor)); + $table-border-color: mix($color, $background, percentage($table-border-factor)); + + --#{$prefix}table-color: #{$color}; + --#{$prefix}table-bg: #{$background}; + --#{$prefix}table-border-color: #{$table-border-color}; + --#{$prefix}table-striped-bg: #{$striped-bg}; + --#{$prefix}table-striped-color: #{color-contrast($striped-bg)}; + --#{$prefix}table-active-bg: #{$active-bg}; + --#{$prefix}table-active-color: #{color-contrast($active-bg)}; + --#{$prefix}table-hover-bg: #{$hover-bg}; + --#{$prefix}table-hover-color: #{color-contrast($hover-bg)}; + + color: var(--#{$prefix}table-color); + border-color: var(--#{$prefix}table-border-color); + } +} +// scss-docs-end table-variant diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_text-truncate.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_text-truncate.scss new file mode 100644 index 00000000..3504bb1a --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_text-truncate.scss @@ -0,0 +1,8 @@ +// Text truncate +// Requires inline-block or block for proper styling + +@mixin text-truncate() { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_transition.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_transition.scss new file mode 100644 index 00000000..d437f6d8 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_transition.scss @@ -0,0 +1,26 @@ +// stylelint-disable property-disallowed-list +@mixin transition($transition...) { + @if length($transition) == 0 { + $transition: $transition-base; + } + + @if length($transition) > 1 { + @each $value in $transition { + @if $value == null or $value == none { + @warn "The keyword 'none' or 'null' must be used as a single argument."; + } + } + } + + @if $enable-transitions { + @if nth($transition, 1) != null { + transition: $transition; + } + + @if $enable-reduced-motion and nth($transition, 1) != null and nth($transition, 1) != none { + @media (prefers-reduced-motion: reduce) { + transition: none; + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_utilities.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_utilities.scss new file mode 100644 index 00000000..4795e894 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_utilities.scss @@ -0,0 +1,97 @@ +// Utility generator +// Used to generate utilities & print utilities +@mixin generate-utility($utility, $infix: "", $is-rfs-media-query: false) { + $values: map-get($utility, values); + + // If the values are a list or string, convert it into a map + @if type-of($values) == "string" or type-of(nth($values, 1)) != "list" { + $values: zip($values, $values); + } + + @each $key, $value in $values { + $properties: map-get($utility, property); + + // Multiple properties are possible, for example with vertical or horizontal margins or paddings + @if type-of($properties) == "string" { + $properties: append((), $properties); + } + + // Use custom class if present + $property-class: if(map-has-key($utility, class), map-get($utility, class), nth($properties, 1)); + $property-class: if($property-class == null, "", $property-class); + + // Use custom CSS variable name if present, otherwise default to `class` + $css-variable-name: if(map-has-key($utility, css-variable-name), map-get($utility, css-variable-name), map-get($utility, class)); + + // State params to generate pseudo-classes + $state: if(map-has-key($utility, state), map-get($utility, state), ()); + + $infix: if($property-class == "" and str-slice($infix, 1, 1) == "-", str-slice($infix, 2), $infix); + + // Don't prefix if value key is null (e.g. with shadow class) + $property-class-modifier: if($key, if($property-class == "" and $infix == "", "", "-") + $key, ""); + + @if map-get($utility, rfs) { + // Inside the media query + @if $is-rfs-media-query { + $val: rfs-value($value); + + // Do not render anything if fluid and non fluid values are the same + $value: if($val == rfs-fluid-value($value), null, $val); + } + @else { + $value: rfs-fluid-value($value); + } + } + + $is-css-var: map-get($utility, css-var); + $is-local-vars: map-get($utility, local-vars); + $is-rtl: map-get($utility, rtl); + + @if $value != null { + @if $is-rtl == false { + /* rtl:begin:remove */ + } + + @if $is-css-var { + .#{$property-class + $infix + $property-class-modifier} { + --#{$prefix}#{$css-variable-name}: #{$value}; + } + + @each $pseudo in $state { + .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} { + --#{$prefix}#{$css-variable-name}: #{$value}; + } + } + } @else { + .#{$property-class + $infix + $property-class-modifier} { + @each $property in $properties { + @if $is-local-vars { + @each $local-var, $variable in $is-local-vars { + --#{$prefix}#{$local-var}: #{$variable}; + } + } + #{$property}: $value if($enable-important-utilities, !important, null); + } + } + + @each $pseudo in $state { + .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} { + @each $property in $properties { + @if $is-local-vars { + @each $local-var, $variable in $is-local-vars { + --#{$prefix}#{$local-var}: #{$variable}; + } + } + #{$property}: $value if($enable-important-utilities, !important, null); + } + } + } + } + + @if $is-rtl == false { + /* rtl:end:remove */ + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_visually-hidden.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_visually-hidden.scss new file mode 100644 index 00000000..082aeec9 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_visually-hidden.scss @@ -0,0 +1,33 @@ +// stylelint-disable declaration-no-important + +// Hide content visually while keeping it accessible to assistive technologies +// +// See: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/ +// See: https://kittygiraudel.com/2016/10/13/css-hide-and-seek/ + +@mixin visually-hidden() { + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; // Fix for https://github.com/twbs/bootstrap/issues/25686 + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; + + // Fix for positioned table caption that could become anonymous cells + &:not(caption) { + position: absolute !important; + } +} + +// Use to only display content when it's focused, or one of its child elements is focused +// (i.e. when focus is within the element/container that the class was applied to) +// +// Useful for "Skip to main content" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 + +@mixin visually-hidden-focusable() { + &:not(:focus):not(:focus-within) { + @include visually-hidden(); + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/jasmine.js b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/jasmine.js new file mode 100644 index 00000000..25d838c9 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/jasmine.js @@ -0,0 +1,16 @@ +/* eslint-disable camelcase */ + +'use strict' + +const path = require('node:path') + +module.exports = { + spec_dir: 'scss', + // Make Jasmine look for `.test.scss` files + spec_files: ['**/*.{test,spec}.scss'], + // Compile them into JS scripts running `sass-true` + requires: [path.join(__dirname, 'sass-true/register')], + // Ensure we use `require` so that the require.extensions works + // as `import` completely bypasses it + jsLoader: 'require' +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_auto-import-of-variables-dark.test.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_auto-import-of-variables-dark.test.scss new file mode 100644 index 00000000..f08ae587 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_auto-import-of-variables-dark.test.scss @@ -0,0 +1,7 @@ +// TODO: this file can be removed safely in v6 when `@import "variables-dark"` will be removed at the end of _variables.scss + +@import "../../functions"; +@import "../../variables"; +// Voluntarily not importing _variables-dark.scss +@import "../../maps"; +@import "../../mixins"; diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_color-modes.test.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_color-modes.test.scss new file mode 100644 index 00000000..9ecc628d --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_color-modes.test.scss @@ -0,0 +1,69 @@ +// stylelint-disable selector-attribute-quotes + +@import "../../functions"; +@import "../../variables"; +@import "../../variables-dark"; +@import "../../maps"; +@import "../../mixins"; + +@include describe("global $color-mode-type: data") { + @include it("generates data attribute selectors for dark mode") { + @include assert() { + @include output() { + @include color-mode(dark) { + .element { + color: var(--bs-primary-text-emphasis); + background-color: var(--bs-primary-bg-subtle); + } + } + @include color-mode(dark, true) { + --custom-color: #{mix($indigo, $blue, 50%)}; + } + } + @include expect() { + [data-bs-theme=dark] .element { + color: var(--bs-primary-text-emphasis); + background-color: var(--bs-primary-bg-subtle); + } + [data-bs-theme=dark] { + --custom-color: #3a3ff8; + } + } + } + } +} + +@include describe("global $color-mode-type: media-query") { + @include it("generates media queries for dark mode") { + $color-mode-type: media-query !global; + + @include assert() { + @include output() { + @include color-mode(dark) { + .element { + color: var(--bs-primary-text-emphasis); + background-color: var(--bs-primary-bg-subtle); + } + } + @include color-mode(dark, true) { + --custom-color: #{mix($indigo, $blue, 50%)}; + } + } + @include expect() { + @media (prefers-color-scheme: dark) { + .element { + color: var(--bs-primary-text-emphasis); + background-color: var(--bs-primary-bg-subtle); + } + } + @media (prefers-color-scheme: dark) { + :root { + --custom-color: #3a3ff8; + } + } + } + } + + $color-mode-type: data !global; + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_media-query-color-mode-full.test.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_media-query-color-mode-full.test.scss new file mode 100644 index 00000000..00ed82d6 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_media-query-color-mode-full.test.scss @@ -0,0 +1,8 @@ +$color-mode-type: media-query; + +@import "../../bootstrap"; + +@include describe("global $color-mode-type: media-query") { + @include it("compiles entirely Bootstrap CSS with media-query color mode") { // stylelint-disable-line block-no-empty + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_utilities.test.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_utilities.test.scss new file mode 100644 index 00000000..8140ac47 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_utilities.test.scss @@ -0,0 +1,393 @@ +$prefix: bs-; +$enable-important-utilities: false; + +// Important: Do not import rfs to check that the mixin just calls the appropriate functions from it +@import "../../mixins/utilities"; + +@mixin test-generate-utility($params...) { + @include assert() { + @include output() { + @include generate-utility($params...); + } + + @include expect() { + @content; + } + } +} + +@include describe(generate-utility) { + @include it("generates a utility class for each value") { + @include test-generate-utility( + ( + property: "padding", + values: (small: .5rem, large: 2rem) + ) + ) { + .padding-small { + padding: .5rem; + } + + .padding-large { + padding: 2rem; + } + } + } + + @include describe("global $enable-important-utilities: true") { + @include it("sets !important") { + $enable-important-utilities: true !global; + + @include test-generate-utility( + ( + property: "padding", + values: (small: .5rem, large: 2rem) + ) + ) { + .padding-small { + padding: .5rem !important; + } + + .padding-large { + padding: 2rem !important; + } + } + + $enable-important-utilities: false !global; + } + } + + @include describe("$utility") { + @include describe("values") { + @include it("supports null keys") { + @include test-generate-utility( + ( + property: "padding", + values: (null: 1rem, small: .5rem, large: 2rem) + ), + ) { + .padding { + padding: 1rem; + } + + .padding-small { + padding: .5rem; + } + + .padding-large { + padding: 2rem; + } + } + } + + @include it("ignores null values") { + @include test-generate-utility( + ( + property: "padding", + values: (small: null, large: 2rem) + ) + ) { + .padding-large { + padding: 2rem; + } + } + } + + @include it("supports lists") { + @include test-generate-utility( + ( + property: "padding", + values: 1rem 2rem + ) + ) { + .padding-1rem { + padding: 1rem; + } + + .padding-2rem { + padding: 2rem; + } + } + } + + @include it("supports single values") { + @include test-generate-utility( + ( + property: padding, + values: 1rem + ) + ) { + .padding-1rem { + padding: 1rem; + } + } + } + } + + @include describe("class & property") { + @include it("adds each property to the declaration") { + @include test-generate-utility( + ( + class: padding-x, + property: padding-inline-start padding-inline-end, + values: 1rem + ) + ) { + .padding-x-1rem { + padding-inline-start: 1rem; + padding-inline-end: 1rem; + } + } + } + + @include it("uses the first property as class name") { + @include test-generate-utility( + ( + property: padding-inline-start padding-inline-end, + values: 1rem + ) + ) { + .padding-inline-start-1rem { + padding-inline-start: 1rem; + padding-inline-end: 1rem; + } + } + } + + @include it("supports a null class to create classes straight from the values") { + @include test-generate-utility( + ( + property: visibility, + class: null, + values: ( + visible: visible, + invisible: hidden, + ) + ) + ) { + .visible { + visibility: visible; + } + + .invisible { + visibility: hidden; + } + } + } + } + + @include describe("state") { + @include it("Generates selectors for each states") { + @include test-generate-utility( + ( + property: padding, + values: 1rem, + state: hover focus, + ) + ) { + .padding-1rem { + padding: 1rem; + } + + .padding-1rem-hover:hover { + padding: 1rem; + } + + .padding-1rem-focus:focus { + padding: 1rem; + } + } + } + } + + @include describe("css-var"){ + @include it("sets a CSS variable instead of the property") { + @include test-generate-utility( + ( + property: padding, + css-variable-name: padding, + css-var: true, + values: 1rem 2rem + ) + ) { + .padding-1rem { + --bs-padding: 1rem; + } + + .padding-2rem { + --bs-padding: 2rem; + } + } + } + + @include it("defaults to class") { + @include test-generate-utility( + ( + property: padding, + class: padding, + css-var: true, + values: 1rem 2rem + ) + ) { + .padding-1rem { + --bs-padding: 1rem; + } + + .padding-2rem { + --bs-padding: 2rem; + } + } + } + } + + @include describe("local-vars") { + @include it("generates the listed variables") { + @include test-generate-utility( + ( + property: color, + class: desaturated-color, + local-vars: ( + color-opacity: 1, + color-saturation: .25 + ), + values: ( + blue: hsla(192deg, var(--bs-color-saturation), 0, var(--bs-color-opacity)) + ) + ) + ) { + .desaturated-color-blue { + --bs-color-opacity: 1; + // Sass compilation will put a leading zero so we want to keep that one + // stylelint-disable-next-line @stylistic/number-leading-zero + --bs-color-saturation: 0.25; + color: hsla(192deg, var(--bs-color-saturation), 0, var(--bs-color-opacity)); + } + } + } + } + + @include describe("css-var & state") { + @include it("Generates a rule with for each state with a CSS variable") { + @include test-generate-utility( + ( + property: padding, + css-var: true, + css-variable-name: padding, + values: 1rem, + state: hover focus, + ) + ) { + .padding-1rem { + --bs-padding: 1rem; + } + + .padding-1rem-hover:hover { + --bs-padding: 1rem; + } + + .padding-1rem-focus:focus { + --bs-padding: 1rem; + } + } + } + } + + @include describe("rtl") { + @include it("sets up RTLCSS for removal when false") { + @include test-generate-utility( + ( + property: padding, + values: 1rem, + rtl: false + ) + ) { + /* rtl:begin:remove */ + + .padding-1rem { + padding: 1rem; + } + + /* rtl:end:remove */ + + } + } + } + + @include describe("rfs") { + @include it("sets the fluid value when not inside media query") { + @include test-generate-utility( + ( + property: padding, + values: 1rem, + rfs: true + ) + ) { + .padding-1rem { + padding: rfs-fluid-value(1rem); + } + } + } + + @include it("sets the value when inside the media query") { + @include test-generate-utility( + ( + property: padding, + values: 1rem, + rfs: true + ), + $is-rfs-media-query: true + ) { + .padding-1rem { + padding: rfs-value(1rem); + } + } + } + } + } + + @include describe("$infix") { + @include it("inserts the given infix") { + @include test-generate-utility( + ( + property: "padding", + values: (null: 1rem, small: .5rem, large: 2rem) + ), + $infix: -sm + ) { + .padding-sm { + padding: 1rem; + } + + .padding-sm-small { + padding: .5rem; + } + + .padding-sm-large { + padding: 2rem; + } + } + } + + @include it("strips leading - if class is null") { + @include test-generate-utility( + ( + property: visibility, + class: null, + values: ( + visible: visible, + invisible: hidden, + ) + ), + -sm + ) { + .sm-visible { + visibility: visible; + } + + .sm-invisible { + visibility: hidden; + } + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/sass-true/register.js b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/sass-true/register.js new file mode 100644 index 00000000..d93e414c --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/sass-true/register.js @@ -0,0 +1,14 @@ +'use strict' + +const path = require('node:path') + +const runnerPath = path.join(__dirname, 'runner').replace(/\\/g, '/') + +require.extensions['.scss'] = (module, filename) => { + const normalizedFilename = filename.replace(/\\/g, '/') + + return module._compile(` + const runner = require('${runnerPath}') + runner('${normalizedFilename}', { describe, it }) + `, filename) +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/sass-true/runner.js b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/sass-true/runner.js new file mode 100644 index 00000000..bef870ac --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/sass-true/runner.js @@ -0,0 +1,17 @@ +'use strict' + +const fs = require('node:fs') +const path = require('node:path') +const { runSass } = require('sass-true') + +module.exports = (filename, { describe, it }) => { + const data = fs.readFileSync(filename, 'utf8') + const TRUE_SETUP = '$true-terminal-output: false; @import "true";' + const sassString = TRUE_SETUP + data + + runSass( + { describe, it, sourceType: 'string' }, + sassString, + { loadPaths: [path.dirname(filename)] } + ) +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/utilities/_api.test.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/utilities/_api.test.scss new file mode 100644 index 00000000..304d8d1c --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/utilities/_api.test.scss @@ -0,0 +1,75 @@ +@import "../../functions"; +@import "../../variables"; +@import "../../variables-dark"; +@import "../../maps"; +@import "../../mixins"; + +$utilities: (); + +@include describe("utilities/api") { + @include it("generates utilities for each breakpoints") { + $utilities: ( + margin: ( + property: margin, + values: auto + ), + padding: ( + property: padding, + responsive: true, + values: 1rem + ), + font-size: ( + property: font-size, + values: (large: 1.25rem), + print: true + ) + ) !global; + + $grid-breakpoints: ( + xs: 0, + sm: 333px, + md: 666px + ) !global; + + @include assert() { + @include output() { + @import "../../utilities/api"; + } + + @include expect() { + // margin is not set to responsive + .margin-auto { + margin: auto !important; + } + + // padding is, though + .padding-1rem { + padding: 1rem !important; + } + + .font-size-large { + font-size: 1.25rem !important; + } + + @media (min-width: 333px) { + .padding-sm-1rem { + padding: 1rem !important; + } + } + + @media (min-width: 666px) { + .padding-md-1rem { + padding: 1rem !important; + } + } + + @media print { + .font-size-print-large { + font-size: 1.25rem !important; + } + } + } + + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/utilities/_api.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/utilities/_api.scss new file mode 100644 index 00000000..62e1d398 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/utilities/_api.scss @@ -0,0 +1,47 @@ +// Loop over each breakpoint +@each $breakpoint in map-keys($grid-breakpoints) { + + // Generate media query if needed + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + // Loop over each utility property + @each $key, $utility in $utilities { + // The utility can be disabled with `false`, thus check if the utility is a map first + // Only proceed if responsive media queries are enabled or if it's the base media query + @if type-of($utility) == "map" and (map-get($utility, responsive) or $infix == "") { + @include generate-utility($utility, $infix); + } + } + } +} + +// RFS rescaling +@media (min-width: $rfs-mq-value) { + @each $breakpoint in map-keys($grid-breakpoints) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + @if (map-get($grid-breakpoints, $breakpoint) < $rfs-breakpoint) { + // Loop over each utility property + @each $key, $utility in $utilities { + // The utility can be disabled with `false`, thus check if the utility is a map first + // Only proceed if responsive media queries are enabled or if it's the base media query + @if type-of($utility) == "map" and map-get($utility, rfs) and (map-get($utility, responsive) or $infix == "") { + @include generate-utility($utility, $infix, true); + } + } + } + } +} + + +// Print utilities +@media print { + @each $key, $utility in $utilities { + // The utility can be disabled with `false`, thus check if the utility is a map first + // Then check if the utility needs print styles + @if type-of($utility) == "map" and map-get($utility, print) == true { + @include generate-utility($utility, "-print"); + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/vendor/_rfs.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/vendor/_rfs.scss new file mode 100644 index 00000000..aa1f82b9 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/vendor/_rfs.scss @@ -0,0 +1,348 @@ +// stylelint-disable scss/dimension-no-non-numeric-values + +// SCSS RFS mixin +// +// Automated responsive values for font sizes, paddings, margins and much more +// +// Licensed under MIT (https://github.com/twbs/rfs/blob/main/LICENSE) + +// Configuration + +// Base value +$rfs-base-value: 1.25rem !default; +$rfs-unit: rem !default; + +@if $rfs-unit != rem and $rfs-unit != px { + @error "`#{$rfs-unit}` is not a valid unit for $rfs-unit. Use `px` or `rem`."; +} + +// Breakpoint at where values start decreasing if screen width is smaller +$rfs-breakpoint: 1200px !default; +$rfs-breakpoint-unit: px !default; + +@if $rfs-breakpoint-unit != px and $rfs-breakpoint-unit != em and $rfs-breakpoint-unit != rem { + @error "`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`."; +} + +// Resize values based on screen height and width +$rfs-two-dimensional: false !default; + +// Factor of decrease +$rfs-factor: 10 !default; + +@if type-of($rfs-factor) != number or $rfs-factor <= 1 { + @error "`#{$rfs-factor}` is not a valid $rfs-factor, it must be greater than 1."; +} + +// Mode. Possibilities: "min-media-query", "max-media-query" +$rfs-mode: min-media-query !default; + +// Generate enable or disable classes. Possibilities: false, "enable" or "disable" +$rfs-class: false !default; + +// 1 rem = $rfs-rem-value px +$rfs-rem-value: 16 !default; + +// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14 +$rfs-safari-iframe-resize-bug-fix: false !default; + +// Disable RFS by setting $enable-rfs to false +$enable-rfs: true !default; + +// Cache $rfs-base-value unit +$rfs-base-value-unit: unit($rfs-base-value); + +@function divide($dividend, $divisor, $precision: 10) { + $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1); + $dividend: abs($dividend); + $divisor: abs($divisor); + @if $dividend == 0 { + @return 0; + } + @if $divisor == 0 { + @error "Cannot divide by 0"; + } + $remainder: $dividend; + $result: 0; + $factor: 10; + @while ($remainder > 0 and $precision >= 0) { + $quotient: 0; + @while ($remainder >= $divisor) { + $remainder: $remainder - $divisor; + $quotient: $quotient + 1; + } + $result: $result * 10 + $quotient; + $factor: $factor * .1; + $remainder: $remainder * 10; + $precision: $precision - 1; + @if ($precision < 0 and $remainder >= $divisor * 5) { + $result: $result + 1; + } + } + $result: $result * $factor * $sign; + $dividend-unit: unit($dividend); + $divisor-unit: unit($divisor); + $unit-map: ( + "px": 1px, + "rem": 1rem, + "em": 1em, + "%": 1% + ); + @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) { + $result: $result * map-get($unit-map, $dividend-unit); + } + @return $result; +} + +// Remove px-unit from $rfs-base-value for calculations +@if $rfs-base-value-unit == px { + $rfs-base-value: divide($rfs-base-value, $rfs-base-value * 0 + 1); +} +@else if $rfs-base-value-unit == rem { + $rfs-base-value: divide($rfs-base-value, divide($rfs-base-value * 0 + 1, $rfs-rem-value)); +} + +// Cache $rfs-breakpoint unit to prevent multiple calls +$rfs-breakpoint-unit-cache: unit($rfs-breakpoint); + +// Remove unit from $rfs-breakpoint for calculations +@if $rfs-breakpoint-unit-cache == px { + $rfs-breakpoint: divide($rfs-breakpoint, $rfs-breakpoint * 0 + 1); +} +@else if $rfs-breakpoint-unit-cache == rem or $rfs-breakpoint-unit-cache == "em" { + $rfs-breakpoint: divide($rfs-breakpoint, divide($rfs-breakpoint * 0 + 1, $rfs-rem-value)); +} + +// Calculate the media query value +$rfs-mq-value: if($rfs-breakpoint-unit == px, #{$rfs-breakpoint}px, #{divide($rfs-breakpoint, $rfs-rem-value)}#{$rfs-breakpoint-unit}); +$rfs-mq-property-width: if($rfs-mode == max-media-query, max-width, min-width); +$rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height); + +// Internal mixin used to determine which media query needs to be used +@mixin _rfs-media-query { + @if $rfs-two-dimensional { + @if $rfs-mode == max-media-query { + @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}), (#{$rfs-mq-property-height}: #{$rfs-mq-value}) { + @content; + } + } + @else { + @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) and (#{$rfs-mq-property-height}: #{$rfs-mq-value}) { + @content; + } + } + } + @else { + @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) { + @content; + } + } +} + +// Internal mixin that adds disable classes to the selector if needed. +@mixin _rfs-rule { + @if $rfs-class == disable and $rfs-mode == max-media-query { + // Adding an extra class increases specificity, which prevents the media query to override the property + &, + .disable-rfs &, + &.disable-rfs { + @content; + } + } + @else if $rfs-class == enable and $rfs-mode == min-media-query { + .enable-rfs &, + &.enable-rfs { + @content; + } + } @else { + @content; + } +} + +// Internal mixin that adds enable classes to the selector if needed. +@mixin _rfs-media-query-rule { + + @if $rfs-class == enable { + @if $rfs-mode == min-media-query { + @content; + } + + @include _rfs-media-query () { + .enable-rfs &, + &.enable-rfs { + @content; + } + } + } + @else { + @if $rfs-class == disable and $rfs-mode == min-media-query { + .disable-rfs &, + &.disable-rfs { + @content; + } + } + @include _rfs-media-query () { + @content; + } + } +} + +// Helper function to get the formatted non-responsive value +@function rfs-value($values) { + // Convert to list + $values: if(type-of($values) != list, ($values,), $values); + + $val: ""; + + // Loop over each value and calculate value + @each $value in $values { + @if $value == 0 { + $val: $val + " 0"; + } + @else { + // Cache $value unit + $unit: if(type-of($value) == "number", unit($value), false); + + @if $unit == px { + // Convert to rem if needed + $val: $val + " " + if($rfs-unit == rem, #{divide($value, $value * 0 + $rfs-rem-value)}rem, $value); + } + @else if $unit == rem { + // Convert to px if needed + $val: $val + " " + if($rfs-unit == px, #{divide($value, $value * 0 + 1) * $rfs-rem-value}px, $value); + } @else { + // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value + $val: $val + " " + $value; + } + } + } + + // Remove first space + @return unquote(str-slice($val, 2)); +} + +// Helper function to get the responsive value calculated by RFS +@function rfs-fluid-value($values) { + // Convert to list + $values: if(type-of($values) != list, ($values,), $values); + + $val: ""; + + // Loop over each value and calculate value + @each $value in $values { + @if $value == 0 { + $val: $val + " 0"; + } @else { + // Cache $value unit + $unit: if(type-of($value) == "number", unit($value), false); + + // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value + @if not $unit or $unit != px and $unit != rem { + $val: $val + " " + $value; + } @else { + // Remove unit from $value for calculations + $value: divide($value, $value * 0 + if($unit == px, 1, divide(1, $rfs-rem-value))); + + // Only add the media query if the value is greater than the minimum value + @if abs($value) <= $rfs-base-value or not $enable-rfs { + $val: $val + " " + if($rfs-unit == rem, #{divide($value, $rfs-rem-value)}rem, #{$value}px); + } + @else { + // Calculate the minimum value + $value-min: $rfs-base-value + divide(abs($value) - $rfs-base-value, $rfs-factor); + + // Calculate difference between $value and the minimum value + $value-diff: abs($value) - $value-min; + + // Base value formatting + $min-width: if($rfs-unit == rem, #{divide($value-min, $rfs-rem-value)}rem, #{$value-min}px); + + // Use negative value if needed + $min-width: if($value < 0, -$min-width, $min-width); + + // Use `vmin` if two-dimensional is enabled + $variable-unit: if($rfs-two-dimensional, vmin, vw); + + // Calculate the variable width between 0 and $rfs-breakpoint + $variable-width: #{divide($value-diff * 100, $rfs-breakpoint)}#{$variable-unit}; + + // Return the calculated value + $val: $val + " calc(" + $min-width + if($value < 0, " - ", " + ") + $variable-width + ")"; + } + } + } + } + + // Remove first space + @return unquote(str-slice($val, 2)); +} + +// RFS mixin +@mixin rfs($values, $property: font-size) { + @if $values != null { + $val: rfs-value($values); + $fluid-val: rfs-fluid-value($values); + + // Do not print the media query if responsive & non-responsive values are the same + @if $val == $fluid-val { + #{$property}: $val; + } + @else { + @include _rfs-rule () { + #{$property}: if($rfs-mode == max-media-query, $val, $fluid-val); + + // Include safari iframe resize fix if needed + min-width: if($rfs-safari-iframe-resize-bug-fix, (0 * 1vw), null); + } + + @include _rfs-media-query-rule () { + #{$property}: if($rfs-mode == max-media-query, $fluid-val, $val); + } + } + } +} + +// Shorthand helper mixins +@mixin font-size($value) { + @include rfs($value); +} + +@mixin padding($value) { + @include rfs($value, padding); +} + +@mixin padding-top($value) { + @include rfs($value, padding-top); +} + +@mixin padding-right($value) { + @include rfs($value, padding-right); +} + +@mixin padding-bottom($value) { + @include rfs($value, padding-bottom); +} + +@mixin padding-left($value) { + @include rfs($value, padding-left); +} + +@mixin margin($value) { + @include rfs($value, margin); +} + +@mixin margin-top($value) { + @include rfs($value, margin-top); +} + +@mixin margin-right($value) { + @include rfs($value, margin-right); +} + +@mixin margin-bottom($value) { + @include rfs($value, margin-bottom); +} + +@mixin margin-left($value) { + @include rfs($value, margin-left); +} diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.js b/extensions/pagetop-bootsier/static/js/bootstrap.js new file mode 100644 index 00000000..e3a59e3a --- /dev/null +++ b/extensions/pagetop-bootsier/static/js/bootstrap.js @@ -0,0 +1,4494 @@ +/*! + * Bootstrap v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@popperjs/core')) : + typeof define === 'function' && define.amd ? define(['@popperjs/core'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bootstrap = factory(global.Popper)); +})(this, (function (Popper) { 'use strict'; + + function _interopNamespaceDefault(e) { + const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } }); + if (e) { + for (const k in e) { + if (k !== 'default') { + const d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: () => e[k] + }); + } + } + } + n.default = e; + return Object.freeze(n); + } + + const Popper__namespace = /*#__PURE__*/_interopNamespaceDefault(Popper); + + /** + * -------------------------------------------------------------------------- + * Bootstrap dom/data.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + /** + * Constants + */ + + const elementMap = new Map(); + const Data = { + set(element, key, instance) { + if (!elementMap.has(element)) { + elementMap.set(element, new Map()); + } + const instanceMap = elementMap.get(element); + + // make it clear we only want one instance per element + // can be removed later when multiple key/instances are fine to be used + if (!instanceMap.has(key) && instanceMap.size !== 0) { + // eslint-disable-next-line no-console + console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`); + return; + } + instanceMap.set(key, instance); + }, + get(element, key) { + if (elementMap.has(element)) { + return elementMap.get(element).get(key) || null; + } + return null; + }, + remove(element, key) { + if (!elementMap.has(element)) { + return; + } + const instanceMap = elementMap.get(element); + instanceMap.delete(key); + + // free up element references if there are no instances left for an element + if (instanceMap.size === 0) { + elementMap.delete(element); + } + } + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/index.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + const MAX_UID = 1000000; + const MILLISECONDS_MULTIPLIER = 1000; + const TRANSITION_END = 'transitionend'; + + /** + * Properly escape IDs selectors to handle weird IDs + * @param {string} selector + * @returns {string} + */ + const parseSelector = selector => { + if (selector && window.CSS && window.CSS.escape) { + // document.querySelector needs escaping to handle IDs (html5+) containing for instance / + selector = selector.replace(/#([^\s"#']+)/g, (match, id) => `#${CSS.escape(id)}`); + } + return selector; + }; + + // Shout-out Angus Croll (https://goo.gl/pxwQGp) + const toType = object => { + if (object === null || object === undefined) { + return `${object}`; + } + return Object.prototype.toString.call(object).match(/\s([a-z]+)/i)[1].toLowerCase(); + }; + + /** + * Public Util API + */ + + const getUID = prefix => { + do { + prefix += Math.floor(Math.random() * MAX_UID); + } while (document.getElementById(prefix)); + return prefix; + }; + const getTransitionDurationFromElement = element => { + if (!element) { + return 0; + } + + // Get transition-duration of the element + let { + transitionDuration, + transitionDelay + } = window.getComputedStyle(element); + const floatTransitionDuration = Number.parseFloat(transitionDuration); + const floatTransitionDelay = Number.parseFloat(transitionDelay); + + // Return 0 if element or transition duration is not found + if (!floatTransitionDuration && !floatTransitionDelay) { + return 0; + } + + // If multiple durations are defined, take the first + transitionDuration = transitionDuration.split(',')[0]; + transitionDelay = transitionDelay.split(',')[0]; + return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER; + }; + const triggerTransitionEnd = element => { + element.dispatchEvent(new Event(TRANSITION_END)); + }; + const isElement = object => { + if (!object || typeof object !== 'object') { + return false; + } + if (typeof object.jquery !== 'undefined') { + object = object[0]; + } + return typeof object.nodeType !== 'undefined'; + }; + const getElement = object => { + // it's a jQuery object or a node element + if (isElement(object)) { + return object.jquery ? object[0] : object; + } + if (typeof object === 'string' && object.length > 0) { + return document.querySelector(parseSelector(object)); + } + return null; + }; + const isVisible = element => { + if (!isElement(element) || element.getClientRects().length === 0) { + return false; + } + const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'; + // Handle `details` element as its content may falsie appear visible when it is closed + const closedDetails = element.closest('details:not([open])'); + if (!closedDetails) { + return elementIsVisible; + } + if (closedDetails !== element) { + const summary = element.closest('summary'); + if (summary && summary.parentNode !== closedDetails) { + return false; + } + if (summary === null) { + return false; + } + } + return elementIsVisible; + }; + const isDisabled = element => { + if (!element || element.nodeType !== Node.ELEMENT_NODE) { + return true; + } + if (element.classList.contains('disabled')) { + return true; + } + if (typeof element.disabled !== 'undefined') { + return element.disabled; + } + return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'; + }; + const findShadowRoot = element => { + if (!document.documentElement.attachShadow) { + return null; + } + + // Can find the shadow root otherwise it'll return the document + if (typeof element.getRootNode === 'function') { + const root = element.getRootNode(); + return root instanceof ShadowRoot ? root : null; + } + if (element instanceof ShadowRoot) { + return element; + } + + // when we don't find a shadow root + if (!element.parentNode) { + return null; + } + return findShadowRoot(element.parentNode); + }; + const noop = () => {}; + + /** + * Trick to restart an element's animation + * + * @param {HTMLElement} element + * @return void + * + * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation + */ + const reflow = element => { + element.offsetHeight; // eslint-disable-line no-unused-expressions + }; + const getjQuery = () => { + if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) { + return window.jQuery; + } + return null; + }; + const DOMContentLoadedCallbacks = []; + const onDOMContentLoaded = callback => { + if (document.readyState === 'loading') { + // add listener on the first call when the document is in loading state + if (!DOMContentLoadedCallbacks.length) { + document.addEventListener('DOMContentLoaded', () => { + for (const callback of DOMContentLoadedCallbacks) { + callback(); + } + }); + } + DOMContentLoadedCallbacks.push(callback); + } else { + callback(); + } + }; + const isRTL = () => document.documentElement.dir === 'rtl'; + const defineJQueryPlugin = plugin => { + onDOMContentLoaded(() => { + const $ = getjQuery(); + /* istanbul ignore if */ + if ($) { + const name = plugin.NAME; + const JQUERY_NO_CONFLICT = $.fn[name]; + $.fn[name] = plugin.jQueryInterface; + $.fn[name].Constructor = plugin; + $.fn[name].noConflict = () => { + $.fn[name] = JQUERY_NO_CONFLICT; + return plugin.jQueryInterface; + }; + } + }); + }; + const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => { + return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue; + }; + const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => { + if (!waitForTransition) { + execute(callback); + return; + } + const durationPadding = 5; + const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding; + let called = false; + const handler = ({ + target + }) => { + if (target !== transitionElement) { + return; + } + called = true; + transitionElement.removeEventListener(TRANSITION_END, handler); + execute(callback); + }; + transitionElement.addEventListener(TRANSITION_END, handler); + setTimeout(() => { + if (!called) { + triggerTransitionEnd(transitionElement); + } + }, emulatedDuration); + }; + + /** + * Return the previous/next element of a list. + * + * @param {array} list The list of elements + * @param activeElement The active element + * @param shouldGetNext Choose to get next or previous element + * @param isCycleAllowed + * @return {Element|elem} The proper element + */ + const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => { + const listLength = list.length; + let index = list.indexOf(activeElement); + + // if the element does not exist in the list return an element + // depending on the direction and if cycle is allowed + if (index === -1) { + return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]; + } + index += shouldGetNext ? 1 : -1; + if (isCycleAllowed) { + index = (index + listLength) % listLength; + } + return list[Math.max(0, Math.min(index, listLength - 1))]; + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap dom/event-handler.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const namespaceRegex = /[^.]*(?=\..*)\.|.*/; + const stripNameRegex = /\..*/; + const stripUidRegex = /::\d+$/; + const eventRegistry = {}; // Events storage + let uidEvent = 1; + const customEvents = { + mouseenter: 'mouseover', + mouseleave: 'mouseout' + }; + const nativeEvents = new Set(['click', 'dblclick', 'mouseup', 'mousedown', 'contextmenu', 'mousewheel', 'DOMMouseScroll', 'mouseover', 'mouseout', 'mousemove', 'selectstart', 'selectend', 'keydown', 'keypress', 'keyup', 'orientationchange', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel', 'gesturestart', 'gesturechange', 'gestureend', 'focus', 'blur', 'change', 'reset', 'select', 'submit', 'focusin', 'focusout', 'load', 'unload', 'beforeunload', 'resize', 'move', 'DOMContentLoaded', 'readystatechange', 'error', 'abort', 'scroll']); + + /** + * Private methods + */ + + function makeEventUid(element, uid) { + return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++; + } + function getElementEvents(element) { + const uid = makeEventUid(element); + element.uidEvent = uid; + eventRegistry[uid] = eventRegistry[uid] || {}; + return eventRegistry[uid]; + } + function bootstrapHandler(element, fn) { + return function handler(event) { + hydrateObj(event, { + delegateTarget: element + }); + if (handler.oneOff) { + EventHandler.off(element, event.type, fn); + } + return fn.apply(element, [event]); + }; + } + function bootstrapDelegationHandler(element, selector, fn) { + return function handler(event) { + const domElements = element.querySelectorAll(selector); + for (let { + target + } = event; target && target !== this; target = target.parentNode) { + for (const domElement of domElements) { + if (domElement !== target) { + continue; + } + hydrateObj(event, { + delegateTarget: target + }); + if (handler.oneOff) { + EventHandler.off(element, event.type, selector, fn); + } + return fn.apply(target, [event]); + } + } + }; + } + function findHandler(events, callable, delegationSelector = null) { + return Object.values(events).find(event => event.callable === callable && event.delegationSelector === delegationSelector); + } + function normalizeParameters(originalTypeEvent, handler, delegationFunction) { + const isDelegated = typeof handler === 'string'; + // TODO: tooltip passes `false` instead of selector, so we need to check + const callable = isDelegated ? delegationFunction : handler || delegationFunction; + let typeEvent = getTypeEvent(originalTypeEvent); + if (!nativeEvents.has(typeEvent)) { + typeEvent = originalTypeEvent; + } + return [isDelegated, callable, typeEvent]; + } + function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) { + if (typeof originalTypeEvent !== 'string' || !element) { + return; + } + let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction); + + // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position + // this prevents the handler from being dispatched the same way as mouseover or mouseout does + if (originalTypeEvent in customEvents) { + const wrapFunction = fn => { + return function (event) { + if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) { + return fn.call(this, event); + } + }; + }; + callable = wrapFunction(callable); + } + const events = getElementEvents(element); + const handlers = events[typeEvent] || (events[typeEvent] = {}); + const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null); + if (previousFunction) { + previousFunction.oneOff = previousFunction.oneOff && oneOff; + return; + } + const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, '')); + const fn = isDelegated ? bootstrapDelegationHandler(element, handler, callable) : bootstrapHandler(element, callable); + fn.delegationSelector = isDelegated ? handler : null; + fn.callable = callable; + fn.oneOff = oneOff; + fn.uidEvent = uid; + handlers[uid] = fn; + element.addEventListener(typeEvent, fn, isDelegated); + } + function removeHandler(element, events, typeEvent, handler, delegationSelector) { + const fn = findHandler(events[typeEvent], handler, delegationSelector); + if (!fn) { + return; + } + element.removeEventListener(typeEvent, fn, Boolean(delegationSelector)); + delete events[typeEvent][fn.uidEvent]; + } + function removeNamespacedHandlers(element, events, typeEvent, namespace) { + const storeElementEvent = events[typeEvent] || {}; + for (const [handlerKey, event] of Object.entries(storeElementEvent)) { + if (handlerKey.includes(namespace)) { + removeHandler(element, events, typeEvent, event.callable, event.delegationSelector); + } + } + } + function getTypeEvent(event) { + // allow to get the native events from namespaced events ('click.bs.button' --> 'click') + event = event.replace(stripNameRegex, ''); + return customEvents[event] || event; + } + const EventHandler = { + on(element, event, handler, delegationFunction) { + addHandler(element, event, handler, delegationFunction, false); + }, + one(element, event, handler, delegationFunction) { + addHandler(element, event, handler, delegationFunction, true); + }, + off(element, originalTypeEvent, handler, delegationFunction) { + if (typeof originalTypeEvent !== 'string' || !element) { + return; + } + const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction); + const inNamespace = typeEvent !== originalTypeEvent; + const events = getElementEvents(element); + const storeElementEvent = events[typeEvent] || {}; + const isNamespace = originalTypeEvent.startsWith('.'); + if (typeof callable !== 'undefined') { + // Simplest case: handler is passed, remove that listener ONLY. + if (!Object.keys(storeElementEvent).length) { + return; + } + removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null); + return; + } + if (isNamespace) { + for (const elementEvent of Object.keys(events)) { + removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1)); + } + } + for (const [keyHandlers, event] of Object.entries(storeElementEvent)) { + const handlerKey = keyHandlers.replace(stripUidRegex, ''); + if (!inNamespace || originalTypeEvent.includes(handlerKey)) { + removeHandler(element, events, typeEvent, event.callable, event.delegationSelector); + } + } + }, + trigger(element, event, args) { + if (typeof event !== 'string' || !element) { + return null; + } + const $ = getjQuery(); + const typeEvent = getTypeEvent(event); + const inNamespace = event !== typeEvent; + let jQueryEvent = null; + let bubbles = true; + let nativeDispatch = true; + let defaultPrevented = false; + if (inNamespace && $) { + jQueryEvent = $.Event(event, args); + $(element).trigger(jQueryEvent); + bubbles = !jQueryEvent.isPropagationStopped(); + nativeDispatch = !jQueryEvent.isImmediatePropagationStopped(); + defaultPrevented = jQueryEvent.isDefaultPrevented(); + } + const evt = hydrateObj(new Event(event, { + bubbles, + cancelable: true + }), args); + if (defaultPrevented) { + evt.preventDefault(); + } + if (nativeDispatch) { + element.dispatchEvent(evt); + } + if (evt.defaultPrevented && jQueryEvent) { + jQueryEvent.preventDefault(); + } + return evt; + } + }; + function hydrateObj(obj, meta = {}) { + for (const [key, value] of Object.entries(meta)) { + try { + obj[key] = value; + } catch (_unused) { + Object.defineProperty(obj, key, { + configurable: true, + get() { + return value; + } + }); + } + } + return obj; + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap dom/manipulator.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + function normalizeData(value) { + if (value === 'true') { + return true; + } + if (value === 'false') { + return false; + } + if (value === Number(value).toString()) { + return Number(value); + } + if (value === '' || value === 'null') { + return null; + } + if (typeof value !== 'string') { + return value; + } + try { + return JSON.parse(decodeURIComponent(value)); + } catch (_unused) { + return value; + } + } + function normalizeDataKey(key) { + return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`); + } + const Manipulator = { + setDataAttribute(element, key, value) { + element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value); + }, + removeDataAttribute(element, key) { + element.removeAttribute(`data-bs-${normalizeDataKey(key)}`); + }, + getDataAttributes(element) { + if (!element) { + return {}; + } + const attributes = {}; + const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig')); + for (const key of bsKeys) { + let pureKey = key.replace(/^bs/, ''); + pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length); + attributes[pureKey] = normalizeData(element.dataset[key]); + } + return attributes; + }, + getDataAttribute(element, key) { + return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`)); + } + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/config.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Class definition + */ + + class Config { + // Getters + static get Default() { + return {}; + } + static get DefaultType() { + return {}; + } + static get NAME() { + throw new Error('You have to implement the static method "NAME", for each component!'); + } + _getConfig(config) { + config = this._mergeConfigObj(config); + config = this._configAfterMerge(config); + this._typeCheckConfig(config); + return config; + } + _configAfterMerge(config) { + return config; + } + _mergeConfigObj(config, element) { + const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {}; // try to parse + + return { + ...this.constructor.Default, + ...(typeof jsonConfig === 'object' ? jsonConfig : {}), + ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}), + ...(typeof config === 'object' ? config : {}) + }; + } + _typeCheckConfig(config, configTypes = this.constructor.DefaultType) { + for (const [property, expectedTypes] of Object.entries(configTypes)) { + const value = config[property]; + const valueType = isElement(value) ? 'element' : toType(value); + if (!new RegExp(expectedTypes).test(valueType)) { + throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`); + } + } + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap base-component.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const VERSION = '5.3.3'; + + /** + * Class definition + */ + + class BaseComponent extends Config { + constructor(element, config) { + super(); + element = getElement(element); + if (!element) { + return; + } + this._element = element; + this._config = this._getConfig(config); + Data.set(this._element, this.constructor.DATA_KEY, this); + } + + // Public + dispose() { + Data.remove(this._element, this.constructor.DATA_KEY); + EventHandler.off(this._element, this.constructor.EVENT_KEY); + for (const propertyName of Object.getOwnPropertyNames(this)) { + this[propertyName] = null; + } + } + _queueCallback(callback, element, isAnimated = true) { + executeAfterTransition(callback, element, isAnimated); + } + _getConfig(config) { + config = this._mergeConfigObj(config, this._element); + config = this._configAfterMerge(config); + this._typeCheckConfig(config); + return config; + } + + // Static + static getInstance(element) { + return Data.get(getElement(element), this.DATA_KEY); + } + static getOrCreateInstance(element, config = {}) { + return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null); + } + static get VERSION() { + return VERSION; + } + static get DATA_KEY() { + return `bs.${this.NAME}`; + } + static get EVENT_KEY() { + return `.${this.DATA_KEY}`; + } + static eventName(name) { + return `${name}${this.EVENT_KEY}`; + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap dom/selector-engine.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + const getSelector = element => { + let selector = element.getAttribute('data-bs-target'); + if (!selector || selector === '#') { + let hrefAttribute = element.getAttribute('href'); + + // The only valid content that could double as a selector are IDs or classes, + // so everything starting with `#` or `.`. If a "real" URL is used as the selector, + // `document.querySelector` will rightfully complain it is invalid. + // See https://github.com/twbs/bootstrap/issues/32273 + if (!hrefAttribute || !hrefAttribute.includes('#') && !hrefAttribute.startsWith('.')) { + return null; + } + + // Just in case some CMS puts out a full URL with the anchor appended + if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) { + hrefAttribute = `#${hrefAttribute.split('#')[1]}`; + } + selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null; + } + return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null; + }; + const SelectorEngine = { + find(selector, element = document.documentElement) { + return [].concat(...Element.prototype.querySelectorAll.call(element, selector)); + }, + findOne(selector, element = document.documentElement) { + return Element.prototype.querySelector.call(element, selector); + }, + children(element, selector) { + return [].concat(...element.children).filter(child => child.matches(selector)); + }, + parents(element, selector) { + const parents = []; + let ancestor = element.parentNode.closest(selector); + while (ancestor) { + parents.push(ancestor); + ancestor = ancestor.parentNode.closest(selector); + } + return parents; + }, + prev(element, selector) { + let previous = element.previousElementSibling; + while (previous) { + if (previous.matches(selector)) { + return [previous]; + } + previous = previous.previousElementSibling; + } + return []; + }, + // TODO: this is now unused; remove later along with prev() + next(element, selector) { + let next = element.nextElementSibling; + while (next) { + if (next.matches(selector)) { + return [next]; + } + next = next.nextElementSibling; + } + return []; + }, + focusableChildren(element) { + const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable="true"]'].map(selector => `${selector}:not([tabindex^="-"])`).join(','); + return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el)); + }, + getSelectorFromElement(element) { + const selector = getSelector(element); + if (selector) { + return SelectorEngine.findOne(selector) ? selector : null; + } + return null; + }, + getElementFromSelector(element) { + const selector = getSelector(element); + return selector ? SelectorEngine.findOne(selector) : null; + }, + getMultipleElementsFromSelector(element) { + const selector = getSelector(element); + return selector ? SelectorEngine.find(selector) : []; + } + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/component-functions.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + const enableDismissTrigger = (component, method = 'hide') => { + const clickEvent = `click.dismiss${component.EVENT_KEY}`; + const name = component.NAME; + EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) { + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + if (isDisabled(this)) { + return; + } + const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`); + const instance = component.getOrCreateInstance(target); + + // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method + instance[method](); + }); + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap alert.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$f = 'alert'; + const DATA_KEY$a = 'bs.alert'; + const EVENT_KEY$b = `.${DATA_KEY$a}`; + const EVENT_CLOSE = `close${EVENT_KEY$b}`; + const EVENT_CLOSED = `closed${EVENT_KEY$b}`; + const CLASS_NAME_FADE$5 = 'fade'; + const CLASS_NAME_SHOW$8 = 'show'; + + /** + * Class definition + */ + + class Alert extends BaseComponent { + // Getters + static get NAME() { + return NAME$f; + } + + // Public + close() { + const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE); + if (closeEvent.defaultPrevented) { + return; + } + this._element.classList.remove(CLASS_NAME_SHOW$8); + const isAnimated = this._element.classList.contains(CLASS_NAME_FADE$5); + this._queueCallback(() => this._destroyElement(), this._element, isAnimated); + } + + // Private + _destroyElement() { + this._element.remove(); + EventHandler.trigger(this._element, EVENT_CLOSED); + this.dispose(); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Alert.getOrCreateInstance(this); + if (typeof config !== 'string') { + return; + } + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + data[config](this); + }); + } + } + + /** + * Data API implementation + */ + + enableDismissTrigger(Alert, 'close'); + + /** + * jQuery + */ + + defineJQueryPlugin(Alert); + + /** + * -------------------------------------------------------------------------- + * Bootstrap button.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$e = 'button'; + const DATA_KEY$9 = 'bs.button'; + const EVENT_KEY$a = `.${DATA_KEY$9}`; + const DATA_API_KEY$6 = '.data-api'; + const CLASS_NAME_ACTIVE$3 = 'active'; + const SELECTOR_DATA_TOGGLE$5 = '[data-bs-toggle="button"]'; + const EVENT_CLICK_DATA_API$6 = `click${EVENT_KEY$a}${DATA_API_KEY$6}`; + + /** + * Class definition + */ + + class Button extends BaseComponent { + // Getters + static get NAME() { + return NAME$e; + } + + // Public + toggle() { + // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method + this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE$3)); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Button.getOrCreateInstance(this); + if (config === 'toggle') { + data[config](); + } + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$6, SELECTOR_DATA_TOGGLE$5, event => { + event.preventDefault(); + const button = event.target.closest(SELECTOR_DATA_TOGGLE$5); + const data = Button.getOrCreateInstance(button); + data.toggle(); + }); + + /** + * jQuery + */ + + defineJQueryPlugin(Button); + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/swipe.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$d = 'swipe'; + const EVENT_KEY$9 = '.bs.swipe'; + const EVENT_TOUCHSTART = `touchstart${EVENT_KEY$9}`; + const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY$9}`; + const EVENT_TOUCHEND = `touchend${EVENT_KEY$9}`; + const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY$9}`; + const EVENT_POINTERUP = `pointerup${EVENT_KEY$9}`; + const POINTER_TYPE_TOUCH = 'touch'; + const POINTER_TYPE_PEN = 'pen'; + const CLASS_NAME_POINTER_EVENT = 'pointer-event'; + const SWIPE_THRESHOLD = 40; + const Default$c = { + endCallback: null, + leftCallback: null, + rightCallback: null + }; + const DefaultType$c = { + endCallback: '(function|null)', + leftCallback: '(function|null)', + rightCallback: '(function|null)' + }; + + /** + * Class definition + */ + + class Swipe extends Config { + constructor(element, config) { + super(); + this._element = element; + if (!element || !Swipe.isSupported()) { + return; + } + this._config = this._getConfig(config); + this._deltaX = 0; + this._supportPointerEvents = Boolean(window.PointerEvent); + this._initEvents(); + } + + // Getters + static get Default() { + return Default$c; + } + static get DefaultType() { + return DefaultType$c; + } + static get NAME() { + return NAME$d; + } + + // Public + dispose() { + EventHandler.off(this._element, EVENT_KEY$9); + } + + // Private + _start(event) { + if (!this._supportPointerEvents) { + this._deltaX = event.touches[0].clientX; + return; + } + if (this._eventIsPointerPenTouch(event)) { + this._deltaX = event.clientX; + } + } + _end(event) { + if (this._eventIsPointerPenTouch(event)) { + this._deltaX = event.clientX - this._deltaX; + } + this._handleSwipe(); + execute(this._config.endCallback); + } + _move(event) { + this._deltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this._deltaX; + } + _handleSwipe() { + const absDeltaX = Math.abs(this._deltaX); + if (absDeltaX <= SWIPE_THRESHOLD) { + return; + } + const direction = absDeltaX / this._deltaX; + this._deltaX = 0; + if (!direction) { + return; + } + execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback); + } + _initEvents() { + if (this._supportPointerEvents) { + EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event)); + EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event)); + this._element.classList.add(CLASS_NAME_POINTER_EVENT); + } else { + EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event)); + EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event)); + EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event)); + } + } + _eventIsPointerPenTouch(event) { + return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH); + } + + // Static + static isSupported() { + return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0; + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap carousel.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$c = 'carousel'; + const DATA_KEY$8 = 'bs.carousel'; + const EVENT_KEY$8 = `.${DATA_KEY$8}`; + const DATA_API_KEY$5 = '.data-api'; + const ARROW_LEFT_KEY$1 = 'ArrowLeft'; + const ARROW_RIGHT_KEY$1 = 'ArrowRight'; + const TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch + + const ORDER_NEXT = 'next'; + const ORDER_PREV = 'prev'; + const DIRECTION_LEFT = 'left'; + const DIRECTION_RIGHT = 'right'; + const EVENT_SLIDE = `slide${EVENT_KEY$8}`; + const EVENT_SLID = `slid${EVENT_KEY$8}`; + const EVENT_KEYDOWN$1 = `keydown${EVENT_KEY$8}`; + const EVENT_MOUSEENTER$1 = `mouseenter${EVENT_KEY$8}`; + const EVENT_MOUSELEAVE$1 = `mouseleave${EVENT_KEY$8}`; + const EVENT_DRAG_START = `dragstart${EVENT_KEY$8}`; + const EVENT_LOAD_DATA_API$3 = `load${EVENT_KEY$8}${DATA_API_KEY$5}`; + const EVENT_CLICK_DATA_API$5 = `click${EVENT_KEY$8}${DATA_API_KEY$5}`; + const CLASS_NAME_CAROUSEL = 'carousel'; + const CLASS_NAME_ACTIVE$2 = 'active'; + const CLASS_NAME_SLIDE = 'slide'; + const CLASS_NAME_END = 'carousel-item-end'; + const CLASS_NAME_START = 'carousel-item-start'; + const CLASS_NAME_NEXT = 'carousel-item-next'; + const CLASS_NAME_PREV = 'carousel-item-prev'; + const SELECTOR_ACTIVE = '.active'; + const SELECTOR_ITEM = '.carousel-item'; + const SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM; + const SELECTOR_ITEM_IMG = '.carousel-item img'; + const SELECTOR_INDICATORS = '.carousel-indicators'; + const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'; + const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]'; + const KEY_TO_DIRECTION = { + [ARROW_LEFT_KEY$1]: DIRECTION_RIGHT, + [ARROW_RIGHT_KEY$1]: DIRECTION_LEFT + }; + const Default$b = { + interval: 5000, + keyboard: true, + pause: 'hover', + ride: false, + touch: true, + wrap: true + }; + const DefaultType$b = { + interval: '(number|boolean)', + // TODO:v6 remove boolean support + keyboard: 'boolean', + pause: '(string|boolean)', + ride: '(boolean|string)', + touch: 'boolean', + wrap: 'boolean' + }; + + /** + * Class definition + */ + + class Carousel extends BaseComponent { + constructor(element, config) { + super(element, config); + this._interval = null; + this._activeElement = null; + this._isSliding = false; + this.touchTimeout = null; + this._swipeHelper = null; + this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element); + this._addEventListeners(); + if (this._config.ride === CLASS_NAME_CAROUSEL) { + this.cycle(); + } + } + + // Getters + static get Default() { + return Default$b; + } + static get DefaultType() { + return DefaultType$b; + } + static get NAME() { + return NAME$c; + } + + // Public + next() { + this._slide(ORDER_NEXT); + } + nextWhenVisible() { + // FIXME TODO use `document.visibilityState` + // Don't call next when the page isn't visible + // or the carousel or its parent isn't visible + if (!document.hidden && isVisible(this._element)) { + this.next(); + } + } + prev() { + this._slide(ORDER_PREV); + } + pause() { + if (this._isSliding) { + triggerTransitionEnd(this._element); + } + this._clearInterval(); + } + cycle() { + this._clearInterval(); + this._updateInterval(); + this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval); + } + _maybeEnableCycle() { + if (!this._config.ride) { + return; + } + if (this._isSliding) { + EventHandler.one(this._element, EVENT_SLID, () => this.cycle()); + return; + } + this.cycle(); + } + to(index) { + const items = this._getItems(); + if (index > items.length - 1 || index < 0) { + return; + } + if (this._isSliding) { + EventHandler.one(this._element, EVENT_SLID, () => this.to(index)); + return; + } + const activeIndex = this._getItemIndex(this._getActive()); + if (activeIndex === index) { + return; + } + const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV; + this._slide(order, items[index]); + } + dispose() { + if (this._swipeHelper) { + this._swipeHelper.dispose(); + } + super.dispose(); + } + + // Private + _configAfterMerge(config) { + config.defaultInterval = config.interval; + return config; + } + _addEventListeners() { + if (this._config.keyboard) { + EventHandler.on(this._element, EVENT_KEYDOWN$1, event => this._keydown(event)); + } + if (this._config.pause === 'hover') { + EventHandler.on(this._element, EVENT_MOUSEENTER$1, () => this.pause()); + EventHandler.on(this._element, EVENT_MOUSELEAVE$1, () => this._maybeEnableCycle()); + } + if (this._config.touch && Swipe.isSupported()) { + this._addTouchEventListeners(); + } + } + _addTouchEventListeners() { + for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) { + EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault()); + } + const endCallBack = () => { + if (this._config.pause !== 'hover') { + return; + } + + // If it's a touch-enabled device, mouseenter/leave are fired as + // part of the mouse compatibility events on first tap - the carousel + // would stop cycling until user tapped out of it; + // here, we listen for touchend, explicitly pause the carousel + // (as if it's the second time we tap on it, mouseenter compat event + // is NOT fired) and after a timeout (to allow for mouse compatibility + // events to fire) we explicitly restart cycling + + this.pause(); + if (this.touchTimeout) { + clearTimeout(this.touchTimeout); + } + this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval); + }; + const swipeConfig = { + leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)), + rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)), + endCallback: endCallBack + }; + this._swipeHelper = new Swipe(this._element, swipeConfig); + } + _keydown(event) { + if (/input|textarea/i.test(event.target.tagName)) { + return; + } + const direction = KEY_TO_DIRECTION[event.key]; + if (direction) { + event.preventDefault(); + this._slide(this._directionToOrder(direction)); + } + } + _getItemIndex(element) { + return this._getItems().indexOf(element); + } + _setActiveIndicatorElement(index) { + if (!this._indicatorsElement) { + return; + } + const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement); + activeIndicator.classList.remove(CLASS_NAME_ACTIVE$2); + activeIndicator.removeAttribute('aria-current'); + const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to="${index}"]`, this._indicatorsElement); + if (newActiveIndicator) { + newActiveIndicator.classList.add(CLASS_NAME_ACTIVE$2); + newActiveIndicator.setAttribute('aria-current', 'true'); + } + } + _updateInterval() { + const element = this._activeElement || this._getActive(); + if (!element) { + return; + } + const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10); + this._config.interval = elementInterval || this._config.defaultInterval; + } + _slide(order, element = null) { + if (this._isSliding) { + return; + } + const activeElement = this._getActive(); + const isNext = order === ORDER_NEXT; + const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap); + if (nextElement === activeElement) { + return; + } + const nextElementIndex = this._getItemIndex(nextElement); + const triggerEvent = eventName => { + return EventHandler.trigger(this._element, eventName, { + relatedTarget: nextElement, + direction: this._orderToDirection(order), + from: this._getItemIndex(activeElement), + to: nextElementIndex + }); + }; + const slideEvent = triggerEvent(EVENT_SLIDE); + if (slideEvent.defaultPrevented) { + return; + } + if (!activeElement || !nextElement) { + // Some weirdness is happening, so we bail + // TODO: change tests that use empty divs to avoid this check + return; + } + const isCycling = Boolean(this._interval); + this.pause(); + this._isSliding = true; + this._setActiveIndicatorElement(nextElementIndex); + this._activeElement = nextElement; + const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END; + const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV; + nextElement.classList.add(orderClassName); + reflow(nextElement); + activeElement.classList.add(directionalClassName); + nextElement.classList.add(directionalClassName); + const completeCallBack = () => { + nextElement.classList.remove(directionalClassName, orderClassName); + nextElement.classList.add(CLASS_NAME_ACTIVE$2); + activeElement.classList.remove(CLASS_NAME_ACTIVE$2, orderClassName, directionalClassName); + this._isSliding = false; + triggerEvent(EVENT_SLID); + }; + this._queueCallback(completeCallBack, activeElement, this._isAnimated()); + if (isCycling) { + this.cycle(); + } + } + _isAnimated() { + return this._element.classList.contains(CLASS_NAME_SLIDE); + } + _getActive() { + return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element); + } + _getItems() { + return SelectorEngine.find(SELECTOR_ITEM, this._element); + } + _clearInterval() { + if (this._interval) { + clearInterval(this._interval); + this._interval = null; + } + } + _directionToOrder(direction) { + if (isRTL()) { + return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT; + } + return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV; + } + _orderToDirection(order) { + if (isRTL()) { + return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT; + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Carousel.getOrCreateInstance(this, config); + if (typeof config === 'number') { + data.to(config); + return; + } + if (typeof config === 'string') { + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + } + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$5, SELECTOR_DATA_SLIDE, function (event) { + const target = SelectorEngine.getElementFromSelector(this); + if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) { + return; + } + event.preventDefault(); + const carousel = Carousel.getOrCreateInstance(target); + const slideIndex = this.getAttribute('data-bs-slide-to'); + if (slideIndex) { + carousel.to(slideIndex); + carousel._maybeEnableCycle(); + return; + } + if (Manipulator.getDataAttribute(this, 'slide') === 'next') { + carousel.next(); + carousel._maybeEnableCycle(); + return; + } + carousel.prev(); + carousel._maybeEnableCycle(); + }); + EventHandler.on(window, EVENT_LOAD_DATA_API$3, () => { + const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE); + for (const carousel of carousels) { + Carousel.getOrCreateInstance(carousel); + } + }); + + /** + * jQuery + */ + + defineJQueryPlugin(Carousel); + + /** + * -------------------------------------------------------------------------- + * Bootstrap collapse.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$b = 'collapse'; + const DATA_KEY$7 = 'bs.collapse'; + const EVENT_KEY$7 = `.${DATA_KEY$7}`; + const DATA_API_KEY$4 = '.data-api'; + const EVENT_SHOW$6 = `show${EVENT_KEY$7}`; + const EVENT_SHOWN$6 = `shown${EVENT_KEY$7}`; + const EVENT_HIDE$6 = `hide${EVENT_KEY$7}`; + const EVENT_HIDDEN$6 = `hidden${EVENT_KEY$7}`; + const EVENT_CLICK_DATA_API$4 = `click${EVENT_KEY$7}${DATA_API_KEY$4}`; + const CLASS_NAME_SHOW$7 = 'show'; + const CLASS_NAME_COLLAPSE = 'collapse'; + const CLASS_NAME_COLLAPSING = 'collapsing'; + const CLASS_NAME_COLLAPSED = 'collapsed'; + const CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`; + const CLASS_NAME_HORIZONTAL = 'collapse-horizontal'; + const WIDTH = 'width'; + const HEIGHT = 'height'; + const SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'; + const SELECTOR_DATA_TOGGLE$4 = '[data-bs-toggle="collapse"]'; + const Default$a = { + parent: null, + toggle: true + }; + const DefaultType$a = { + parent: '(null|element)', + toggle: 'boolean' + }; + + /** + * Class definition + */ + + class Collapse extends BaseComponent { + constructor(element, config) { + super(element, config); + this._isTransitioning = false; + this._triggerArray = []; + const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE$4); + for (const elem of toggleList) { + const selector = SelectorEngine.getSelectorFromElement(elem); + const filterElement = SelectorEngine.find(selector).filter(foundElement => foundElement === this._element); + if (selector !== null && filterElement.length) { + this._triggerArray.push(elem); + } + } + this._initializeChildren(); + if (!this._config.parent) { + this._addAriaAndCollapsedClass(this._triggerArray, this._isShown()); + } + if (this._config.toggle) { + this.toggle(); + } + } + + // Getters + static get Default() { + return Default$a; + } + static get DefaultType() { + return DefaultType$a; + } + static get NAME() { + return NAME$b; + } + + // Public + toggle() { + if (this._isShown()) { + this.hide(); + } else { + this.show(); + } + } + show() { + if (this._isTransitioning || this._isShown()) { + return; + } + let activeChildren = []; + + // find active children + if (this._config.parent) { + activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES).filter(element => element !== this._element).map(element => Collapse.getOrCreateInstance(element, { + toggle: false + })); + } + if (activeChildren.length && activeChildren[0]._isTransitioning) { + return; + } + const startEvent = EventHandler.trigger(this._element, EVENT_SHOW$6); + if (startEvent.defaultPrevented) { + return; + } + for (const activeInstance of activeChildren) { + activeInstance.hide(); + } + const dimension = this._getDimension(); + this._element.classList.remove(CLASS_NAME_COLLAPSE); + this._element.classList.add(CLASS_NAME_COLLAPSING); + this._element.style[dimension] = 0; + this._addAriaAndCollapsedClass(this._triggerArray, true); + this._isTransitioning = true; + const complete = () => { + this._isTransitioning = false; + this._element.classList.remove(CLASS_NAME_COLLAPSING); + this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7); + this._element.style[dimension] = ''; + EventHandler.trigger(this._element, EVENT_SHOWN$6); + }; + const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1); + const scrollSize = `scroll${capitalizedDimension}`; + this._queueCallback(complete, this._element, true); + this._element.style[dimension] = `${this._element[scrollSize]}px`; + } + hide() { + if (this._isTransitioning || !this._isShown()) { + return; + } + const startEvent = EventHandler.trigger(this._element, EVENT_HIDE$6); + if (startEvent.defaultPrevented) { + return; + } + const dimension = this._getDimension(); + this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`; + reflow(this._element); + this._element.classList.add(CLASS_NAME_COLLAPSING); + this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7); + for (const trigger of this._triggerArray) { + const element = SelectorEngine.getElementFromSelector(trigger); + if (element && !this._isShown(element)) { + this._addAriaAndCollapsedClass([trigger], false); + } + } + this._isTransitioning = true; + const complete = () => { + this._isTransitioning = false; + this._element.classList.remove(CLASS_NAME_COLLAPSING); + this._element.classList.add(CLASS_NAME_COLLAPSE); + EventHandler.trigger(this._element, EVENT_HIDDEN$6); + }; + this._element.style[dimension] = ''; + this._queueCallback(complete, this._element, true); + } + _isShown(element = this._element) { + return element.classList.contains(CLASS_NAME_SHOW$7); + } + + // Private + _configAfterMerge(config) { + config.toggle = Boolean(config.toggle); // Coerce string values + config.parent = getElement(config.parent); + return config; + } + _getDimension() { + return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT; + } + _initializeChildren() { + if (!this._config.parent) { + return; + } + const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE$4); + for (const element of children) { + const selected = SelectorEngine.getElementFromSelector(element); + if (selected) { + this._addAriaAndCollapsedClass([element], this._isShown(selected)); + } + } + } + _getFirstLevelChildren(selector) { + const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent); + // remove children if greater depth + return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element)); + } + _addAriaAndCollapsedClass(triggerArray, isOpen) { + if (!triggerArray.length) { + return; + } + for (const element of triggerArray) { + element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen); + element.setAttribute('aria-expanded', isOpen); + } + } + + // Static + static jQueryInterface(config) { + const _config = {}; + if (typeof config === 'string' && /show|hide/.test(config)) { + _config.toggle = false; + } + return this.each(function () { + const data = Collapse.getOrCreateInstance(this, _config); + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + } + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$4, function (event) { + // preventDefault only for <a> elements (which change the URL) not inside the collapsible element + if (event.target.tagName === 'A' || event.delegateTarget && event.delegateTarget.tagName === 'A') { + event.preventDefault(); + } + for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) { + Collapse.getOrCreateInstance(element, { + toggle: false + }).toggle(); + } + }); + + /** + * jQuery + */ + + defineJQueryPlugin(Collapse); + + /** + * -------------------------------------------------------------------------- + * Bootstrap dropdown.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$a = 'dropdown'; + const DATA_KEY$6 = 'bs.dropdown'; + const EVENT_KEY$6 = `.${DATA_KEY$6}`; + const DATA_API_KEY$3 = '.data-api'; + const ESCAPE_KEY$2 = 'Escape'; + const TAB_KEY$1 = 'Tab'; + const ARROW_UP_KEY$1 = 'ArrowUp'; + const ARROW_DOWN_KEY$1 = 'ArrowDown'; + const RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button + + const EVENT_HIDE$5 = `hide${EVENT_KEY$6}`; + const EVENT_HIDDEN$5 = `hidden${EVENT_KEY$6}`; + const EVENT_SHOW$5 = `show${EVENT_KEY$6}`; + const EVENT_SHOWN$5 = `shown${EVENT_KEY$6}`; + const EVENT_CLICK_DATA_API$3 = `click${EVENT_KEY$6}${DATA_API_KEY$3}`; + const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY$6}${DATA_API_KEY$3}`; + const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY$6}${DATA_API_KEY$3}`; + const CLASS_NAME_SHOW$6 = 'show'; + const CLASS_NAME_DROPUP = 'dropup'; + const CLASS_NAME_DROPEND = 'dropend'; + const CLASS_NAME_DROPSTART = 'dropstart'; + const CLASS_NAME_DROPUP_CENTER = 'dropup-center'; + const CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'; + const SELECTOR_DATA_TOGGLE$3 = '[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)'; + const SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE$3}.${CLASS_NAME_SHOW$6}`; + const SELECTOR_MENU = '.dropdown-menu'; + const SELECTOR_NAVBAR = '.navbar'; + const SELECTOR_NAVBAR_NAV = '.navbar-nav'; + const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'; + const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'; + const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'; + const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'; + const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'; + const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'; + const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'; + const PLACEMENT_TOPCENTER = 'top'; + const PLACEMENT_BOTTOMCENTER = 'bottom'; + const Default$9 = { + autoClose: true, + boundary: 'clippingParents', + display: 'dynamic', + offset: [0, 2], + popperConfig: null, + reference: 'toggle' + }; + const DefaultType$9 = { + autoClose: '(boolean|string)', + boundary: '(string|element)', + display: 'string', + offset: '(array|string|function)', + popperConfig: '(null|object|function)', + reference: '(string|element|object)' + }; + + /** + * Class definition + */ + + class Dropdown extends BaseComponent { + constructor(element, config) { + super(element, config); + this._popper = null; + this._parent = this._element.parentNode; // dropdown wrapper + // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/ + this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] || SelectorEngine.prev(this._element, SELECTOR_MENU)[0] || SelectorEngine.findOne(SELECTOR_MENU, this._parent); + this._inNavbar = this._detectNavbar(); + } + + // Getters + static get Default() { + return Default$9; + } + static get DefaultType() { + return DefaultType$9; + } + static get NAME() { + return NAME$a; + } + + // Public + toggle() { + return this._isShown() ? this.hide() : this.show(); + } + show() { + if (isDisabled(this._element) || this._isShown()) { + return; + } + const relatedTarget = { + relatedTarget: this._element + }; + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$5, relatedTarget); + if (showEvent.defaultPrevented) { + return; + } + this._createPopper(); + + // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) { + for (const element of [].concat(...document.body.children)) { + EventHandler.on(element, 'mouseover', noop); + } + } + this._element.focus(); + this._element.setAttribute('aria-expanded', true); + this._menu.classList.add(CLASS_NAME_SHOW$6); + this._element.classList.add(CLASS_NAME_SHOW$6); + EventHandler.trigger(this._element, EVENT_SHOWN$5, relatedTarget); + } + hide() { + if (isDisabled(this._element) || !this._isShown()) { + return; + } + const relatedTarget = { + relatedTarget: this._element + }; + this._completeHide(relatedTarget); + } + dispose() { + if (this._popper) { + this._popper.destroy(); + } + super.dispose(); + } + update() { + this._inNavbar = this._detectNavbar(); + if (this._popper) { + this._popper.update(); + } + } + + // Private + _completeHide(relatedTarget) { + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$5, relatedTarget); + if (hideEvent.defaultPrevented) { + return; + } + + // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + if ('ontouchstart' in document.documentElement) { + for (const element of [].concat(...document.body.children)) { + EventHandler.off(element, 'mouseover', noop); + } + } + if (this._popper) { + this._popper.destroy(); + } + this._menu.classList.remove(CLASS_NAME_SHOW$6); + this._element.classList.remove(CLASS_NAME_SHOW$6); + this._element.setAttribute('aria-expanded', 'false'); + Manipulator.removeDataAttribute(this._menu, 'popper'); + EventHandler.trigger(this._element, EVENT_HIDDEN$5, relatedTarget); + } + _getConfig(config) { + config = super._getConfig(config); + if (typeof config.reference === 'object' && !isElement(config.reference) && typeof config.reference.getBoundingClientRect !== 'function') { + // Popper virtual elements require a getBoundingClientRect method + throw new TypeError(`${NAME$a.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`); + } + return config; + } + _createPopper() { + if (typeof Popper__namespace === 'undefined') { + throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)'); + } + let referenceElement = this._element; + if (this._config.reference === 'parent') { + referenceElement = this._parent; + } else if (isElement(this._config.reference)) { + referenceElement = getElement(this._config.reference); + } else if (typeof this._config.reference === 'object') { + referenceElement = this._config.reference; + } + const popperConfig = this._getPopperConfig(); + this._popper = Popper__namespace.createPopper(referenceElement, this._menu, popperConfig); + } + _isShown() { + return this._menu.classList.contains(CLASS_NAME_SHOW$6); + } + _getPlacement() { + const parentDropdown = this._parent; + if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) { + return PLACEMENT_RIGHT; + } + if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) { + return PLACEMENT_LEFT; + } + if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) { + return PLACEMENT_TOPCENTER; + } + if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) { + return PLACEMENT_BOTTOMCENTER; + } + + // We need to trim the value because custom properties can also include spaces + const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'; + if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) { + return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP; + } + return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM; + } + _detectNavbar() { + return this._element.closest(SELECTOR_NAVBAR) !== null; + } + _getOffset() { + const { + offset + } = this._config; + if (typeof offset === 'string') { + return offset.split(',').map(value => Number.parseInt(value, 10)); + } + if (typeof offset === 'function') { + return popperData => offset(popperData, this._element); + } + return offset; + } + _getPopperConfig() { + const defaultBsPopperConfig = { + placement: this._getPlacement(), + modifiers: [{ + name: 'preventOverflow', + options: { + boundary: this._config.boundary + } + }, { + name: 'offset', + options: { + offset: this._getOffset() + } + }] + }; + + // Disable Popper if we have a static display or Dropdown is in Navbar + if (this._inNavbar || this._config.display === 'static') { + Manipulator.setDataAttribute(this._menu, 'popper', 'static'); // TODO: v6 remove + defaultBsPopperConfig.modifiers = [{ + name: 'applyStyles', + enabled: false + }]; + } + return { + ...defaultBsPopperConfig, + ...execute(this._config.popperConfig, [defaultBsPopperConfig]) + }; + } + _selectMenuItem({ + key, + target + }) { + const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element)); + if (!items.length) { + return; + } + + // if target isn't included in items (e.g. when expanding the dropdown) + // allow cycling to get the last item in case key equals ARROW_UP_KEY + getNextActiveElement(items, target, key === ARROW_DOWN_KEY$1, !items.includes(target)).focus(); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Dropdown.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + }); + } + static clearMenus(event) { + if (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1) { + return; + } + const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN); + for (const toggle of openToggles) { + const context = Dropdown.getInstance(toggle); + if (!context || context._config.autoClose === false) { + continue; + } + const composedPath = event.composedPath(); + const isMenuTarget = composedPath.includes(context._menu); + if (composedPath.includes(context._element) || context._config.autoClose === 'inside' && !isMenuTarget || context._config.autoClose === 'outside' && isMenuTarget) { + continue; + } + + // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu + if (context._menu.contains(event.target) && (event.type === 'keyup' && event.key === TAB_KEY$1 || /input|select|option|textarea|form/i.test(event.target.tagName))) { + continue; + } + const relatedTarget = { + relatedTarget: context._element + }; + if (event.type === 'click') { + relatedTarget.clickEvent = event; + } + context._completeHide(relatedTarget); + } + } + static dataApiKeydownHandler(event) { + // If not an UP | DOWN | ESCAPE key => not a dropdown command + // If input/textarea && if key is other than ESCAPE => not a dropdown command + + const isInput = /input|textarea/i.test(event.target.tagName); + const isEscapeEvent = event.key === ESCAPE_KEY$2; + const isUpOrDownEvent = [ARROW_UP_KEY$1, ARROW_DOWN_KEY$1].includes(event.key); + if (!isUpOrDownEvent && !isEscapeEvent) { + return; + } + if (isInput && !isEscapeEvent) { + return; + } + event.preventDefault(); + + // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/ + const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE$3) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.next(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.findOne(SELECTOR_DATA_TOGGLE$3, event.delegateTarget.parentNode); + const instance = Dropdown.getOrCreateInstance(getToggleButton); + if (isUpOrDownEvent) { + event.stopPropagation(); + instance.show(); + instance._selectMenuItem(event); + return; + } + if (instance._isShown()) { + // else is escape and we check if it is shown + event.stopPropagation(); + instance.hide(); + getToggleButton.focus(); + } + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$3, Dropdown.dataApiKeydownHandler); + EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler); + EventHandler.on(document, EVENT_CLICK_DATA_API$3, Dropdown.clearMenus); + EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus); + EventHandler.on(document, EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$3, function (event) { + event.preventDefault(); + Dropdown.getOrCreateInstance(this).toggle(); + }); + + /** + * jQuery + */ + + defineJQueryPlugin(Dropdown); + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/backdrop.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$9 = 'backdrop'; + const CLASS_NAME_FADE$4 = 'fade'; + const CLASS_NAME_SHOW$5 = 'show'; + const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$9}`; + const Default$8 = { + className: 'modal-backdrop', + clickCallback: null, + isAnimated: false, + isVisible: true, + // if false, we use the backdrop helper without adding any element to the dom + rootElement: 'body' // give the choice to place backdrop under different elements + }; + const DefaultType$8 = { + className: 'string', + clickCallback: '(function|null)', + isAnimated: 'boolean', + isVisible: 'boolean', + rootElement: '(element|string)' + }; + + /** + * Class definition + */ + + class Backdrop extends Config { + constructor(config) { + super(); + this._config = this._getConfig(config); + this._isAppended = false; + this._element = null; + } + + // Getters + static get Default() { + return Default$8; + } + static get DefaultType() { + return DefaultType$8; + } + static get NAME() { + return NAME$9; + } + + // Public + show(callback) { + if (!this._config.isVisible) { + execute(callback); + return; + } + this._append(); + const element = this._getElement(); + if (this._config.isAnimated) { + reflow(element); + } + element.classList.add(CLASS_NAME_SHOW$5); + this._emulateAnimation(() => { + execute(callback); + }); + } + hide(callback) { + if (!this._config.isVisible) { + execute(callback); + return; + } + this._getElement().classList.remove(CLASS_NAME_SHOW$5); + this._emulateAnimation(() => { + this.dispose(); + execute(callback); + }); + } + dispose() { + if (!this._isAppended) { + return; + } + EventHandler.off(this._element, EVENT_MOUSEDOWN); + this._element.remove(); + this._isAppended = false; + } + + // Private + _getElement() { + if (!this._element) { + const backdrop = document.createElement('div'); + backdrop.className = this._config.className; + if (this._config.isAnimated) { + backdrop.classList.add(CLASS_NAME_FADE$4); + } + this._element = backdrop; + } + return this._element; + } + _configAfterMerge(config) { + // use getElement() with the default "body" to get a fresh Element on each instantiation + config.rootElement = getElement(config.rootElement); + return config; + } + _append() { + if (this._isAppended) { + return; + } + const element = this._getElement(); + this._config.rootElement.append(element); + EventHandler.on(element, EVENT_MOUSEDOWN, () => { + execute(this._config.clickCallback); + }); + this._isAppended = true; + } + _emulateAnimation(callback) { + executeAfterTransition(callback, this._getElement(), this._config.isAnimated); + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/focustrap.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$8 = 'focustrap'; + const DATA_KEY$5 = 'bs.focustrap'; + const EVENT_KEY$5 = `.${DATA_KEY$5}`; + const EVENT_FOCUSIN$2 = `focusin${EVENT_KEY$5}`; + const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$5}`; + const TAB_KEY = 'Tab'; + const TAB_NAV_FORWARD = 'forward'; + const TAB_NAV_BACKWARD = 'backward'; + const Default$7 = { + autofocus: true, + trapElement: null // The element to trap focus inside of + }; + const DefaultType$7 = { + autofocus: 'boolean', + trapElement: 'element' + }; + + /** + * Class definition + */ + + class FocusTrap extends Config { + constructor(config) { + super(); + this._config = this._getConfig(config); + this._isActive = false; + this._lastTabNavDirection = null; + } + + // Getters + static get Default() { + return Default$7; + } + static get DefaultType() { + return DefaultType$7; + } + static get NAME() { + return NAME$8; + } + + // Public + activate() { + if (this._isActive) { + return; + } + if (this._config.autofocus) { + this._config.trapElement.focus(); + } + EventHandler.off(document, EVENT_KEY$5); // guard against infinite focus loop + EventHandler.on(document, EVENT_FOCUSIN$2, event => this._handleFocusin(event)); + EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event)); + this._isActive = true; + } + deactivate() { + if (!this._isActive) { + return; + } + this._isActive = false; + EventHandler.off(document, EVENT_KEY$5); + } + + // Private + _handleFocusin(event) { + const { + trapElement + } = this._config; + if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) { + return; + } + const elements = SelectorEngine.focusableChildren(trapElement); + if (elements.length === 0) { + trapElement.focus(); + } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) { + elements[elements.length - 1].focus(); + } else { + elements[0].focus(); + } + } + _handleKeydown(event) { + if (event.key !== TAB_KEY) { + return; + } + this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD; + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/scrollBar.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'; + const SELECTOR_STICKY_CONTENT = '.sticky-top'; + const PROPERTY_PADDING = 'padding-right'; + const PROPERTY_MARGIN = 'margin-right'; + + /** + * Class definition + */ + + class ScrollBarHelper { + constructor() { + this._element = document.body; + } + + // Public + getWidth() { + // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes + const documentWidth = document.documentElement.clientWidth; + return Math.abs(window.innerWidth - documentWidth); + } + hide() { + const width = this.getWidth(); + this._disableOverFlow(); + // give padding to element to balance the hidden scrollbar width + this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width); + // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth + this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width); + this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width); + } + reset() { + this._resetElementAttributes(this._element, 'overflow'); + this._resetElementAttributes(this._element, PROPERTY_PADDING); + this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING); + this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN); + } + isOverflowing() { + return this.getWidth() > 0; + } + + // Private + _disableOverFlow() { + this._saveInitialAttribute(this._element, 'overflow'); + this._element.style.overflow = 'hidden'; + } + _setElementAttributes(selector, styleProperty, callback) { + const scrollbarWidth = this.getWidth(); + const manipulationCallBack = element => { + if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) { + return; + } + this._saveInitialAttribute(element, styleProperty); + const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty); + element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`); + }; + this._applyManipulationCallback(selector, manipulationCallBack); + } + _saveInitialAttribute(element, styleProperty) { + const actualValue = element.style.getPropertyValue(styleProperty); + if (actualValue) { + Manipulator.setDataAttribute(element, styleProperty, actualValue); + } + } + _resetElementAttributes(selector, styleProperty) { + const manipulationCallBack = element => { + const value = Manipulator.getDataAttribute(element, styleProperty); + // We only want to remove the property if the value is `null`; the value can also be zero + if (value === null) { + element.style.removeProperty(styleProperty); + return; + } + Manipulator.removeDataAttribute(element, styleProperty); + element.style.setProperty(styleProperty, value); + }; + this._applyManipulationCallback(selector, manipulationCallBack); + } + _applyManipulationCallback(selector, callBack) { + if (isElement(selector)) { + callBack(selector); + return; + } + for (const sel of SelectorEngine.find(selector, this._element)) { + callBack(sel); + } + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap modal.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$7 = 'modal'; + const DATA_KEY$4 = 'bs.modal'; + const EVENT_KEY$4 = `.${DATA_KEY$4}`; + const DATA_API_KEY$2 = '.data-api'; + const ESCAPE_KEY$1 = 'Escape'; + const EVENT_HIDE$4 = `hide${EVENT_KEY$4}`; + const EVENT_HIDE_PREVENTED$1 = `hidePrevented${EVENT_KEY$4}`; + const EVENT_HIDDEN$4 = `hidden${EVENT_KEY$4}`; + const EVENT_SHOW$4 = `show${EVENT_KEY$4}`; + const EVENT_SHOWN$4 = `shown${EVENT_KEY$4}`; + const EVENT_RESIZE$1 = `resize${EVENT_KEY$4}`; + const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY$4}`; + const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY$4}`; + const EVENT_KEYDOWN_DISMISS$1 = `keydown.dismiss${EVENT_KEY$4}`; + const EVENT_CLICK_DATA_API$2 = `click${EVENT_KEY$4}${DATA_API_KEY$2}`; + const CLASS_NAME_OPEN = 'modal-open'; + const CLASS_NAME_FADE$3 = 'fade'; + const CLASS_NAME_SHOW$4 = 'show'; + const CLASS_NAME_STATIC = 'modal-static'; + const OPEN_SELECTOR$1 = '.modal.show'; + const SELECTOR_DIALOG = '.modal-dialog'; + const SELECTOR_MODAL_BODY = '.modal-body'; + const SELECTOR_DATA_TOGGLE$2 = '[data-bs-toggle="modal"]'; + const Default$6 = { + backdrop: true, + focus: true, + keyboard: true + }; + const DefaultType$6 = { + backdrop: '(boolean|string)', + focus: 'boolean', + keyboard: 'boolean' + }; + + /** + * Class definition + */ + + class Modal extends BaseComponent { + constructor(element, config) { + super(element, config); + this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element); + this._backdrop = this._initializeBackDrop(); + this._focustrap = this._initializeFocusTrap(); + this._isShown = false; + this._isTransitioning = false; + this._scrollBar = new ScrollBarHelper(); + this._addEventListeners(); + } + + // Getters + static get Default() { + return Default$6; + } + static get DefaultType() { + return DefaultType$6; + } + static get NAME() { + return NAME$7; + } + + // Public + toggle(relatedTarget) { + return this._isShown ? this.hide() : this.show(relatedTarget); + } + show(relatedTarget) { + if (this._isShown || this._isTransitioning) { + return; + } + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$4, { + relatedTarget + }); + if (showEvent.defaultPrevented) { + return; + } + this._isShown = true; + this._isTransitioning = true; + this._scrollBar.hide(); + document.body.classList.add(CLASS_NAME_OPEN); + this._adjustDialog(); + this._backdrop.show(() => this._showElement(relatedTarget)); + } + hide() { + if (!this._isShown || this._isTransitioning) { + return; + } + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$4); + if (hideEvent.defaultPrevented) { + return; + } + this._isShown = false; + this._isTransitioning = true; + this._focustrap.deactivate(); + this._element.classList.remove(CLASS_NAME_SHOW$4); + this._queueCallback(() => this._hideModal(), this._element, this._isAnimated()); + } + dispose() { + EventHandler.off(window, EVENT_KEY$4); + EventHandler.off(this._dialog, EVENT_KEY$4); + this._backdrop.dispose(); + this._focustrap.deactivate(); + super.dispose(); + } + handleUpdate() { + this._adjustDialog(); + } + + // Private + _initializeBackDrop() { + return new Backdrop({ + isVisible: Boolean(this._config.backdrop), + // 'static' option will be translated to true, and booleans will keep their value, + isAnimated: this._isAnimated() + }); + } + _initializeFocusTrap() { + return new FocusTrap({ + trapElement: this._element + }); + } + _showElement(relatedTarget) { + // try to append dynamic modal + if (!document.body.contains(this._element)) { + document.body.append(this._element); + } + this._element.style.display = 'block'; + this._element.removeAttribute('aria-hidden'); + this._element.setAttribute('aria-modal', true); + this._element.setAttribute('role', 'dialog'); + this._element.scrollTop = 0; + const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog); + if (modalBody) { + modalBody.scrollTop = 0; + } + reflow(this._element); + this._element.classList.add(CLASS_NAME_SHOW$4); + const transitionComplete = () => { + if (this._config.focus) { + this._focustrap.activate(); + } + this._isTransitioning = false; + EventHandler.trigger(this._element, EVENT_SHOWN$4, { + relatedTarget + }); + }; + this._queueCallback(transitionComplete, this._dialog, this._isAnimated()); + } + _addEventListeners() { + EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS$1, event => { + if (event.key !== ESCAPE_KEY$1) { + return; + } + if (this._config.keyboard) { + this.hide(); + return; + } + this._triggerBackdropTransition(); + }); + EventHandler.on(window, EVENT_RESIZE$1, () => { + if (this._isShown && !this._isTransitioning) { + this._adjustDialog(); + } + }); + EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => { + // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks + EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => { + if (this._element !== event.target || this._element !== event2.target) { + return; + } + if (this._config.backdrop === 'static') { + this._triggerBackdropTransition(); + return; + } + if (this._config.backdrop) { + this.hide(); + } + }); + }); + } + _hideModal() { + this._element.style.display = 'none'; + this._element.setAttribute('aria-hidden', true); + this._element.removeAttribute('aria-modal'); + this._element.removeAttribute('role'); + this._isTransitioning = false; + this._backdrop.hide(() => { + document.body.classList.remove(CLASS_NAME_OPEN); + this._resetAdjustments(); + this._scrollBar.reset(); + EventHandler.trigger(this._element, EVENT_HIDDEN$4); + }); + } + _isAnimated() { + return this._element.classList.contains(CLASS_NAME_FADE$3); + } + _triggerBackdropTransition() { + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED$1); + if (hideEvent.defaultPrevented) { + return; + } + const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; + const initialOverflowY = this._element.style.overflowY; + // return if the following background transition hasn't yet completed + if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) { + return; + } + if (!isModalOverflowing) { + this._element.style.overflowY = 'hidden'; + } + this._element.classList.add(CLASS_NAME_STATIC); + this._queueCallback(() => { + this._element.classList.remove(CLASS_NAME_STATIC); + this._queueCallback(() => { + this._element.style.overflowY = initialOverflowY; + }, this._dialog); + }, this._dialog); + this._element.focus(); + } + + /** + * The following methods are used to handle overflowing modals + */ + + _adjustDialog() { + const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; + const scrollbarWidth = this._scrollBar.getWidth(); + const isBodyOverflowing = scrollbarWidth > 0; + if (isBodyOverflowing && !isModalOverflowing) { + const property = isRTL() ? 'paddingLeft' : 'paddingRight'; + this._element.style[property] = `${scrollbarWidth}px`; + } + if (!isBodyOverflowing && isModalOverflowing) { + const property = isRTL() ? 'paddingRight' : 'paddingLeft'; + this._element.style[property] = `${scrollbarWidth}px`; + } + } + _resetAdjustments() { + this._element.style.paddingLeft = ''; + this._element.style.paddingRight = ''; + } + + // Static + static jQueryInterface(config, relatedTarget) { + return this.each(function () { + const data = Modal.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](relatedTarget); + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$2, function (event) { + const target = SelectorEngine.getElementFromSelector(this); + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + EventHandler.one(target, EVENT_SHOW$4, showEvent => { + if (showEvent.defaultPrevented) { + // only register focus restorer if modal will actually get shown + return; + } + EventHandler.one(target, EVENT_HIDDEN$4, () => { + if (isVisible(this)) { + this.focus(); + } + }); + }); + + // avoid conflict when clicking modal toggler while another one is open + const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR$1); + if (alreadyOpen) { + Modal.getInstance(alreadyOpen).hide(); + } + const data = Modal.getOrCreateInstance(target); + data.toggle(this); + }); + enableDismissTrigger(Modal); + + /** + * jQuery + */ + + defineJQueryPlugin(Modal); + + /** + * -------------------------------------------------------------------------- + * Bootstrap offcanvas.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$6 = 'offcanvas'; + const DATA_KEY$3 = 'bs.offcanvas'; + const EVENT_KEY$3 = `.${DATA_KEY$3}`; + const DATA_API_KEY$1 = '.data-api'; + const EVENT_LOAD_DATA_API$2 = `load${EVENT_KEY$3}${DATA_API_KEY$1}`; + const ESCAPE_KEY = 'Escape'; + const CLASS_NAME_SHOW$3 = 'show'; + const CLASS_NAME_SHOWING$1 = 'showing'; + const CLASS_NAME_HIDING = 'hiding'; + const CLASS_NAME_BACKDROP = 'offcanvas-backdrop'; + const OPEN_SELECTOR = '.offcanvas.show'; + const EVENT_SHOW$3 = `show${EVENT_KEY$3}`; + const EVENT_SHOWN$3 = `shown${EVENT_KEY$3}`; + const EVENT_HIDE$3 = `hide${EVENT_KEY$3}`; + const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY$3}`; + const EVENT_HIDDEN$3 = `hidden${EVENT_KEY$3}`; + const EVENT_RESIZE = `resize${EVENT_KEY$3}`; + const EVENT_CLICK_DATA_API$1 = `click${EVENT_KEY$3}${DATA_API_KEY$1}`; + const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY$3}`; + const SELECTOR_DATA_TOGGLE$1 = '[data-bs-toggle="offcanvas"]'; + const Default$5 = { + backdrop: true, + keyboard: true, + scroll: false + }; + const DefaultType$5 = { + backdrop: '(boolean|string)', + keyboard: 'boolean', + scroll: 'boolean' + }; + + /** + * Class definition + */ + + class Offcanvas extends BaseComponent { + constructor(element, config) { + super(element, config); + this._isShown = false; + this._backdrop = this._initializeBackDrop(); + this._focustrap = this._initializeFocusTrap(); + this._addEventListeners(); + } + + // Getters + static get Default() { + return Default$5; + } + static get DefaultType() { + return DefaultType$5; + } + static get NAME() { + return NAME$6; + } + + // Public + toggle(relatedTarget) { + return this._isShown ? this.hide() : this.show(relatedTarget); + } + show(relatedTarget) { + if (this._isShown) { + return; + } + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$3, { + relatedTarget + }); + if (showEvent.defaultPrevented) { + return; + } + this._isShown = true; + this._backdrop.show(); + if (!this._config.scroll) { + new ScrollBarHelper().hide(); + } + this._element.setAttribute('aria-modal', true); + this._element.setAttribute('role', 'dialog'); + this._element.classList.add(CLASS_NAME_SHOWING$1); + const completeCallBack = () => { + if (!this._config.scroll || this._config.backdrop) { + this._focustrap.activate(); + } + this._element.classList.add(CLASS_NAME_SHOW$3); + this._element.classList.remove(CLASS_NAME_SHOWING$1); + EventHandler.trigger(this._element, EVENT_SHOWN$3, { + relatedTarget + }); + }; + this._queueCallback(completeCallBack, this._element, true); + } + hide() { + if (!this._isShown) { + return; + } + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$3); + if (hideEvent.defaultPrevented) { + return; + } + this._focustrap.deactivate(); + this._element.blur(); + this._isShown = false; + this._element.classList.add(CLASS_NAME_HIDING); + this._backdrop.hide(); + const completeCallback = () => { + this._element.classList.remove(CLASS_NAME_SHOW$3, CLASS_NAME_HIDING); + this._element.removeAttribute('aria-modal'); + this._element.removeAttribute('role'); + if (!this._config.scroll) { + new ScrollBarHelper().reset(); + } + EventHandler.trigger(this._element, EVENT_HIDDEN$3); + }; + this._queueCallback(completeCallback, this._element, true); + } + dispose() { + this._backdrop.dispose(); + this._focustrap.deactivate(); + super.dispose(); + } + + // Private + _initializeBackDrop() { + const clickCallback = () => { + if (this._config.backdrop === 'static') { + EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED); + return; + } + this.hide(); + }; + + // 'static' option will be translated to true, and booleans will keep their value + const isVisible = Boolean(this._config.backdrop); + return new Backdrop({ + className: CLASS_NAME_BACKDROP, + isVisible, + isAnimated: true, + rootElement: this._element.parentNode, + clickCallback: isVisible ? clickCallback : null + }); + } + _initializeFocusTrap() { + return new FocusTrap({ + trapElement: this._element + }); + } + _addEventListeners() { + EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => { + if (event.key !== ESCAPE_KEY) { + return; + } + if (this._config.keyboard) { + this.hide(); + return; + } + EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED); + }); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Offcanvas.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + data[config](this); + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE$1, function (event) { + const target = SelectorEngine.getElementFromSelector(this); + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + if (isDisabled(this)) { + return; + } + EventHandler.one(target, EVENT_HIDDEN$3, () => { + // focus on trigger when it is closed + if (isVisible(this)) { + this.focus(); + } + }); + + // avoid conflict when clicking a toggler of an offcanvas, while another is open + const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR); + if (alreadyOpen && alreadyOpen !== target) { + Offcanvas.getInstance(alreadyOpen).hide(); + } + const data = Offcanvas.getOrCreateInstance(target); + data.toggle(this); + }); + EventHandler.on(window, EVENT_LOAD_DATA_API$2, () => { + for (const selector of SelectorEngine.find(OPEN_SELECTOR)) { + Offcanvas.getOrCreateInstance(selector).show(); + } + }); + EventHandler.on(window, EVENT_RESIZE, () => { + for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) { + if (getComputedStyle(element).position !== 'fixed') { + Offcanvas.getOrCreateInstance(element).hide(); + } + } + }); + enableDismissTrigger(Offcanvas); + + /** + * jQuery + */ + + defineJQueryPlugin(Offcanvas); + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/sanitizer.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + // js-docs-start allow-list + const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i; + const DefaultAllowlist = { + // Global attributes allowed on any supplied element below. + '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN], + a: ['target', 'href', 'title', 'rel'], + area: [], + b: [], + br: [], + col: [], + code: [], + dd: [], + div: [], + dl: [], + dt: [], + em: [], + hr: [], + h1: [], + h2: [], + h3: [], + h4: [], + h5: [], + h6: [], + i: [], + img: ['src', 'srcset', 'alt', 'title', 'width', 'height'], + li: [], + ol: [], + p: [], + pre: [], + s: [], + small: [], + span: [], + sub: [], + sup: [], + strong: [], + u: [], + ul: [] + }; + // js-docs-end allow-list + + const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']); + + /** + * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation + * contexts. + * + * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38 + */ + // eslint-disable-next-line unicorn/better-regex + const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i; + const allowedAttribute = (attribute, allowedAttributeList) => { + const attributeName = attribute.nodeName.toLowerCase(); + if (allowedAttributeList.includes(attributeName)) { + if (uriAttributes.has(attributeName)) { + return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue)); + } + return true; + } + + // Check if a regular expression validates the attribute. + return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName)); + }; + function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) { + if (!unsafeHtml.length) { + return unsafeHtml; + } + if (sanitizeFunction && typeof sanitizeFunction === 'function') { + return sanitizeFunction(unsafeHtml); + } + const domParser = new window.DOMParser(); + const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html'); + const elements = [].concat(...createdDocument.body.querySelectorAll('*')); + for (const element of elements) { + const elementName = element.nodeName.toLowerCase(); + if (!Object.keys(allowList).includes(elementName)) { + element.remove(); + continue; + } + const attributeList = [].concat(...element.attributes); + const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []); + for (const attribute of attributeList) { + if (!allowedAttribute(attribute, allowedAttributes)) { + element.removeAttribute(attribute.nodeName); + } + } + } + return createdDocument.body.innerHTML; + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/template-factory.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$5 = 'TemplateFactory'; + const Default$4 = { + allowList: DefaultAllowlist, + content: {}, + // { selector : text , selector2 : text2 , } + extraClass: '', + html: false, + sanitize: true, + sanitizeFn: null, + template: '<div></div>' + }; + const DefaultType$4 = { + allowList: 'object', + content: 'object', + extraClass: '(string|function)', + html: 'boolean', + sanitize: 'boolean', + sanitizeFn: '(null|function)', + template: 'string' + }; + const DefaultContentType = { + entry: '(string|element|function|null)', + selector: '(string|element)' + }; + + /** + * Class definition + */ + + class TemplateFactory extends Config { + constructor(config) { + super(); + this._config = this._getConfig(config); + } + + // Getters + static get Default() { + return Default$4; + } + static get DefaultType() { + return DefaultType$4; + } + static get NAME() { + return NAME$5; + } + + // Public + getContent() { + return Object.values(this._config.content).map(config => this._resolvePossibleFunction(config)).filter(Boolean); + } + hasContent() { + return this.getContent().length > 0; + } + changeContent(content) { + this._checkContent(content); + this._config.content = { + ...this._config.content, + ...content + }; + return this; + } + toHtml() { + const templateWrapper = document.createElement('div'); + templateWrapper.innerHTML = this._maybeSanitize(this._config.template); + for (const [selector, text] of Object.entries(this._config.content)) { + this._setContent(templateWrapper, text, selector); + } + const template = templateWrapper.children[0]; + const extraClass = this._resolvePossibleFunction(this._config.extraClass); + if (extraClass) { + template.classList.add(...extraClass.split(' ')); + } + return template; + } + + // Private + _typeCheckConfig(config) { + super._typeCheckConfig(config); + this._checkContent(config.content); + } + _checkContent(arg) { + for (const [selector, content] of Object.entries(arg)) { + super._typeCheckConfig({ + selector, + entry: content + }, DefaultContentType); + } + } + _setContent(template, content, selector) { + const templateElement = SelectorEngine.findOne(selector, template); + if (!templateElement) { + return; + } + content = this._resolvePossibleFunction(content); + if (!content) { + templateElement.remove(); + return; + } + if (isElement(content)) { + this._putElementInTemplate(getElement(content), templateElement); + return; + } + if (this._config.html) { + templateElement.innerHTML = this._maybeSanitize(content); + return; + } + templateElement.textContent = content; + } + _maybeSanitize(arg) { + return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg; + } + _resolvePossibleFunction(arg) { + return execute(arg, [this]); + } + _putElementInTemplate(element, templateElement) { + if (this._config.html) { + templateElement.innerHTML = ''; + templateElement.append(element); + return; + } + templateElement.textContent = element.textContent; + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap tooltip.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$4 = 'tooltip'; + const DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']); + const CLASS_NAME_FADE$2 = 'fade'; + const CLASS_NAME_MODAL = 'modal'; + const CLASS_NAME_SHOW$2 = 'show'; + const SELECTOR_TOOLTIP_INNER = '.tooltip-inner'; + const SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`; + const EVENT_MODAL_HIDE = 'hide.bs.modal'; + const TRIGGER_HOVER = 'hover'; + const TRIGGER_FOCUS = 'focus'; + const TRIGGER_CLICK = 'click'; + const TRIGGER_MANUAL = 'manual'; + const EVENT_HIDE$2 = 'hide'; + const EVENT_HIDDEN$2 = 'hidden'; + const EVENT_SHOW$2 = 'show'; + const EVENT_SHOWN$2 = 'shown'; + const EVENT_INSERTED = 'inserted'; + const EVENT_CLICK$1 = 'click'; + const EVENT_FOCUSIN$1 = 'focusin'; + const EVENT_FOCUSOUT$1 = 'focusout'; + const EVENT_MOUSEENTER = 'mouseenter'; + const EVENT_MOUSELEAVE = 'mouseleave'; + const AttachmentMap = { + AUTO: 'auto', + TOP: 'top', + RIGHT: isRTL() ? 'left' : 'right', + BOTTOM: 'bottom', + LEFT: isRTL() ? 'right' : 'left' + }; + const Default$3 = { + allowList: DefaultAllowlist, + animation: true, + boundary: 'clippingParents', + container: false, + customClass: '', + delay: 0, + fallbackPlacements: ['top', 'right', 'bottom', 'left'], + html: false, + offset: [0, 6], + placement: 'top', + popperConfig: null, + sanitize: true, + sanitizeFn: null, + selector: false, + template: '<div class="tooltip" role="tooltip">' + '<div class="tooltip-arrow"></div>' + '<div class="tooltip-inner"></div>' + '</div>', + title: '', + trigger: 'hover focus' + }; + const DefaultType$3 = { + allowList: 'object', + animation: 'boolean', + boundary: '(string|element)', + container: '(string|element|boolean)', + customClass: '(string|function)', + delay: '(number|object)', + fallbackPlacements: 'array', + html: 'boolean', + offset: '(array|string|function)', + placement: '(string|function)', + popperConfig: '(null|object|function)', + sanitize: 'boolean', + sanitizeFn: '(null|function)', + selector: '(string|boolean)', + template: 'string', + title: '(string|element|function)', + trigger: 'string' + }; + + /** + * Class definition + */ + + class Tooltip extends BaseComponent { + constructor(element, config) { + if (typeof Popper__namespace === 'undefined') { + throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)'); + } + super(element, config); + + // Private + this._isEnabled = true; + this._timeout = 0; + this._isHovered = null; + this._activeTrigger = {}; + this._popper = null; + this._templateFactory = null; + this._newContent = null; + + // Protected + this.tip = null; + this._setListeners(); + if (!this._config.selector) { + this._fixTitle(); + } + } + + // Getters + static get Default() { + return Default$3; + } + static get DefaultType() { + return DefaultType$3; + } + static get NAME() { + return NAME$4; + } + + // Public + enable() { + this._isEnabled = true; + } + disable() { + this._isEnabled = false; + } + toggleEnabled() { + this._isEnabled = !this._isEnabled; + } + toggle() { + if (!this._isEnabled) { + return; + } + this._activeTrigger.click = !this._activeTrigger.click; + if (this._isShown()) { + this._leave(); + return; + } + this._enter(); + } + dispose() { + clearTimeout(this._timeout); + EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); + if (this._element.getAttribute('data-bs-original-title')) { + this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title')); + } + this._disposePopper(); + super.dispose(); + } + show() { + if (this._element.style.display === 'none') { + throw new Error('Please use show on visible elements'); + } + if (!(this._isWithContent() && this._isEnabled)) { + return; + } + const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW$2)); + const shadowRoot = findShadowRoot(this._element); + const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element); + if (showEvent.defaultPrevented || !isInTheDom) { + return; + } + + // TODO: v6 remove this or make it optional + this._disposePopper(); + const tip = this._getTipElement(); + this._element.setAttribute('aria-describedby', tip.getAttribute('id')); + const { + container + } = this._config; + if (!this._element.ownerDocument.documentElement.contains(this.tip)) { + container.append(tip); + EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED)); + } + this._popper = this._createPopper(tip); + tip.classList.add(CLASS_NAME_SHOW$2); + + // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + if ('ontouchstart' in document.documentElement) { + for (const element of [].concat(...document.body.children)) { + EventHandler.on(element, 'mouseover', noop); + } + } + const complete = () => { + EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN$2)); + if (this._isHovered === false) { + this._leave(); + } + this._isHovered = false; + }; + this._queueCallback(complete, this.tip, this._isAnimated()); + } + hide() { + if (!this._isShown()) { + return; + } + const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE$2)); + if (hideEvent.defaultPrevented) { + return; + } + const tip = this._getTipElement(); + tip.classList.remove(CLASS_NAME_SHOW$2); + + // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + if ('ontouchstart' in document.documentElement) { + for (const element of [].concat(...document.body.children)) { + EventHandler.off(element, 'mouseover', noop); + } + } + this._activeTrigger[TRIGGER_CLICK] = false; + this._activeTrigger[TRIGGER_FOCUS] = false; + this._activeTrigger[TRIGGER_HOVER] = false; + this._isHovered = null; // it is a trick to support manual triggering + + const complete = () => { + if (this._isWithActiveTrigger()) { + return; + } + if (!this._isHovered) { + this._disposePopper(); + } + this._element.removeAttribute('aria-describedby'); + EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN$2)); + }; + this._queueCallback(complete, this.tip, this._isAnimated()); + } + update() { + if (this._popper) { + this._popper.update(); + } + } + + // Protected + _isWithContent() { + return Boolean(this._getTitle()); + } + _getTipElement() { + if (!this.tip) { + this.tip = this._createTipElement(this._newContent || this._getContentForTemplate()); + } + return this.tip; + } + _createTipElement(content) { + const tip = this._getTemplateFactory(content).toHtml(); + + // TODO: remove this check in v6 + if (!tip) { + return null; + } + tip.classList.remove(CLASS_NAME_FADE$2, CLASS_NAME_SHOW$2); + // TODO: v6 the following can be achieved with CSS only + tip.classList.add(`bs-${this.constructor.NAME}-auto`); + const tipId = getUID(this.constructor.NAME).toString(); + tip.setAttribute('id', tipId); + if (this._isAnimated()) { + tip.classList.add(CLASS_NAME_FADE$2); + } + return tip; + } + setContent(content) { + this._newContent = content; + if (this._isShown()) { + this._disposePopper(); + this.show(); + } + } + _getTemplateFactory(content) { + if (this._templateFactory) { + this._templateFactory.changeContent(content); + } else { + this._templateFactory = new TemplateFactory({ + ...this._config, + // the `content` var has to be after `this._config` + // to override config.content in case of popover + content, + extraClass: this._resolvePossibleFunction(this._config.customClass) + }); + } + return this._templateFactory; + } + _getContentForTemplate() { + return { + [SELECTOR_TOOLTIP_INNER]: this._getTitle() + }; + } + _getTitle() { + return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title'); + } + + // Private + _initializeOnDelegatedTarget(event) { + return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig()); + } + _isAnimated() { + return this._config.animation || this.tip && this.tip.classList.contains(CLASS_NAME_FADE$2); + } + _isShown() { + return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW$2); + } + _createPopper(tip) { + const placement = execute(this._config.placement, [this, tip, this._element]); + const attachment = AttachmentMap[placement.toUpperCase()]; + return Popper__namespace.createPopper(this._element, tip, this._getPopperConfig(attachment)); + } + _getOffset() { + const { + offset + } = this._config; + if (typeof offset === 'string') { + return offset.split(',').map(value => Number.parseInt(value, 10)); + } + if (typeof offset === 'function') { + return popperData => offset(popperData, this._element); + } + return offset; + } + _resolvePossibleFunction(arg) { + return execute(arg, [this._element]); + } + _getPopperConfig(attachment) { + const defaultBsPopperConfig = { + placement: attachment, + modifiers: [{ + name: 'flip', + options: { + fallbackPlacements: this._config.fallbackPlacements + } + }, { + name: 'offset', + options: { + offset: this._getOffset() + } + }, { + name: 'preventOverflow', + options: { + boundary: this._config.boundary + } + }, { + name: 'arrow', + options: { + element: `.${this.constructor.NAME}-arrow` + } + }, { + name: 'preSetPlacement', + enabled: true, + phase: 'beforeMain', + fn: data => { + // Pre-set Popper's placement attribute in order to read the arrow sizes properly. + // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement + this._getTipElement().setAttribute('data-popper-placement', data.state.placement); + } + }] + }; + return { + ...defaultBsPopperConfig, + ...execute(this._config.popperConfig, [defaultBsPopperConfig]) + }; + } + _setListeners() { + const triggers = this._config.trigger.split(' '); + for (const trigger of triggers) { + if (trigger === 'click') { + EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK$1), this._config.selector, event => { + const context = this._initializeOnDelegatedTarget(event); + context.toggle(); + }); + } else if (trigger !== TRIGGER_MANUAL) { + const eventIn = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSEENTER) : this.constructor.eventName(EVENT_FOCUSIN$1); + const eventOut = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSELEAVE) : this.constructor.eventName(EVENT_FOCUSOUT$1); + EventHandler.on(this._element, eventIn, this._config.selector, event => { + const context = this._initializeOnDelegatedTarget(event); + context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true; + context._enter(); + }); + EventHandler.on(this._element, eventOut, this._config.selector, event => { + const context = this._initializeOnDelegatedTarget(event); + context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget); + context._leave(); + }); + } + } + this._hideModalHandler = () => { + if (this._element) { + this.hide(); + } + }; + EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); + } + _fixTitle() { + const title = this._element.getAttribute('title'); + if (!title) { + return; + } + if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) { + this._element.setAttribute('aria-label', title); + } + this._element.setAttribute('data-bs-original-title', title); // DO NOT USE IT. Is only for backwards compatibility + this._element.removeAttribute('title'); + } + _enter() { + if (this._isShown() || this._isHovered) { + this._isHovered = true; + return; + } + this._isHovered = true; + this._setTimeout(() => { + if (this._isHovered) { + this.show(); + } + }, this._config.delay.show); + } + _leave() { + if (this._isWithActiveTrigger()) { + return; + } + this._isHovered = false; + this._setTimeout(() => { + if (!this._isHovered) { + this.hide(); + } + }, this._config.delay.hide); + } + _setTimeout(handler, timeout) { + clearTimeout(this._timeout); + this._timeout = setTimeout(handler, timeout); + } + _isWithActiveTrigger() { + return Object.values(this._activeTrigger).includes(true); + } + _getConfig(config) { + const dataAttributes = Manipulator.getDataAttributes(this._element); + for (const dataAttribute of Object.keys(dataAttributes)) { + if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) { + delete dataAttributes[dataAttribute]; + } + } + config = { + ...dataAttributes, + ...(typeof config === 'object' && config ? config : {}) + }; + config = this._mergeConfigObj(config); + config = this._configAfterMerge(config); + this._typeCheckConfig(config); + return config; + } + _configAfterMerge(config) { + config.container = config.container === false ? document.body : getElement(config.container); + if (typeof config.delay === 'number') { + config.delay = { + show: config.delay, + hide: config.delay + }; + } + if (typeof config.title === 'number') { + config.title = config.title.toString(); + } + if (typeof config.content === 'number') { + config.content = config.content.toString(); + } + return config; + } + _getDelegateConfig() { + const config = {}; + for (const [key, value] of Object.entries(this._config)) { + if (this.constructor.Default[key] !== value) { + config[key] = value; + } + } + config.selector = false; + config.trigger = 'manual'; + + // In the future can be replaced with: + // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]]) + // `Object.fromEntries(keysWithDifferentValues)` + return config; + } + _disposePopper() { + if (this._popper) { + this._popper.destroy(); + this._popper = null; + } + if (this.tip) { + this.tip.remove(); + this.tip = null; + } + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Tooltip.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + }); + } + } + + /** + * jQuery + */ + + defineJQueryPlugin(Tooltip); + + /** + * -------------------------------------------------------------------------- + * Bootstrap popover.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$3 = 'popover'; + const SELECTOR_TITLE = '.popover-header'; + const SELECTOR_CONTENT = '.popover-body'; + const Default$2 = { + ...Tooltip.Default, + content: '', + offset: [0, 8], + placement: 'right', + template: '<div class="popover" role="tooltip">' + '<div class="popover-arrow"></div>' + '<h3 class="popover-header"></h3>' + '<div class="popover-body"></div>' + '</div>', + trigger: 'click' + }; + const DefaultType$2 = { + ...Tooltip.DefaultType, + content: '(null|string|element|function)' + }; + + /** + * Class definition + */ + + class Popover extends Tooltip { + // Getters + static get Default() { + return Default$2; + } + static get DefaultType() { + return DefaultType$2; + } + static get NAME() { + return NAME$3; + } + + // Overrides + _isWithContent() { + return this._getTitle() || this._getContent(); + } + + // Private + _getContentForTemplate() { + return { + [SELECTOR_TITLE]: this._getTitle(), + [SELECTOR_CONTENT]: this._getContent() + }; + } + _getContent() { + return this._resolvePossibleFunction(this._config.content); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Popover.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + }); + } + } + + /** + * jQuery + */ + + defineJQueryPlugin(Popover); + + /** + * -------------------------------------------------------------------------- + * Bootstrap scrollspy.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$2 = 'scrollspy'; + const DATA_KEY$2 = 'bs.scrollspy'; + const EVENT_KEY$2 = `.${DATA_KEY$2}`; + const DATA_API_KEY = '.data-api'; + const EVENT_ACTIVATE = `activate${EVENT_KEY$2}`; + const EVENT_CLICK = `click${EVENT_KEY$2}`; + const EVENT_LOAD_DATA_API$1 = `load${EVENT_KEY$2}${DATA_API_KEY}`; + const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'; + const CLASS_NAME_ACTIVE$1 = 'active'; + const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]'; + const SELECTOR_TARGET_LINKS = '[href]'; + const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'; + const SELECTOR_NAV_LINKS = '.nav-link'; + const SELECTOR_NAV_ITEMS = '.nav-item'; + const SELECTOR_LIST_ITEMS = '.list-group-item'; + const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`; + const SELECTOR_DROPDOWN = '.dropdown'; + const SELECTOR_DROPDOWN_TOGGLE$1 = '.dropdown-toggle'; + const Default$1 = { + offset: null, + // TODO: v6 @deprecated, keep it for backwards compatibility reasons + rootMargin: '0px 0px -25%', + smoothScroll: false, + target: null, + threshold: [0.1, 0.5, 1] + }; + const DefaultType$1 = { + offset: '(number|null)', + // TODO v6 @deprecated, keep it for backwards compatibility reasons + rootMargin: 'string', + smoothScroll: 'boolean', + target: 'element', + threshold: 'array' + }; + + /** + * Class definition + */ + + class ScrollSpy extends BaseComponent { + constructor(element, config) { + super(element, config); + + // this._element is the observablesContainer and config.target the menu links wrapper + this._targetLinks = new Map(); + this._observableSections = new Map(); + this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element; + this._activeTarget = null; + this._observer = null; + this._previousScrollData = { + visibleEntryTop: 0, + parentScrollTop: 0 + }; + this.refresh(); // initialize + } + + // Getters + static get Default() { + return Default$1; + } + static get DefaultType() { + return DefaultType$1; + } + static get NAME() { + return NAME$2; + } + + // Public + refresh() { + this._initializeTargetsAndObservables(); + this._maybeEnableSmoothScroll(); + if (this._observer) { + this._observer.disconnect(); + } else { + this._observer = this._getNewObserver(); + } + for (const section of this._observableSections.values()) { + this._observer.observe(section); + } + } + dispose() { + this._observer.disconnect(); + super.dispose(); + } + + // Private + _configAfterMerge(config) { + // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case + config.target = getElement(config.target) || document.body; + + // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only + config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin; + if (typeof config.threshold === 'string') { + config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value)); + } + return config; + } + _maybeEnableSmoothScroll() { + if (!this._config.smoothScroll) { + return; + } + + // unregister any previous listeners + EventHandler.off(this._config.target, EVENT_CLICK); + EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => { + const observableSection = this._observableSections.get(event.target.hash); + if (observableSection) { + event.preventDefault(); + const root = this._rootElement || window; + const height = observableSection.offsetTop - this._element.offsetTop; + if (root.scrollTo) { + root.scrollTo({ + top: height, + behavior: 'smooth' + }); + return; + } + + // Chrome 60 doesn't support `scrollTo` + root.scrollTop = height; + } + }); + } + _getNewObserver() { + const options = { + root: this._rootElement, + threshold: this._config.threshold, + rootMargin: this._config.rootMargin + }; + return new IntersectionObserver(entries => this._observerCallback(entries), options); + } + + // The logic of selection + _observerCallback(entries) { + const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`); + const activate = entry => { + this._previousScrollData.visibleEntryTop = entry.target.offsetTop; + this._process(targetElement(entry)); + }; + const parentScrollTop = (this._rootElement || document.documentElement).scrollTop; + const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop; + this._previousScrollData.parentScrollTop = parentScrollTop; + for (const entry of entries) { + if (!entry.isIntersecting) { + this._activeTarget = null; + this._clearActiveClass(targetElement(entry)); + continue; + } + const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop; + // if we are scrolling down, pick the bigger offsetTop + if (userScrollsDown && entryIsLowerThanPrevious) { + activate(entry); + // if parent isn't scrolled, let's keep the first visible item, breaking the iteration + if (!parentScrollTop) { + return; + } + continue; + } + + // if we are scrolling up, pick the smallest offsetTop + if (!userScrollsDown && !entryIsLowerThanPrevious) { + activate(entry); + } + } + } + _initializeTargetsAndObservables() { + this._targetLinks = new Map(); + this._observableSections = new Map(); + const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target); + for (const anchor of targetLinks) { + // ensure that the anchor has an id and is not disabled + if (!anchor.hash || isDisabled(anchor)) { + continue; + } + const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element); + + // ensure that the observableSection exists & is visible + if (isVisible(observableSection)) { + this._targetLinks.set(decodeURI(anchor.hash), anchor); + this._observableSections.set(anchor.hash, observableSection); + } + } + } + _process(target) { + if (this._activeTarget === target) { + return; + } + this._clearActiveClass(this._config.target); + this._activeTarget = target; + target.classList.add(CLASS_NAME_ACTIVE$1); + this._activateParents(target); + EventHandler.trigger(this._element, EVENT_ACTIVATE, { + relatedTarget: target + }); + } + _activateParents(target) { + // Activate dropdown parents + if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) { + SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE$1, target.closest(SELECTOR_DROPDOWN)).classList.add(CLASS_NAME_ACTIVE$1); + return; + } + for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) { + // Set triggered links parents as active + // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor + for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) { + item.classList.add(CLASS_NAME_ACTIVE$1); + } + } + } + _clearActiveClass(parent) { + parent.classList.remove(CLASS_NAME_ACTIVE$1); + const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE$1}`, parent); + for (const node of activeNodes) { + node.classList.remove(CLASS_NAME_ACTIVE$1); + } + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = ScrollSpy.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(window, EVENT_LOAD_DATA_API$1, () => { + for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) { + ScrollSpy.getOrCreateInstance(spy); + } + }); + + /** + * jQuery + */ + + defineJQueryPlugin(ScrollSpy); + + /** + * -------------------------------------------------------------------------- + * Bootstrap tab.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$1 = 'tab'; + const DATA_KEY$1 = 'bs.tab'; + const EVENT_KEY$1 = `.${DATA_KEY$1}`; + const EVENT_HIDE$1 = `hide${EVENT_KEY$1}`; + const EVENT_HIDDEN$1 = `hidden${EVENT_KEY$1}`; + const EVENT_SHOW$1 = `show${EVENT_KEY$1}`; + const EVENT_SHOWN$1 = `shown${EVENT_KEY$1}`; + const EVENT_CLICK_DATA_API = `click${EVENT_KEY$1}`; + const EVENT_KEYDOWN = `keydown${EVENT_KEY$1}`; + const EVENT_LOAD_DATA_API = `load${EVENT_KEY$1}`; + const ARROW_LEFT_KEY = 'ArrowLeft'; + const ARROW_RIGHT_KEY = 'ArrowRight'; + const ARROW_UP_KEY = 'ArrowUp'; + const ARROW_DOWN_KEY = 'ArrowDown'; + const HOME_KEY = 'Home'; + const END_KEY = 'End'; + const CLASS_NAME_ACTIVE = 'active'; + const CLASS_NAME_FADE$1 = 'fade'; + const CLASS_NAME_SHOW$1 = 'show'; + const CLASS_DROPDOWN = 'dropdown'; + const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'; + const SELECTOR_DROPDOWN_MENU = '.dropdown-menu'; + const NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`; + const SELECTOR_TAB_PANEL = '.list-group, .nav, [role="tablist"]'; + const SELECTOR_OUTER = '.nav-item, .list-group-item'; + const SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role="tab"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`; + const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]'; // TODO: could only be `tab` in v6 + const SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`; + const SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle="tab"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="pill"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="list"]`; + + /** + * Class definition + */ + + class Tab extends BaseComponent { + constructor(element) { + super(element); + this._parent = this._element.closest(SELECTOR_TAB_PANEL); + if (!this._parent) { + return; + // TODO: should throw exception in v6 + // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`) + } + + // Set up initial aria attributes + this._setInitialAttributes(this._parent, this._getChildren()); + EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event)); + } + + // Getters + static get NAME() { + return NAME$1; + } + + // Public + show() { + // Shows this elem and deactivate the active sibling if exists + const innerElem = this._element; + if (this._elemIsActive(innerElem)) { + return; + } + + // Search for active tab on same parent to deactivate it + const active = this._getActiveElem(); + const hideEvent = active ? EventHandler.trigger(active, EVENT_HIDE$1, { + relatedTarget: innerElem + }) : null; + const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW$1, { + relatedTarget: active + }); + if (showEvent.defaultPrevented || hideEvent && hideEvent.defaultPrevented) { + return; + } + this._deactivate(active, innerElem); + this._activate(innerElem, active); + } + + // Private + _activate(element, relatedElem) { + if (!element) { + return; + } + element.classList.add(CLASS_NAME_ACTIVE); + this._activate(SelectorEngine.getElementFromSelector(element)); // Search and activate/show the proper section + + const complete = () => { + if (element.getAttribute('role') !== 'tab') { + element.classList.add(CLASS_NAME_SHOW$1); + return; + } + element.removeAttribute('tabindex'); + element.setAttribute('aria-selected', true); + this._toggleDropDown(element, true); + EventHandler.trigger(element, EVENT_SHOWN$1, { + relatedTarget: relatedElem + }); + }; + this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE$1)); + } + _deactivate(element, relatedElem) { + if (!element) { + return; + } + element.classList.remove(CLASS_NAME_ACTIVE); + element.blur(); + this._deactivate(SelectorEngine.getElementFromSelector(element)); // Search and deactivate the shown section too + + const complete = () => { + if (element.getAttribute('role') !== 'tab') { + element.classList.remove(CLASS_NAME_SHOW$1); + return; + } + element.setAttribute('aria-selected', false); + element.setAttribute('tabindex', '-1'); + this._toggleDropDown(element, false); + EventHandler.trigger(element, EVENT_HIDDEN$1, { + relatedTarget: relatedElem + }); + }; + this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE$1)); + } + _keydown(event) { + if (![ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key)) { + return; + } + event.stopPropagation(); // stopPropagation/preventDefault both added to support up/down keys without scrolling the page + event.preventDefault(); + const children = this._getChildren().filter(element => !isDisabled(element)); + let nextActiveElement; + if ([HOME_KEY, END_KEY].includes(event.key)) { + nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]; + } else { + const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key); + nextActiveElement = getNextActiveElement(children, event.target, isNext, true); + } + if (nextActiveElement) { + nextActiveElement.focus({ + preventScroll: true + }); + Tab.getOrCreateInstance(nextActiveElement).show(); + } + } + _getChildren() { + // collection of inner elements + return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent); + } + _getActiveElem() { + return this._getChildren().find(child => this._elemIsActive(child)) || null; + } + _setInitialAttributes(parent, children) { + this._setAttributeIfNotExists(parent, 'role', 'tablist'); + for (const child of children) { + this._setInitialAttributesOnChild(child); + } + } + _setInitialAttributesOnChild(child) { + child = this._getInnerElement(child); + const isActive = this._elemIsActive(child); + const outerElem = this._getOuterElement(child); + child.setAttribute('aria-selected', isActive); + if (outerElem !== child) { + this._setAttributeIfNotExists(outerElem, 'role', 'presentation'); + } + if (!isActive) { + child.setAttribute('tabindex', '-1'); + } + this._setAttributeIfNotExists(child, 'role', 'tab'); + + // set attributes to the related panel too + this._setInitialAttributesOnTargetPanel(child); + } + _setInitialAttributesOnTargetPanel(child) { + const target = SelectorEngine.getElementFromSelector(child); + if (!target) { + return; + } + this._setAttributeIfNotExists(target, 'role', 'tabpanel'); + if (child.id) { + this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`); + } + } + _toggleDropDown(element, open) { + const outerElem = this._getOuterElement(element); + if (!outerElem.classList.contains(CLASS_DROPDOWN)) { + return; + } + const toggle = (selector, className) => { + const element = SelectorEngine.findOne(selector, outerElem); + if (element) { + element.classList.toggle(className, open); + } + }; + toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE); + toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW$1); + outerElem.setAttribute('aria-expanded', open); + } + _setAttributeIfNotExists(element, attribute, value) { + if (!element.hasAttribute(attribute)) { + element.setAttribute(attribute, value); + } + } + _elemIsActive(elem) { + return elem.classList.contains(CLASS_NAME_ACTIVE); + } + + // Try to get the inner element (usually the .nav-link) + _getInnerElement(elem) { + return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem); + } + + // Try to get the outer element (usually the .nav-item) + _getOuterElement(elem) { + return elem.closest(SELECTOR_OUTER) || elem; + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Tab.getOrCreateInstance(this); + if (typeof config !== 'string') { + return; + } + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + if (isDisabled(this)) { + return; + } + Tab.getOrCreateInstance(this).show(); + }); + + /** + * Initialize on focus + */ + EventHandler.on(window, EVENT_LOAD_DATA_API, () => { + for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) { + Tab.getOrCreateInstance(element); + } + }); + /** + * jQuery + */ + + defineJQueryPlugin(Tab); + + /** + * -------------------------------------------------------------------------- + * Bootstrap toast.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME = 'toast'; + const DATA_KEY = 'bs.toast'; + const EVENT_KEY = `.${DATA_KEY}`; + const EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`; + const EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`; + const EVENT_FOCUSIN = `focusin${EVENT_KEY}`; + const EVENT_FOCUSOUT = `focusout${EVENT_KEY}`; + const EVENT_HIDE = `hide${EVENT_KEY}`; + const EVENT_HIDDEN = `hidden${EVENT_KEY}`; + const EVENT_SHOW = `show${EVENT_KEY}`; + const EVENT_SHOWN = `shown${EVENT_KEY}`; + const CLASS_NAME_FADE = 'fade'; + const CLASS_NAME_HIDE = 'hide'; // @deprecated - kept here only for backwards compatibility + const CLASS_NAME_SHOW = 'show'; + const CLASS_NAME_SHOWING = 'showing'; + const DefaultType = { + animation: 'boolean', + autohide: 'boolean', + delay: 'number' + }; + const Default = { + animation: true, + autohide: true, + delay: 5000 + }; + + /** + * Class definition + */ + + class Toast extends BaseComponent { + constructor(element, config) { + super(element, config); + this._timeout = null; + this._hasMouseInteraction = false; + this._hasKeyboardInteraction = false; + this._setListeners(); + } + + // Getters + static get Default() { + return Default; + } + static get DefaultType() { + return DefaultType; + } + static get NAME() { + return NAME; + } + + // Public + show() { + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW); + if (showEvent.defaultPrevented) { + return; + } + this._clearTimeout(); + if (this._config.animation) { + this._element.classList.add(CLASS_NAME_FADE); + } + const complete = () => { + this._element.classList.remove(CLASS_NAME_SHOWING); + EventHandler.trigger(this._element, EVENT_SHOWN); + this._maybeScheduleHide(); + }; + this._element.classList.remove(CLASS_NAME_HIDE); // @deprecated + reflow(this._element); + this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING); + this._queueCallback(complete, this._element, this._config.animation); + } + hide() { + if (!this.isShown()) { + return; + } + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE); + if (hideEvent.defaultPrevented) { + return; + } + const complete = () => { + this._element.classList.add(CLASS_NAME_HIDE); // @deprecated + this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW); + EventHandler.trigger(this._element, EVENT_HIDDEN); + }; + this._element.classList.add(CLASS_NAME_SHOWING); + this._queueCallback(complete, this._element, this._config.animation); + } + dispose() { + this._clearTimeout(); + if (this.isShown()) { + this._element.classList.remove(CLASS_NAME_SHOW); + } + super.dispose(); + } + isShown() { + return this._element.classList.contains(CLASS_NAME_SHOW); + } + + // Private + + _maybeScheduleHide() { + if (!this._config.autohide) { + return; + } + if (this._hasMouseInteraction || this._hasKeyboardInteraction) { + return; + } + this._timeout = setTimeout(() => { + this.hide(); + }, this._config.delay); + } + _onInteraction(event, isInteracting) { + switch (event.type) { + case 'mouseover': + case 'mouseout': + { + this._hasMouseInteraction = isInteracting; + break; + } + case 'focusin': + case 'focusout': + { + this._hasKeyboardInteraction = isInteracting; + break; + } + } + if (isInteracting) { + this._clearTimeout(); + return; + } + const nextElement = event.relatedTarget; + if (this._element === nextElement || this._element.contains(nextElement)) { + return; + } + this._maybeScheduleHide(); + } + _setListeners() { + EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true)); + EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false)); + EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true)); + EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false)); + } + _clearTimeout() { + clearTimeout(this._timeout); + this._timeout = null; + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Toast.getOrCreateInstance(this, config); + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](this); + } + }); + } + } + + /** + * Data API implementation + */ + + enableDismissTrigger(Toast); + + /** + * jQuery + */ + + defineJQueryPlugin(Toast); + + /** + * -------------------------------------------------------------------------- + * Bootstrap index.umd.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + const index_umd = { + Alert, + Button, + Carousel, + Collapse, + Dropdown, + Modal, + Offcanvas, + Popover, + ScrollSpy, + Tab, + Toast, + Tooltip + }; + + return index_umd; + +})); +//# sourceMappingURL=bootstrap.js.map diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.js.map b/extensions/pagetop-bootsier/static/js/bootstrap.js.map new file mode 100644 index 00000000..98a87052 --- /dev/null +++ b/extensions/pagetop-bootsier/static/js/bootstrap.js.map @@ -0,0 +1 @@ +{"version":3,"file":"bootstrap.js","sources":["../../js/src/dom/data.js","../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/manipulator.js","../../js/src/util/config.js","../../js/src/base-component.js","../../js/src/dom/selector-engine.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/util/swipe.js","../../js/src/carousel.js","../../js/src/collapse.js","../../js/src/dropdown.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/util/scrollbar.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/util/template-factory.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1_000_000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`)\n }\n\n return selector\n}\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`\n }\n\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = object => {\n if (!object || typeof object !== 'object') {\n return false\n }\n\n if (typeof object.jquery !== 'undefined') {\n object = object[0]\n }\n\n return typeof object.nodeType !== 'undefined'\n}\n\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (isElement(object)) {\n return object.jquery ? object[0] : object\n }\n\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object))\n }\n\n return null\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])')\n\n if (!closedDetails) {\n return elementIsVisible\n }\n\n if (closedDetails !== element) {\n const summary = element.closest('summary')\n if (summary && summary.parentNode !== closedDetails) {\n return false\n }\n\n if (summary === null) {\n return false\n }\n }\n\n return elementIsVisible\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight // eslint-disable-line no-unused-expressions\n}\n\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback()\n }\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]\n }\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n defineJQueryPlugin,\n execute,\n executeAfterTransition,\n findShadowRoot,\n getElement,\n getjQuery,\n getNextActiveElement,\n getTransitionDurationFromElement,\n getUID,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n onDOMContentLoaded,\n parseSelector,\n reflow,\n triggerTransitionEnd,\n toType\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index.js'\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\n\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getElementEvents(element) {\n const uid = makeEventUid(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, { delegateTarget: element })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue\n }\n\n hydrateObj(event, { delegateTarget: target })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n}\n\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events)\n .find(event => event.callable === callable && event.delegationSelector === delegationSelector)\n}\n\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string'\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : (handler || delegationFunction)\n let typeEvent = getTypeEvent(originalTypeEvent)\n\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent\n }\n\n return [isDelegated, callable, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n callable = wrapFunction(callable)\n }\n\n const events = getElementEvents(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)\n\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff\n\n return\n }\n\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = isDelegated ?\n bootstrapDelegationHandler(element, handler, callable) :\n bootstrapHandler(element, callable)\n\n fn.delegationSelector = isDelegated ? handler : null\n fn.callable = callable\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, isDelegated)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false)\n },\n\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getElementEvents(element)\n const storeElementEvent = events[typeEvent] || {}\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return\n }\n\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)\n return\n }\n\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n }\n }\n\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n\n let jQueryEvent = null\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value\n } catch {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value\n }\n })\n }\n }\n\n return obj\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true\n }\n\n if (value === 'false') {\n return false\n }\n\n if (value === Number(value).toString()) {\n return Number(value)\n }\n\n if (value === '' || value === 'null') {\n return null\n }\n\n if (typeof value !== 'string') {\n return value\n }\n\n try {\n return JSON.parse(decodeURIComponent(value))\n } catch {\n return value\n }\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))\n\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)\n attributes[pureKey] = normalizeData(element.dataset[key])\n }\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport { isElement, toType } from './index.js'\n\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {}\n }\n\n static get DefaultType() {\n return {}\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n return config\n }\n\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n }\n }\n\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property]\n const valueType = isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n }\n }\n}\n\nexport default Config\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data.js'\nimport EventHandler from './dom/event-handler.js'\nimport Config from './util/config.js'\nimport { executeAfterTransition, getElement } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.3'\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super()\n\n element = getElement(element)\n if (!element) {\n return\n }\n\n this._element = element\n this._config = this._getConfig(config)\n\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null\n }\n }\n\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible, parseSelector } from '../util/index.js'\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`\n }\n\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null\n }\n\n return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null\n}\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n let ancestor = element.parentNode.closest(selector)\n\n while (ancestor) {\n parents.push(ancestor)\n ancestor = ancestor.parentNode.closest(selector)\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n },\n\n getSelectorFromElement(element) {\n const selector = getSelector(element)\n\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null\n }\n\n return null\n },\n\n getElementFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.findOne(selector) : null\n },\n\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.find(selector) : []\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isDisabled } from './index.js'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport { execute } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'swipe'\nconst EVENT_KEY = '.bs.swipe'\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n}\n\nconst DefaultType = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n}\n\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super()\n this._element = element\n\n if (!element || !Swipe.isSupported()) {\n return\n }\n\n this._config = this._getConfig(config)\n this._deltaX = 0\n this._supportPointerEvents = Boolean(window.PointerEvent)\n this._initEvents()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY)\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX\n\n return\n }\n\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX\n }\n }\n\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX\n }\n\n this._handleSwipe()\n execute(this._config.endCallback)\n }\n\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this._deltaX\n }\n\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX)\n\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltaX / this._deltaX\n\n this._deltaX = 0\n\n if (!direction) {\n return\n }\n\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)\n }\n\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))\n }\n }\n\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n }\n}\n\nexport default Swipe\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getNextActiveElement,\n isRTL,\n isVisible,\n reflow,\n triggerTransitionEnd\n} from './util/index.js'\nimport Swipe from './util/swipe.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)', // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._interval = null\n this._activeElement = null\n this._isSliding = false\n this.touchTimeout = null\n this._swipeHelper = null\n\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._addEventListeners()\n\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element)\n }\n\n this._clearInterval()\n }\n\n cycle() {\n this._clearInterval()\n this._updateInterval()\n\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval)\n }\n\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle())\n return\n }\n\n this.cycle()\n }\n\n to(index) {\n const items = this._getItems()\n if (index > items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n const activeIndex = this._getItemIndex(this._getActive())\n if (activeIndex === index) {\n return\n }\n\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV\n\n this._slide(order, items[index])\n }\n\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose()\n }\n\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval\n return config\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause())\n EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle())\n }\n\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault())\n }\n\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n }\n\n this._swipeHelper = new Swipe(this._element, swipeConfig)\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(this._directionToOrder(direction))\n }\n }\n\n _getItemIndex(element) {\n return this._getItems().indexOf(element)\n }\n\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return\n }\n\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement)\n\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE)\n newActiveIndicator.setAttribute('aria-current', 'true')\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || this._getActive()\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n this._config.interval = elementInterval || this._config.defaultInterval\n }\n\n _slide(order, element = null) {\n if (this._isSliding) {\n return\n }\n\n const activeElement = this._getActive()\n const isNext = order === ORDER_NEXT\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap)\n\n if (nextElement === activeElement) {\n return\n }\n\n const nextElementIndex = this._getItemIndex(nextElement)\n\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n })\n }\n\n const slideEvent = triggerEvent(EVENT_SLIDE)\n\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return\n }\n\n const isCycling = Boolean(this._interval)\n this.pause()\n\n this._isSliding = true\n\n this._setActiveIndicatorElement(nextElementIndex)\n this._activeElement = nextElement\n\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n triggerEvent(EVENT_SLID)\n }\n\n this._queueCallback(completeCallBack, activeElement, this._isAnimated())\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE)\n }\n\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n }\n\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element)\n }\n\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n }\n\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config)\n\n if (typeof config === 'number') {\n data.to(config)\n return\n }\n\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n event.preventDefault()\n\n const carousel = Carousel.getOrCreateInstance(target)\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n carousel.to(slideIndex)\n carousel._maybeEnableCycle()\n return\n }\n\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next()\n carousel._maybeEnableCycle()\n return\n }\n\n carousel.prev()\n carousel._maybeEnableCycle()\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getElement,\n reflow\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\nconst Default = {\n parent: null,\n toggle: true\n}\n\nconst DefaultType = {\n parent: '(null|element)',\n toggle: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isTransitioning = false\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElement => foundElement === this._element)\n\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let activeChildren = []\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)\n .filter(element => element !== this._element)\n .map(element => Collapse.getOrCreateInstance(element, { toggle: false }))\n }\n\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n for (const activeInstance of activeChildren) {\n activeInstance.hide()\n }\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger)\n\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)\n\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n }\n }\n\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element))\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen)\n element.setAttribute('aria-expanded', isOpen)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n execute,\n getElement,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center'\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)'\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR = '.navbar'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\nconst PLACEMENT_TOPCENTER = 'top'\nconst PLACEMENT_BOTTOMCENTER = 'bottom'\n\nconst Default = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n}\n\nconst DefaultType = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n}\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._popper = null\n this._parent = this._element.parentNode // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.findOne(SELECTOR_MENU, this._parent)\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._createPopper()\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = super._getConfig(config)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = this._parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n }\n\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getPlacement() {\n const parentDropdown = this._parent\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {\n return\n }\n\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)\n\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle)\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n const relatedTarget = { relatedTarget: context._element }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName)\n const isEscapeEvent = event.key === ESCAPE_KEY\n const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)\n\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return\n }\n\n if (isInput && !isEscapeEvent) {\n return\n }\n\n event.preventDefault()\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?\n this :\n (SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode))\n\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (isUpOrDownEvent) {\n event.stopPropagation()\n instance.show()\n instance._selectMenuItem(event)\n return\n }\n\n if (instance._isShown()) { // else is escape and we check if it is shown\n event.stopPropagation()\n instance.hide()\n getToggleButton.focus()\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport {\n execute, executeAfterTransition, getElement, reflow\n} from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nconst Default = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n}\n\nconst DefaultType = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n}\n\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n const element = this._getElement()\n if (this._config.isAnimated) {\n reflow(element)\n }\n\n element.classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n const element = this._getElement()\n this._config.rootElement.append(element)\n\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nconst Default = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n}\n\nconst DefaultType = {\n autofocus: 'boolean',\n trapElement: 'element'\n}\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return\n }\n\n if (this._config.autofocus) {\n this._config.trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n _handleFocusin(event) {\n const { trapElement } = this._config\n\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\nconst PROPERTY_PADDING = 'padding-right'\nconst PROPERTY_MARGIN = 'margin-right'\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProperty)\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty)\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty)\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty)\n return\n }\n\n Manipulator.removeDataAttribute(element, styleProperty)\n element.style.setProperty(styleProperty, value)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n return\n }\n\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel)\n }\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin, isRTL, isVisible, reflow\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\nconst Default = {\n backdrop: true,\n focus: true,\n keyboard: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._isTransitioning = true\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._backdrop.show(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n this._isTransitioning = true\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated())\n }\n\n dispose() {\n EventHandler.off(window, EVENT_KEY)\n EventHandler.off(this._dialog, EVENT_KEY)\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated())\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n this._triggerBackdropTransition()\n })\n\n EventHandler.on(window, EVENT_RESIZE, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog()\n }\n })\n\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return\n }\n\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n return\n }\n\n if (this._config.backdrop) {\n this.hide()\n }\n })\n })\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const initialOverflowY = this._element.style.overflowY\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden'\n }\n\n this._element.classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY\n }, this._dialog)\n }, this._dialog)\n\n this._element.focus()\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin,\n isDisabled,\n isVisible\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\nconst CLASS_NAME_HIDING = 'hiding'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate()\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.add(CLASS_NAME_HIDING)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n return\n }\n\n this.hide()\n }\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop)\n\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n })\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show()\n }\n})\n\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide()\n }\n }\n})\n\nenableDismissTrigger(Offcanvas)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n dd: [],\n div: [],\n dl: [],\n dt: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n// js-docs-end allow-list\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\n// eslint-disable-next-line unicorn/better-regex\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n .some(regex => regex.test(attributeName))\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n }\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\nimport { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'\nimport { execute, getElement, isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'TemplateFactory'\n\nconst Default = {\n allowList: DefaultAllowlist,\n content: {}, // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '<div></div>'\n}\n\nconst DefaultType = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n}\n\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n}\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content)\n .map(config => this._resolvePossibleFunction(config))\n .filter(Boolean)\n }\n\n hasContent() {\n return this.getContent().length > 0\n }\n\n changeContent(content) {\n this._checkContent(content)\n this._config.content = { ...this._config.content, ...content }\n return this\n }\n\n toHtml() {\n const templateWrapper = document.createElement('div')\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template)\n\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector)\n }\n\n const template = templateWrapper.children[0]\n const extraClass = this._resolvePossibleFunction(this._config.extraClass)\n\n if (extraClass) {\n template.classList.add(...extraClass.split(' '))\n }\n\n return template\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config)\n this._checkContent(config.content)\n }\n\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({ selector, entry: content }, DefaultContentType)\n }\n }\n\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!templateElement) {\n return\n }\n\n content = this._resolvePossibleFunction(content)\n\n if (!content) {\n templateElement.remove()\n return\n }\n\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement)\n return\n }\n\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content)\n return\n }\n\n templateElement.textContent = content\n }\n\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this])\n }\n\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = ''\n templateElement.append(element)\n return\n }\n\n templateElement.textContent = element.textContent\n }\n}\n\nexport default TemplateFactory\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport {\n defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop\n} from './util/index.js'\nimport { DefaultAllowlist } from './util/sanitizer.js'\nimport TemplateFactory from './util/template-factory.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\nconst EVENT_HIDE = 'hide'\nconst EVENT_HIDDEN = 'hidden'\nconst EVENT_SHOW = 'show'\nconst EVENT_SHOWN = 'shown'\nconst EVENT_INSERTED = 'inserted'\nconst EVENT_CLICK = 'click'\nconst EVENT_FOCUSIN = 'focusin'\nconst EVENT_FOCUSOUT = 'focusout'\nconst EVENT_MOUSEENTER = 'mouseenter'\nconst EVENT_MOUSELEAVE = 'mouseleave'\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '<div class=\"tooltip\" role=\"tooltip\">' +\n '<div class=\"tooltip-arrow\"></div>' +\n '<div class=\"tooltip-inner\"></div>' +\n '</div>',\n title: '',\n trigger: 'hover focus'\n}\n\nconst DefaultType = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n}\n\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org)')\n }\n\n super(element, config)\n\n // Private\n this._isEnabled = true\n this._timeout = 0\n this._isHovered = null\n this._activeTrigger = {}\n this._popper = null\n this._templateFactory = null\n this._newContent = null\n\n // Protected\n this.tip = null\n\n this._setListeners()\n\n if (!this._config.selector) {\n this._fixTitle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle() {\n if (!this._isEnabled) {\n return\n }\n\n this._activeTrigger.click = !this._activeTrigger.click\n if (this._isShown()) {\n this._leave()\n return\n }\n\n this._enter()\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'))\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this._isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW))\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper()\n\n const tip = this._getTipElement()\n\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'))\n\n const { container } = this._config\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))\n }\n\n this._popper = this._createPopper(tip)\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN))\n\n if (this._isHovered === false) {\n this._leave()\n }\n\n this._isHovered = false\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n hide() {\n if (!this._isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE))\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const tip = this._getTipElement()\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n this._isHovered = null // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (!this._isHovered) {\n this._disposePopper()\n }\n\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN))\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n update() {\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle())\n }\n\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())\n }\n\n return this.tip\n }\n\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml()\n\n // TODO: remove this check in v6\n if (!tip) {\n return null\n }\n\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`)\n\n const tipId = getUID(this.constructor.NAME).toString()\n\n tip.setAttribute('id', tipId)\n\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n return tip\n }\n\n setContent(content) {\n this._newContent = content\n if (this._isShown()) {\n this._disposePopper()\n this.show()\n }\n }\n\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content)\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n })\n }\n\n return this._templateFactory\n }\n\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n }\n }\n\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title')\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _isAnimated() {\n return this._config.animation || (this.tip && this.tip.classList.contains(CLASS_NAME_FADE))\n }\n\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW)\n }\n\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element])\n const attachment = AttachmentMap[placement.toUpperCase()]\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element])\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement)\n }\n }\n ]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n }\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context.toggle()\n })\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSEENTER) :\n this.constructor.eventName(EVENT_FOCUSIN)\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSELEAVE) :\n this.constructor.eventName(EVENT_FOCUSOUT)\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true\n context._enter()\n })\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] =\n context._element.contains(event.relatedTarget)\n\n context._leave()\n })\n }\n }\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n\n if (!title) {\n return\n }\n\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('data-bs-original-title', title) // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title')\n }\n\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true\n return\n }\n\n this._isHovered = true\n\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show()\n }\n }, this._config.delay.show)\n }\n\n _leave() {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n this._isHovered = false\n\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide()\n }\n }, this._config.delay.hide)\n }\n\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout)\n this._timeout = setTimeout(handler, timeout)\n }\n\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true)\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute]\n }\n }\n\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value\n }\n }\n\n config.selector = false\n config.trigger = 'manual'\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n\n if (this.tip) {\n this.tip.remove()\n this.tip = null\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Tooltip from './tooltip.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'popover'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Default = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>',\n trigger: 'click'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n}\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent()\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n }\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin, getElement, isDisabled, isVisible\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_CLICK = `click${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_TARGET_LINKS = '[href]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst Default = {\n offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n}\n\nconst DefaultType = {\n offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n}\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map()\n this._observableSections = new Map()\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element\n this._activeTarget = null\n this._observer = null\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n }\n this.refresh() // initialize\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables()\n this._maybeEnableSmoothScroll()\n\n if (this._observer) {\n this._observer.disconnect()\n } else {\n this._observer = this._getNewObserver()\n }\n\n for (const section of this._observableSections.values()) {\n this._observer.observe(section)\n }\n }\n\n dispose() {\n this._observer.disconnect()\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin\n\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))\n }\n\n return config\n }\n\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK)\n\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash)\n if (observableSection) {\n event.preventDefault()\n const root = this._rootElement || window\n const height = observableSection.offsetTop - this._element.offsetTop\n if (root.scrollTo) {\n root.scrollTo({ top: height, behavior: 'smooth' })\n return\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height\n }\n })\n }\n\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n }\n\n return new IntersectionObserver(entries => this._observerCallback(entries), options)\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop\n this._process(targetElement(entry))\n }\n\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop\n this._previousScrollData.parentScrollTop = parentScrollTop\n\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null\n this._clearActiveClass(targetElement(entry))\n\n continue\n }\n\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry)\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return\n }\n\n continue\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry)\n }\n }\n }\n\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map()\n this._observableSections = new Map()\n\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)\n\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue\n }\n\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor)\n this._observableSections.set(anchor.hash, observableSection)\n }\n }\n }\n\n _process(target) {\n if (this._activeTarget === target) {\n return\n }\n\n this._clearActiveClass(this._config.target)\n this._activeTarget = target\n target.classList.add(CLASS_NAME_ACTIVE)\n this._activateParents(target)\n\n EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })\n }\n\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n return\n }\n\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {\n item.classList.add(CLASS_NAME_ACTIVE)\n }\n }\n }\n\n _clearActiveClass(parent) {\n parent.classList.remove(CLASS_NAME_ACTIVE)\n\n const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent)\n for (const node of activeNodes) {\n node.classList.remove(CLASS_NAME_ACTIVE)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = ScrollSpy.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {\n ScrollSpy.getOrCreateInstance(spy)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(ScrollSpy)\n\nexport default ScrollSpy\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tab.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tab'\nconst DATA_KEY = 'bs.tab'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}`\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst HOME_KEY = 'Home'\nconst END_KEY = 'End'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_DROPDOWN = 'dropdown'\n\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\nconst SELECTOR_DROPDOWN_MENU = '.dropdown-menu'\nconst NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`\n\nconst SELECTOR_TAB_PANEL = '.list-group, .nav, [role=\"tablist\"]'\nconst SELECTOR_OUTER = '.nav-item, .list-group-item'\nconst SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role=\"tab\"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]' // TODO: could only be `tab` in v6\nconst SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`\n\nconst SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle=\"tab\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"pill\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"list\"]`\n\n/**\n * Class definition\n */\n\nclass Tab extends BaseComponent {\n constructor(element) {\n super(element)\n this._parent = this._element.closest(SELECTOR_TAB_PANEL)\n\n if (!this._parent) {\n return\n // TODO: should throw exception in v6\n // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)\n }\n\n // Set up initial aria attributes\n this._setInitialAttributes(this._parent, this._getChildren())\n\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n show() { // Shows this elem and deactivate the active sibling if exists\n const innerElem = this._element\n if (this._elemIsActive(innerElem)) {\n return\n }\n\n // Search for active tab on same parent to deactivate it\n const active = this._getActiveElem()\n\n const hideEvent = active ?\n EventHandler.trigger(active, EVENT_HIDE, { relatedTarget: innerElem }) :\n null\n\n const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, { relatedTarget: active })\n\n if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {\n return\n }\n\n this._deactivate(active, innerElem)\n this._activate(innerElem, active)\n }\n\n // Private\n _activate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.add(CLASS_NAME_ACTIVE)\n\n this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.add(CLASS_NAME_SHOW)\n return\n }\n\n element.removeAttribute('tabindex')\n element.setAttribute('aria-selected', true)\n this._toggleDropDown(element, true)\n EventHandler.trigger(element, EVENT_SHOWN, {\n relatedTarget: relatedElem\n })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _deactivate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.remove(CLASS_NAME_ACTIVE)\n element.blur()\n\n this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.remove(CLASS_NAME_SHOW)\n return\n }\n\n element.setAttribute('aria-selected', false)\n element.setAttribute('tabindex', '-1')\n this._toggleDropDown(element, false)\n EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _keydown(event) {\n if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key))) {\n return\n }\n\n event.stopPropagation()// stopPropagation/preventDefault both added to support up/down keys without scrolling the page\n event.preventDefault()\n\n const children = this._getChildren().filter(element => !isDisabled(element))\n let nextActiveElement\n\n if ([HOME_KEY, END_KEY].includes(event.key)) {\n nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]\n } else {\n const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)\n nextActiveElement = getNextActiveElement(children, event.target, isNext, true)\n }\n\n if (nextActiveElement) {\n nextActiveElement.focus({ preventScroll: true })\n Tab.getOrCreateInstance(nextActiveElement).show()\n }\n }\n\n _getChildren() { // collection of inner elements\n return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent)\n }\n\n _getActiveElem() {\n return this._getChildren().find(child => this._elemIsActive(child)) || null\n }\n\n _setInitialAttributes(parent, children) {\n this._setAttributeIfNotExists(parent, 'role', 'tablist')\n\n for (const child of children) {\n this._setInitialAttributesOnChild(child)\n }\n }\n\n _setInitialAttributesOnChild(child) {\n child = this._getInnerElement(child)\n const isActive = this._elemIsActive(child)\n const outerElem = this._getOuterElement(child)\n child.setAttribute('aria-selected', isActive)\n\n if (outerElem !== child) {\n this._setAttributeIfNotExists(outerElem, 'role', 'presentation')\n }\n\n if (!isActive) {\n child.setAttribute('tabindex', '-1')\n }\n\n this._setAttributeIfNotExists(child, 'role', 'tab')\n\n // set attributes to the related panel too\n this._setInitialAttributesOnTargetPanel(child)\n }\n\n _setInitialAttributesOnTargetPanel(child) {\n const target = SelectorEngine.getElementFromSelector(child)\n\n if (!target) {\n return\n }\n\n this._setAttributeIfNotExists(target, 'role', 'tabpanel')\n\n if (child.id) {\n this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)\n }\n }\n\n _toggleDropDown(element, open) {\n const outerElem = this._getOuterElement(element)\n if (!outerElem.classList.contains(CLASS_DROPDOWN)) {\n return\n }\n\n const toggle = (selector, className) => {\n const element = SelectorEngine.findOne(selector, outerElem)\n if (element) {\n element.classList.toggle(className, open)\n }\n }\n\n toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)\n toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)\n outerElem.setAttribute('aria-expanded', open)\n }\n\n _setAttributeIfNotExists(element, attribute, value) {\n if (!element.hasAttribute(attribute)) {\n element.setAttribute(attribute, value)\n }\n }\n\n _elemIsActive(elem) {\n return elem.classList.contains(CLASS_NAME_ACTIVE)\n }\n\n // Try to get the inner element (usually the .nav-link)\n _getInnerElement(elem) {\n return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem)\n }\n\n // Try to get the outer element (usually the .nav-item)\n _getOuterElement(elem) {\n return elem.closest(SELECTOR_OUTER) || elem\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tab.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n Tab.getOrCreateInstance(this).show()\n})\n\n/**\n * Initialize on focus\n */\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {\n Tab.getOrCreateInstance(element)\n }\n})\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tab)\n\nexport default Tab\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap toast.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin, reflow } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'toast'\nconst DATA_KEY = 'bs.toast'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\n\nconst DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n}\n\nconst Default = {\n animation: true,\n autohide: true,\n delay: 5000\n}\n\n/**\n * Class definition\n */\n\nclass Toast extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._timeout = null\n this._hasMouseInteraction = false\n this._hasKeyboardInteraction = false\n this._setListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show() {\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._clearTimeout()\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE)\n }\n\n const complete = () => {\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN)\n\n this._maybeScheduleHide()\n }\n\n this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\n reflow(this._element)\n this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)\n\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n hide() {\n if (!this.isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const complete = () => {\n this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\n this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.classList.add(CLASS_NAME_SHOWING)\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n dispose() {\n this._clearTimeout()\n\n if (this.isShown()) {\n this._element.classList.remove(CLASS_NAME_SHOW)\n }\n\n super.dispose()\n }\n\n isShown() {\n return this._element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n\n _maybeScheduleHide() {\n if (!this._config.autohide) {\n return\n }\n\n if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\n return\n }\n\n this._timeout = setTimeout(() => {\n this.hide()\n }, this._config.delay)\n }\n\n _onInteraction(event, isInteracting) {\n switch (event.type) {\n case 'mouseover':\n case 'mouseout': {\n this._hasMouseInteraction = isInteracting\n break\n }\n\n case 'focusin':\n case 'focusout': {\n this._hasKeyboardInteraction = isInteracting\n break\n }\n\n default: {\n break\n }\n }\n\n if (isInteracting) {\n this._clearTimeout()\n return\n }\n\n const nextElement = event.relatedTarget\n if (this._element === nextElement || this._element.contains(nextElement)) {\n return\n }\n\n this._maybeScheduleHide()\n }\n\n _setListeners() {\n EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\n EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\n }\n\n _clearTimeout() {\n clearTimeout(this._timeout)\n this._timeout = null\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Toast.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Toast)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Toast)\n\nexport default Toast\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap index.umd.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './src/alert.js'\nimport Button from './src/button.js'\nimport Carousel from './src/carousel.js'\nimport Collapse from './src/collapse.js'\nimport Dropdown from './src/dropdown.js'\nimport Modal from './src/modal.js'\nimport Offcanvas from './src/offcanvas.js'\nimport Popover from './src/popover.js'\nimport ScrollSpy from './src/scrollspy.js'\nimport Tab from './src/tab.js'\nimport Toast from './src/toast.js'\nimport Tooltip from './src/tooltip.js'\n\nexport default {\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Offcanvas,\n Popover,\n ScrollSpy,\n Tab,\n Toast,\n Tooltip\n}\n"],"names":["elementMap","Map","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete","MAX_UID","MILLISECONDS_MULTIPLIER","TRANSITION_END","parseSelector","selector","window","CSS","escape","replace","match","id","toType","object","undefined","Object","prototype","toString","call","toLowerCase","getUID","prefix","Math","floor","random","document","getElementById","getTransitionDurationFromElement","transitionDuration","transitionDelay","getComputedStyle","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","split","triggerTransitionEnd","dispatchEvent","Event","isElement","jquery","nodeType","getElement","length","querySelector","isVisible","getClientRects","elementIsVisible","getPropertyValue","closedDetails","closest","summary","parentNode","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","getAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","noop","reflow","offsetHeight","getjQuery","jQuery","body","DOMContentLoadedCallbacks","onDOMContentLoaded","callback","readyState","addEventListener","push","isRTL","dir","defineJQueryPlugin","plugin","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","execute","possibleCallback","args","defaultValue","executeAfterTransition","transitionElement","waitForTransition","durationPadding","emulatedDuration","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","listLength","index","indexOf","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","nativeEvents","Set","makeEventUid","uid","getElementEvents","bootstrapHandler","event","hydrateObj","delegateTarget","oneOff","EventHandler","off","type","apply","bootstrapDelegationHandler","domElements","querySelectorAll","domElement","findHandler","events","callable","delegationSelector","values","find","normalizeParameters","originalTypeEvent","delegationFunction","isDelegated","typeEvent","getTypeEvent","addHandler","wrapFunction","relatedTarget","handlers","previousFunction","removeHandler","Boolean","removeNamespacedHandlers","namespace","storeElementEvent","handlerKey","entries","includes","on","one","inNamespace","isNamespace","startsWith","elementEvent","slice","keyHandlers","trigger","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","evt","cancelable","preventDefault","obj","meta","value","_unused","defineProperty","configurable","normalizeData","JSON","parse","decodeURIComponent","normalizeDataKey","chr","Manipulator","setDataAttribute","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","dataset","filter","pureKey","charAt","getDataAttribute","Config","Default","DefaultType","Error","_getConfig","config","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","jsonConfig","constructor","configTypes","property","expectedTypes","valueType","RegExp","test","TypeError","toUpperCase","VERSION","BaseComponent","_element","_config","Data","DATA_KEY","dispose","EVENT_KEY","propertyName","getOwnPropertyNames","_queueCallback","isAnimated","getInstance","getOrCreateInstance","eventName","getSelector","hrefAttribute","trim","map","sel","join","SelectorEngine","concat","Element","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","el","getSelectorFromElement","getElementFromSelector","getMultipleElementsFromSelector","enableDismissTrigger","component","method","clickEvent","tagName","EVENT_CLOSE","EVENT_CLOSED","CLASS_NAME_FADE","CLASS_NAME_SHOW","Alert","close","closeEvent","_destroyElement","each","data","DATA_API_KEY","CLASS_NAME_ACTIVE","SELECTOR_DATA_TOGGLE","EVENT_CLICK_DATA_API","Button","toggle","button","EVENT_TOUCHSTART","EVENT_TOUCHMOVE","EVENT_TOUCHEND","EVENT_POINTERDOWN","EVENT_POINTERUP","POINTER_TYPE_TOUCH","POINTER_TYPE_PEN","CLASS_NAME_POINTER_EVENT","SWIPE_THRESHOLD","endCallback","leftCallback","rightCallback","Swipe","isSupported","_deltaX","_supportPointerEvents","PointerEvent","_initEvents","_start","touches","clientX","_eventIsPointerPenTouch","_end","_handleSwipe","_move","absDeltaX","abs","direction","add","pointerType","navigator","maxTouchPoints","ARROW_LEFT_KEY","ARROW_RIGHT_KEY","TOUCHEVENT_COMPAT_WAIT","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","EVENT_SLIDE","EVENT_SLID","EVENT_KEYDOWN","EVENT_MOUSEENTER","EVENT_MOUSELEAVE","EVENT_DRAG_START","EVENT_LOAD_DATA_API","CLASS_NAME_CAROUSEL","CLASS_NAME_SLIDE","CLASS_NAME_END","CLASS_NAME_START","CLASS_NAME_NEXT","CLASS_NAME_PREV","SELECTOR_ACTIVE","SELECTOR_ITEM","SELECTOR_ACTIVE_ITEM","SELECTOR_ITEM_IMG","SELECTOR_INDICATORS","SELECTOR_DATA_SLIDE","SELECTOR_DATA_RIDE","KEY_TO_DIRECTION","interval","keyboard","pause","ride","touch","wrap","Carousel","_interval","_activeElement","_isSliding","touchTimeout","_swipeHelper","_indicatorsElement","_addEventListeners","cycle","_slide","nextWhenVisible","hidden","_clearInterval","_updateInterval","setInterval","_maybeEnableCycle","to","items","_getItems","activeIndex","_getItemIndex","_getActive","order","defaultInterval","_keydown","_addTouchEventListeners","img","endCallBack","clearTimeout","swipeConfig","_directionToOrder","_setActiveIndicatorElement","activeIndicator","newActiveIndicator","elementInterval","parseInt","isNext","nextElement","nextElementIndex","triggerEvent","_orderToDirection","slideEvent","isCycling","directionalClassName","orderClassName","completeCallBack","_isAnimated","clearInterval","carousel","slideIndex","carousels","EVENT_SHOW","EVENT_SHOWN","EVENT_HIDE","EVENT_HIDDEN","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_COLLAPSED","CLASS_NAME_DEEPER_CHILDREN","CLASS_NAME_HORIZONTAL","WIDTH","HEIGHT","SELECTOR_ACTIVES","parent","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElement","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activeChildren","_getFirstLevelChildren","startEvent","activeInstance","dimension","_getDimension","style","complete","capitalizedDimension","scrollSize","getBoundingClientRect","selected","triggerArray","isOpen","ESCAPE_KEY","TAB_KEY","ARROW_UP_KEY","ARROW_DOWN_KEY","RIGHT_MOUSE_BUTTON","EVENT_KEYDOWN_DATA_API","EVENT_KEYUP_DATA_API","CLASS_NAME_DROPUP","CLASS_NAME_DROPEND","CLASS_NAME_DROPSTART","CLASS_NAME_DROPUP_CENTER","CLASS_NAME_DROPDOWN_CENTER","SELECTOR_DATA_TOGGLE_SHOWN","SELECTOR_MENU","SELECTOR_NAVBAR","SELECTOR_NAVBAR_NAV","SELECTOR_VISIBLE_ITEMS","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","PLACEMENT_TOPCENTER","PLACEMENT_BOTTOMCENTER","autoClose","boundary","display","offset","popperConfig","reference","Dropdown","_popper","_parent","_menu","_inNavbar","_detectNavbar","showEvent","_createPopper","focus","_completeHide","destroy","update","hideEvent","Popper","referenceElement","_getPopperConfig","createPopper","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","placement","modifiers","options","enabled","_selectMenuItem","clearMenus","openToggles","context","composedPath","isMenuTarget","dataApiKeydownHandler","isInput","isEscapeEvent","isUpOrDownEvent","getToggleButton","stopPropagation","EVENT_MOUSEDOWN","className","clickCallback","rootElement","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","EVENT_FOCUSIN","EVENT_KEYDOWN_TAB","TAB_NAV_FORWARD","TAB_NAV_BACKWARD","autofocus","trapElement","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","elements","shiftKey","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","PROPERTY_PADDING","PROPERTY_MARGIN","ScrollBarHelper","getWidth","documentWidth","clientWidth","innerWidth","width","_disableOverFlow","_setElementAttributes","calculatedValue","reset","_resetElementAttributes","isOverflowing","_saveInitialAttribute","overflow","styleProperty","scrollbarWidth","manipulationCallBack","setProperty","_applyManipulationCallback","actualValue","removeProperty","callBack","EVENT_HIDE_PREVENTED","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_MOUSEDOWN_DISMISS","EVENT_KEYDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","OPEN_SELECTOR","SELECTOR_DIALOG","SELECTOR_MODAL_BODY","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_scrollBar","_adjustDialog","_showElement","_hideModal","handleUpdate","scrollTop","modalBody","transitionComplete","_triggerBackdropTransition","event2","_resetAdjustments","isModalOverflowing","scrollHeight","clientHeight","initialOverflowY","overflowY","isBodyOverflowing","paddingLeft","paddingRight","alreadyOpen","CLASS_NAME_SHOWING","CLASS_NAME_HIDING","CLASS_NAME_BACKDROP","scroll","Offcanvas","blur","completeCallback","position","ARIA_ATTRIBUTE_PATTERN","DefaultAllowlist","a","area","b","br","col","code","dd","div","dl","dt","em","hr","h1","h2","h3","h4","h5","h6","i","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","uriAttributes","SAFE_URL_PATTERN","allowedAttribute","attribute","allowedAttributeList","attributeName","nodeName","nodeValue","attributeRegex","some","regex","sanitizeHtml","unsafeHtml","allowList","sanitizeFunction","domParser","DOMParser","createdDocument","parseFromString","elementName","attributeList","allowedAttributes","innerHTML","content","extraClass","html","sanitize","sanitizeFn","template","DefaultContentType","entry","TemplateFactory","getContent","_resolvePossibleFunction","hasContent","changeContent","_checkContent","toHtml","templateWrapper","_maybeSanitize","text","_setContent","arg","templateElement","_putElementInTemplate","textContent","DISALLOWED_ATTRIBUTES","CLASS_NAME_MODAL","SELECTOR_TOOLTIP_INNER","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","TRIGGER_CLICK","TRIGGER_MANUAL","EVENT_INSERTED","EVENT_CLICK","EVENT_FOCUSOUT","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","animation","container","customClass","delay","fallbackPlacements","title","Tooltip","_isEnabled","_timeout","_isHovered","_activeTrigger","_templateFactory","_newContent","tip","_setListeners","_fixTitle","enable","disable","toggleEnabled","click","_leave","_enter","_hideModalHandler","_disposePopper","_isWithContent","shadowRoot","isInTheDom","ownerDocument","_getTipElement","_isWithActiveTrigger","_getTitle","_createTipElement","_getContentForTemplate","_getTemplateFactory","tipId","setContent","_initializeOnDelegatedTarget","_getDelegateConfig","attachment","phase","state","triggers","eventIn","eventOut","_setTimeout","timeout","dataAttributes","dataAttribute","SELECTOR_TITLE","SELECTOR_CONTENT","Popover","_getContent","EVENT_ACTIVATE","CLASS_NAME_DROPDOWN_ITEM","SELECTOR_DATA_SPY","SELECTOR_TARGET_LINKS","SELECTOR_NAV_LIST_GROUP","SELECTOR_NAV_LINKS","SELECTOR_NAV_ITEMS","SELECTOR_LIST_ITEMS","SELECTOR_LINK_ITEMS","SELECTOR_DROPDOWN","SELECTOR_DROPDOWN_TOGGLE","rootMargin","smoothScroll","threshold","ScrollSpy","_targetLinks","_observableSections","_rootElement","_activeTarget","_observer","_previousScrollData","visibleEntryTop","parentScrollTop","refresh","_initializeTargetsAndObservables","_maybeEnableSmoothScroll","disconnect","_getNewObserver","section","observe","observableSection","hash","height","offsetTop","scrollTo","top","behavior","IntersectionObserver","_observerCallback","targetElement","_process","userScrollsDown","isIntersecting","_clearActiveClass","entryIsLowerThanPrevious","targetLinks","anchor","decodeURI","_activateParents","listGroup","item","activeNodes","node","spy","HOME_KEY","END_KEY","CLASS_DROPDOWN","SELECTOR_DROPDOWN_MENU","NOT_SELECTOR_DROPDOWN_TOGGLE","SELECTOR_TAB_PANEL","SELECTOR_OUTER","SELECTOR_INNER","SELECTOR_INNER_ELEM","SELECTOR_DATA_TOGGLE_ACTIVE","Tab","_setInitialAttributes","_getChildren","innerElem","_elemIsActive","active","_getActiveElem","_deactivate","_activate","relatedElem","_toggleDropDown","nextActiveElement","preventScroll","_setAttributeIfNotExists","_setInitialAttributesOnChild","_getInnerElement","isActive","outerElem","_getOuterElement","_setInitialAttributesOnTargetPanel","open","EVENT_MOUSEOVER","EVENT_MOUSEOUT","CLASS_NAME_HIDE","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","isShown","_onInteraction","isInteracting"],"mappings":"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"} \ No newline at end of file diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.min.js b/extensions/pagetop-bootsier/static/js/bootstrap.min.js new file mode 100644 index 00000000..d5dc5ea1 --- /dev/null +++ b/extensions/pagetop-bootsier/static/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e(t.Popper)}(this,(function(t){"use strict";function e(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t)for(const i in t)if("default"!==i){const s=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,s.get?s:{enumerable:!0,get:()=>t[i]})}return e.default=t,Object.freeze(e)}const i=e(t),s=new Map,n={set(t,e,i){s.has(t)||s.set(t,new Map);const n=s.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>s.has(t)&&s.get(t).get(e)||null,remove(t,e){if(!s.has(t))return;const i=s.get(t);i.delete(e),0===i.size&&s.delete(t)}},o="transitionend",r=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),a=t=>{t.dispatchEvent(new Event(o))},l=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),c=t=>l(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(r(t)):null,h=t=>{if(!l(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},d=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),u=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?u(t.parentNode):null},_=()=>{},g=t=>{t.offsetHeight},f=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,m=[],p=()=>"rtl"===document.documentElement.dir,b=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,s=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=s,t.jQueryInterface)}},"loading"===document.readyState?(m.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of m)t()})),m.push(e)):e()},v=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,y=(t,e,i=!0)=>{if(!i)return void v(t);const s=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const s=Number.parseFloat(e),n=Number.parseFloat(i);return s||n?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let n=!1;const r=({target:i})=>{i===e&&(n=!0,e.removeEventListener(o,r),v(t))};e.addEventListener(o,r),setTimeout((()=>{n||a(e)}),s)},w=(t,e,i,s)=>{const n=t.length;let o=t.indexOf(e);return-1===o?!i&&s?t[n-1]:t[0]:(o+=i?1:-1,s&&(o=(o+n)%n),t[Math.max(0,Math.min(o,n-1))])},A=/[^.]*(?=\..*)\.|.*/,E=/\..*/,C=/::\d+$/,T={};let k=1;const $={mouseenter:"mouseover",mouseleave:"mouseout"},S=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${k++}`||t.uidEvent||k++}function O(t){const e=L(t);return t.uidEvent=e,T[e]=T[e]||{},T[e]}function I(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function D(t,e,i){const s="string"==typeof e,n=s?i:e||i;let o=M(t);return S.has(o)||(o=t),[s,n,o]}function N(t,e,i,s,n){if("string"!=typeof e||!t)return;let[o,r,a]=D(e,i,s);if(e in $){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=O(t),c=l[a]||(l[a]={}),h=I(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&n);const d=L(r,e.replace(A,"")),u=o?function(t,e,i){return function s(n){const o=t.querySelectorAll(e);for(let{target:r}=n;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return F(n,{delegateTarget:r}),s.oneOff&&j.off(t,n.type,e,i),i.apply(r,[n])}}(t,i,r):function(t,e){return function i(s){return F(s,{delegateTarget:t}),i.oneOff&&j.off(t,s.type,e),e.apply(t,[s])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=n,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function P(t,e,i,s,n){const o=I(e[i],s,n);o&&(t.removeEventListener(i,o,Boolean(n)),delete e[i][o.uidEvent])}function x(t,e,i,s){const n=e[i]||{};for(const[o,r]of Object.entries(n))o.includes(s)&&P(t,e,i,r.callable,r.delegationSelector)}function M(t){return t=t.replace(E,""),$[t]||t}const j={on(t,e,i,s){N(t,e,i,s,!1)},one(t,e,i,s){N(t,e,i,s,!0)},off(t,e,i,s){if("string"!=typeof e||!t)return;const[n,o,r]=D(e,i,s),a=r!==e,l=O(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))x(t,l,i,e.slice(1));for(const[i,s]of Object.entries(c)){const n=i.replace(C,"");a&&!e.includes(n)||P(t,l,r,s.callable,s.delegationSelector)}}else{if(!Object.keys(c).length)return;P(t,l,r,o,n?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const s=f();let n=null,o=!0,r=!0,a=!1;e!==M(e)&&s&&(n=s.Event(e,i),s(t).trigger(n),o=!n.isPropagationStopped(),r=!n.isImmediatePropagationStopped(),a=n.isDefaultPrevented());const l=F(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&n&&n.preventDefault(),l}};function F(t,e={}){for(const[i,s]of Object.entries(e))try{t[i]=s}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>s})}return t}function z(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function H(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const B={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${H(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${H(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const s of i){let i=s.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=z(t.dataset[s])}return e},getDataAttribute:(t,e)=>z(t.getAttribute(`data-bs-${H(e)}`))};class q{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=l(e)?B.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...l(e)?B.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[s,n]of Object.entries(e)){const e=t[s],o=l(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(n).test(o))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${s}" provided type "${o}" but expected type "${n}".`)}var i}}class W extends q{constructor(t,e){super(),(t=c(t))&&(this._element=t,this._config=this._getConfig(e),n.set(this._element,this.constructor.DATA_KEY,this))}dispose(){n.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){y(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return n.get(c(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.3"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const R=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map((t=>r(t))).join(","):null},K={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let s=t.parentNode.closest(e);for(;s;)i.push(s),s=s.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!d(t)&&h(t)))},getSelectorFromElement(t){const e=R(t);return e&&K.findOne(e)?e:null},getElementFromSelector(t){const e=R(t);return e?K.findOne(e):null},getMultipleElementsFromSelector(t){const e=R(t);return e?K.find(e):[]}},V=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),d(this))return;const n=K.getElementFromSelector(this)||this.closest(`.${s}`);t.getOrCreateInstance(n)[e]()}))},Q=".bs.alert",X=`close${Q}`,Y=`closed${Q}`;class U extends W{static get NAME(){return"alert"}close(){if(j.trigger(this._element,X).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,Y),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=U.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}V(U,"close"),b(U);const G='[data-bs-toggle="button"]';class J extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=J.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}j.on(document,"click.bs.button.data-api",G,(t=>{t.preventDefault();const e=t.target.closest(G);J.getOrCreateInstance(e).toggle()})),b(J);const Z=".bs.swipe",tt=`touchstart${Z}`,et=`touchmove${Z}`,it=`touchend${Z}`,st=`pointerdown${Z}`,nt=`pointerup${Z}`,ot={endCallback:null,leftCallback:null,rightCallback:null},rt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class at extends q{constructor(t,e){super(),this._element=t,t&&at.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return ot}static get DefaultType(){return rt}static get NAME(){return"swipe"}dispose(){j.off(this._element,Z)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),v(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&v(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(j.on(this._element,st,(t=>this._start(t))),j.on(this._element,nt,(t=>this._end(t))),this._element.classList.add("pointer-event")):(j.on(this._element,tt,(t=>this._start(t))),j.on(this._element,et,(t=>this._move(t))),j.on(this._element,it,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const lt=".bs.carousel",ct=".data-api",ht="next",dt="prev",ut="left",_t="right",gt=`slide${lt}`,ft=`slid${lt}`,mt=`keydown${lt}`,pt=`mouseenter${lt}`,bt=`mouseleave${lt}`,vt=`dragstart${lt}`,yt=`load${lt}${ct}`,wt=`click${lt}${ct}`,At="carousel",Et="active",Ct=".active",Tt=".carousel-item",kt=Ct+Tt,$t={ArrowLeft:_t,ArrowRight:ut},St={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Lt={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class Ot extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=K.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===At&&this.cycle()}static get Default(){return St}static get DefaultType(){return Lt}static get NAME(){return"carousel"}next(){this._slide(ht)}nextWhenVisible(){!document.hidden&&h(this._element)&&this.next()}prev(){this._slide(dt)}pause(){this._isSliding&&a(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?j.one(this._element,ft,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,ft,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const s=t>i?ht:dt;this._slide(s,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&j.on(this._element,mt,(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,pt,(()=>this.pause())),j.on(this._element,bt,(()=>this._maybeEnableCycle()))),this._config.touch&&at.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of K.find(".carousel-item img",this._element))j.on(t,vt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ut)),rightCallback:()=>this._slide(this._directionToOrder(_t)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new at(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=$t[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=K.findOne(Ct,this._indicatorsElement);e.classList.remove(Et),e.removeAttribute("aria-current");const i=K.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(Et),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),s=t===ht,n=e||w(this._getItems(),i,s,this._config.wrap);if(n===i)return;const o=this._getItemIndex(n),r=e=>j.trigger(this._element,e,{relatedTarget:n,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(gt).defaultPrevented)return;if(!i||!n)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=n;const l=s?"carousel-item-start":"carousel-item-end",c=s?"carousel-item-next":"carousel-item-prev";n.classList.add(c),g(n),i.classList.add(l),n.classList.add(l),this._queueCallback((()=>{n.classList.remove(l,c),n.classList.add(Et),i.classList.remove(Et,c,l),this._isSliding=!1,r(ft)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return K.findOne(kt,this._element)}_getItems(){return K.find(Tt,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ut?dt:ht:t===ut?ht:dt}_orderToDirection(t){return p()?t===dt?ut:_t:t===dt?_t:ut}static jQueryInterface(t){return this.each((function(){const e=Ot.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}j.on(document,wt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=K.getElementFromSelector(this);if(!e||!e.classList.contains(At))return;t.preventDefault();const i=Ot.getOrCreateInstance(e),s=this.getAttribute("data-bs-slide-to");return s?(i.to(s),void i._maybeEnableCycle()):"next"===B.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),j.on(window,yt,(()=>{const t=K.find('[data-bs-ride="carousel"]');for(const e of t)Ot.getOrCreateInstance(e)})),b(Ot);const It=".bs.collapse",Dt=`show${It}`,Nt=`shown${It}`,Pt=`hide${It}`,xt=`hidden${It}`,Mt=`click${It}.data-api`,jt="show",Ft="collapse",zt="collapsing",Ht=`:scope .${Ft} .${Ft}`,Bt='[data-bs-toggle="collapse"]',qt={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Rt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=K.find(Bt);for(const t of i){const e=K.getSelectorFromElement(t),i=K.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return qt}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Rt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(j.trigger(this._element,Dt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Ft),this._element.classList.add(zt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(zt),this._element.classList.add(Ft,jt),this._element.style[e]="",j.trigger(this._element,Nt)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,Pt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,g(this._element),this._element.classList.add(zt),this._element.classList.remove(Ft,jt);for(const t of this._triggerArray){const e=K.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(zt),this._element.classList.add(Ft),j.trigger(this._element,xt)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(jt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=c(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Bt);for(const e of t){const t=K.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=K.find(Ht,this._config.parent);return K.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Rt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,Mt,Bt,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of K.getMultipleElementsFromSelector(this))Rt.getOrCreateInstance(t,{toggle:!1}).toggle()})),b(Rt);const Kt="dropdown",Vt=".bs.dropdown",Qt=".data-api",Xt="ArrowUp",Yt="ArrowDown",Ut=`hide${Vt}`,Gt=`hidden${Vt}`,Jt=`show${Vt}`,Zt=`shown${Vt}`,te=`click${Vt}${Qt}`,ee=`keydown${Vt}${Qt}`,ie=`keyup${Vt}${Qt}`,se="show",ne='[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)',oe=`${ne}.${se}`,re=".dropdown-menu",ae=p()?"top-end":"top-start",le=p()?"top-start":"top-end",ce=p()?"bottom-end":"bottom-start",he=p()?"bottom-start":"bottom-end",de=p()?"left-start":"right-start",ue=p()?"right-start":"left-start",_e={autoClose:!0,boundary:"clippingParents",display:"dynamic",offset:[0,2],popperConfig:null,reference:"toggle"},ge={autoClose:"(boolean|string)",boundary:"(string|element)",display:"string",offset:"(array|string|function)",popperConfig:"(null|object|function)",reference:"(string|element|object)"};class fe extends W{constructor(t,e){super(t,e),this._popper=null,this._parent=this._element.parentNode,this._menu=K.next(this._element,re)[0]||K.prev(this._element,re)[0]||K.findOne(re,this._parent),this._inNavbar=this._detectNavbar()}static get Default(){return _e}static get DefaultType(){return ge}static get NAME(){return Kt}toggle(){return this._isShown()?this.hide():this.show()}show(){if(d(this._element)||this._isShown())return;const t={relatedTarget:this._element};if(!j.trigger(this._element,Jt,t).defaultPrevented){if(this._createPopper(),"ontouchstart"in document.documentElement&&!this._parent.closest(".navbar-nav"))for(const t of[].concat(...document.body.children))j.on(t,"mouseover",_);this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(se),this._element.classList.add(se),j.trigger(this._element,Zt,t)}}hide(){if(d(this._element)||!this._isShown())return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){if(!j.trigger(this._element,Ut,t).defaultPrevented){if("ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))j.off(t,"mouseover",_);this._popper&&this._popper.destroy(),this._menu.classList.remove(se),this._element.classList.remove(se),this._element.setAttribute("aria-expanded","false"),B.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,Gt,t)}}_getConfig(t){if("object"==typeof(t=super._getConfig(t)).reference&&!l(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Kt.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(){if(void 0===i)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let t=this._element;"parent"===this._config.reference?t=this._parent:l(this._config.reference)?t=c(this._config.reference):"object"==typeof this._config.reference&&(t=this._config.reference);const e=this._getPopperConfig();this._popper=i.createPopper(t,this._menu,e)}_isShown(){return this._menu.classList.contains(se)}_getPlacement(){const t=this._parent;if(t.classList.contains("dropend"))return de;if(t.classList.contains("dropstart"))return ue;if(t.classList.contains("dropup-center"))return"top";if(t.classList.contains("dropdown-center"))return"bottom";const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?le:ae:e?he:ce}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(B.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...v(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=K.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>h(t)));i.length&&w(i,e,t===Yt,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=fe.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=K.find(oe);for(const i of e){const e=fe.getInstance(i);if(!e||!1===e._config.autoClose)continue;const s=t.composedPath(),n=s.includes(e._menu);if(s.includes(e._element)||"inside"===e._config.autoClose&&!n||"outside"===e._config.autoClose&&n)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,s=[Xt,Yt].includes(t.key);if(!s&&!i)return;if(e&&!i)return;t.preventDefault();const n=this.matches(ne)?this:K.prev(this,ne)[0]||K.next(this,ne)[0]||K.findOne(ne,t.delegateTarget.parentNode),o=fe.getOrCreateInstance(n);if(s)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),n.focus())}}j.on(document,ee,ne,fe.dataApiKeydownHandler),j.on(document,ee,re,fe.dataApiKeydownHandler),j.on(document,te,fe.clearMenus),j.on(document,ie,fe.clearMenus),j.on(document,te,ne,(function(t){t.preventDefault(),fe.getOrCreateInstance(this).toggle()})),b(fe);const me="backdrop",pe="show",be=`mousedown.bs.${me}`,ve={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},ye={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class we extends q{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return ve}static get DefaultType(){return ye}static get NAME(){return me}show(t){if(!this._config.isVisible)return void v(t);this._append();const e=this._getElement();this._config.isAnimated&&g(e),e.classList.add(pe),this._emulateAnimation((()=>{v(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(pe),this._emulateAnimation((()=>{this.dispose(),v(t)}))):v(t)}dispose(){this._isAppended&&(j.off(this._element,be),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=c(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),j.on(t,be,(()=>{v(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){y(t,this._getElement(),this._config.isAnimated)}}const Ae=".bs.focustrap",Ee=`focusin${Ae}`,Ce=`keydown.tab${Ae}`,Te="backward",ke={autofocus:!0,trapElement:null},$e={autofocus:"boolean",trapElement:"element"};class Se extends q{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return ke}static get DefaultType(){return $e}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),j.off(document,Ae),j.on(document,Ee,(t=>this._handleFocusin(t))),j.on(document,Ce,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,Ae))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=K.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===Te?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Te:"forward")}}const Le=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",Oe=".sticky-top",Ie="padding-right",De="margin-right";class Ne{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,Ie,(e=>e+t)),this._setElementAttributes(Le,Ie,(e=>e+t)),this._setElementAttributes(Oe,De,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,Ie),this._resetElementAttributes(Le,Ie),this._resetElementAttributes(Oe,De)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const s=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+s)return;this._saveInitialAttribute(t,e);const n=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(n))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&B.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=B.getDataAttribute(t,e);null!==i?(B.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(l(t))e(t);else for(const i of K.find(t,this._element))e(i)}}const Pe=".bs.modal",xe=`hide${Pe}`,Me=`hidePrevented${Pe}`,je=`hidden${Pe}`,Fe=`show${Pe}`,ze=`shown${Pe}`,He=`resize${Pe}`,Be=`click.dismiss${Pe}`,qe=`mousedown.dismiss${Pe}`,We=`keydown.dismiss${Pe}`,Re=`click${Pe}.data-api`,Ke="modal-open",Ve="show",Qe="modal-static",Xe={backdrop:!0,focus:!0,keyboard:!0},Ye={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class Ue extends W{constructor(t,e){super(t,e),this._dialog=K.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new Ne,this._addEventListeners()}static get Default(){return Xe}static get DefaultType(){return Ye}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,Fe,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Ke),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(j.trigger(this._element,xe).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(Ve),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){j.off(window,Pe),j.off(this._dialog,Pe),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new we({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Se({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=K.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),g(this._element),this._element.classList.add(Ve),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,ze,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){j.on(this._element,We,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),j.on(window,He,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),j.on(this._element,qe,(t=>{j.one(this._element,Be,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Ke),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,je)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,Me).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(Qe)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(Qe),this._queueCallback((()=>{this._element.classList.remove(Qe),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Ue.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,Re,'[data-bs-toggle="modal"]',(function(t){const e=K.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,Fe,(t=>{t.defaultPrevented||j.one(e,je,(()=>{h(this)&&this.focus()}))}));const i=K.findOne(".modal.show");i&&Ue.getInstance(i).hide(),Ue.getOrCreateInstance(e).toggle(this)})),V(Ue),b(Ue);const Ge=".bs.offcanvas",Je=".data-api",Ze=`load${Ge}${Je}`,ti="show",ei="showing",ii="hiding",si=".offcanvas.show",ni=`show${Ge}`,oi=`shown${Ge}`,ri=`hide${Ge}`,ai=`hidePrevented${Ge}`,li=`hidden${Ge}`,ci=`resize${Ge}`,hi=`click${Ge}${Je}`,di=`keydown.dismiss${Ge}`,ui={backdrop:!0,keyboard:!0,scroll:!1},_i={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class gi extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return ui}static get DefaultType(){return _i}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,ni,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new Ne).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(ei),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(ti),this._element.classList.remove(ei),j.trigger(this._element,oi,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,ri).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(ii),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(ti,ii),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new Ne).reset(),j.trigger(this._element,li)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new we({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():j.trigger(this._element,ai)}:null})}_initializeFocusTrap(){return new Se({trapElement:this._element})}_addEventListeners(){j.on(this._element,di,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():j.trigger(this._element,ai))}))}static jQueryInterface(t){return this.each((function(){const e=gi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,hi,'[data-bs-toggle="offcanvas"]',(function(t){const e=K.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),d(this))return;j.one(e,li,(()=>{h(this)&&this.focus()}));const i=K.findOne(si);i&&i!==e&&gi.getInstance(i).hide(),gi.getOrCreateInstance(e).toggle(this)})),j.on(window,Ze,(()=>{for(const t of K.find(si))gi.getOrCreateInstance(t).show()})),j.on(window,ci,(()=>{for(const t of K.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&gi.getOrCreateInstance(t).hide()})),V(gi),b(gi);const fi={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},mi=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),pi=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,bi=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!mi.has(i)||Boolean(pi.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},vi={allowList:fi,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"<div></div>"},yi={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},wi={entry:"(string|element|function|null)",selector:"(string|element)"};class Ai extends q{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return vi}static get DefaultType(){return yi}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},wi)}_setContent(t,e,i){const s=K.findOne(i,t);s&&((e=this._resolvePossibleFunction(e))?l(e)?this._putElementInTemplate(c(e),s):this._config.html?s.innerHTML=this._maybeSanitize(e):s.textContent=e:s.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const s=(new window.DOMParser).parseFromString(t,"text/html"),n=[].concat(...s.body.querySelectorAll("*"));for(const t of n){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const s=[].concat(...t.attributes),n=[].concat(e["*"]||[],e[i]||[]);for(const e of s)bi(e,n)||t.removeAttribute(e.nodeName)}return s.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return v(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Ei=new Set(["sanitize","allowList","sanitizeFn"]),Ci="fade",Ti="show",ki=".modal",$i="hide.bs.modal",Si="hover",Li="focus",Oi={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},Ii={allowList:fi,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',title:"",trigger:"hover focus"},Di={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class Ni extends W{constructor(t,e){if(void 0===i)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return Ii}static get DefaultType(){return Di}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ki),$i,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.eventName("show")),e=(u(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:s}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(s.append(i),j.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(Ti),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))j.on(t,"mouseover",_);this._queueCallback((()=>{j.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!j.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(Ti),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))j.off(t,"mouseover",_);this._activeTrigger.click=!1,this._activeTrigger[Li]=!1,this._activeTrigger[Si]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(Ci,Ti),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(Ci),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Ai({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(Ci)}_isShown(){return this.tip&&this.tip.classList.contains(Ti)}_createPopper(t){const e=v(this._config.placement,[this,t,this._element]),s=Oi[e.toUpperCase()];return i.createPopper(this._element,t,this._getPopperConfig(s))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return v(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...v(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)j.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===Si?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===Si?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");j.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?Li:Si]=!0,e._enter()})),j.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?Li:Si]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ki),$i,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=B.getDataAttributes(this._element);for(const t of Object.keys(e))Ei.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:c(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=Ni.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}b(Ni);const Pi={...Ni.Default,content:"",offset:[0,8],placement:"right",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>',trigger:"click"},xi={...Ni.DefaultType,content:"(null|string|element|function)"};class Mi extends Ni{static get Default(){return Pi}static get DefaultType(){return xi}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=Mi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}b(Mi);const ji=".bs.scrollspy",Fi=`activate${ji}`,zi=`click${ji}`,Hi=`load${ji}.data-api`,Bi="active",qi="[href]",Wi=".nav-link",Ri=`${Wi}, .nav-item > ${Wi}, .list-group-item`,Ki={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},Vi={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Qi extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return Ki}static get DefaultType(){return Vi}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=c(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(j.off(this._config.target,zi),j.on(this._config.target,zi,qi,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,s=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:s,behavior:"smooth"});i.scrollTop=s}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},s=(this._rootElement||document.documentElement).scrollTop,n=s>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=s;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(n&&t){if(i(o),!s)return}else n||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=K.find(qi,this._config.target);for(const e of t){if(!e.hash||d(e))continue;const t=K.findOne(decodeURI(e.hash),this._element);h(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(Bi),this._activateParents(t),j.trigger(this._element,Fi,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))K.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(Bi);else for(const e of K.parents(t,".nav, .list-group"))for(const t of K.prev(e,Ri))t.classList.add(Bi)}_clearActiveClass(t){t.classList.remove(Bi);const e=K.find(`${qi}.${Bi}`,t);for(const t of e)t.classList.remove(Bi)}static jQueryInterface(t){return this.each((function(){const e=Qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,Hi,(()=>{for(const t of K.find('[data-bs-spy="scroll"]'))Qi.getOrCreateInstance(t)})),b(Qi);const Xi=".bs.tab",Yi=`hide${Xi}`,Ui=`hidden${Xi}`,Gi=`show${Xi}`,Ji=`shown${Xi}`,Zi=`click${Xi}`,ts=`keydown${Xi}`,es=`load${Xi}`,is="ArrowLeft",ss="ArrowRight",ns="ArrowUp",os="ArrowDown",rs="Home",as="End",ls="active",cs="fade",hs="show",ds=".dropdown-toggle",us=`:not(${ds})`,_s='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',gs=`.nav-link${us}, .list-group-item${us}, [role="tab"]${us}, ${_s}`,fs=`.${ls}[data-bs-toggle="tab"], .${ls}[data-bs-toggle="pill"], .${ls}[data-bs-toggle="list"]`;class ms extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),j.on(this._element,ts,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?j.trigger(e,Yi,{relatedTarget:t}):null;j.trigger(t,Gi,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(ls),this._activate(K.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),j.trigger(t,Ji,{relatedTarget:e})):t.classList.add(hs)}),t,t.classList.contains(cs)))}_deactivate(t,e){t&&(t.classList.remove(ls),t.blur(),this._deactivate(K.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),j.trigger(t,Ui,{relatedTarget:e})):t.classList.remove(hs)}),t,t.classList.contains(cs)))}_keydown(t){if(![is,ss,ns,os,rs,as].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!d(t)));let i;if([rs,as].includes(t.key))i=e[t.key===rs?0:e.length-1];else{const s=[ss,os].includes(t.key);i=w(e,t.target,s,!0)}i&&(i.focus({preventScroll:!0}),ms.getOrCreateInstance(i).show())}_getChildren(){return K.find(gs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=K.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const s=(t,s)=>{const n=K.findOne(t,i);n&&n.classList.toggle(s,e)};s(ds,ls),s(".dropdown-menu",hs),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(ls)}_getInnerElement(t){return t.matches(gs)?t:K.findOne(gs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=ms.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,Zi,_s,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),d(this)||ms.getOrCreateInstance(this).show()})),j.on(window,es,(()=>{for(const t of K.find(fs))ms.getOrCreateInstance(t)})),b(ms);const ps=".bs.toast",bs=`mouseover${ps}`,vs=`mouseout${ps}`,ys=`focusin${ps}`,ws=`focusout${ps}`,As=`hide${ps}`,Es=`hidden${ps}`,Cs=`show${ps}`,Ts=`shown${ps}`,ks="hide",$s="show",Ss="showing",Ls={animation:"boolean",autohide:"boolean",delay:"number"},Os={animation:!0,autohide:!0,delay:5e3};class Is extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return Os}static get DefaultType(){return Ls}static get NAME(){return"toast"}show(){j.trigger(this._element,Cs).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(ks),g(this._element),this._element.classList.add($s,Ss),this._queueCallback((()=>{this._element.classList.remove(Ss),j.trigger(this._element,Ts),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(j.trigger(this._element,As).defaultPrevented||(this._element.classList.add(Ss),this._queueCallback((()=>{this._element.classList.add(ks),this._element.classList.remove(Ss,$s),j.trigger(this._element,Es)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove($s),super.dispose()}isShown(){return this._element.classList.contains($s)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,bs,(t=>this._onInteraction(t,!0))),j.on(this._element,vs,(t=>this._onInteraction(t,!1))),j.on(this._element,ys,(t=>this._onInteraction(t,!0))),j.on(this._element,ws,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Is.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return V(Is),b(Is),{Alert:U,Button:J,Carousel:Ot,Collapse:Rt,Dropdown:fe,Modal:Ue,Offcanvas:gi,Popover:Mi,ScrollSpy:Qi,Tab:ms,Toast:Is,Tooltip:Ni}})); +//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.min.js.map b/extensions/pagetop-bootsier/static/js/bootstrap.min.js.map new file mode 100644 index 00000000..4d437152 --- /dev/null +++ b/extensions/pagetop-bootsier/static/js/bootstrap.min.js.map @@ -0,0 +1 @@ +{"version":3,"names":["elementMap","Map","Data","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete","TRANSITION_END","parseSelector","selector","window","CSS","escape","replace","match","id","triggerTransitionEnd","dispatchEvent","Event","isElement","object","jquery","nodeType","getElement","length","document","querySelector","isVisible","getClientRects","elementIsVisible","getComputedStyle","getPropertyValue","closedDetails","closest","summary","parentNode","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","getAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","noop","reflow","offsetHeight","getjQuery","jQuery","body","DOMContentLoadedCallbacks","isRTL","dir","defineJQueryPlugin","plugin","callback","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","readyState","addEventListener","push","execute","possibleCallback","args","defaultValue","executeAfterTransition","transitionElement","waitForTransition","emulatedDuration","transitionDuration","transitionDelay","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","split","getTransitionDurationFromElement","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","listLength","index","indexOf","Math","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","nativeEvents","Set","makeEventUid","uid","getElementEvents","findHandler","events","callable","delegationSelector","Object","values","find","event","normalizeParameters","originalTypeEvent","delegationFunction","isDelegated","typeEvent","getTypeEvent","addHandler","oneOff","wrapFunction","relatedTarget","delegateTarget","call","this","handlers","previousFunction","domElements","querySelectorAll","domElement","hydrateObj","EventHandler","off","type","apply","bootstrapDelegationHandler","bootstrapHandler","removeHandler","Boolean","removeNamespacedHandlers","namespace","storeElementEvent","handlerKey","entries","includes","on","one","inNamespace","isNamespace","startsWith","elementEvent","slice","keyHandlers","trigger","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","evt","cancelable","preventDefault","obj","meta","value","_unused","defineProperty","configurable","normalizeData","toString","JSON","parse","decodeURIComponent","normalizeDataKey","chr","toLowerCase","Manipulator","setDataAttribute","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","dataset","filter","pureKey","charAt","getDataAttribute","Config","Default","DefaultType","Error","_getConfig","config","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","jsonConfig","constructor","configTypes","property","expectedTypes","valueType","prototype","RegExp","test","TypeError","toUpperCase","BaseComponent","super","_element","_config","DATA_KEY","dispose","EVENT_KEY","propertyName","getOwnPropertyNames","_queueCallback","isAnimated","getInstance","getOrCreateInstance","VERSION","eventName","getSelector","hrefAttribute","trim","map","sel","join","SelectorEngine","concat","Element","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","el","getSelectorFromElement","getElementFromSelector","getMultipleElementsFromSelector","enableDismissTrigger","component","method","clickEvent","tagName","EVENT_CLOSE","EVENT_CLOSED","Alert","close","_destroyElement","each","data","undefined","SELECTOR_DATA_TOGGLE","Button","toggle","button","EVENT_TOUCHSTART","EVENT_TOUCHMOVE","EVENT_TOUCHEND","EVENT_POINTERDOWN","EVENT_POINTERUP","endCallback","leftCallback","rightCallback","Swipe","isSupported","_deltaX","_supportPointerEvents","PointerEvent","_initEvents","_start","_eventIsPointerPenTouch","clientX","touches","_end","_handleSwipe","_move","absDeltaX","abs","direction","add","pointerType","navigator","maxTouchPoints","DATA_API_KEY","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","EVENT_SLIDE","EVENT_SLID","EVENT_KEYDOWN","EVENT_MOUSEENTER","EVENT_MOUSELEAVE","EVENT_DRAG_START","EVENT_LOAD_DATA_API","EVENT_CLICK_DATA_API","CLASS_NAME_CAROUSEL","CLASS_NAME_ACTIVE","SELECTOR_ACTIVE","SELECTOR_ITEM","SELECTOR_ACTIVE_ITEM","KEY_TO_DIRECTION","ArrowLeft","ArrowRight","interval","keyboard","pause","ride","touch","wrap","Carousel","_interval","_activeElement","_isSliding","touchTimeout","_swipeHelper","_indicatorsElement","_addEventListeners","cycle","_slide","nextWhenVisible","hidden","_clearInterval","_updateInterval","setInterval","_maybeEnableCycle","to","items","_getItems","activeIndex","_getItemIndex","_getActive","order","defaultInterval","_keydown","_addTouchEventListeners","img","swipeConfig","_directionToOrder","endCallBack","clearTimeout","_setActiveIndicatorElement","activeIndicator","newActiveIndicator","elementInterval","parseInt","isNext","nextElement","nextElementIndex","triggerEvent","_orderToDirection","isCycling","directionalClassName","orderClassName","completeCallBack","_isAnimated","clearInterval","carousel","slideIndex","carousels","EVENT_SHOW","EVENT_SHOWN","EVENT_HIDE","EVENT_HIDDEN","CLASS_NAME_SHOW","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_DEEPER_CHILDREN","parent","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElement","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activeChildren","_getFirstLevelChildren","activeInstance","dimension","_getDimension","style","scrollSize","complete","getBoundingClientRect","selected","triggerArray","isOpen","ARROW_UP_KEY","ARROW_DOWN_KEY","EVENT_KEYDOWN_DATA_API","EVENT_KEYUP_DATA_API","SELECTOR_DATA_TOGGLE_SHOWN","SELECTOR_MENU","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","autoClose","boundary","display","offset","popperConfig","reference","Dropdown","_popper","_parent","_menu","_inNavbar","_detectNavbar","_createPopper","focus","_completeHide","destroy","update","Popper","referenceElement","_getPopperConfig","createPopper","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","placement","modifiers","options","enabled","_selectMenuItem","clearMenus","openToggles","context","composedPath","isMenuTarget","dataApiKeydownHandler","isInput","isEscapeEvent","isUpOrDownEvent","getToggleButton","stopPropagation","EVENT_MOUSEDOWN","className","clickCallback","rootElement","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","EVENT_FOCUSIN","EVENT_KEYDOWN_TAB","TAB_NAV_BACKWARD","autofocus","trapElement","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","elements","shiftKey","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","PROPERTY_PADDING","PROPERTY_MARGIN","ScrollBarHelper","getWidth","documentWidth","clientWidth","innerWidth","width","_disableOverFlow","_setElementAttributes","calculatedValue","reset","_resetElementAttributes","isOverflowing","_saveInitialAttribute","overflow","styleProperty","scrollbarWidth","_applyManipulationCallback","setProperty","actualValue","removeProperty","callBack","EVENT_HIDE_PREVENTED","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_MOUSEDOWN_DISMISS","EVENT_KEYDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_scrollBar","_adjustDialog","_showElement","_hideModal","handleUpdate","scrollTop","modalBody","transitionComplete","_triggerBackdropTransition","event2","_resetAdjustments","isModalOverflowing","scrollHeight","clientHeight","initialOverflowY","overflowY","isBodyOverflowing","paddingLeft","paddingRight","showEvent","alreadyOpen","CLASS_NAME_SHOWING","CLASS_NAME_HIDING","OPEN_SELECTOR","scroll","Offcanvas","blur","completeCallback","position","DefaultAllowlist","a","area","b","br","col","code","dd","div","dl","dt","em","hr","h1","h2","h3","h4","h5","h6","i","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","uriAttributes","SAFE_URL_PATTERN","allowedAttribute","attribute","allowedAttributeList","attributeName","nodeName","nodeValue","attributeRegex","some","regex","allowList","content","extraClass","html","sanitize","sanitizeFn","template","DefaultContentType","entry","TemplateFactory","getContent","_resolvePossibleFunction","hasContent","changeContent","_checkContent","toHtml","templateWrapper","innerHTML","_maybeSanitize","text","_setContent","arg","templateElement","_putElementInTemplate","textContent","unsafeHtml","sanitizeFunction","createdDocument","DOMParser","parseFromString","elementName","attributeList","allowedAttributes","sanitizeHtml","DISALLOWED_ATTRIBUTES","CLASS_NAME_FADE","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","animation","container","customClass","delay","fallbackPlacements","title","Tooltip","_isEnabled","_timeout","_isHovered","_activeTrigger","_templateFactory","_newContent","tip","_setListeners","_fixTitle","enable","disable","toggleEnabled","click","_leave","_enter","_hideModalHandler","_disposePopper","_isWithContent","isInTheDom","ownerDocument","_getTipElement","_isWithActiveTrigger","_getTitle","_createTipElement","_getContentForTemplate","_getTemplateFactory","tipId","prefix","floor","random","getElementById","getUID","setContent","_initializeOnDelegatedTarget","_getDelegateConfig","attachment","phase","state","triggers","eventIn","eventOut","_setTimeout","timeout","dataAttributes","dataAttribute","Popover","_getContent","EVENT_ACTIVATE","EVENT_CLICK","SELECTOR_TARGET_LINKS","SELECTOR_NAV_LINKS","SELECTOR_LINK_ITEMS","rootMargin","smoothScroll","threshold","ScrollSpy","_targetLinks","_observableSections","_rootElement","_activeTarget","_observer","_previousScrollData","visibleEntryTop","parentScrollTop","refresh","_initializeTargetsAndObservables","_maybeEnableSmoothScroll","disconnect","_getNewObserver","section","observe","observableSection","hash","height","offsetTop","scrollTo","top","behavior","IntersectionObserver","_observerCallback","targetElement","_process","userScrollsDown","isIntersecting","_clearActiveClass","entryIsLowerThanPrevious","targetLinks","anchor","decodeURI","_activateParents","listGroup","item","activeNodes","node","spy","ARROW_LEFT_KEY","ARROW_RIGHT_KEY","HOME_KEY","END_KEY","SELECTOR_DROPDOWN_TOGGLE","NOT_SELECTOR_DROPDOWN_TOGGLE","SELECTOR_INNER_ELEM","SELECTOR_DATA_TOGGLE_ACTIVE","Tab","_setInitialAttributes","_getChildren","innerElem","_elemIsActive","active","_getActiveElem","hideEvent","_deactivate","_activate","relatedElem","_toggleDropDown","nextActiveElement","preventScroll","_setAttributeIfNotExists","_setInitialAttributesOnChild","_getInnerElement","isActive","outerElem","_getOuterElement","_setInitialAttributesOnTargetPanel","open","EVENT_MOUSEOVER","EVENT_MOUSEOUT","EVENT_FOCUSOUT","CLASS_NAME_HIDE","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","isShown","_onInteraction","isInteracting"],"sources":["../../js/src/dom/data.js","../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/manipulator.js","../../js/src/util/config.js","../../js/src/base-component.js","../../js/src/dom/selector-engine.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/util/swipe.js","../../js/src/carousel.js","../../js/src/collapse.js","../../js/src/dropdown.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/util/scrollbar.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/util/template-factory.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1_000_000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`)\n }\n\n return selector\n}\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`\n }\n\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = object => {\n if (!object || typeof object !== 'object') {\n return false\n }\n\n if (typeof object.jquery !== 'undefined') {\n object = object[0]\n }\n\n return typeof object.nodeType !== 'undefined'\n}\n\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (isElement(object)) {\n return object.jquery ? object[0] : object\n }\n\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object))\n }\n\n return null\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])')\n\n if (!closedDetails) {\n return elementIsVisible\n }\n\n if (closedDetails !== element) {\n const summary = element.closest('summary')\n if (summary && summary.parentNode !== closedDetails) {\n return false\n }\n\n if (summary === null) {\n return false\n }\n }\n\n return elementIsVisible\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight // eslint-disable-line no-unused-expressions\n}\n\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback()\n }\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]\n }\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n defineJQueryPlugin,\n execute,\n executeAfterTransition,\n findShadowRoot,\n getElement,\n getjQuery,\n getNextActiveElement,\n getTransitionDurationFromElement,\n getUID,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n onDOMContentLoaded,\n parseSelector,\n reflow,\n triggerTransitionEnd,\n toType\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index.js'\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\n\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getElementEvents(element) {\n const uid = makeEventUid(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, { delegateTarget: element })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue\n }\n\n hydrateObj(event, { delegateTarget: target })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n}\n\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events)\n .find(event => event.callable === callable && event.delegationSelector === delegationSelector)\n}\n\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string'\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : (handler || delegationFunction)\n let typeEvent = getTypeEvent(originalTypeEvent)\n\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent\n }\n\n return [isDelegated, callable, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n callable = wrapFunction(callable)\n }\n\n const events = getElementEvents(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)\n\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff\n\n return\n }\n\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = isDelegated ?\n bootstrapDelegationHandler(element, handler, callable) :\n bootstrapHandler(element, callable)\n\n fn.delegationSelector = isDelegated ? handler : null\n fn.callable = callable\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, isDelegated)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false)\n },\n\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getElementEvents(element)\n const storeElementEvent = events[typeEvent] || {}\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return\n }\n\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)\n return\n }\n\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n }\n }\n\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n\n let jQueryEvent = null\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value\n } catch {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value\n }\n })\n }\n }\n\n return obj\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true\n }\n\n if (value === 'false') {\n return false\n }\n\n if (value === Number(value).toString()) {\n return Number(value)\n }\n\n if (value === '' || value === 'null') {\n return null\n }\n\n if (typeof value !== 'string') {\n return value\n }\n\n try {\n return JSON.parse(decodeURIComponent(value))\n } catch {\n return value\n }\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))\n\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)\n attributes[pureKey] = normalizeData(element.dataset[key])\n }\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport { isElement, toType } from './index.js'\n\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {}\n }\n\n static get DefaultType() {\n return {}\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n return config\n }\n\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n }\n }\n\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property]\n const valueType = isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n }\n }\n}\n\nexport default Config\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data.js'\nimport EventHandler from './dom/event-handler.js'\nimport Config from './util/config.js'\nimport { executeAfterTransition, getElement } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.3'\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super()\n\n element = getElement(element)\n if (!element) {\n return\n }\n\n this._element = element\n this._config = this._getConfig(config)\n\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null\n }\n }\n\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible, parseSelector } from '../util/index.js'\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`\n }\n\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null\n }\n\n return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null\n}\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n let ancestor = element.parentNode.closest(selector)\n\n while (ancestor) {\n parents.push(ancestor)\n ancestor = ancestor.parentNode.closest(selector)\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n },\n\n getSelectorFromElement(element) {\n const selector = getSelector(element)\n\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null\n }\n\n return null\n },\n\n getElementFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.findOne(selector) : null\n },\n\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.find(selector) : []\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isDisabled } from './index.js'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport { execute } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'swipe'\nconst EVENT_KEY = '.bs.swipe'\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n}\n\nconst DefaultType = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n}\n\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super()\n this._element = element\n\n if (!element || !Swipe.isSupported()) {\n return\n }\n\n this._config = this._getConfig(config)\n this._deltaX = 0\n this._supportPointerEvents = Boolean(window.PointerEvent)\n this._initEvents()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY)\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX\n\n return\n }\n\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX\n }\n }\n\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX\n }\n\n this._handleSwipe()\n execute(this._config.endCallback)\n }\n\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this._deltaX\n }\n\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX)\n\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltaX / this._deltaX\n\n this._deltaX = 0\n\n if (!direction) {\n return\n }\n\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)\n }\n\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))\n }\n }\n\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n }\n}\n\nexport default Swipe\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getNextActiveElement,\n isRTL,\n isVisible,\n reflow,\n triggerTransitionEnd\n} from './util/index.js'\nimport Swipe from './util/swipe.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)', // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._interval = null\n this._activeElement = null\n this._isSliding = false\n this.touchTimeout = null\n this._swipeHelper = null\n\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._addEventListeners()\n\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element)\n }\n\n this._clearInterval()\n }\n\n cycle() {\n this._clearInterval()\n this._updateInterval()\n\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval)\n }\n\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle())\n return\n }\n\n this.cycle()\n }\n\n to(index) {\n const items = this._getItems()\n if (index > items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n const activeIndex = this._getItemIndex(this._getActive())\n if (activeIndex === index) {\n return\n }\n\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV\n\n this._slide(order, items[index])\n }\n\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose()\n }\n\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval\n return config\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause())\n EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle())\n }\n\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault())\n }\n\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n }\n\n this._swipeHelper = new Swipe(this._element, swipeConfig)\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(this._directionToOrder(direction))\n }\n }\n\n _getItemIndex(element) {\n return this._getItems().indexOf(element)\n }\n\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return\n }\n\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement)\n\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE)\n newActiveIndicator.setAttribute('aria-current', 'true')\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || this._getActive()\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n this._config.interval = elementInterval || this._config.defaultInterval\n }\n\n _slide(order, element = null) {\n if (this._isSliding) {\n return\n }\n\n const activeElement = this._getActive()\n const isNext = order === ORDER_NEXT\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap)\n\n if (nextElement === activeElement) {\n return\n }\n\n const nextElementIndex = this._getItemIndex(nextElement)\n\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n })\n }\n\n const slideEvent = triggerEvent(EVENT_SLIDE)\n\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return\n }\n\n const isCycling = Boolean(this._interval)\n this.pause()\n\n this._isSliding = true\n\n this._setActiveIndicatorElement(nextElementIndex)\n this._activeElement = nextElement\n\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n triggerEvent(EVENT_SLID)\n }\n\n this._queueCallback(completeCallBack, activeElement, this._isAnimated())\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE)\n }\n\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n }\n\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element)\n }\n\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n }\n\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config)\n\n if (typeof config === 'number') {\n data.to(config)\n return\n }\n\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n event.preventDefault()\n\n const carousel = Carousel.getOrCreateInstance(target)\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n carousel.to(slideIndex)\n carousel._maybeEnableCycle()\n return\n }\n\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next()\n carousel._maybeEnableCycle()\n return\n }\n\n carousel.prev()\n carousel._maybeEnableCycle()\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getElement,\n reflow\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\nconst Default = {\n parent: null,\n toggle: true\n}\n\nconst DefaultType = {\n parent: '(null|element)',\n toggle: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isTransitioning = false\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElement => foundElement === this._element)\n\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let activeChildren = []\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)\n .filter(element => element !== this._element)\n .map(element => Collapse.getOrCreateInstance(element, { toggle: false }))\n }\n\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n for (const activeInstance of activeChildren) {\n activeInstance.hide()\n }\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger)\n\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)\n\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n }\n }\n\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element))\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen)\n element.setAttribute('aria-expanded', isOpen)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n execute,\n getElement,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center'\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)'\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR = '.navbar'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\nconst PLACEMENT_TOPCENTER = 'top'\nconst PLACEMENT_BOTTOMCENTER = 'bottom'\n\nconst Default = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n}\n\nconst DefaultType = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n}\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._popper = null\n this._parent = this._element.parentNode // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.findOne(SELECTOR_MENU, this._parent)\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._createPopper()\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = super._getConfig(config)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = this._parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n }\n\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getPlacement() {\n const parentDropdown = this._parent\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {\n return\n }\n\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)\n\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle)\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n const relatedTarget = { relatedTarget: context._element }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName)\n const isEscapeEvent = event.key === ESCAPE_KEY\n const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)\n\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return\n }\n\n if (isInput && !isEscapeEvent) {\n return\n }\n\n event.preventDefault()\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?\n this :\n (SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode))\n\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (isUpOrDownEvent) {\n event.stopPropagation()\n instance.show()\n instance._selectMenuItem(event)\n return\n }\n\n if (instance._isShown()) { // else is escape and we check if it is shown\n event.stopPropagation()\n instance.hide()\n getToggleButton.focus()\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport {\n execute, executeAfterTransition, getElement, reflow\n} from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nconst Default = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n}\n\nconst DefaultType = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n}\n\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n const element = this._getElement()\n if (this._config.isAnimated) {\n reflow(element)\n }\n\n element.classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n const element = this._getElement()\n this._config.rootElement.append(element)\n\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nconst Default = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n}\n\nconst DefaultType = {\n autofocus: 'boolean',\n trapElement: 'element'\n}\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return\n }\n\n if (this._config.autofocus) {\n this._config.trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n _handleFocusin(event) {\n const { trapElement } = this._config\n\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\nconst PROPERTY_PADDING = 'padding-right'\nconst PROPERTY_MARGIN = 'margin-right'\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProperty)\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty)\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty)\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty)\n return\n }\n\n Manipulator.removeDataAttribute(element, styleProperty)\n element.style.setProperty(styleProperty, value)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n return\n }\n\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel)\n }\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin, isRTL, isVisible, reflow\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\nconst Default = {\n backdrop: true,\n focus: true,\n keyboard: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._isTransitioning = true\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._backdrop.show(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n this._isTransitioning = true\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated())\n }\n\n dispose() {\n EventHandler.off(window, EVENT_KEY)\n EventHandler.off(this._dialog, EVENT_KEY)\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated())\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n this._triggerBackdropTransition()\n })\n\n EventHandler.on(window, EVENT_RESIZE, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog()\n }\n })\n\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return\n }\n\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n return\n }\n\n if (this._config.backdrop) {\n this.hide()\n }\n })\n })\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const initialOverflowY = this._element.style.overflowY\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden'\n }\n\n this._element.classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY\n }, this._dialog)\n }, this._dialog)\n\n this._element.focus()\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin,\n isDisabled,\n isVisible\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\nconst CLASS_NAME_HIDING = 'hiding'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate()\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.add(CLASS_NAME_HIDING)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n return\n }\n\n this.hide()\n }\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop)\n\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n })\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show()\n }\n})\n\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide()\n }\n }\n})\n\nenableDismissTrigger(Offcanvas)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n dd: [],\n div: [],\n dl: [],\n dt: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n// js-docs-end allow-list\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\n// eslint-disable-next-line unicorn/better-regex\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n .some(regex => regex.test(attributeName))\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n }\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\nimport { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'\nimport { execute, getElement, isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'TemplateFactory'\n\nconst Default = {\n allowList: DefaultAllowlist,\n content: {}, // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '<div></div>'\n}\n\nconst DefaultType = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n}\n\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n}\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content)\n .map(config => this._resolvePossibleFunction(config))\n .filter(Boolean)\n }\n\n hasContent() {\n return this.getContent().length > 0\n }\n\n changeContent(content) {\n this._checkContent(content)\n this._config.content = { ...this._config.content, ...content }\n return this\n }\n\n toHtml() {\n const templateWrapper = document.createElement('div')\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template)\n\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector)\n }\n\n const template = templateWrapper.children[0]\n const extraClass = this._resolvePossibleFunction(this._config.extraClass)\n\n if (extraClass) {\n template.classList.add(...extraClass.split(' '))\n }\n\n return template\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config)\n this._checkContent(config.content)\n }\n\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({ selector, entry: content }, DefaultContentType)\n }\n }\n\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!templateElement) {\n return\n }\n\n content = this._resolvePossibleFunction(content)\n\n if (!content) {\n templateElement.remove()\n return\n }\n\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement)\n return\n }\n\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content)\n return\n }\n\n templateElement.textContent = content\n }\n\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this])\n }\n\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = ''\n templateElement.append(element)\n return\n }\n\n templateElement.textContent = element.textContent\n }\n}\n\nexport default TemplateFactory\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport {\n defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop\n} from './util/index.js'\nimport { DefaultAllowlist } from './util/sanitizer.js'\nimport TemplateFactory from './util/template-factory.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\nconst EVENT_HIDE = 'hide'\nconst EVENT_HIDDEN = 'hidden'\nconst EVENT_SHOW = 'show'\nconst EVENT_SHOWN = 'shown'\nconst EVENT_INSERTED = 'inserted'\nconst EVENT_CLICK = 'click'\nconst EVENT_FOCUSIN = 'focusin'\nconst EVENT_FOCUSOUT = 'focusout'\nconst EVENT_MOUSEENTER = 'mouseenter'\nconst EVENT_MOUSELEAVE = 'mouseleave'\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '<div class=\"tooltip\" role=\"tooltip\">' +\n '<div class=\"tooltip-arrow\"></div>' +\n '<div class=\"tooltip-inner\"></div>' +\n '</div>',\n title: '',\n trigger: 'hover focus'\n}\n\nconst DefaultType = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n}\n\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org)')\n }\n\n super(element, config)\n\n // Private\n this._isEnabled = true\n this._timeout = 0\n this._isHovered = null\n this._activeTrigger = {}\n this._popper = null\n this._templateFactory = null\n this._newContent = null\n\n // Protected\n this.tip = null\n\n this._setListeners()\n\n if (!this._config.selector) {\n this._fixTitle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle() {\n if (!this._isEnabled) {\n return\n }\n\n this._activeTrigger.click = !this._activeTrigger.click\n if (this._isShown()) {\n this._leave()\n return\n }\n\n this._enter()\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'))\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this._isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW))\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper()\n\n const tip = this._getTipElement()\n\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'))\n\n const { container } = this._config\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))\n }\n\n this._popper = this._createPopper(tip)\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN))\n\n if (this._isHovered === false) {\n this._leave()\n }\n\n this._isHovered = false\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n hide() {\n if (!this._isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE))\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const tip = this._getTipElement()\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n this._isHovered = null // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (!this._isHovered) {\n this._disposePopper()\n }\n\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN))\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n update() {\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle())\n }\n\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())\n }\n\n return this.tip\n }\n\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml()\n\n // TODO: remove this check in v6\n if (!tip) {\n return null\n }\n\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`)\n\n const tipId = getUID(this.constructor.NAME).toString()\n\n tip.setAttribute('id', tipId)\n\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n return tip\n }\n\n setContent(content) {\n this._newContent = content\n if (this._isShown()) {\n this._disposePopper()\n this.show()\n }\n }\n\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content)\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n })\n }\n\n return this._templateFactory\n }\n\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n }\n }\n\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title')\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _isAnimated() {\n return this._config.animation || (this.tip && this.tip.classList.contains(CLASS_NAME_FADE))\n }\n\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW)\n }\n\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element])\n const attachment = AttachmentMap[placement.toUpperCase()]\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element])\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement)\n }\n }\n ]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n }\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context.toggle()\n })\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSEENTER) :\n this.constructor.eventName(EVENT_FOCUSIN)\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSELEAVE) :\n this.constructor.eventName(EVENT_FOCUSOUT)\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true\n context._enter()\n })\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] =\n context._element.contains(event.relatedTarget)\n\n context._leave()\n })\n }\n }\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n\n if (!title) {\n return\n }\n\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('data-bs-original-title', title) // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title')\n }\n\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true\n return\n }\n\n this._isHovered = true\n\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show()\n }\n }, this._config.delay.show)\n }\n\n _leave() {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n this._isHovered = false\n\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide()\n }\n }, this._config.delay.hide)\n }\n\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout)\n this._timeout = setTimeout(handler, timeout)\n }\n\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true)\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute]\n }\n }\n\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value\n }\n }\n\n config.selector = false\n config.trigger = 'manual'\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n\n if (this.tip) {\n this.tip.remove()\n this.tip = null\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Tooltip from './tooltip.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'popover'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Default = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>',\n trigger: 'click'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n}\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent()\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n }\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin, getElement, isDisabled, isVisible\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_CLICK = `click${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_TARGET_LINKS = '[href]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst Default = {\n offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n}\n\nconst DefaultType = {\n offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n}\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map()\n this._observableSections = new Map()\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element\n this._activeTarget = null\n this._observer = null\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n }\n this.refresh() // initialize\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables()\n this._maybeEnableSmoothScroll()\n\n if (this._observer) {\n this._observer.disconnect()\n } else {\n this._observer = this._getNewObserver()\n }\n\n for (const section of this._observableSections.values()) {\n this._observer.observe(section)\n }\n }\n\n dispose() {\n this._observer.disconnect()\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin\n\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))\n }\n\n return config\n }\n\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK)\n\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash)\n if (observableSection) {\n event.preventDefault()\n const root = this._rootElement || window\n const height = observableSection.offsetTop - this._element.offsetTop\n if (root.scrollTo) {\n root.scrollTo({ top: height, behavior: 'smooth' })\n return\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height\n }\n })\n }\n\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n }\n\n return new IntersectionObserver(entries => this._observerCallback(entries), options)\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop\n this._process(targetElement(entry))\n }\n\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop\n this._previousScrollData.parentScrollTop = parentScrollTop\n\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null\n this._clearActiveClass(targetElement(entry))\n\n continue\n }\n\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry)\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return\n }\n\n continue\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry)\n }\n }\n }\n\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map()\n this._observableSections = new Map()\n\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)\n\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue\n }\n\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor)\n this._observableSections.set(anchor.hash, observableSection)\n }\n }\n }\n\n _process(target) {\n if (this._activeTarget === target) {\n return\n }\n\n this._clearActiveClass(this._config.target)\n this._activeTarget = target\n target.classList.add(CLASS_NAME_ACTIVE)\n this._activateParents(target)\n\n EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })\n }\n\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n return\n }\n\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {\n item.classList.add(CLASS_NAME_ACTIVE)\n }\n }\n }\n\n _clearActiveClass(parent) {\n parent.classList.remove(CLASS_NAME_ACTIVE)\n\n const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent)\n for (const node of activeNodes) {\n node.classList.remove(CLASS_NAME_ACTIVE)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = ScrollSpy.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {\n ScrollSpy.getOrCreateInstance(spy)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(ScrollSpy)\n\nexport default ScrollSpy\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tab.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tab'\nconst DATA_KEY = 'bs.tab'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}`\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst HOME_KEY = 'Home'\nconst END_KEY = 'End'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_DROPDOWN = 'dropdown'\n\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\nconst SELECTOR_DROPDOWN_MENU = '.dropdown-menu'\nconst NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`\n\nconst SELECTOR_TAB_PANEL = '.list-group, .nav, [role=\"tablist\"]'\nconst SELECTOR_OUTER = '.nav-item, .list-group-item'\nconst SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role=\"tab\"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]' // TODO: could only be `tab` in v6\nconst SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`\n\nconst SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle=\"tab\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"pill\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"list\"]`\n\n/**\n * Class definition\n */\n\nclass Tab extends BaseComponent {\n constructor(element) {\n super(element)\n this._parent = this._element.closest(SELECTOR_TAB_PANEL)\n\n if (!this._parent) {\n return\n // TODO: should throw exception in v6\n // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)\n }\n\n // Set up initial aria attributes\n this._setInitialAttributes(this._parent, this._getChildren())\n\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n show() { // Shows this elem and deactivate the active sibling if exists\n const innerElem = this._element\n if (this._elemIsActive(innerElem)) {\n return\n }\n\n // Search for active tab on same parent to deactivate it\n const active = this._getActiveElem()\n\n const hideEvent = active ?\n EventHandler.trigger(active, EVENT_HIDE, { relatedTarget: innerElem }) :\n null\n\n const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, { relatedTarget: active })\n\n if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {\n return\n }\n\n this._deactivate(active, innerElem)\n this._activate(innerElem, active)\n }\n\n // Private\n _activate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.add(CLASS_NAME_ACTIVE)\n\n this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.add(CLASS_NAME_SHOW)\n return\n }\n\n element.removeAttribute('tabindex')\n element.setAttribute('aria-selected', true)\n this._toggleDropDown(element, true)\n EventHandler.trigger(element, EVENT_SHOWN, {\n relatedTarget: relatedElem\n })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _deactivate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.remove(CLASS_NAME_ACTIVE)\n element.blur()\n\n this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.remove(CLASS_NAME_SHOW)\n return\n }\n\n element.setAttribute('aria-selected', false)\n element.setAttribute('tabindex', '-1')\n this._toggleDropDown(element, false)\n EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _keydown(event) {\n if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key))) {\n return\n }\n\n event.stopPropagation()// stopPropagation/preventDefault both added to support up/down keys without scrolling the page\n event.preventDefault()\n\n const children = this._getChildren().filter(element => !isDisabled(element))\n let nextActiveElement\n\n if ([HOME_KEY, END_KEY].includes(event.key)) {\n nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]\n } else {\n const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)\n nextActiveElement = getNextActiveElement(children, event.target, isNext, true)\n }\n\n if (nextActiveElement) {\n nextActiveElement.focus({ preventScroll: true })\n Tab.getOrCreateInstance(nextActiveElement).show()\n }\n }\n\n _getChildren() { // collection of inner elements\n return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent)\n }\n\n _getActiveElem() {\n return this._getChildren().find(child => this._elemIsActive(child)) || null\n }\n\n _setInitialAttributes(parent, children) {\n this._setAttributeIfNotExists(parent, 'role', 'tablist')\n\n for (const child of children) {\n this._setInitialAttributesOnChild(child)\n }\n }\n\n _setInitialAttributesOnChild(child) {\n child = this._getInnerElement(child)\n const isActive = this._elemIsActive(child)\n const outerElem = this._getOuterElement(child)\n child.setAttribute('aria-selected', isActive)\n\n if (outerElem !== child) {\n this._setAttributeIfNotExists(outerElem, 'role', 'presentation')\n }\n\n if (!isActive) {\n child.setAttribute('tabindex', '-1')\n }\n\n this._setAttributeIfNotExists(child, 'role', 'tab')\n\n // set attributes to the related panel too\n this._setInitialAttributesOnTargetPanel(child)\n }\n\n _setInitialAttributesOnTargetPanel(child) {\n const target = SelectorEngine.getElementFromSelector(child)\n\n if (!target) {\n return\n }\n\n this._setAttributeIfNotExists(target, 'role', 'tabpanel')\n\n if (child.id) {\n this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)\n }\n }\n\n _toggleDropDown(element, open) {\n const outerElem = this._getOuterElement(element)\n if (!outerElem.classList.contains(CLASS_DROPDOWN)) {\n return\n }\n\n const toggle = (selector, className) => {\n const element = SelectorEngine.findOne(selector, outerElem)\n if (element) {\n element.classList.toggle(className, open)\n }\n }\n\n toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)\n toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)\n outerElem.setAttribute('aria-expanded', open)\n }\n\n _setAttributeIfNotExists(element, attribute, value) {\n if (!element.hasAttribute(attribute)) {\n element.setAttribute(attribute, value)\n }\n }\n\n _elemIsActive(elem) {\n return elem.classList.contains(CLASS_NAME_ACTIVE)\n }\n\n // Try to get the inner element (usually the .nav-link)\n _getInnerElement(elem) {\n return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem)\n }\n\n // Try to get the outer element (usually the .nav-item)\n _getOuterElement(elem) {\n return elem.closest(SELECTOR_OUTER) || elem\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tab.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n Tab.getOrCreateInstance(this).show()\n})\n\n/**\n * Initialize on focus\n */\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {\n Tab.getOrCreateInstance(element)\n }\n})\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tab)\n\nexport default Tab\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap toast.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin, reflow } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'toast'\nconst DATA_KEY = 'bs.toast'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\n\nconst DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n}\n\nconst Default = {\n animation: true,\n autohide: true,\n delay: 5000\n}\n\n/**\n * Class definition\n */\n\nclass Toast extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._timeout = null\n this._hasMouseInteraction = false\n this._hasKeyboardInteraction = false\n this._setListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show() {\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._clearTimeout()\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE)\n }\n\n const complete = () => {\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN)\n\n this._maybeScheduleHide()\n }\n\n this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\n reflow(this._element)\n this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)\n\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n hide() {\n if (!this.isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const complete = () => {\n this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\n this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.classList.add(CLASS_NAME_SHOWING)\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n dispose() {\n this._clearTimeout()\n\n if (this.isShown()) {\n this._element.classList.remove(CLASS_NAME_SHOW)\n }\n\n super.dispose()\n }\n\n isShown() {\n return this._element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n\n _maybeScheduleHide() {\n if (!this._config.autohide) {\n return\n }\n\n if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\n return\n }\n\n this._timeout = setTimeout(() => {\n this.hide()\n }, this._config.delay)\n }\n\n _onInteraction(event, isInteracting) {\n switch (event.type) {\n case 'mouseover':\n case 'mouseout': {\n this._hasMouseInteraction = isInteracting\n break\n }\n\n case 'focusin':\n case 'focusout': {\n this._hasKeyboardInteraction = isInteracting\n break\n }\n\n default: {\n break\n }\n }\n\n if (isInteracting) {\n this._clearTimeout()\n return\n }\n\n const nextElement = event.relatedTarget\n if (this._element === nextElement || this._element.contains(nextElement)) {\n return\n }\n\n this._maybeScheduleHide()\n }\n\n _setListeners() {\n EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\n EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\n }\n\n _clearTimeout() {\n clearTimeout(this._timeout)\n this._timeout = null\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Toast.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Toast)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Toast)\n\nexport default Toast\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap index.umd.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './src/alert.js'\nimport Button from './src/button.js'\nimport Carousel from './src/carousel.js'\nimport Collapse from './src/collapse.js'\nimport Dropdown from './src/dropdown.js'\nimport Modal from './src/modal.js'\nimport Offcanvas from './src/offcanvas.js'\nimport Popover from './src/popover.js'\nimport ScrollSpy from './src/scrollspy.js'\nimport Tab from './src/tab.js'\nimport Toast from './src/toast.js'\nimport Tooltip from './src/tooltip.js'\n\nexport default {\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Offcanvas,\n Popover,\n ScrollSpy,\n Tab,\n Toast,\n Tooltip\n}\n"],"mappings":"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"} \ No newline at end of file diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs index 865807a1..d94afad7 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -25,7 +25,6 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { let app = &global::SETTINGS.app.name; Page::new(request) - .with_theme("Basic") .with_title(L10n::l("welcome_title")) .add_component( Intro::new() diff --git a/tools/changelog.sh b/tools/changelog.sh index 253f22bc..bd5f20bb 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -50,15 +50,23 @@ case "$CRATE" in pagetop) CHANGELOG_FILE="CHANGELOG.md" PATH_FLAGS=( + # Helpers --exclude-path "helpers/pagetop-statics/**/*" --exclude-path "helpers/pagetop-build/**/*" --exclude-path "helpers/pagetop-macros/**/*" + # Extensions + --exclude-path "extensions/pagetop-aliner/**/*" + --exclude-path "extensions/pagetop-bootsier/**/*" ) ;; pagetop-aliner) CHANGELOG_FILE="extensions/pagetop-aliner/CHANGELOG.md" PATH_FLAGS=(--include-path "extensions/pagetop-aliner/**/*") ;; + pagetop-bootsier) + CHANGELOG_FILE="extensions/pagetop-bootsier/CHANGELOG.md" + PATH_FLAGS=(--include-path "extensions/pagetop-bootsier/**/*") + ;; *) echo "Error: unsupported crate '$CRATE'" >&2 exit 1 From 345bac9d2548168539933c93b6418399f084f21e Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 12 Oct 2025 12:29:16 +0200 Subject: [PATCH 207/244] =?UTF-8?q?=F0=9F=93=9D=20Repasa=20doc=20y=20cambi?= =?UTF-8?q?a=20caracteres=20Unicode=20ambiguos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++++ src/core.rs | 2 +- src/core/theme/definition.rs | 4 ++-- src/html/assets/javascript.rs | 12 ++++++------ src/html/assets/stylesheet.rs | 4 ++-- src/service.rs | 8 ++++---- 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 0e635189..2a05be13 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,10 @@ El código se organiza en un *workspace* donde actualmente se incluyen los sigui * **[pagetop-aliner](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-aliner)**, es un tema para demos y pruebas que muestra esquemáticamente la composición de las páginas HTML. + * **[pagetop-bootsier](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-bootsier)**, + tema basado en [Bootstrap](https://getbootstrap.com) para ofrecer su catálogo de estilos y + componentes flexibles. + # 🧪 Pruebas diff --git a/src/core.rs b/src/core.rs index 9ecbd2e9..ab4d693b 100644 --- a/src/core.rs +++ b/src/core.rs @@ -7,7 +7,7 @@ use std::any::Any; pub enum TypeInfo { /// Ruta completa tal y como la devuelve [`core::any::type_name`]. FullName, - /// Último segmento de la ruta – por ejemplo `Vec<i32>` en lugar de `alloc::vec::Vec<i32>`. + /// Último segmento de la ruta, por ejemplo `Vec<i32>` en lugar de `alloc::vec::Vec<i32>`. ShortName, /// Conserva todo **desde** `start` inclusive hasta el final. NameFrom(isize), diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 1eb7b226..2a20c078 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -283,14 +283,14 @@ pub trait Theme: Extension + ThemePage + Send + Sync { <Self as ThemePage>::render_head(self, page) } - /// Contenido predeterminado para la página de error "*403 – Forbidden*". + /// 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").using(page)) } } } } - /// Contenido predeterminado para la página de error "*404 – Not Found*". + /// 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 { diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs index 6dc9b852..0e86f0d4 100644 --- a/src/html/assets/javascript.rs +++ b/src/html/assets/javascript.rs @@ -8,16 +8,16 @@ use crate::{join, join_pair, AutoDefault, Weight}; // Los distintos modos de carga permiten optimizar el rendimiento y controlar el comportamiento del // script en relación con el análisis del documento HTML y la ejecución del resto de scripts. // -// - [`From`] – Carga estándar con la etiqueta `<script src="...">`. -// - [`Defer`] – Igual que [`From`], pero con el atributo `defer`, descarga en paralelo y se +// - [`From`] - Carga estándar con la etiqueta `<script src="...">`. +// - [`Defer`] - Igual que [`From`], pero con el atributo `defer`, descarga en paralelo y se // ejecuta tras el análisis del documento HTML, respetando el orden de // aparición. -// - [`Async`] – Igual que [`From`], pero con el atributo `async`, descarga en paralelo y se +// - [`Async`] - Igual que [`From`], pero con el atributo `async`, descarga en paralelo y se // ejecuta en cuanto esté listo, **sin garantizar** el orden relativo respecto a // otros scripts. -// - [`Inline`] – Inserta el código directamente en la etiqueta `<script>`. -// - [`OnLoad`] – Inserta el código JavaScript y lo ejecuta tras el evento `DOMContentLoaded`. -// - [`OnLoadAsync`] – Igual que [`OnLoad`], pero con manejador asíncrono (`async`), útil si dentro +// - [`Inline`] - Inserta el código directamente en la etiqueta `<script>`. +// - [`OnLoad`] - Inserta el código JavaScript y lo ejecuta tras el evento `DOMContentLoaded`. +// - [`OnLoadAsync`] - Igual que [`OnLoad`], pero con manejador asíncrono (`async`), útil si dentro // del código JavaScript se utiliza `await`. #[derive(AutoDefault)] enum Source { diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index 8d1bf29f..5f0eaaa0 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -8,9 +8,9 @@ use crate::{join_pair, AutoDefault, Weight}; // Los estilos pueden cargarse desde un archivo externo o estar embebidos directamente en una // etiqueta `<style>`. // -// - [`From`] – Carga la hoja de estilos desde un archivo externo, insertándola mediante una +// - [`From`] - Carga la hoja de estilos desde un archivo externo, insertándola mediante una // etiqueta `<link>` con `rel="stylesheet"`. -// - [`Inline`] – Inserta directamente el contenido CSS dentro de una etiqueta `<style>`. +// - [`Inline`] - Inserta directamente el contenido CSS dentro de una etiqueta `<style>`. #[derive(AutoDefault)] enum Source { #[default] diff --git a/src/service.rs b/src/service.rs index 9a936fc3..1b2f766c 100644 --- a/src/service.rs +++ b/src/service.rs @@ -93,11 +93,11 @@ macro_rules! include_files_service { /// /// # Argumentos /// -/// * `$scfg` – Instancia de [`ServiceConfig`](crate::service::web::ServiceConfig) donde aplicar la +/// * `$scfg` - Instancia de [`ServiceConfig`](crate::service::web::ServiceConfig) donde aplicar la /// configuración. -/// * `$path` – Ruta al directorio local con los archivos estáticos. -/// * `$bundle` – Nombre del conjunto de recursos que esta macro integra en el binario. -/// * `$route` – Ruta URL base desde la que se servirán los archivos. +/// * `$path` - Ruta al directorio local con los archivos estáticos. +/// * `$bundle` - Nombre del conjunto de recursos que esta macro integra en el binario. +/// * `$route` - Ruta URL base desde la que se servirán los archivos. /// /// # Ejemplos /// From 6052b87c9c50378cf2f324e66b038411d2779364 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 12 Oct 2025 13:08:33 +0200 Subject: [PATCH 208/244] =?UTF-8?q?=F0=9F=93=84=20Actualiza=20licencias=20?= =?UTF-8?q?y=20revisa=20*badges*=20de=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- extensions/pagetop-aliner/LICENSE-APACHE | 201 +++++++++++++++++++++ extensions/pagetop-aliner/LICENSE-MIT | 21 +++ extensions/pagetop-aliner/README.md | 2 +- extensions/pagetop-aliner/src/lib.rs | 2 +- extensions/pagetop-bootsier/LICENSE-APACHE | 201 +++++++++++++++++++++ extensions/pagetop-bootsier/LICENSE-MIT | 21 +++ extensions/pagetop-bootsier/README.md | 2 +- extensions/pagetop-bootsier/src/lib.rs | 2 +- helpers/pagetop-build/README.md | 2 +- helpers/pagetop-build/src/lib.rs | 2 +- helpers/pagetop-macros/README.md | 2 +- helpers/pagetop-macros/src/lib.rs | 2 +- helpers/pagetop-statics/README.md | 5 +- helpers/pagetop-statics/src/lib.rs | 5 +- src/lib.rs | 2 +- 16 files changed, 462 insertions(+), 12 deletions(-) create mode 100644 extensions/pagetop-aliner/LICENSE-APACHE create mode 100644 extensions/pagetop-aliner/LICENSE-MIT create mode 100644 extensions/pagetop-bootsier/LICENSE-APACHE create mode 100644 extensions/pagetop-bootsier/LICENSE-MIT diff --git a/README.md b/README.md index 2a05be13..d9eeb402 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ <p>Un entorno para el desarrollo de soluciones web modulares, extensibles y configurables.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop) [![Crates.io](https://img.shields.io/crates/v/pagetop.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop) [![Descargas](https://img.shields.io/crates/d/pagetop.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop) + ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) <br> </div> diff --git a/extensions/pagetop-aliner/LICENSE-APACHE b/extensions/pagetop-aliner/LICENSE-APACHE new file mode 100644 index 00000000..263ddac1 --- /dev/null +++ b/extensions/pagetop-aliner/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 Manuel Cillero + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/extensions/pagetop-aliner/LICENSE-MIT b/extensions/pagetop-aliner/LICENSE-MIT new file mode 100644 index 00000000..cd8af3d6 --- /dev/null +++ b/extensions/pagetop-aliner/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Manuel Cillero + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/extensions/pagetop-aliner/README.md b/extensions/pagetop-aliner/README.md index ac6da910..798c6596 100644 --- a/extensions/pagetop-aliner/README.md +++ b/extensions/pagetop-aliner/README.md @@ -4,10 +4,10 @@ <p>Tema de <strong>PageTop</strong> que muestra esquemáticamente la composición de las páginas HTML.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-aliner?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-aliner) [![Crates.io](https://img.shields.io/crates/v/pagetop-aliner.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-aliner) [![Descargas](https://img.shields.io/crates/d/pagetop-aliner.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-aliner) + ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) <br> </div> diff --git a/extensions/pagetop-aliner/src/lib.rs b/extensions/pagetop-aliner/src/lib.rs index 92f9aa41..54898b5d 100644 --- a/extensions/pagetop-aliner/src/lib.rs +++ b/extensions/pagetop-aliner/src/lib.rs @@ -5,10 +5,10 @@ <p>Tema para <strong>PageTop</strong> que muestra esquemáticamente la composición de las páginas HTML.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-aliner?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-aliner) [![Crates.io](https://img.shields.io/crates/v/pagetop-aliner.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-aliner) [![Descargas](https://img.shields.io/crates/d/pagetop-aliner.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-aliner) + ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) <br> </div> diff --git a/extensions/pagetop-bootsier/LICENSE-APACHE b/extensions/pagetop-bootsier/LICENSE-APACHE new file mode 100644 index 00000000..263ddac1 --- /dev/null +++ b/extensions/pagetop-bootsier/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 Manuel Cillero + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/extensions/pagetop-bootsier/LICENSE-MIT b/extensions/pagetop-bootsier/LICENSE-MIT new file mode 100644 index 00000000..cd8af3d6 --- /dev/null +++ b/extensions/pagetop-bootsier/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Manuel Cillero + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/extensions/pagetop-bootsier/README.md b/extensions/pagetop-bootsier/README.md index 87bd3c7b..120b3680 100644 --- a/extensions/pagetop-bootsier/README.md +++ b/extensions/pagetop-bootsier/README.md @@ -4,10 +4,10 @@ <p>Tema de <strong>PageTop</strong> basado en Bootstrap para ofrecer su catálogo de estilos y componentes flexibles.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier) [![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier) [![Descargas](https://img.shields.io/crates/d/pagetop-bootsier.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-bootsier) + ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) <br> </div> diff --git a/extensions/pagetop-bootsier/src/lib.rs b/extensions/pagetop-bootsier/src/lib.rs index 8157ec2d..fbb97c63 100644 --- a/extensions/pagetop-bootsier/src/lib.rs +++ b/extensions/pagetop-bootsier/src/lib.rs @@ -5,10 +5,10 @@ <p>Tema de <strong>PageTop</strong> basado en Bootstrap para ofrecer su catálogo de estilos y componentes flexibles.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier) [![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier) [![Descargas](https://img.shields.io/crates/d/pagetop-bootsier.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-bootsier) + ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) <br> </div> diff --git a/helpers/pagetop-build/README.md b/helpers/pagetop-build/README.md index 57273e83..948429cc 100644 --- a/helpers/pagetop-build/README.md +++ b/helpers/pagetop-build/README.md @@ -4,10 +4,10 @@ <p>Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el binario de un proyecto <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-build?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-build) [![Crates.io](https://img.shields.io/crates/v/pagetop-build.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-build) [![Descargas](https://img.shields.io/crates/d/pagetop-build.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-build) + ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) </div> diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index c6e72367..30fcfe32 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -5,10 +5,10 @@ <p>Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el binario de un proyecto <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-build?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-build) [![Crates.io](https://img.shields.io/crates/v/pagetop-build.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-build) [![Descargas](https://img.shields.io/crates/d/pagetop-build.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-build) + ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) </div> diff --git a/helpers/pagetop-macros/README.md b/helpers/pagetop-macros/README.md index 7c9c2e86..fc2f976c 100644 --- a/helpers/pagetop-macros/README.md +++ b/helpers/pagetop-macros/README.md @@ -4,10 +4,10 @@ <p>Una colección de macros que mejoran la experiencia de desarrollo con <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-macros?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-macros) [![Crates.io](https://img.shields.io/crates/v/pagetop-macros.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-macros) [![Descargas](https://img.shields.io/crates/d/pagetop-macros.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-macros) + ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) </div> diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 709ce572..61780cce 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -5,10 +5,10 @@ <p>Una colección de macros que mejoran la experiencia de desarrollo con <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-macros?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-macros) [![Crates.io](https://img.shields.io/crates/v/pagetop-macros.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-macros) [![Descargas](https://img.shields.io/crates/d/pagetop-macros.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-macros) + ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) </div> diff --git a/helpers/pagetop-statics/README.md b/helpers/pagetop-statics/README.md index 4168cd4a..ba7ae266 100644 --- a/helpers/pagetop-statics/README.md +++ b/helpers/pagetop-statics/README.md @@ -4,7 +4,10 @@ <p>Librería para automatizar la recopilación de recursos estáticos en <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) +[![Doc API](https://img.shields.io/docsrs/pagetop-statics?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-statics) +[![Crates.io](https://img.shields.io/crates/v/pagetop-statics.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-statics) +[![Descargas](https://img.shields.io/crates/d/pagetop-statics.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-statics) + ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) </div> diff --git a/helpers/pagetop-statics/src/lib.rs b/helpers/pagetop-statics/src/lib.rs index 201d90ef..05570933 100644 --- a/helpers/pagetop-statics/src/lib.rs +++ b/helpers/pagetop-statics/src/lib.rs @@ -5,7 +5,10 @@ <p>Librería para automatizar la recopilación de recursos estáticos en <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) +[![Doc API](https://img.shields.io/docsrs/pagetop-statics?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-statics) +[![Crates.io](https://img.shields.io/crates/v/pagetop-statics.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-statics) +[![Descargas](https://img.shields.io/crates/d/pagetop-statics.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-statics) + ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) </div> diff --git a/src/lib.rs b/src/lib.rs index 6f5c5cfb..daef77a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,10 +7,10 @@ <p>Un entorno para el desarrollo de soluciones web modulares, extensibles y configurables.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop) [![Crates.io](https://img.shields.io/crates/v/pagetop.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop) [![Descargas](https://img.shields.io/crates/d/pagetop.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop) + ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) <br> </div> From f68f33a7a2fca80975b9bb922f0bb0535dfe3ee6 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 12 Oct 2025 13:27:05 +0200 Subject: [PATCH 209/244] =?UTF-8?q?=F0=9F=93=9D=20depura=20enlaces=20de=20?= =?UTF-8?q?informaci=C3=B3n=20de=20licencias?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- extensions/pagetop-aliner/README.md | 2 +- extensions/pagetop-aliner/src/lib.rs | 2 +- extensions/pagetop-bootsier/README.md | 2 +- extensions/pagetop-bootsier/src/lib.rs | 2 +- helpers/pagetop-build/README.md | 2 +- helpers/pagetop-build/src/lib.rs | 2 +- helpers/pagetop-macros/README.md | 2 +- helpers/pagetop-macros/src/lib.rs | 2 +- helpers/pagetop-statics/README.md | 2 +- helpers/pagetop-statics/src/lib.rs | 2 +- src/lib.rs | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index d9eeb402..be720910 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![Doc API](https://img.shields.io/docsrs/pagetop?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop) [![Crates.io](https://img.shields.io/crates/v/pagetop.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop) [![Descargas](https://img.shields.io/crates/d/pagetop.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop) - ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop#licencia) <br> </div> diff --git a/extensions/pagetop-aliner/README.md b/extensions/pagetop-aliner/README.md index 798c6596..0560a067 100644 --- a/extensions/pagetop-aliner/README.md +++ b/extensions/pagetop-aliner/README.md @@ -7,7 +7,7 @@ [![Doc API](https://img.shields.io/docsrs/pagetop-aliner?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-aliner) [![Crates.io](https://img.shields.io/crates/v/pagetop-aliner.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-aliner) [![Descargas](https://img.shields.io/crates/d/pagetop-aliner.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-aliner) - ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-aliner#licencia) <br> </div> diff --git a/extensions/pagetop-aliner/src/lib.rs b/extensions/pagetop-aliner/src/lib.rs index 54898b5d..b51800c2 100644 --- a/extensions/pagetop-aliner/src/lib.rs +++ b/extensions/pagetop-aliner/src/lib.rs @@ -8,7 +8,7 @@ [![Doc API](https://img.shields.io/docsrs/pagetop-aliner?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-aliner) [![Crates.io](https://img.shields.io/crates/v/pagetop-aliner.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-aliner) [![Descargas](https://img.shields.io/crates/d/pagetop-aliner.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-aliner) - ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-aliner#licencia) <br> </div> diff --git a/extensions/pagetop-bootsier/README.md b/extensions/pagetop-bootsier/README.md index 120b3680..1a33b4ea 100644 --- a/extensions/pagetop-bootsier/README.md +++ b/extensions/pagetop-bootsier/README.md @@ -7,7 +7,7 @@ [![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier) [![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier) [![Descargas](https://img.shields.io/crates/d/pagetop-bootsier.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-bootsier) - ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-bootsier#licencia) <br> </div> diff --git a/extensions/pagetop-bootsier/src/lib.rs b/extensions/pagetop-bootsier/src/lib.rs index fbb97c63..c413e8e5 100644 --- a/extensions/pagetop-bootsier/src/lib.rs +++ b/extensions/pagetop-bootsier/src/lib.rs @@ -8,7 +8,7 @@ [![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier) [![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier) [![Descargas](https://img.shields.io/crates/d/pagetop-bootsier.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-bootsier) - ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-bootsier#licencia) <br> </div> diff --git a/helpers/pagetop-build/README.md b/helpers/pagetop-build/README.md index 948429cc..875acbd9 100644 --- a/helpers/pagetop-build/README.md +++ b/helpers/pagetop-build/README.md @@ -7,7 +7,7 @@ [![Doc API](https://img.shields.io/docsrs/pagetop-build?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-build) [![Crates.io](https://img.shields.io/crates/v/pagetop-build.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-build) [![Descargas](https://img.shields.io/crates/d/pagetop-build.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-build) - ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-build#licencia) </div> diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index 30fcfe32..9088ec99 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -8,7 +8,7 @@ [![Doc API](https://img.shields.io/docsrs/pagetop-build?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-build) [![Crates.io](https://img.shields.io/crates/v/pagetop-build.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-build) [![Descargas](https://img.shields.io/crates/d/pagetop-build.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-build) - ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-build#licencia) </div> diff --git a/helpers/pagetop-macros/README.md b/helpers/pagetop-macros/README.md index fc2f976c..66fdc1fa 100644 --- a/helpers/pagetop-macros/README.md +++ b/helpers/pagetop-macros/README.md @@ -7,7 +7,7 @@ [![Doc API](https://img.shields.io/docsrs/pagetop-macros?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-macros) [![Crates.io](https://img.shields.io/crates/v/pagetop-macros.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-macros) [![Descargas](https://img.shields.io/crates/d/pagetop-macros.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-macros) - ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-macros#licencia) </div> diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 61780cce..2781aef8 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -8,7 +8,7 @@ [![Doc API](https://img.shields.io/docsrs/pagetop-macros?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-macros) [![Crates.io](https://img.shields.io/crates/v/pagetop-macros.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-macros) [![Descargas](https://img.shields.io/crates/d/pagetop-macros.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-macros) - ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-macros#licencia) </div> diff --git a/helpers/pagetop-statics/README.md b/helpers/pagetop-statics/README.md index ba7ae266..cd1da6ac 100644 --- a/helpers/pagetop-statics/README.md +++ b/helpers/pagetop-statics/README.md @@ -7,7 +7,7 @@ [![Doc API](https://img.shields.io/docsrs/pagetop-statics?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-statics) [![Crates.io](https://img.shields.io/crates/v/pagetop-statics.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-statics) [![Descargas](https://img.shields.io/crates/d/pagetop-statics.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-statics) - ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-statics#licencia) </div> diff --git a/helpers/pagetop-statics/src/lib.rs b/helpers/pagetop-statics/src/lib.rs index 05570933..6f04bd2a 100644 --- a/helpers/pagetop-statics/src/lib.rs +++ b/helpers/pagetop-statics/src/lib.rs @@ -8,7 +8,7 @@ [![Doc API](https://img.shields.io/docsrs/pagetop-statics?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-statics) [![Crates.io](https://img.shields.io/crates/v/pagetop-statics.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-statics) [![Descargas](https://img.shields.io/crates/d/pagetop-statics.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-statics) - ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-statics#licencia) </div> diff --git a/src/lib.rs b/src/lib.rs index daef77a8..de6d9e68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ [![Doc API](https://img.shields.io/docsrs/pagetop?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop) [![Crates.io](https://img.shields.io/crates/v/pagetop.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop) [![Descargas](https://img.shields.io/crates/d/pagetop.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop) - ![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop#licencia) <br> </div> From e4cd1e56e09b825a22bc9509ab6f9f32b31a5743 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 12 Oct 2025 20:04:35 +0200 Subject: [PATCH 210/244] =?UTF-8?q?=F0=9F=8D=B1=20(bootsier):=20Actualiza?= =?UTF-8?q?=20bootstrap=20v5.3.3=20a=20v5.3.8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extensions/pagetop-bootsier/build.rs | 9 +- extensions/pagetop-bootsier/src/lib.rs | 2 +- .../bootstrap-5.3.3/mixins/_box-shadow.scss | 18 -- .../_accordion.scss | 13 +- .../_alert.scss | 0 .../_badge.scss | 0 .../_breadcrumb.scss | 0 .../_button-group.scss | 11 +- .../_buttons.scss | 0 .../{bootstrap-5.3.3 => bootstrap}/_card.scss | 19 +- .../_carousel.scss | 40 ++-- .../_close.scss | 15 +- .../_containers.scss | 0 .../_dropdown.scss | 0 .../_forms.scss | 0 .../_functions.scss | 4 +- .../{bootstrap-5.3.3 => bootstrap}/_grid.scss | 0 .../_helpers.scss | 0 .../_images.scss | 0 .../_list-group.scss | 52 ++--- .../{bootstrap-5.3.3 => bootstrap}/_maps.scss | 0 .../_mixins.scss | 0 .../_modal.scss | 8 +- .../{bootstrap-5.3.3 => bootstrap}/_nav.scss | 2 +- .../_navbar.scss | 2 +- .../_offcanvas.scss | 6 +- .../_pagination.scss | 2 +- .../_placeholders.scss | 0 .../_popover.scss | 0 .../_progress.scss | 2 +- .../_reboot.scss | 8 +- .../{bootstrap-5.3.3 => bootstrap}/_root.scss | 0 .../_spinners.scss | 1 + .../_tables.scss | 0 .../_toasts.scss | 0 .../_tooltip.scss | 0 .../_transitions.scss | 0 .../{bootstrap-5.3.3 => bootstrap}/_type.scss | 2 +- .../_utilities.scss | 0 .../_variables-dark.scss | 19 +- .../_variables.scss | 30 +-- .../bootstrap-grid.scss | 0 .../bootstrap-reboot.scss | 0 .../bootstrap-utilities.scss | 0 .../bootstrap.scss | 0 .../forms/_floating-labels.scss | 34 ++-- .../forms/_form-check.scss | 0 .../forms/_form-control.scss | 0 .../forms/_form-range.scss | 0 .../forms/_form-select.scss | 0 .../forms/_form-text.scss | 0 .../forms/_input-group.scss | 2 +- .../forms/_labels.scss | 0 .../forms/_validation.scss | 0 .../helpers/_clearfix.scss | 0 .../helpers/_color-bg.scss | 0 .../helpers/_colored-links.scss | 0 .../helpers/_focus-ring.scss | 0 .../helpers/_icon-link.scss | 0 .../helpers/_position.scss | 0 .../helpers/_ratio.scss | 0 .../helpers/_stacks.scss | 0 .../helpers/_stretched-link.scss | 0 .../helpers/_text-truncation.scss | 0 .../helpers/_visually-hidden.scss | 0 .../helpers/_vr.scss | 0 .../mixins/_alert.scss | 0 .../mixins/_backdrop.scss | 0 .../mixins/_banner.scss | 4 +- .../mixins/_border-radius.scss | 0 .../static/bootstrap/mixins/_box-shadow.scss | 24 +++ .../mixins/_breakpoints.scss | 0 .../mixins/_buttons.scss | 0 .../mixins/_caret.scss | 0 .../mixins/_clearfix.scss | 0 .../mixins/_color-mode.scss | 0 .../mixins/_color-scheme.scss | 0 .../mixins/_container.scss | 0 .../mixins/_deprecate.scss | 0 .../mixins/_forms.scss | 0 .../mixins/_gradients.scss | 0 .../mixins/_grid.scss | 2 +- .../mixins/_image.scss | 0 .../mixins/_list-group.scss | 0 .../mixins/_lists.scss | 0 .../mixins/_pagination.scss | 0 .../mixins/_reset-text.scss | 0 .../mixins/_resize.scss | 0 .../mixins/_table-variants.scss | 0 .../mixins/_text-truncate.scss | 0 .../mixins/_transition.scss | 0 .../mixins/_utilities.scss | 0 .../mixins/_visually-hidden.scss | 7 +- .../tests/jasmine.js | 0 .../_auto-import-of-variables-dark.test.scss | 0 .../tests/mixins/_box-shadow.test.scss | 188 ++++++++++++++++++ .../tests/mixins/_color-contrast.test.scss | 139 +++++++++++++ .../tests/mixins/_color-modes.test.scss | 0 .../_media-query-color-mode-full.test.scss | 0 .../tests/mixins/_utilities.test.scss | 0 .../tests/sass-true/register.js | 0 .../tests/sass-true/runner.js | 0 .../tests/utilities/_api.test.scss | 0 .../utilities/_api.scss | 0 .../vendor/_rfs.scss | 0 .../pagetop-bootsier/static/js/bootstrap.js | 34 ++-- .../static/js/bootstrap.js.map | 2 +- .../static/js/bootstrap.min.js | 6 +- .../static/js/bootstrap.min.js.map | 2 +- 109 files changed, 536 insertions(+), 173 deletions(-) delete mode 100644 extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_box-shadow.scss rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_accordion.scss (97%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_alert.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_badge.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_breadcrumb.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_button-group.scss (87%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_buttons.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_card.scss (95%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_carousel.scss (87%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_close.scss (87%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_containers.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_dropdown.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_forms.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_functions.scss (99%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_grid.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_helpers.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_images.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_list-group.scss (93%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_maps.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_mixins.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_modal.scss (96%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_nav.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_navbar.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_offcanvas.scss (93%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_pagination.scss (98%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_placeholders.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_popover.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_progress.scss (96%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_reboot.scss (98%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_root.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_spinners.scss (99%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_tables.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_toasts.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_tooltip.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_transitions.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_type.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_utilities.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_variables-dark.scss (90%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/_variables.scss (98%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/bootstrap-grid.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/bootstrap-reboot.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/bootstrap-utilities.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/bootstrap.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/forms/_floating-labels.scss (78%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/forms/_form-check.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/forms/_form-control.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/forms/_form-range.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/forms/_form-select.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/forms/_form-text.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/forms/_input-group.scss (98%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/forms/_labels.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/forms/_validation.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/helpers/_clearfix.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/helpers/_color-bg.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/helpers/_colored-links.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/helpers/_focus-ring.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/helpers/_icon-link.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/helpers/_position.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/helpers/_ratio.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/helpers/_stacks.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/helpers/_stretched-link.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/helpers/_text-truncation.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/helpers/_visually-hidden.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/helpers/_vr.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_alert.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_backdrop.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_banner.scss (52%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_border-radius.scss (100%) create mode 100644 extensions/pagetop-bootsier/static/bootstrap/mixins/_box-shadow.scss rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_breakpoints.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_buttons.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_caret.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_clearfix.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_color-mode.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_color-scheme.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_container.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_deprecate.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_forms.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_gradients.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_grid.scss (98%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_image.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_list-group.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_lists.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_pagination.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_reset-text.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_resize.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_table-variants.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_text-truncate.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_transition.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_utilities.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/mixins/_visually-hidden.scss (87%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/tests/jasmine.js (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/tests/mixins/_auto-import-of-variables-dark.test.scss (100%) create mode 100644 extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_box-shadow.test.scss create mode 100644 extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_color-contrast.test.scss rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/tests/mixins/_color-modes.test.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/tests/mixins/_media-query-color-mode-full.test.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/tests/mixins/_utilities.test.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/tests/sass-true/register.js (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/tests/sass-true/runner.js (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/tests/utilities/_api.test.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/utilities/_api.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap-5.3.3 => bootstrap}/vendor/_rfs.scss (100%) diff --git a/extensions/pagetop-bootsier/build.rs b/extensions/pagetop-bootsier/build.rs index 47cb4740..f2d0f794 100644 --- a/extensions/pagetop-bootsier/build.rs +++ b/extensions/pagetop-bootsier/build.rs @@ -4,12 +4,9 @@ use std::env; use std::path::Path; fn main() -> std::io::Result<()> { - StaticFilesBundle::from_scss( - "./static/bootstrap-5.3.3/bootstrap.scss", - "bootstrap.min.css", - ) - .with_name("bootsier") - .build()?; + StaticFilesBundle::from_scss("./static/bootstrap/bootstrap.scss", "bootstrap.min.css") + .with_name("bootsier") + .build()?; StaticFilesBundle::from_dir("./static/js", Some(bootstrap_js_files)) .with_name("bootsier_js") .build() diff --git a/extensions/pagetop-bootsier/src/lib.rs b/extensions/pagetop-bootsier/src/lib.rs index c413e8e5..fecf1273 100644 --- a/extensions/pagetop-bootsier/src/lib.rs +++ b/extensions/pagetop-bootsier/src/lib.rs @@ -86,7 +86,7 @@ use pagetop::prelude::*; pub type BootsierRegion = ThemeRegion; // Versión de la librería Bootstrap. -const BOOTSTRAP_VERSION: &str = "5.3.3"; +const BOOTSTRAP_VERSION: &str = "5.3.8"; /// Tema basado en [Bootstrap](https://getbootstrap.com/) para los componentes base de PageTop. /// diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_box-shadow.scss b/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_box-shadow.scss deleted file mode 100644 index 4172541f..00000000 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_box-shadow.scss +++ /dev/null @@ -1,18 +0,0 @@ -@mixin box-shadow($shadow...) { - @if $enable-shadows { - $result: (); - - @each $value in $shadow { - @if $value != null { - $result: append($result, $value, "comma"); - } - @if $value == none and length($shadow) > 1 { - @warn "The keyword 'none' must be used as a single argument."; - } - } - - @if (length($result) > 0) { - box-shadow: $result; - } - } -} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_accordion.scss b/extensions/pagetop-bootsier/static/bootstrap/_accordion.scss similarity index 97% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_accordion.scss rename to extensions/pagetop-bootsier/static/bootstrap/_accordion.scss index 17e5436e..e9f267fb 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_accordion.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_accordion.scss @@ -134,17 +134,12 @@ &:last-child { border-bottom: 0; } // stylelint-disable selector-max-class - > .accordion-header .accordion-button { - &, - &.collapsed { - @include border-radius(0); - } - } - // stylelint-enable selector-max-class - - > .accordion-collapse { + > .accordion-collapse, + > .accordion-header .accordion-button, + > .accordion-header .accordion-button.collapsed { @include border-radius(0); } + // stylelint-enable selector-max-class } } diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_alert.scss b/extensions/pagetop-bootsier/static/bootstrap/_alert.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_alert.scss rename to extensions/pagetop-bootsier/static/bootstrap/_alert.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_badge.scss b/extensions/pagetop-bootsier/static/bootstrap/_badge.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_badge.scss rename to extensions/pagetop-bootsier/static/bootstrap/_badge.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_breadcrumb.scss b/extensions/pagetop-bootsier/static/bootstrap/_breadcrumb.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_breadcrumb.scss rename to extensions/pagetop-bootsier/static/bootstrap/_breadcrumb.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_button-group.scss b/extensions/pagetop-bootsier/static/bootstrap/_button-group.scss similarity index 87% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_button-group.scss rename to extensions/pagetop-bootsier/static/bootstrap/_button-group.scss index 55ae3f65..78e12522 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_button-group.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_button-group.scss @@ -39,7 +39,7 @@ // Prevent double borders when buttons are next to each other > :not(.btn-check:first-child) + .btn, > .btn-group:not(:first-child) { - margin-left: calc(#{$btn-border-width} * -1); // stylelint-disable-line function-disallowed-list + margin-left: calc(-1 * #{$btn-border-width}); // stylelint-disable-line function-disallowed-list } // Reset rounded corners @@ -126,7 +126,7 @@ > .btn:not(:first-child), > .btn-group:not(:first-child) { - margin-top: calc(#{$btn-border-width} * -1); // stylelint-disable-line function-disallowed-list + margin-top: calc(-1 * #{$btn-border-width}); // stylelint-disable-line function-disallowed-list } // Reset rounded corners @@ -135,7 +135,12 @@ @include border-bottom-radius(0); } - > .btn ~ .btn, + // The top radius should be 0 if the button is: + // - the "third or more" child + // - the second child and the previous element isn't `.btn-check` (making it the first child visually) + // - part of a btn-group which isn't the first child + > .btn:nth-child(n + 3), + > :not(.btn-check) + .btn, > .btn-group:not(:first-child) > .btn { @include border-top-radius(0); } diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_buttons.scss b/extensions/pagetop-bootsier/static/bootstrap/_buttons.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_buttons.scss rename to extensions/pagetop-bootsier/static/bootstrap/_buttons.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_card.scss b/extensions/pagetop-bootsier/static/bootstrap/_card.scss similarity index 95% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_card.scss rename to extensions/pagetop-bootsier/static/bootstrap/_card.scss index d3535a98..dcebe6ac 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_card.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_card.scss @@ -193,8 +193,7 @@ // The child selector allows nested `.card` within `.card-group` // to display properly. > .card { - // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4 - flex: 1 0 0%; + flex: 1 0 0; margin-bottom: 0; + .card { @@ -207,13 +206,13 @@ &:not(:last-child) { @include border-end-radius(0); - .card-img-top, - .card-header { + > .card-img-top, + > .card-header { // stylelint-disable-next-line property-disallowed-list border-top-right-radius: 0; } - .card-img-bottom, - .card-footer { + > .card-img-bottom, + > .card-footer { // stylelint-disable-next-line property-disallowed-list border-bottom-right-radius: 0; } @@ -222,13 +221,13 @@ &:not(:first-child) { @include border-start-radius(0); - .card-img-top, - .card-header { + > .card-img-top, + > .card-header { // stylelint-disable-next-line property-disallowed-list border-top-left-radius: 0; } - .card-img-bottom, - .card-footer { + > .card-img-bottom, + > .card-footer { // stylelint-disable-next-line property-disallowed-list border-bottom-left-radius: 0; } diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_carousel.scss b/extensions/pagetop-bootsier/static/bootstrap/_carousel.scss similarity index 87% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_carousel.scss rename to extensions/pagetop-bootsier/static/bootstrap/_carousel.scss index 3a135220..5ebf6b15 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_carousel.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_carousel.scss @@ -99,6 +99,7 @@ color: $carousel-control-color; text-align: center; background: none; + filter: var(--#{$prefix}carousel-control-icon-filter); border: 0; opacity: $carousel-control-opacity; @include transition($carousel-control-transition); @@ -168,7 +169,7 @@ margin-left: $carousel-indicator-spacer; text-indent: -999px; cursor: pointer; - background-color: $carousel-indicator-active-bg; + background-color: var(--#{$prefix}carousel-indicator-active-bg); background-clip: padding-box; border: 0; // Use transparent borders to increase the hit area by 10px on top and bottom. @@ -195,42 +196,31 @@ left: (100% - $carousel-caption-width) * .5; padding-top: $carousel-caption-padding-y; padding-bottom: $carousel-caption-padding-y; - color: $carousel-caption-color; + color: var(--#{$prefix}carousel-caption-color); text-align: center; } // Dark mode carousel @mixin carousel-dark() { - .carousel-control-prev-icon, - .carousel-control-next-icon { - filter: $carousel-dark-control-icon-filter; - } - - .carousel-indicators [data-bs-target] { - background-color: $carousel-dark-indicator-active-bg; - } - - .carousel-caption { - color: $carousel-dark-caption-color; - } + --#{$prefix}carousel-indicator-active-bg: #{$carousel-indicator-active-bg-dark}; + --#{$prefix}carousel-caption-color: #{$carousel-caption-color-dark}; + --#{$prefix}carousel-control-icon-filter: #{$carousel-control-icon-filter-dark}; } .carousel-dark { @include carousel-dark(); } +:root, +[data-bs-theme="light"] { + --#{$prefix}carousel-indicator-active-bg: #{$carousel-indicator-active-bg}; + --#{$prefix}carousel-caption-color: #{$carousel-caption-color}; + --#{$prefix}carousel-control-icon-filter: #{$carousel-control-icon-filter}; +} + @if $enable-dark-mode { - @include color-mode(dark) { - @if $color-mode-type == "media-query" { - .carousel { - @include carousel-dark(); - } - } @else { - .carousel, - &.carousel { - @include carousel-dark(); - } - } + @include color-mode(dark, true) { + @include carousel-dark(); } } diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_close.scss b/extensions/pagetop-bootsier/static/bootstrap/_close.scss similarity index 87% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_close.scss rename to extensions/pagetop-bootsier/static/bootstrap/_close.scss index 4d6e73c1..d53c96fb 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_close.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_close.scss @@ -12,7 +12,6 @@ --#{$prefix}btn-close-focus-shadow: #{$btn-close-focus-shadow}; --#{$prefix}btn-close-focus-opacity: #{$btn-close-focus-opacity}; --#{$prefix}btn-close-disabled-opacity: #{$btn-close-disabled-opacity}; - --#{$prefix}btn-close-white-filter: #{$btn-close-white-filter}; // scss-docs-end close-css-vars box-sizing: content-box; @@ -21,6 +20,7 @@ padding: $btn-close-padding-y $btn-close-padding-x; color: var(--#{$prefix}btn-close-color); background: transparent var(--#{$prefix}btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements + filter: var(--#{$prefix}btn-close-filter); border: 0; // for button elements @include border-radius(); opacity: var(--#{$prefix}btn-close-opacity); @@ -47,17 +47,20 @@ } @mixin btn-close-white() { - filter: var(--#{$prefix}btn-close-white-filter); + --#{$prefix}btn-close-filter: #{$btn-close-filter-dark}; } .btn-close-white { @include btn-close-white(); } +:root, +[data-bs-theme="light"] { + --#{$prefix}btn-close-filter: #{$btn-close-filter}; +} + @if $enable-dark-mode { - @include color-mode(dark) { - .btn-close { - @include btn-close-white(); - } + @include color-mode(dark, true) { + @include btn-close-white(); } } diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_containers.scss b/extensions/pagetop-bootsier/static/bootstrap/_containers.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_containers.scss rename to extensions/pagetop-bootsier/static/bootstrap/_containers.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_dropdown.scss b/extensions/pagetop-bootsier/static/bootstrap/_dropdown.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_dropdown.scss rename to extensions/pagetop-bootsier/static/bootstrap/_dropdown.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_forms.scss b/extensions/pagetop-bootsier/static/bootstrap/_forms.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_forms.scss rename to extensions/pagetop-bootsier/static/bootstrap/_forms.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_functions.scss b/extensions/pagetop-bootsier/static/bootstrap/_functions.scss similarity index 99% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_functions.scss rename to extensions/pagetop-bootsier/static/bootstrap/_functions.scss index 90296586..59d431a1 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_functions.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_functions.scss @@ -157,7 +157,7 @@ $_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003 @each $color in $foregrounds { $contrast-ratio: contrast-ratio($background, $color); - @if $contrast-ratio > $min-contrast-ratio { + @if $contrast-ratio >= $min-contrast-ratio { @return $color; } @else if $contrast-ratio > $max-ratio { $max-ratio: $contrast-ratio; @@ -177,7 +177,7 @@ $_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003 @return if($l1 > $l2, divide($l1 + .05, $l2 + .05), divide($l2 + .05, $l1 + .05)); } -// Return WCAG2.1 relative luminance +// Return WCAG2.2 relative luminance // See https://www.w3.org/TR/WCAG/#dfn-relative-luminance // See https://www.w3.org/TR/WCAG/#dfn-contrast-ratio @function luminance($color) { diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_grid.scss b/extensions/pagetop-bootsier/static/bootstrap/_grid.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_grid.scss rename to extensions/pagetop-bootsier/static/bootstrap/_grid.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_helpers.scss b/extensions/pagetop-bootsier/static/bootstrap/_helpers.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_helpers.scss rename to extensions/pagetop-bootsier/static/bootstrap/_helpers.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_images.scss b/extensions/pagetop-bootsier/static/bootstrap/_images.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_images.scss rename to extensions/pagetop-bootsier/static/bootstrap/_images.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_list-group.scss b/extensions/pagetop-bootsier/static/bootstrap/_list-group.scss similarity index 93% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_list-group.scss rename to extensions/pagetop-bootsier/static/bootstrap/_list-group.scss index 455531ee..3bdff679 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_list-group.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_list-group.scss @@ -43,31 +43,6 @@ } } -// Interactive list items -// -// Use anchor or button elements instead of `li`s or `div`s to create interactive -// list items. Includes an extra `.active` modifier class for selected items. - -.list-group-item-action { - width: 100%; // For `<button>`s (anchors become 100% by default though) - color: var(--#{$prefix}list-group-action-color); - text-align: inherit; // For `<button>`s (anchors inherit) - - // Hover state - &:hover, - &:focus { - z-index: 1; // Place hover/focus items above their siblings for proper border styling - color: var(--#{$prefix}list-group-action-hover-color); - text-decoration: none; - background-color: var(--#{$prefix}list-group-action-hover-bg); - } - - &:active { - color: var(--#{$prefix}list-group-action-active-color); - background-color: var(--#{$prefix}list-group-action-active-bg); - } -} - // Individual list items // // Use on `li`s or `div`s within the `.list-group` parent. @@ -115,6 +90,33 @@ } } +// Interactive list items +// +// Use anchor or button elements instead of `li`s or `div`s to create interactive +// list items. Includes an extra `.active` modifier class for selected items. + +.list-group-item-action { + width: 100%; // For `<button>`s (anchors become 100% by default though) + color: var(--#{$prefix}list-group-action-color); + text-align: inherit; // For `<button>`s (anchors inherit) + + &:not(.active) { + // Hover state + &:hover, + &:focus { + z-index: 1; // Place hover/focus items above their siblings for proper border styling + color: var(--#{$prefix}list-group-action-hover-color); + text-decoration: none; + background-color: var(--#{$prefix}list-group-action-hover-bg); + } + + &:active { + color: var(--#{$prefix}list-group-action-active-color); + background-color: var(--#{$prefix}list-group-action-active-bg); + } + } +} + // Horizontal // // Change the layout of list group items from vertical (default) to horizontal. diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_maps.scss b/extensions/pagetop-bootsier/static/bootstrap/_maps.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_maps.scss rename to extensions/pagetop-bootsier/static/bootstrap/_maps.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_mixins.scss b/extensions/pagetop-bootsier/static/bootstrap/_mixins.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_mixins.scss rename to extensions/pagetop-bootsier/static/bootstrap/_mixins.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_modal.scss b/extensions/pagetop-bootsier/static/bootstrap/_modal.scss similarity index 96% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_modal.scss rename to extensions/pagetop-bootsier/static/bootstrap/_modal.scss index 494db94e..a3492c17 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_modal.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_modal.scss @@ -59,8 +59,8 @@ // When fading in the modal, animate it to slide down .modal.fade & { - @include transition($modal-transition); transform: $modal-fade-transform; + @include transition($modal-transition); } .modal.show & { transform: $modal-show-transform; @@ -132,7 +132,11 @@ .btn-close { padding: calc(var(--#{$prefix}modal-header-padding-y) * .5) calc(var(--#{$prefix}modal-header-padding-x) * .5); - margin: calc(-.5 * var(--#{$prefix}modal-header-padding-y)) calc(-.5 * var(--#{$prefix}modal-header-padding-x)) calc(-.5 * var(--#{$prefix}modal-header-padding-y)) auto; + // Split properties to avoid invalid calc() function if value is 0 + margin-top: calc(-.5 * var(--#{$prefix}modal-header-padding-y)); + margin-right: calc(-.5 * var(--#{$prefix}modal-header-padding-x)); + margin-bottom: calc(-.5 * var(--#{$prefix}modal-header-padding-y)); + margin-left: auto; } } diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_nav.scss b/extensions/pagetop-bootsier/static/bootstrap/_nav.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_nav.scss rename to extensions/pagetop-bootsier/static/bootstrap/_nav.scss index ff073d36..96fa5289 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_nav.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_nav.scss @@ -169,8 +169,8 @@ .nav-justified { > .nav-link, .nav-item { - flex-basis: 0; flex-grow: 1; + flex-basis: 0; text-align: center; } } diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_navbar.scss b/extensions/pagetop-bootsier/static/bootstrap/_navbar.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_navbar.scss rename to extensions/pagetop-bootsier/static/bootstrap/_navbar.scss index 71619382..86aa441e 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_navbar.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_navbar.scss @@ -139,8 +139,8 @@ // the default flexbox row orientation. Requires the use of `flex-wrap: wrap` // on the `.navbar` parent. .navbar-collapse { - flex-basis: 100%; flex-grow: 1; + flex-basis: 100%; // For always expanded or extra full navbars, ensure content aligns itself // properly vertically. Can be easily overridden with flex utilities. align-items: center; diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_offcanvas.scss b/extensions/pagetop-bootsier/static/bootstrap/_offcanvas.scss similarity index 93% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_offcanvas.scss rename to extensions/pagetop-bootsier/static/bootstrap/_offcanvas.scss index eb2c97ab..b40b2cd9 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_offcanvas.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_offcanvas.scss @@ -127,7 +127,11 @@ .btn-close { padding: calc(var(--#{$prefix}offcanvas-padding-y) * .5) calc(var(--#{$prefix}offcanvas-padding-x) * .5); - margin: calc(-.5 * var(--#{$prefix}offcanvas-padding-y)) calc(-.5 * var(--#{$prefix}offcanvas-padding-x)) calc(-.5 * var(--#{$prefix}offcanvas-padding-y)) auto; + // Split properties to avoid invalid calc() function if value is 0 + margin-top: calc(-.5 * var(--#{$prefix}offcanvas-padding-y)); + margin-right: calc(-.5 * var(--#{$prefix}offcanvas-padding-x)); + margin-bottom: calc(-.5 * var(--#{$prefix}offcanvas-padding-y)); + margin-left: auto; } } diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_pagination.scss b/extensions/pagetop-bootsier/static/bootstrap/_pagination.scss similarity index 98% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_pagination.scss rename to extensions/pagetop-bootsier/static/bootstrap/_pagination.scss index f275a62e..9f09694c 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_pagination.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_pagination.scss @@ -75,7 +75,7 @@ margin-left: $pagination-margin-start; } - @if $pagination-margin-start == calc(#{$pagination-border-width} * -1) { + @if $pagination-margin-start == calc(-1 * #{$pagination-border-width}) { &:first-child { .page-link { @include border-start-radius(var(--#{$prefix}pagination-border-radius)); diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_placeholders.scss b/extensions/pagetop-bootsier/static/bootstrap/_placeholders.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_placeholders.scss rename to extensions/pagetop-bootsier/static/bootstrap/_placeholders.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_popover.scss b/extensions/pagetop-bootsier/static/bootstrap/_popover.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_popover.scss rename to extensions/pagetop-bootsier/static/bootstrap/_popover.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_progress.scss b/extensions/pagetop-bootsier/static/bootstrap/_progress.scss similarity index 96% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_progress.scss rename to extensions/pagetop-bootsier/static/bootstrap/_progress.scss index 148c3815..732365c5 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_progress.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_progress.scss @@ -3,7 +3,7 @@ // scss-docs-start progress-keyframes @if $enable-transitions { @keyframes progress-bar-stripes { - 0% { background-position-x: $progress-height; } + 0% { background-position-x: var(--#{$prefix}progress-height); } } } // scss-docs-end progress-keyframes diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_reboot.scss b/extensions/pagetop-bootsier/static/bootstrap/_reboot.scss similarity index 98% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_reboot.scss rename to extensions/pagetop-bootsier/static/bootstrap/_reboot.scss index 18791753..524645fb 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_reboot.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_reboot.scss @@ -499,9 +499,9 @@ legend { width: 100%; padding: 0; margin-bottom: $legend-margin-bottom; - @include font-size($legend-font-size); font-weight: $legend-font-weight; line-height: inherit; + @include font-size($legend-font-size); + * { clear: left; // 2 @@ -534,6 +534,12 @@ legend { [type="search"] { -webkit-appearance: textfield; // 1 outline-offset: -2px; // 2 + + // 3. Better affordance and consistent appearance for search cancel button + &::-webkit-search-cancel-button { + cursor: pointer; + filter: grayscale(1); + } } // 1. A few input types should stay LTR diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_root.scss b/extensions/pagetop-bootsier/static/bootstrap/_root.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_root.scss rename to extensions/pagetop-bootsier/static/bootstrap/_root.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_spinners.scss b/extensions/pagetop-bootsier/static/bootstrap/_spinners.scss similarity index 99% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_spinners.scss rename to extensions/pagetop-bootsier/static/bootstrap/_spinners.scss index ec847320..9dff2892 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_spinners.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_spinners.scss @@ -5,6 +5,7 @@ .spinner-grow, .spinner-border { display: inline-block; + flex-shrink: 0; width: var(--#{$prefix}spinner-width); height: var(--#{$prefix}spinner-height); vertical-align: var(--#{$prefix}spinner-vertical-align); diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_tables.scss b/extensions/pagetop-bootsier/static/bootstrap/_tables.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_tables.scss rename to extensions/pagetop-bootsier/static/bootstrap/_tables.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_toasts.scss b/extensions/pagetop-bootsier/static/bootstrap/_toasts.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_toasts.scss rename to extensions/pagetop-bootsier/static/bootstrap/_toasts.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_tooltip.scss b/extensions/pagetop-bootsier/static/bootstrap/_tooltip.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_tooltip.scss rename to extensions/pagetop-bootsier/static/bootstrap/_tooltip.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_transitions.scss b/extensions/pagetop-bootsier/static/bootstrap/_transitions.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_transitions.scss rename to extensions/pagetop-bootsier/static/bootstrap/_transitions.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_type.scss b/extensions/pagetop-bootsier/static/bootstrap/_type.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_type.scss rename to extensions/pagetop-bootsier/static/bootstrap/_type.scss index 37d64bf8..6961390f 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_type.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_type.scss @@ -34,11 +34,11 @@ // Type display classes @each $display, $font-size in $display-font-sizes { .display-#{$display} { - @include font-size($font-size); font-family: $display-font-family; font-style: $display-font-style; font-weight: $display-font-weight; line-height: $display-line-height; + @include font-size($font-size); } } diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_utilities.scss b/extensions/pagetop-bootsier/static/bootstrap/_utilities.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_utilities.scss rename to extensions/pagetop-bootsier/static/bootstrap/_utilities.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables-dark.scss b/extensions/pagetop-bootsier/static/bootstrap/_variables-dark.scss similarity index 90% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables-dark.scss rename to extensions/pagetop-bootsier/static/bootstrap/_variables-dark.scss index 6422b387..260f6dcc 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables-dark.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_variables-dark.scss @@ -82,6 +82,21 @@ $form-invalid-border-color-dark: $red-300 !default; $accordion-icon-color-dark: $primary-text-emphasis-dark !default; $accordion-icon-active-color-dark: $primary-text-emphasis-dark !default; -$accordion-button-icon-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-color-dark}'><path fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/></svg>") !default; -$accordion-button-active-icon-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-active-color-dark}'><path fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/></svg>") !default; +$accordion-button-icon-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-color-dark}'><path fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/></svg>") !default; +$accordion-button-active-icon-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-active-color-dark}'><path fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/></svg>") !default; // scss-docs-end sass-dark-mode-vars + + +// +// Carousel +// + +$carousel-indicator-active-bg-dark: $carousel-dark-indicator-active-bg !default; +$carousel-caption-color-dark: $carousel-dark-caption-color !default; +$carousel-control-icon-filter-dark: $carousel-dark-control-icon-filter !default; + +// +// Close button +// + +$btn-close-filter-dark: $btn-close-white-filter !default; diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables.scss b/extensions/pagetop-bootsier/static/bootstrap/_variables.scss similarity index 98% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables.scss rename to extensions/pagetop-bootsier/static/bootstrap/_variables.scss index 06531395..1ffa7e74 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/_variables.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/_variables.scss @@ -67,8 +67,8 @@ $colors: ( ) !default; // scss-docs-end colors-map -// The contrast ratio to reach against white, to determine if color changes from "light" to "dark". Acceptable values for WCAG 2.0 are 3, 4.5 and 7. -// See https://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast +// The contrast ratio to reach against white, to determine if color changes from "light" to "dark". Acceptable values for WCAG 2.2 are 3, 4.5 and 7. +// See https://www.w3.org/TR/WCAG/#contrast-minimum $min-contrast-ratio: 4.5 !default; // Customize the light and dark text colors for use in our color contrast function. @@ -1091,7 +1091,7 @@ $form-feedback-valid-color: $success !default; $form-feedback-invalid-color: $danger !default; $form-feedback-icon-valid-color: $form-feedback-valid-color !default; -$form-feedback-icon-valid: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/></svg>") !default; +$form-feedback-icon-valid: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/></svg>") !default; $form-feedback-icon-invalid-color: $form-feedback-invalid-color !default; $form-feedback-icon-invalid: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='#{$form-feedback-icon-invalid-color}'><circle cx='6' cy='6' r='4.5'/><path stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/><circle cx='6' cy='8.2' r='.6' fill='#{$form-feedback-icon-invalid-color}' stroke='none'/></svg>") !default; // scss-docs-end form-feedback-variables @@ -1302,7 +1302,7 @@ $pagination-color: var(--#{$prefix}link-color) !default; $pagination-bg: var(--#{$prefix}body-bg) !default; $pagination-border-radius: var(--#{$prefix}border-radius) !default; $pagination-border-width: var(--#{$prefix}border-width) !default; -$pagination-margin-start: calc(#{$pagination-border-width} * -1) !default; // stylelint-disable-line function-disallowed-list +$pagination-margin-start: calc(-1 * #{$pagination-border-width}) !default; // stylelint-disable-line function-disallowed-list $pagination-border-color: var(--#{$prefix}border-color) !default; $pagination-focus-color: var(--#{$prefix}link-hover-color) !default; @@ -1394,8 +1394,8 @@ $accordion-icon-active-color: $primary-text-emphasis !default; $accordion-icon-transition: transform .2s ease-in-out !default; $accordion-icon-transform: rotate(-180deg) !default; -$accordion-button-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='#{$accordion-icon-color}' stroke-linecap='round' stroke-linejoin='round'><path d='M2 5L8 11L14 5'/></svg>") !default; -$accordion-button-active-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='#{$accordion-icon-active-color}' stroke-linecap='round' stroke-linejoin='round'><path d='M2 5L8 11L14 5'/></svg>") !default; +$accordion-button-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='#{$accordion-icon-color}' stroke-linecap='round' stroke-linejoin='round'><path d='m2 5 6 6 6-6'/></svg>") !default; +$accordion-button-active-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='#{$accordion-icon-active-color}' stroke-linecap='round' stroke-linejoin='round'><path d='m2 5 6 6 6-6'/></svg>") !default; // scss-docs-end accordion-variables // Tooltips @@ -1507,7 +1507,7 @@ $modal-dialog-margin-y-sm-up: 1.75rem !default; $modal-title-line-height: $line-height-base !default; -$modal-content-color: null !default; +$modal-content-color: var(--#{$prefix}body-color) !default; $modal-content-bg: var(--#{$prefix}body-bg) !default; $modal-content-border-color: var(--#{$prefix}border-color-translucent) !default; $modal-content-border-width: var(--#{$prefix}border-width) !default; @@ -1652,6 +1652,7 @@ $carousel-control-width: 15% !default; $carousel-control-opacity: .5 !default; $carousel-control-hover-opacity: .9 !default; $carousel-control-transition: opacity .15s ease !default; +$carousel-control-icon-filter: null !default; $carousel-indicator-width: 30px !default; $carousel-indicator-height: 3px !default; @@ -1669,17 +1670,17 @@ $carousel-caption-spacer: 1.25rem !default; $carousel-control-icon-width: 2rem !default; -$carousel-control-prev-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$carousel-control-color}'><path d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/></svg>") !default; -$carousel-control-next-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$carousel-control-color}'><path d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/></svg>") !default; +$carousel-control-prev-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$carousel-control-color}'><path d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0'/></svg>") !default; +$carousel-control-next-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$carousel-control-color}'><path d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708'/></svg>") !default; $carousel-transition-duration: .6s !default; $carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`) // scss-docs-end carousel-variables // scss-docs-start carousel-dark-variables -$carousel-dark-indicator-active-bg: $black !default; -$carousel-dark-caption-color: $black !default; -$carousel-dark-control-icon-filter: invert(1) grayscale(100) !default; +$carousel-dark-indicator-active-bg: $black !default; // Deprecated in v5.3.4 +$carousel-dark-caption-color: $black !default; // Deprecated in v5.3.4 +$carousel-dark-control-icon-filter: invert(1) grayscale(100) !default; // Deprecated in v5.3.4 // scss-docs-end carousel-dark-variables @@ -1706,13 +1707,14 @@ $btn-close-height: $btn-close-width !default; $btn-close-padding-x: .25em !default; $btn-close-padding-y: $btn-close-padding-x !default; $btn-close-color: $black !default; -$btn-close-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$btn-close-color}'><path d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/></svg>") !default; +$btn-close-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$btn-close-color}'><path d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414'/></svg>") !default; $btn-close-focus-shadow: $focus-ring-box-shadow !default; $btn-close-opacity: .5 !default; $btn-close-hover-opacity: .75 !default; $btn-close-focus-opacity: 1 !default; $btn-close-disabled-opacity: .25 !default; -$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%) !default; +$btn-close-filter: null !default; +$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%) !default; // Deprecated in v5.3.4 // scss-docs-end close-variables diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-grid.scss b/extensions/pagetop-bootsier/static/bootstrap/bootstrap-grid.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-grid.scss rename to extensions/pagetop-bootsier/static/bootstrap/bootstrap-grid.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-reboot.scss b/extensions/pagetop-bootsier/static/bootstrap/bootstrap-reboot.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-reboot.scss rename to extensions/pagetop-bootsier/static/bootstrap/bootstrap-reboot.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-utilities.scss b/extensions/pagetop-bootsier/static/bootstrap/bootstrap-utilities.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap-utilities.scss rename to extensions/pagetop-bootsier/static/bootstrap/bootstrap-utilities.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap.scss b/extensions/pagetop-bootsier/static/bootstrap/bootstrap.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/bootstrap.scss rename to extensions/pagetop-bootsier/static/bootstrap/bootstrap.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_floating-labels.scss b/extensions/pagetop-bootsier/static/bootstrap/forms/_floating-labels.scss similarity index 78% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_floating-labels.scss rename to extensions/pagetop-bootsier/static/bootstrap/forms/_floating-labels.scss index 2cf04704..38df1155 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_floating-labels.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/forms/_floating-labels.scss @@ -14,9 +14,11 @@ top: 0; left: 0; z-index: 2; + max-width: 100%; height: 100%; // allow textareas padding: $form-floating-padding-y $form-floating-padding-x; overflow: hidden; + color: rgba(var(--#{$prefix}body-color-rgb), #{$form-floating-label-opacity}); text-align: start; text-overflow: ellipsis; white-space: nowrap; @@ -49,6 +51,7 @@ > .form-select { padding-top: $form-floating-input-padding-t; padding-bottom: $form-floating-input-padding-b; + padding-left: $form-floating-padding-x; } > .form-control:focus, @@ -56,27 +59,30 @@ > .form-control-plaintext, > .form-select { ~ label { - color: rgba(var(--#{$prefix}body-color-rgb), #{$form-floating-label-opacity}); transform: $form-floating-label-transform; - - &::after { - position: absolute; - inset: $form-floating-padding-y ($form-floating-padding-x * .5); - z-index: -1; - height: $form-floating-label-height; - content: ""; - background-color: $input-bg; - @include border-radius($input-border-radius); - } } } // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped > .form-control:-webkit-autofill { ~ label { - color: rgba(var(--#{$prefix}body-color-rgb), #{$form-floating-label-opacity}); transform: $form-floating-label-transform; } } + > textarea:focus, + > textarea:not(:placeholder-shown) { + ~ label::after { + position: absolute; + inset: $form-floating-padding-y ($form-floating-padding-x * .5); + z-index: -1; + height: $form-floating-label-height; + content: ""; + background-color: $input-bg; + @include border-radius($input-border-radius); + } + } + > textarea:disabled ~ label::after { + background-color: $input-disabled-bg; + } > .form-control-plaintext { ~ label { @@ -87,9 +93,5 @@ > :disabled ~ label, > .form-control:disabled ~ label { // Required for `.form-control`s because of specificity color: $form-floating-label-disabled-color; - - &::after { - background-color: $input-disabled-bg; - } } } diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-check.scss b/extensions/pagetop-bootsier/static/bootstrap/forms/_form-check.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-check.scss rename to extensions/pagetop-bootsier/static/bootstrap/forms/_form-check.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-control.scss b/extensions/pagetop-bootsier/static/bootstrap/forms/_form-control.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-control.scss rename to extensions/pagetop-bootsier/static/bootstrap/forms/_form-control.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-range.scss b/extensions/pagetop-bootsier/static/bootstrap/forms/_form-range.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-range.scss rename to extensions/pagetop-bootsier/static/bootstrap/forms/_form-range.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-select.scss b/extensions/pagetop-bootsier/static/bootstrap/forms/_form-select.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-select.scss rename to extensions/pagetop-bootsier/static/bootstrap/forms/_form-select.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-text.scss b/extensions/pagetop-bootsier/static/bootstrap/forms/_form-text.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_form-text.scss rename to extensions/pagetop-bootsier/static/bootstrap/forms/_form-text.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_input-group.scss b/extensions/pagetop-bootsier/static/bootstrap/forms/_input-group.scss similarity index 98% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_input-group.scss rename to extensions/pagetop-bootsier/static/bootstrap/forms/_input-group.scss index 58e4d409..8078ebb1 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_input-group.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/forms/_input-group.scss @@ -121,7 +121,7 @@ } > :not(:first-child):not(.dropdown-menu)#{$validation-messages} { - margin-left: calc(#{$input-border-width} * -1); // stylelint-disable-line function-disallowed-list + margin-left: calc(-1 * #{$input-border-width}); // stylelint-disable-line function-disallowed-list @include border-start-radius(0); } diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_labels.scss b/extensions/pagetop-bootsier/static/bootstrap/forms/_labels.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_labels.scss rename to extensions/pagetop-bootsier/static/bootstrap/forms/_labels.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_validation.scss b/extensions/pagetop-bootsier/static/bootstrap/forms/_validation.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/forms/_validation.scss rename to extensions/pagetop-bootsier/static/bootstrap/forms/_validation.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_clearfix.scss b/extensions/pagetop-bootsier/static/bootstrap/helpers/_clearfix.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_clearfix.scss rename to extensions/pagetop-bootsier/static/bootstrap/helpers/_clearfix.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_color-bg.scss b/extensions/pagetop-bootsier/static/bootstrap/helpers/_color-bg.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_color-bg.scss rename to extensions/pagetop-bootsier/static/bootstrap/helpers/_color-bg.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_colored-links.scss b/extensions/pagetop-bootsier/static/bootstrap/helpers/_colored-links.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_colored-links.scss rename to extensions/pagetop-bootsier/static/bootstrap/helpers/_colored-links.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_focus-ring.scss b/extensions/pagetop-bootsier/static/bootstrap/helpers/_focus-ring.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_focus-ring.scss rename to extensions/pagetop-bootsier/static/bootstrap/helpers/_focus-ring.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_icon-link.scss b/extensions/pagetop-bootsier/static/bootstrap/helpers/_icon-link.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_icon-link.scss rename to extensions/pagetop-bootsier/static/bootstrap/helpers/_icon-link.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_position.scss b/extensions/pagetop-bootsier/static/bootstrap/helpers/_position.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_position.scss rename to extensions/pagetop-bootsier/static/bootstrap/helpers/_position.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_ratio.scss b/extensions/pagetop-bootsier/static/bootstrap/helpers/_ratio.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_ratio.scss rename to extensions/pagetop-bootsier/static/bootstrap/helpers/_ratio.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_stacks.scss b/extensions/pagetop-bootsier/static/bootstrap/helpers/_stacks.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_stacks.scss rename to extensions/pagetop-bootsier/static/bootstrap/helpers/_stacks.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_stretched-link.scss b/extensions/pagetop-bootsier/static/bootstrap/helpers/_stretched-link.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_stretched-link.scss rename to extensions/pagetop-bootsier/static/bootstrap/helpers/_stretched-link.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_text-truncation.scss b/extensions/pagetop-bootsier/static/bootstrap/helpers/_text-truncation.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_text-truncation.scss rename to extensions/pagetop-bootsier/static/bootstrap/helpers/_text-truncation.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_visually-hidden.scss b/extensions/pagetop-bootsier/static/bootstrap/helpers/_visually-hidden.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_visually-hidden.scss rename to extensions/pagetop-bootsier/static/bootstrap/helpers/_visually-hidden.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_vr.scss b/extensions/pagetop-bootsier/static/bootstrap/helpers/_vr.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/helpers/_vr.scss rename to extensions/pagetop-bootsier/static/bootstrap/helpers/_vr.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_alert.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_alert.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_alert.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_alert.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_backdrop.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_backdrop.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_backdrop.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_backdrop.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_banner.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_banner.scss similarity index 52% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_banner.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_banner.scss index 20c2fd12..dd8a5103 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_banner.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/mixins/_banner.scss @@ -1,7 +1,7 @@ @mixin bsBanner($file) { /*! - * Bootstrap #{$file} v5.3.3 (https://getbootstrap.com/) - * Copyright 2011-2024 The Bootstrap Authors + * Bootstrap #{$file} v5.3.8 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ } diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_border-radius.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_border-radius.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_border-radius.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_border-radius.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_box-shadow.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_box-shadow.scss new file mode 100644 index 00000000..0bb6bf7e --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap/mixins/_box-shadow.scss @@ -0,0 +1,24 @@ +@mixin box-shadow($shadow...) { + @if $enable-shadows { + $result: (); + $has-single-value: false; + $single-value: null; + + @each $value in $shadow { + @if $value != null { + @if $value == none or $value == initial or $value == inherit or $value == unset { + $has-single-value: true; + $single-value: $value; + } @else { + $result: append($result, $value, "comma"); + } + } + } + + @if $has-single-value { + box-shadow: $single-value; + } @else if (length($result) > 0) { + box-shadow: $result; + } + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_breakpoints.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_breakpoints.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_breakpoints.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_breakpoints.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_buttons.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_buttons.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_buttons.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_buttons.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_caret.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_caret.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_caret.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_caret.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_clearfix.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_clearfix.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_clearfix.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_clearfix.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_color-mode.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_color-mode.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_color-mode.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_color-mode.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_color-scheme.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_color-scheme.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_color-scheme.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_color-scheme.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_container.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_container.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_container.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_container.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_deprecate.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_deprecate.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_deprecate.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_deprecate.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_forms.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_forms.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_forms.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_forms.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_gradients.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_gradients.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_gradients.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_gradients.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_grid.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_grid.scss similarity index 98% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_grid.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_grid.scss index ea307399..db77e07f 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_grid.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/mixins/_grid.scss @@ -72,7 +72,7 @@ @include media-breakpoint-up($breakpoint, $breakpoints) { // Provide basic `.col-{bp}` classes for equal-width flexbox columns .col#{$infix} { - flex: 1 0 0%; // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4 + flex: 1 0 0; } .row-cols#{$infix}-auto > * { diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_image.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_image.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_image.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_image.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_list-group.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_list-group.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_list-group.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_list-group.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_lists.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_lists.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_lists.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_lists.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_pagination.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_pagination.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_pagination.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_pagination.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_reset-text.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_reset-text.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_reset-text.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_reset-text.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_resize.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_resize.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_resize.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_resize.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_table-variants.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_table-variants.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_table-variants.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_table-variants.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_text-truncate.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_text-truncate.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_text-truncate.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_text-truncate.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_transition.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_transition.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_transition.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_transition.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_utilities.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_utilities.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_utilities.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_utilities.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_visually-hidden.scss b/extensions/pagetop-bootsier/static/bootstrap/mixins/_visually-hidden.scss similarity index 87% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_visually-hidden.scss rename to extensions/pagetop-bootsier/static/bootstrap/mixins/_visually-hidden.scss index 082aeec9..9dd0ad33 100644 --- a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/mixins/_visually-hidden.scss +++ b/extensions/pagetop-bootsier/static/bootstrap/mixins/_visually-hidden.scss @@ -19,12 +19,17 @@ &:not(caption) { position: absolute !important; } + + // Fix to prevent overflowing children to become focusable + * { + overflow: hidden !important; + } } // Use to only display content when it's focused, or one of its child elements is focused // (i.e. when focus is within the element/container that the class was applied to) // -// Useful for "Skip to main content" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 +// Useful for "Skip to main content" links; see https://www.w3.org/WAI/WCAG22/Techniques/general/G1.html @mixin visually-hidden-focusable() { &:not(:focus):not(:focus-within) { diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/jasmine.js b/extensions/pagetop-bootsier/static/bootstrap/tests/jasmine.js similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/jasmine.js rename to extensions/pagetop-bootsier/static/bootstrap/tests/jasmine.js diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_auto-import-of-variables-dark.test.scss b/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_auto-import-of-variables-dark.test.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_auto-import-of-variables-dark.test.scss rename to extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_auto-import-of-variables-dark.test.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_box-shadow.test.scss b/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_box-shadow.test.scss new file mode 100644 index 00000000..f5a07484 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_box-shadow.test.scss @@ -0,0 +1,188 @@ +@import "../../functions"; +@import "../../variables"; +@import "../../mixins"; + +// Store original value +$original-enable-shadows: $enable-shadows; + +// Enable shadows for all tests +$enable-shadows: true !global; + +@include describe("box-shadow mixin") { + @include it("handles single none value") { + @include assert() { + @include output() { + .test { + @include box-shadow(none); + } + } + + @include expect() { + .test { + box-shadow: none; + } + } + } + } + + @include it("handles multiple none values by consolidating them") { + @include assert() { + @include output() { + .test { + @include box-shadow(none, none, none); + } + } + + @include expect() { + .test { + box-shadow: none; + } + } + } + } + + @include it("handles other single-value keywords (initial, inherit, unset)") { + @include assert() { + @include output() { + .test-initial { + @include box-shadow(initial); + } + .test-inherit { + @include box-shadow(inherit); + } + .test-unset { + @include box-shadow(unset); + } + } + + @include expect() { + .test-initial { + box-shadow: initial; + } + .test-inherit { + box-shadow: inherit; + } + .test-unset { + box-shadow: unset; + } + } + } + } + + @include it("handles multiple single-value keywords by using the last one") { + @include assert() { + @include output() { + .test { + @include box-shadow(initial, inherit, unset); + } + } + + @include expect() { + .test { + box-shadow: unset; + } + } + } + } + + @include it("handles regular box-shadow values") { + @include assert() { + @include output() { + .test { + @include box-shadow(0 0 10px rgba(0, 0, 0, .5)); + } + } + + @include expect() { + .test { + box-shadow: 0 0 10px rgba(0, 0, 0, .5); + } + } + } + } + + @include it("handles multiple regular box-shadow values") { + @include assert() { + @include output() { + .test { + @include box-shadow(0 0 10px rgba(0, 0, 0, .5), 0 0 20px rgba(0, 0, 0, .3)); + } + } + + @include expect() { + .test { + box-shadow: 0 0 10px rgba(0, 0, 0, .5), 0 0 20px rgba(0, 0, 0, .3); + } + } + } + } + + @include it("handles null values by ignoring them") { + @include assert() { + @include output() { + .test { + @include box-shadow(null, 0 0 10px rgba(0, 0, 0, .5), null); + } + } + + @include expect() { + .test { + box-shadow: 0 0 10px rgba(0, 0, 0, .5); + } + } + } + } + + @include it("handles mixed values with keywords and regular shadows") { + @include assert() { + @include output() { + .test { + @include box-shadow(none, 0 0 10px rgba(0, 0, 0, .5)); + } + } + + @include expect() { + .test { + box-shadow: none; + } + } + } + } + + @include it("handles empty input") { + @include assert() { + @include output() { + .test { + @include box-shadow(); + } + } + + @include expect() { + .test { // stylelint-disable-line block-no-empty + } + } + } + } + + @include it("respects $enable-shadows variable") { + $enable-shadows: false !global; + + @include assert() { + @include output() { + .test { + @include box-shadow(0 0 10px rgba(0, 0, 0, .5)); + } + } + + @include expect() { + .test { // stylelint-disable-line block-no-empty + } + } + } + + $enable-shadows: true !global; + } +} + +// Restore original value +$enable-shadows: $original-enable-shadows !global; diff --git a/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_color-contrast.test.scss b/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_color-contrast.test.scss new file mode 100644 index 00000000..5b94ac57 --- /dev/null +++ b/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_color-contrast.test.scss @@ -0,0 +1,139 @@ +@import "../../functions"; +@import "../../variables"; +@import "../../variables-dark"; +@import "../../maps"; +@import "../../mixins"; + +@include describe("color-contrast function") { + @include it("should return a color when contrast ratio equals minimum requirement (WCAG 2.1 compliance)") { + // Test case: Background color that produces contrast ratio close to 4.5:1 + // This tests the WCAG 2.1 requirement that contrast should be "at least 4.5:1" (>= 4.5) + // rather than "strictly greater than 4.5:1" (> 4.5) + + // #777777 produces 4.4776:1 contrast ratio with white text + // Since this is below the 4.5:1 threshold, it should return the highest available contrast color + $test-background: #777; + $result: color-contrast($test-background); + + @include assert-equal($result, $black, "Should return black (highest available contrast) for background with 4.4776:1 contrast ratio (below threshold)"); + } + + @include it("should return a color when contrast ratio is above minimum requirement") { + // Test case: Background color that produces contrast ratio above 4.5:1 + // #767676 produces 4.5415:1 contrast ratio with white text + $test-background: #767676; + $result: color-contrast($test-background); + + @include assert-equal($result, $white, "Should return white for background with 4.5415:1 contrast ratio (above threshold)"); + } + + @include it("should return a color when contrast ratio is below minimum requirement") { + // Test case: Background color that produces contrast ratio below 4.5:1 + // #787878 produces 4.4155:1 contrast ratio with white text + $test-background: #787878; + $result: color-contrast($test-background); + + // Should return the color with the highest available contrast ratio + @include assert-equal($result, $black, "Should return black (highest available contrast) for background with 4.4155:1 contrast ratio (below threshold)"); + } + + @include it("should handle edge case with very light background") { + // Test case: Very light background that should return dark text + $test-background: #f8f9fa; // Very light gray + $result: color-contrast($test-background); + + @include assert-equal($result, $color-contrast-dark, "Should return dark text for very light background"); + } + + @include it("should handle edge case with very dark background") { + // Test case: Very dark background that should return light text + $test-background: #212529; // Very dark gray + $result: color-contrast($test-background); + + @include assert-equal($result, $color-contrast-light, "Should return light text for very dark background"); + } + + @include it("should work with custom minimum contrast ratio") { + // Test case: Using a custom minimum contrast ratio + $test-background: #666; + $result: color-contrast($test-background, $color-contrast-dark, $color-contrast-light, 3); + + @include assert-equal($result, $white, "Should return white when using custom minimum contrast ratio of 3.0"); + } + + @include it("should test contrast ratio calculation accuracy") { + // Test case: Verify that contrast-ratio function works correctly + $background: #767676; + $foreground: $white; + $ratio: contrast-ratio($background, $foreground); + // Bootstrap's implementation calculates this as ~4.5415, not exactly 4.5, due to its luminance math. + // We use 4.54 as the threshold for this test to match the actual implementation. + @include assert-true($ratio >= 4.54 and $ratio <= 4.55, "Contrast ratio should be approximately 4.54:1 (Bootstrap's math)"); + } + + @include it("should test luminance calculation") { + // Test case: Verify luminance function works correctly + $white-luminance: luminance($white); + $black-luminance: luminance($black); + + @include assert-equal($white-luminance, 1, "White should have luminance of 1"); + @include assert-equal($black-luminance, 0, "Black should have luminance of 0"); + } + + @include it("should handle rgba colors correctly") { + // Test case: Test with rgba colors + $test-background: rgba(118, 118, 118, 1); // Same as #767676 + $result: color-contrast($test-background); + + @include assert-equal($result, $white, "Should handle rgba colors correctly"); + } + + @include it("should test the WCAG 2.1 boundary condition with color below threshold") { + // Test case: Background color that produces contrast ratio below 4.5:1 + // #787878 produces 4.4155:1 contrast ratio with white + $test-background: #787878; // Produces 4.4155:1 contrast ratio + $contrast-ratio: contrast-ratio($test-background, $white); + + // Verify the contrast ratio is below 4.5:1 + @include assert-true($contrast-ratio < 4.5, "Contrast ratio should be below 4.5:1 threshold"); + + // The color-contrast function should return the color with highest available contrast + $result: color-contrast($test-background); + @include assert-equal($result, $black, "color-contrast should return black (highest available contrast) for below-threshold ratio"); + } + + @include it("should test the WCAG 2.1 boundary condition with color at threshold") { + // Test case: Background color that produces contrast ratio close to 4.5:1 + // #777777 produces 4.4776:1 contrast ratio with white + $test-background: #777; // Produces 4.4776:1 contrast ratio + $contrast-ratio: contrast-ratio($test-background, $white); + + // Verify the contrast ratio is below 4.5:1 threshold + @include assert-true($contrast-ratio < 4.5, "Contrast ratio is below threshold, function should handle gracefully"); + } + + @include it("should demonstrate the difference between > and >= operators") { + // Test case: Demonstrates the difference between > and >= operators + // Uses #767676 with a custom minimum contrast ratio that matches its actual ratio (4.5415) + // With > 4.5415: should return black (fallback to highest available) + // With >= 4.5415: should return white (meets threshold) + + $test-background: #767676; // Produces 4.5415:1 contrast ratio + $actual-ratio: contrast-ratio($test-background, $white); + + // Test with a custom minimum that matches the actual ratio + $result: color-contrast($test-background, $color-contrast-dark, $color-contrast-light, $actual-ratio); + + // Should return white when using >= implementation + @include assert-equal($result, $white, "color-contrast should return white when using exact ratio as threshold (>= implementation)"); + } + + @include it("should test additional working colors above threshold") { + // Test case: Background color that produces contrast ratio well above 4.5:1 + // #757575 produces 4.6047:1 contrast ratio with white text + $test-background: #757575; // Produces 4.6047:1 contrast ratio + $result: color-contrast($test-background); + + @include assert-equal($result, $white, "Should return white for background with 4.6047:1 contrast ratio (well above threshold)"); + } +} diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_color-modes.test.scss b/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_color-modes.test.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_color-modes.test.scss rename to extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_color-modes.test.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_media-query-color-mode-full.test.scss b/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_media-query-color-mode-full.test.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_media-query-color-mode-full.test.scss rename to extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_media-query-color-mode-full.test.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_utilities.test.scss b/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_utilities.test.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/mixins/_utilities.test.scss rename to extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_utilities.test.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/sass-true/register.js b/extensions/pagetop-bootsier/static/bootstrap/tests/sass-true/register.js similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/sass-true/register.js rename to extensions/pagetop-bootsier/static/bootstrap/tests/sass-true/register.js diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/sass-true/runner.js b/extensions/pagetop-bootsier/static/bootstrap/tests/sass-true/runner.js similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/sass-true/runner.js rename to extensions/pagetop-bootsier/static/bootstrap/tests/sass-true/runner.js diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/utilities/_api.test.scss b/extensions/pagetop-bootsier/static/bootstrap/tests/utilities/_api.test.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/tests/utilities/_api.test.scss rename to extensions/pagetop-bootsier/static/bootstrap/tests/utilities/_api.test.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/utilities/_api.scss b/extensions/pagetop-bootsier/static/bootstrap/utilities/_api.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/utilities/_api.scss rename to extensions/pagetop-bootsier/static/bootstrap/utilities/_api.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap-5.3.3/vendor/_rfs.scss b/extensions/pagetop-bootsier/static/bootstrap/vendor/_rfs.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap-5.3.3/vendor/_rfs.scss rename to extensions/pagetop-bootsier/static/bootstrap/vendor/_rfs.scss diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.js b/extensions/pagetop-bootsier/static/js/bootstrap.js index e3a59e3a..e1f6e58f 100644 --- a/extensions/pagetop-bootsier/static/js/bootstrap.js +++ b/extensions/pagetop-bootsier/static/js/bootstrap.js @@ -1,6 +1,6 @@ /*! - * Bootstrap v5.3.3 (https://getbootstrap.com/) - * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Bootstrap v5.3.8 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ (function (global, factory) { @@ -224,7 +224,7 @@ * @param {HTMLElement} element * @return void * - * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation + * @see https://www.harrytheo.com/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation */ const reflow = element => { element.offsetHeight; // eslint-disable-line no-unused-expressions @@ -269,7 +269,7 @@ }); }; const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => { - return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue; + return typeof possibleCallback === 'function' ? possibleCallback.call(...args) : defaultValue; }; const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => { if (!waitForTransition) { @@ -591,7 +591,7 @@ const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig')); for (const key of bsKeys) { let pureKey = key.replace(/^bs/, ''); - pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length); + pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1); attributes[pureKey] = normalizeData(element.dataset[key]); } return attributes; @@ -666,7 +666,7 @@ * Constants */ - const VERSION = '5.3.3'; + const VERSION = '5.3.8'; /** * Class definition @@ -692,6 +692,8 @@ this[propertyName] = null; } } + + // Private _queueCallback(callback, element, isAnimated = true) { executeAfterTransition(callback, element, isAnimated); } @@ -1623,11 +1625,11 @@ this._element.style[dimension] = ''; this._queueCallback(complete, this._element, true); } + + // Private _isShown(element = this._element) { return element.classList.contains(CLASS_NAME_SHOW$7); } - - // Private _configAfterMerge(config) { config.toggle = Boolean(config.toggle); // Coerce string values config.parent = getElement(config.parent); @@ -1881,7 +1883,7 @@ } _createPopper() { if (typeof Popper__namespace === 'undefined') { - throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)'); + throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org/docs/v2/)'); } let referenceElement = this._element; if (this._config.reference === 'parent') { @@ -1960,7 +1962,7 @@ } return { ...defaultBsPopperConfig, - ...execute(this._config.popperConfig, [defaultBsPopperConfig]) + ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig]) }; } _selectMenuItem({ @@ -2982,7 +2984,6 @@ * * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38 */ - // eslint-disable-next-line unicorn/better-regex const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i; const allowedAttribute = (attribute, allowedAttributeList) => { const attributeName = attribute.nodeName.toLowerCase(); @@ -3147,7 +3148,7 @@ return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg; } _resolvePossibleFunction(arg) { - return execute(arg, [this]); + return execute(arg, [undefined, this]); } _putElementInTemplate(element, templateElement) { if (this._config.html) { @@ -3246,7 +3247,7 @@ class Tooltip extends BaseComponent { constructor(element, config) { if (typeof Popper__namespace === 'undefined') { - throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)'); + throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org/docs/v2/)'); } super(element, config); @@ -3292,7 +3293,6 @@ if (!this._isEnabled) { return; } - this._activeTrigger.click = !this._activeTrigger.click; if (this._isShown()) { this._leave(); return; @@ -3480,7 +3480,7 @@ return offset; } _resolvePossibleFunction(arg) { - return execute(arg, [this._element]); + return execute(arg, [this._element, this._element]); } _getPopperConfig(attachment) { const defaultBsPopperConfig = { @@ -3518,7 +3518,7 @@ }; return { ...defaultBsPopperConfig, - ...execute(this._config.popperConfig, [defaultBsPopperConfig]) + ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig]) }; } _setListeners() { @@ -3527,6 +3527,7 @@ if (trigger === 'click') { EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK$1), this._config.selector, event => { const context = this._initializeOnDelegatedTarget(event); + context._activeTrigger[TRIGGER_CLICK] = !(context._isShown() && context._activeTrigger[TRIGGER_CLICK]); context.toggle(); }); } else if (trigger !== TRIGGER_MANUAL) { @@ -4392,7 +4393,6 @@ } // Private - _maybeScheduleHide() { if (!this._config.autohide) { return; diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.js.map b/extensions/pagetop-bootsier/static/js/bootstrap.js.map index 98a87052..062cdd5e 100644 --- a/extensions/pagetop-bootsier/static/js/bootstrap.js.map +++ b/extensions/pagetop-bootsier/static/js/bootstrap.js.map @@ -1 +1 @@ -{"version":3,"file":"bootstrap.js","sources":["../../js/src/dom/data.js","../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/manipulator.js","../../js/src/util/config.js","../../js/src/base-component.js","../../js/src/dom/selector-engine.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/util/swipe.js","../../js/src/carousel.js","../../js/src/collapse.js","../../js/src/dropdown.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/util/scrollbar.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/util/template-factory.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1_000_000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`)\n }\n\n return selector\n}\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`\n }\n\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = object => {\n if (!object || typeof object !== 'object') {\n return false\n }\n\n if (typeof object.jquery !== 'undefined') {\n object = object[0]\n }\n\n return typeof object.nodeType !== 'undefined'\n}\n\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (isElement(object)) {\n return object.jquery ? object[0] : object\n }\n\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object))\n }\n\n return null\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])')\n\n if (!closedDetails) {\n return elementIsVisible\n }\n\n if (closedDetails !== element) {\n const summary = element.closest('summary')\n if (summary && summary.parentNode !== closedDetails) {\n return false\n }\n\n if (summary === null) {\n return false\n }\n }\n\n return elementIsVisible\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight // eslint-disable-line no-unused-expressions\n}\n\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback()\n }\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]\n }\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n defineJQueryPlugin,\n execute,\n executeAfterTransition,\n findShadowRoot,\n getElement,\n getjQuery,\n getNextActiveElement,\n getTransitionDurationFromElement,\n getUID,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n onDOMContentLoaded,\n parseSelector,\n reflow,\n triggerTransitionEnd,\n toType\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index.js'\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\n\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getElementEvents(element) {\n const uid = makeEventUid(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, { delegateTarget: element })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue\n }\n\n hydrateObj(event, { delegateTarget: target })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n}\n\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events)\n .find(event => event.callable === callable && event.delegationSelector === delegationSelector)\n}\n\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string'\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : (handler || delegationFunction)\n let typeEvent = getTypeEvent(originalTypeEvent)\n\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent\n }\n\n return [isDelegated, callable, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n callable = wrapFunction(callable)\n }\n\n const events = getElementEvents(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)\n\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff\n\n return\n }\n\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = isDelegated ?\n bootstrapDelegationHandler(element, handler, callable) :\n bootstrapHandler(element, callable)\n\n fn.delegationSelector = isDelegated ? handler : null\n fn.callable = callable\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, isDelegated)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false)\n },\n\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getElementEvents(element)\n const storeElementEvent = events[typeEvent] || {}\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return\n }\n\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)\n return\n }\n\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n }\n }\n\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n\n let jQueryEvent = null\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value\n } catch {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value\n }\n })\n }\n }\n\n return obj\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true\n }\n\n if (value === 'false') {\n return false\n }\n\n if (value === Number(value).toString()) {\n return Number(value)\n }\n\n if (value === '' || value === 'null') {\n return null\n }\n\n if (typeof value !== 'string') {\n return value\n }\n\n try {\n return JSON.parse(decodeURIComponent(value))\n } catch {\n return value\n }\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))\n\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)\n attributes[pureKey] = normalizeData(element.dataset[key])\n }\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport { isElement, toType } from './index.js'\n\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {}\n }\n\n static get DefaultType() {\n return {}\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n return config\n }\n\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n }\n }\n\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property]\n const valueType = isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n }\n }\n}\n\nexport default Config\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data.js'\nimport EventHandler from './dom/event-handler.js'\nimport Config from './util/config.js'\nimport { executeAfterTransition, getElement } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.3'\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super()\n\n element = getElement(element)\n if (!element) {\n return\n }\n\n this._element = element\n this._config = this._getConfig(config)\n\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null\n }\n }\n\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible, parseSelector } from '../util/index.js'\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`\n }\n\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null\n }\n\n return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null\n}\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n let ancestor = element.parentNode.closest(selector)\n\n while (ancestor) {\n parents.push(ancestor)\n ancestor = ancestor.parentNode.closest(selector)\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n },\n\n getSelectorFromElement(element) {\n const selector = getSelector(element)\n\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null\n }\n\n return null\n },\n\n getElementFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.findOne(selector) : null\n },\n\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.find(selector) : []\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isDisabled } from './index.js'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport { execute } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'swipe'\nconst EVENT_KEY = '.bs.swipe'\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n}\n\nconst DefaultType = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n}\n\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super()\n this._element = element\n\n if (!element || !Swipe.isSupported()) {\n return\n }\n\n this._config = this._getConfig(config)\n this._deltaX = 0\n this._supportPointerEvents = Boolean(window.PointerEvent)\n this._initEvents()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY)\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX\n\n return\n }\n\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX\n }\n }\n\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX\n }\n\n this._handleSwipe()\n execute(this._config.endCallback)\n }\n\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this._deltaX\n }\n\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX)\n\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltaX / this._deltaX\n\n this._deltaX = 0\n\n if (!direction) {\n return\n }\n\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)\n }\n\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))\n }\n }\n\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n }\n}\n\nexport default Swipe\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getNextActiveElement,\n isRTL,\n isVisible,\n reflow,\n triggerTransitionEnd\n} from './util/index.js'\nimport Swipe from './util/swipe.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)', // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._interval = null\n this._activeElement = null\n this._isSliding = false\n this.touchTimeout = null\n this._swipeHelper = null\n\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._addEventListeners()\n\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element)\n }\n\n this._clearInterval()\n }\n\n cycle() {\n this._clearInterval()\n this._updateInterval()\n\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval)\n }\n\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle())\n return\n }\n\n this.cycle()\n }\n\n to(index) {\n const items = this._getItems()\n if (index > items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n const activeIndex = this._getItemIndex(this._getActive())\n if (activeIndex === index) {\n return\n }\n\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV\n\n this._slide(order, items[index])\n }\n\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose()\n }\n\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval\n return config\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause())\n EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle())\n }\n\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault())\n }\n\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n }\n\n this._swipeHelper = new Swipe(this._element, swipeConfig)\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(this._directionToOrder(direction))\n }\n }\n\n _getItemIndex(element) {\n return this._getItems().indexOf(element)\n }\n\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return\n }\n\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement)\n\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE)\n newActiveIndicator.setAttribute('aria-current', 'true')\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || this._getActive()\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n this._config.interval = elementInterval || this._config.defaultInterval\n }\n\n _slide(order, element = null) {\n if (this._isSliding) {\n return\n }\n\n const activeElement = this._getActive()\n const isNext = order === ORDER_NEXT\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap)\n\n if (nextElement === activeElement) {\n return\n }\n\n const nextElementIndex = this._getItemIndex(nextElement)\n\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n })\n }\n\n const slideEvent = triggerEvent(EVENT_SLIDE)\n\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return\n }\n\n const isCycling = Boolean(this._interval)\n this.pause()\n\n this._isSliding = true\n\n this._setActiveIndicatorElement(nextElementIndex)\n this._activeElement = nextElement\n\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n triggerEvent(EVENT_SLID)\n }\n\n this._queueCallback(completeCallBack, activeElement, this._isAnimated())\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE)\n }\n\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n }\n\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element)\n }\n\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n }\n\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config)\n\n if (typeof config === 'number') {\n data.to(config)\n return\n }\n\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n event.preventDefault()\n\n const carousel = Carousel.getOrCreateInstance(target)\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n carousel.to(slideIndex)\n carousel._maybeEnableCycle()\n return\n }\n\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next()\n carousel._maybeEnableCycle()\n return\n }\n\n carousel.prev()\n carousel._maybeEnableCycle()\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getElement,\n reflow\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\nconst Default = {\n parent: null,\n toggle: true\n}\n\nconst DefaultType = {\n parent: '(null|element)',\n toggle: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isTransitioning = false\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElement => foundElement === this._element)\n\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let activeChildren = []\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)\n .filter(element => element !== this._element)\n .map(element => Collapse.getOrCreateInstance(element, { toggle: false }))\n }\n\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n for (const activeInstance of activeChildren) {\n activeInstance.hide()\n }\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger)\n\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)\n\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n }\n }\n\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element))\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen)\n element.setAttribute('aria-expanded', isOpen)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n execute,\n getElement,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center'\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)'\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR = '.navbar'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\nconst PLACEMENT_TOPCENTER = 'top'\nconst PLACEMENT_BOTTOMCENTER = 'bottom'\n\nconst Default = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n}\n\nconst DefaultType = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n}\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._popper = null\n this._parent = this._element.parentNode // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.findOne(SELECTOR_MENU, this._parent)\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._createPopper()\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = super._getConfig(config)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = this._parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n }\n\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getPlacement() {\n const parentDropdown = this._parent\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {\n return\n }\n\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)\n\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle)\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n const relatedTarget = { relatedTarget: context._element }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName)\n const isEscapeEvent = event.key === ESCAPE_KEY\n const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)\n\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return\n }\n\n if (isInput && !isEscapeEvent) {\n return\n }\n\n event.preventDefault()\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?\n this :\n (SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode))\n\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (isUpOrDownEvent) {\n event.stopPropagation()\n instance.show()\n instance._selectMenuItem(event)\n return\n }\n\n if (instance._isShown()) { // else is escape and we check if it is shown\n event.stopPropagation()\n instance.hide()\n getToggleButton.focus()\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport {\n execute, executeAfterTransition, getElement, reflow\n} from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nconst Default = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n}\n\nconst DefaultType = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n}\n\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n const element = this._getElement()\n if (this._config.isAnimated) {\n reflow(element)\n }\n\n element.classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n const element = this._getElement()\n this._config.rootElement.append(element)\n\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nconst Default = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n}\n\nconst DefaultType = {\n autofocus: 'boolean',\n trapElement: 'element'\n}\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return\n }\n\n if (this._config.autofocus) {\n this._config.trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n _handleFocusin(event) {\n const { trapElement } = this._config\n\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\nconst PROPERTY_PADDING = 'padding-right'\nconst PROPERTY_MARGIN = 'margin-right'\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProperty)\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty)\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty)\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty)\n return\n }\n\n Manipulator.removeDataAttribute(element, styleProperty)\n element.style.setProperty(styleProperty, value)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n return\n }\n\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel)\n }\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin, isRTL, isVisible, reflow\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\nconst Default = {\n backdrop: true,\n focus: true,\n keyboard: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._isTransitioning = true\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._backdrop.show(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n this._isTransitioning = true\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated())\n }\n\n dispose() {\n EventHandler.off(window, EVENT_KEY)\n EventHandler.off(this._dialog, EVENT_KEY)\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated())\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n this._triggerBackdropTransition()\n })\n\n EventHandler.on(window, EVENT_RESIZE, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog()\n }\n })\n\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return\n }\n\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n return\n }\n\n if (this._config.backdrop) {\n this.hide()\n }\n })\n })\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const initialOverflowY = this._element.style.overflowY\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden'\n }\n\n this._element.classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY\n }, this._dialog)\n }, this._dialog)\n\n this._element.focus()\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin,\n isDisabled,\n isVisible\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\nconst CLASS_NAME_HIDING = 'hiding'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate()\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.add(CLASS_NAME_HIDING)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n return\n }\n\n this.hide()\n }\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop)\n\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n })\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show()\n }\n})\n\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide()\n }\n }\n})\n\nenableDismissTrigger(Offcanvas)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n dd: [],\n div: [],\n dl: [],\n dt: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n// js-docs-end allow-list\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\n// eslint-disable-next-line unicorn/better-regex\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n .some(regex => regex.test(attributeName))\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n }\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\nimport { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'\nimport { execute, getElement, isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'TemplateFactory'\n\nconst Default = {\n allowList: DefaultAllowlist,\n content: {}, // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '<div></div>'\n}\n\nconst DefaultType = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n}\n\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n}\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content)\n .map(config => this._resolvePossibleFunction(config))\n .filter(Boolean)\n }\n\n hasContent() {\n return this.getContent().length > 0\n }\n\n changeContent(content) {\n this._checkContent(content)\n this._config.content = { ...this._config.content, ...content }\n return this\n }\n\n toHtml() {\n const templateWrapper = document.createElement('div')\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template)\n\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector)\n }\n\n const template = templateWrapper.children[0]\n const extraClass = this._resolvePossibleFunction(this._config.extraClass)\n\n if (extraClass) {\n template.classList.add(...extraClass.split(' '))\n }\n\n return template\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config)\n this._checkContent(config.content)\n }\n\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({ selector, entry: content }, DefaultContentType)\n }\n }\n\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!templateElement) {\n return\n }\n\n content = this._resolvePossibleFunction(content)\n\n if (!content) {\n templateElement.remove()\n return\n }\n\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement)\n return\n }\n\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content)\n return\n }\n\n templateElement.textContent = content\n }\n\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this])\n }\n\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = ''\n templateElement.append(element)\n return\n }\n\n templateElement.textContent = element.textContent\n }\n}\n\nexport default TemplateFactory\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport {\n defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop\n} from './util/index.js'\nimport { DefaultAllowlist } from './util/sanitizer.js'\nimport TemplateFactory from './util/template-factory.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\nconst EVENT_HIDE = 'hide'\nconst EVENT_HIDDEN = 'hidden'\nconst EVENT_SHOW = 'show'\nconst EVENT_SHOWN = 'shown'\nconst EVENT_INSERTED = 'inserted'\nconst EVENT_CLICK = 'click'\nconst EVENT_FOCUSIN = 'focusin'\nconst EVENT_FOCUSOUT = 'focusout'\nconst EVENT_MOUSEENTER = 'mouseenter'\nconst EVENT_MOUSELEAVE = 'mouseleave'\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '<div class=\"tooltip\" role=\"tooltip\">' +\n '<div class=\"tooltip-arrow\"></div>' +\n '<div class=\"tooltip-inner\"></div>' +\n '</div>',\n title: '',\n trigger: 'hover focus'\n}\n\nconst DefaultType = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n}\n\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org)')\n }\n\n super(element, config)\n\n // Private\n this._isEnabled = true\n this._timeout = 0\n this._isHovered = null\n this._activeTrigger = {}\n this._popper = null\n this._templateFactory = null\n this._newContent = null\n\n // Protected\n this.tip = null\n\n this._setListeners()\n\n if (!this._config.selector) {\n this._fixTitle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle() {\n if (!this._isEnabled) {\n return\n }\n\n this._activeTrigger.click = !this._activeTrigger.click\n if (this._isShown()) {\n this._leave()\n return\n }\n\n this._enter()\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'))\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this._isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW))\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper()\n\n const tip = this._getTipElement()\n\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'))\n\n const { container } = this._config\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))\n }\n\n this._popper = this._createPopper(tip)\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN))\n\n if (this._isHovered === false) {\n this._leave()\n }\n\n this._isHovered = false\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n hide() {\n if (!this._isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE))\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const tip = this._getTipElement()\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n this._isHovered = null // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (!this._isHovered) {\n this._disposePopper()\n }\n\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN))\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n update() {\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle())\n }\n\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())\n }\n\n return this.tip\n }\n\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml()\n\n // TODO: remove this check in v6\n if (!tip) {\n return null\n }\n\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`)\n\n const tipId = getUID(this.constructor.NAME).toString()\n\n tip.setAttribute('id', tipId)\n\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n return tip\n }\n\n setContent(content) {\n this._newContent = content\n if (this._isShown()) {\n this._disposePopper()\n this.show()\n }\n }\n\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content)\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n })\n }\n\n return this._templateFactory\n }\n\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n }\n }\n\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title')\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _isAnimated() {\n return this._config.animation || (this.tip && this.tip.classList.contains(CLASS_NAME_FADE))\n }\n\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW)\n }\n\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element])\n const attachment = AttachmentMap[placement.toUpperCase()]\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element])\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement)\n }\n }\n ]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n }\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context.toggle()\n })\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSEENTER) :\n this.constructor.eventName(EVENT_FOCUSIN)\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSELEAVE) :\n this.constructor.eventName(EVENT_FOCUSOUT)\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true\n context._enter()\n })\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] =\n context._element.contains(event.relatedTarget)\n\n context._leave()\n })\n }\n }\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n\n if (!title) {\n return\n }\n\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('data-bs-original-title', title) // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title')\n }\n\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true\n return\n }\n\n this._isHovered = true\n\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show()\n }\n }, this._config.delay.show)\n }\n\n _leave() {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n this._isHovered = false\n\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide()\n }\n }, this._config.delay.hide)\n }\n\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout)\n this._timeout = setTimeout(handler, timeout)\n }\n\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true)\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute]\n }\n }\n\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value\n }\n }\n\n config.selector = false\n config.trigger = 'manual'\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n\n if (this.tip) {\n this.tip.remove()\n this.tip = null\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Tooltip from './tooltip.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'popover'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Default = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>',\n trigger: 'click'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n}\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent()\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n }\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin, getElement, isDisabled, isVisible\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_CLICK = `click${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_TARGET_LINKS = '[href]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst Default = {\n offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n}\n\nconst DefaultType = {\n offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n}\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map()\n this._observableSections = new Map()\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element\n this._activeTarget = null\n this._observer = null\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n }\n this.refresh() // initialize\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables()\n this._maybeEnableSmoothScroll()\n\n if (this._observer) {\n this._observer.disconnect()\n } else {\n this._observer = this._getNewObserver()\n }\n\n for (const section of this._observableSections.values()) {\n this._observer.observe(section)\n }\n }\n\n dispose() {\n this._observer.disconnect()\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin\n\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))\n }\n\n return config\n }\n\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK)\n\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash)\n if (observableSection) {\n event.preventDefault()\n const root = this._rootElement || window\n const height = observableSection.offsetTop - this._element.offsetTop\n if (root.scrollTo) {\n root.scrollTo({ top: height, behavior: 'smooth' })\n return\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height\n }\n })\n }\n\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n }\n\n return new IntersectionObserver(entries => this._observerCallback(entries), options)\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop\n this._process(targetElement(entry))\n }\n\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop\n this._previousScrollData.parentScrollTop = parentScrollTop\n\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null\n this._clearActiveClass(targetElement(entry))\n\n continue\n }\n\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry)\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return\n }\n\n continue\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry)\n }\n }\n }\n\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map()\n this._observableSections = new Map()\n\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)\n\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue\n }\n\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor)\n this._observableSections.set(anchor.hash, observableSection)\n }\n }\n }\n\n _process(target) {\n if (this._activeTarget === target) {\n return\n }\n\n this._clearActiveClass(this._config.target)\n this._activeTarget = target\n target.classList.add(CLASS_NAME_ACTIVE)\n this._activateParents(target)\n\n EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })\n }\n\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n return\n }\n\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {\n item.classList.add(CLASS_NAME_ACTIVE)\n }\n }\n }\n\n _clearActiveClass(parent) {\n parent.classList.remove(CLASS_NAME_ACTIVE)\n\n const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent)\n for (const node of activeNodes) {\n node.classList.remove(CLASS_NAME_ACTIVE)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = ScrollSpy.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {\n ScrollSpy.getOrCreateInstance(spy)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(ScrollSpy)\n\nexport default ScrollSpy\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tab.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tab'\nconst DATA_KEY = 'bs.tab'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}`\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst HOME_KEY = 'Home'\nconst END_KEY = 'End'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_DROPDOWN = 'dropdown'\n\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\nconst SELECTOR_DROPDOWN_MENU = '.dropdown-menu'\nconst NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`\n\nconst SELECTOR_TAB_PANEL = '.list-group, .nav, [role=\"tablist\"]'\nconst SELECTOR_OUTER = '.nav-item, .list-group-item'\nconst SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role=\"tab\"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]' // TODO: could only be `tab` in v6\nconst SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`\n\nconst SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle=\"tab\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"pill\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"list\"]`\n\n/**\n * Class definition\n */\n\nclass Tab extends BaseComponent {\n constructor(element) {\n super(element)\n this._parent = this._element.closest(SELECTOR_TAB_PANEL)\n\n if (!this._parent) {\n return\n // TODO: should throw exception in v6\n // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)\n }\n\n // Set up initial aria attributes\n this._setInitialAttributes(this._parent, this._getChildren())\n\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n show() { // Shows this elem and deactivate the active sibling if exists\n const innerElem = this._element\n if (this._elemIsActive(innerElem)) {\n return\n }\n\n // Search for active tab on same parent to deactivate it\n const active = this._getActiveElem()\n\n const hideEvent = active ?\n EventHandler.trigger(active, EVENT_HIDE, { relatedTarget: innerElem }) :\n null\n\n const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, { relatedTarget: active })\n\n if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {\n return\n }\n\n this._deactivate(active, innerElem)\n this._activate(innerElem, active)\n }\n\n // Private\n _activate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.add(CLASS_NAME_ACTIVE)\n\n this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.add(CLASS_NAME_SHOW)\n return\n }\n\n element.removeAttribute('tabindex')\n element.setAttribute('aria-selected', true)\n this._toggleDropDown(element, true)\n EventHandler.trigger(element, EVENT_SHOWN, {\n relatedTarget: relatedElem\n })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _deactivate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.remove(CLASS_NAME_ACTIVE)\n element.blur()\n\n this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.remove(CLASS_NAME_SHOW)\n return\n }\n\n element.setAttribute('aria-selected', false)\n element.setAttribute('tabindex', '-1')\n this._toggleDropDown(element, false)\n EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _keydown(event) {\n if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key))) {\n return\n }\n\n event.stopPropagation()// stopPropagation/preventDefault both added to support up/down keys without scrolling the page\n event.preventDefault()\n\n const children = this._getChildren().filter(element => !isDisabled(element))\n let nextActiveElement\n\n if ([HOME_KEY, END_KEY].includes(event.key)) {\n nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]\n } else {\n const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)\n nextActiveElement = getNextActiveElement(children, event.target, isNext, true)\n }\n\n if (nextActiveElement) {\n nextActiveElement.focus({ preventScroll: true })\n Tab.getOrCreateInstance(nextActiveElement).show()\n }\n }\n\n _getChildren() { // collection of inner elements\n return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent)\n }\n\n _getActiveElem() {\n return this._getChildren().find(child => this._elemIsActive(child)) || null\n }\n\n _setInitialAttributes(parent, children) {\n this._setAttributeIfNotExists(parent, 'role', 'tablist')\n\n for (const child of children) {\n this._setInitialAttributesOnChild(child)\n }\n }\n\n _setInitialAttributesOnChild(child) {\n child = this._getInnerElement(child)\n const isActive = this._elemIsActive(child)\n const outerElem = this._getOuterElement(child)\n child.setAttribute('aria-selected', isActive)\n\n if (outerElem !== child) {\n this._setAttributeIfNotExists(outerElem, 'role', 'presentation')\n }\n\n if (!isActive) {\n child.setAttribute('tabindex', '-1')\n }\n\n this._setAttributeIfNotExists(child, 'role', 'tab')\n\n // set attributes to the related panel too\n this._setInitialAttributesOnTargetPanel(child)\n }\n\n _setInitialAttributesOnTargetPanel(child) {\n const target = SelectorEngine.getElementFromSelector(child)\n\n if (!target) {\n return\n }\n\n this._setAttributeIfNotExists(target, 'role', 'tabpanel')\n\n if (child.id) {\n this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)\n }\n }\n\n _toggleDropDown(element, open) {\n const outerElem = this._getOuterElement(element)\n if (!outerElem.classList.contains(CLASS_DROPDOWN)) {\n return\n }\n\n const toggle = (selector, className) => {\n const element = SelectorEngine.findOne(selector, outerElem)\n if (element) {\n element.classList.toggle(className, open)\n }\n }\n\n toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)\n toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)\n outerElem.setAttribute('aria-expanded', open)\n }\n\n _setAttributeIfNotExists(element, attribute, value) {\n if (!element.hasAttribute(attribute)) {\n element.setAttribute(attribute, value)\n }\n }\n\n _elemIsActive(elem) {\n return elem.classList.contains(CLASS_NAME_ACTIVE)\n }\n\n // Try to get the inner element (usually the .nav-link)\n _getInnerElement(elem) {\n return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem)\n }\n\n // Try to get the outer element (usually the .nav-item)\n _getOuterElement(elem) {\n return elem.closest(SELECTOR_OUTER) || elem\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tab.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n Tab.getOrCreateInstance(this).show()\n})\n\n/**\n * Initialize on focus\n */\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {\n Tab.getOrCreateInstance(element)\n }\n})\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tab)\n\nexport default Tab\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap toast.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin, reflow } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'toast'\nconst DATA_KEY = 'bs.toast'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\n\nconst DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n}\n\nconst Default = {\n animation: true,\n autohide: true,\n delay: 5000\n}\n\n/**\n * Class definition\n */\n\nclass Toast extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._timeout = null\n this._hasMouseInteraction = false\n this._hasKeyboardInteraction = false\n this._setListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show() {\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._clearTimeout()\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE)\n }\n\n const complete = () => {\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN)\n\n this._maybeScheduleHide()\n }\n\n this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\n reflow(this._element)\n this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)\n\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n hide() {\n if (!this.isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const complete = () => {\n this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\n this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.classList.add(CLASS_NAME_SHOWING)\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n dispose() {\n this._clearTimeout()\n\n if (this.isShown()) {\n this._element.classList.remove(CLASS_NAME_SHOW)\n }\n\n super.dispose()\n }\n\n isShown() {\n return this._element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n\n _maybeScheduleHide() {\n if (!this._config.autohide) {\n return\n }\n\n if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\n return\n }\n\n this._timeout = setTimeout(() => {\n this.hide()\n }, this._config.delay)\n }\n\n _onInteraction(event, isInteracting) {\n switch (event.type) {\n case 'mouseover':\n case 'mouseout': {\n this._hasMouseInteraction = isInteracting\n break\n }\n\n case 'focusin':\n case 'focusout': {\n this._hasKeyboardInteraction = isInteracting\n break\n }\n\n default: {\n break\n }\n }\n\n if (isInteracting) {\n this._clearTimeout()\n return\n }\n\n const nextElement = event.relatedTarget\n if (this._element === nextElement || this._element.contains(nextElement)) {\n return\n }\n\n this._maybeScheduleHide()\n }\n\n _setListeners() {\n EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\n EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\n }\n\n _clearTimeout() {\n clearTimeout(this._timeout)\n this._timeout = null\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Toast.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Toast)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Toast)\n\nexport default Toast\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap index.umd.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './src/alert.js'\nimport Button from './src/button.js'\nimport Carousel from './src/carousel.js'\nimport Collapse from './src/collapse.js'\nimport Dropdown from './src/dropdown.js'\nimport Modal from './src/modal.js'\nimport Offcanvas from './src/offcanvas.js'\nimport Popover from './src/popover.js'\nimport ScrollSpy from './src/scrollspy.js'\nimport Tab from './src/tab.js'\nimport Toast from './src/toast.js'\nimport Tooltip from './src/tooltip.js'\n\nexport default {\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Offcanvas,\n Popover,\n ScrollSpy,\n Tab,\n Toast,\n Tooltip\n}\n"],"names":["elementMap","Map","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete","MAX_UID","MILLISECONDS_MULTIPLIER","TRANSITION_END","parseSelector","selector","window","CSS","escape","replace","match","id","toType","object","undefined","Object","prototype","toString","call","toLowerCase","getUID","prefix","Math","floor","random","document","getElementById","getTransitionDurationFromElement","transitionDuration","transitionDelay","getComputedStyle","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","split","triggerTransitionEnd","dispatchEvent","Event","isElement","jquery","nodeType","getElement","length","querySelector","isVisible","getClientRects","elementIsVisible","getPropertyValue","closedDetails","closest","summary","parentNode","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","getAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","noop","reflow","offsetHeight","getjQuery","jQuery","body","DOMContentLoadedCallbacks","onDOMContentLoaded","callback","readyState","addEventListener","push","isRTL","dir","defineJQueryPlugin","plugin","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","execute","possibleCallback","args","defaultValue","executeAfterTransition","transitionElement","waitForTransition","durationPadding","emulatedDuration","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","listLength","index","indexOf","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","nativeEvents","Set","makeEventUid","uid","getElementEvents","bootstrapHandler","event","hydrateObj","delegateTarget","oneOff","EventHandler","off","type","apply","bootstrapDelegationHandler","domElements","querySelectorAll","domElement","findHandler","events","callable","delegationSelector","values","find","normalizeParameters","originalTypeEvent","delegationFunction","isDelegated","typeEvent","getTypeEvent","addHandler","wrapFunction","relatedTarget","handlers","previousFunction","removeHandler","Boolean","removeNamespacedHandlers","namespace","storeElementEvent","handlerKey","entries","includes","on","one","inNamespace","isNamespace","startsWith","elementEvent","slice","keyHandlers","trigger","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","evt","cancelable","preventDefault","obj","meta","value","_unused","defineProperty","configurable","normalizeData","JSON","parse","decodeURIComponent","normalizeDataKey","chr","Manipulator","setDataAttribute","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","dataset","filter","pureKey","charAt","getDataAttribute","Config","Default","DefaultType","Error","_getConfig","config","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","jsonConfig","constructor","configTypes","property","expectedTypes","valueType","RegExp","test","TypeError","toUpperCase","VERSION","BaseComponent","_element","_config","Data","DATA_KEY","dispose","EVENT_KEY","propertyName","getOwnPropertyNames","_queueCallback","isAnimated","getInstance","getOrCreateInstance","eventName","getSelector","hrefAttribute","trim","map","sel","join","SelectorEngine","concat","Element","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","el","getSelectorFromElement","getElementFromSelector","getMultipleElementsFromSelector","enableDismissTrigger","component","method","clickEvent","tagName","EVENT_CLOSE","EVENT_CLOSED","CLASS_NAME_FADE","CLASS_NAME_SHOW","Alert","close","closeEvent","_destroyElement","each","data","DATA_API_KEY","CLASS_NAME_ACTIVE","SELECTOR_DATA_TOGGLE","EVENT_CLICK_DATA_API","Button","toggle","button","EVENT_TOUCHSTART","EVENT_TOUCHMOVE","EVENT_TOUCHEND","EVENT_POINTERDOWN","EVENT_POINTERUP","POINTER_TYPE_TOUCH","POINTER_TYPE_PEN","CLASS_NAME_POINTER_EVENT","SWIPE_THRESHOLD","endCallback","leftCallback","rightCallback","Swipe","isSupported","_deltaX","_supportPointerEvents","PointerEvent","_initEvents","_start","touches","clientX","_eventIsPointerPenTouch","_end","_handleSwipe","_move","absDeltaX","abs","direction","add","pointerType","navigator","maxTouchPoints","ARROW_LEFT_KEY","ARROW_RIGHT_KEY","TOUCHEVENT_COMPAT_WAIT","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","EVENT_SLIDE","EVENT_SLID","EVENT_KEYDOWN","EVENT_MOUSEENTER","EVENT_MOUSELEAVE","EVENT_DRAG_START","EVENT_LOAD_DATA_API","CLASS_NAME_CAROUSEL","CLASS_NAME_SLIDE","CLASS_NAME_END","CLASS_NAME_START","CLASS_NAME_NEXT","CLASS_NAME_PREV","SELECTOR_ACTIVE","SELECTOR_ITEM","SELECTOR_ACTIVE_ITEM","SELECTOR_ITEM_IMG","SELECTOR_INDICATORS","SELECTOR_DATA_SLIDE","SELECTOR_DATA_RIDE","KEY_TO_DIRECTION","interval","keyboard","pause","ride","touch","wrap","Carousel","_interval","_activeElement","_isSliding","touchTimeout","_swipeHelper","_indicatorsElement","_addEventListeners","cycle","_slide","nextWhenVisible","hidden","_clearInterval","_updateInterval","setInterval","_maybeEnableCycle","to","items","_getItems","activeIndex","_getItemIndex","_getActive","order","defaultInterval","_keydown","_addTouchEventListeners","img","endCallBack","clearTimeout","swipeConfig","_directionToOrder","_setActiveIndicatorElement","activeIndicator","newActiveIndicator","elementInterval","parseInt","isNext","nextElement","nextElementIndex","triggerEvent","_orderToDirection","slideEvent","isCycling","directionalClassName","orderClassName","completeCallBack","_isAnimated","clearInterval","carousel","slideIndex","carousels","EVENT_SHOW","EVENT_SHOWN","EVENT_HIDE","EVENT_HIDDEN","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_COLLAPSED","CLASS_NAME_DEEPER_CHILDREN","CLASS_NAME_HORIZONTAL","WIDTH","HEIGHT","SELECTOR_ACTIVES","parent","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElement","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activeChildren","_getFirstLevelChildren","startEvent","activeInstance","dimension","_getDimension","style","complete","capitalizedDimension","scrollSize","getBoundingClientRect","selected","triggerArray","isOpen","ESCAPE_KEY","TAB_KEY","ARROW_UP_KEY","ARROW_DOWN_KEY","RIGHT_MOUSE_BUTTON","EVENT_KEYDOWN_DATA_API","EVENT_KEYUP_DATA_API","CLASS_NAME_DROPUP","CLASS_NAME_DROPEND","CLASS_NAME_DROPSTART","CLASS_NAME_DROPUP_CENTER","CLASS_NAME_DROPDOWN_CENTER","SELECTOR_DATA_TOGGLE_SHOWN","SELECTOR_MENU","SELECTOR_NAVBAR","SELECTOR_NAVBAR_NAV","SELECTOR_VISIBLE_ITEMS","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","PLACEMENT_TOPCENTER","PLACEMENT_BOTTOMCENTER","autoClose","boundary","display","offset","popperConfig","reference","Dropdown","_popper","_parent","_menu","_inNavbar","_detectNavbar","showEvent","_createPopper","focus","_completeHide","destroy","update","hideEvent","Popper","referenceElement","_getPopperConfig","createPopper","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","placement","modifiers","options","enabled","_selectMenuItem","clearMenus","openToggles","context","composedPath","isMenuTarget","dataApiKeydownHandler","isInput","isEscapeEvent","isUpOrDownEvent","getToggleButton","stopPropagation","EVENT_MOUSEDOWN","className","clickCallback","rootElement","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","EVENT_FOCUSIN","EVENT_KEYDOWN_TAB","TAB_NAV_FORWARD","TAB_NAV_BACKWARD","autofocus","trapElement","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","elements","shiftKey","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","PROPERTY_PADDING","PROPERTY_MARGIN","ScrollBarHelper","getWidth","documentWidth","clientWidth","innerWidth","width","_disableOverFlow","_setElementAttributes","calculatedValue","reset","_resetElementAttributes","isOverflowing","_saveInitialAttribute","overflow","styleProperty","scrollbarWidth","manipulationCallBack","setProperty","_applyManipulationCallback","actualValue","removeProperty","callBack","EVENT_HIDE_PREVENTED","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_MOUSEDOWN_DISMISS","EVENT_KEYDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","OPEN_SELECTOR","SELECTOR_DIALOG","SELECTOR_MODAL_BODY","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_scrollBar","_adjustDialog","_showElement","_hideModal","handleUpdate","scrollTop","modalBody","transitionComplete","_triggerBackdropTransition","event2","_resetAdjustments","isModalOverflowing","scrollHeight","clientHeight","initialOverflowY","overflowY","isBodyOverflowing","paddingLeft","paddingRight","alreadyOpen","CLASS_NAME_SHOWING","CLASS_NAME_HIDING","CLASS_NAME_BACKDROP","scroll","Offcanvas","blur","completeCallback","position","ARIA_ATTRIBUTE_PATTERN","DefaultAllowlist","a","area","b","br","col","code","dd","div","dl","dt","em","hr","h1","h2","h3","h4","h5","h6","i","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","uriAttributes","SAFE_URL_PATTERN","allowedAttribute","attribute","allowedAttributeList","attributeName","nodeName","nodeValue","attributeRegex","some","regex","sanitizeHtml","unsafeHtml","allowList","sanitizeFunction","domParser","DOMParser","createdDocument","parseFromString","elementName","attributeList","allowedAttributes","innerHTML","content","extraClass","html","sanitize","sanitizeFn","template","DefaultContentType","entry","TemplateFactory","getContent","_resolvePossibleFunction","hasContent","changeContent","_checkContent","toHtml","templateWrapper","_maybeSanitize","text","_setContent","arg","templateElement","_putElementInTemplate","textContent","DISALLOWED_ATTRIBUTES","CLASS_NAME_MODAL","SELECTOR_TOOLTIP_INNER","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","TRIGGER_CLICK","TRIGGER_MANUAL","EVENT_INSERTED","EVENT_CLICK","EVENT_FOCUSOUT","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","animation","container","customClass","delay","fallbackPlacements","title","Tooltip","_isEnabled","_timeout","_isHovered","_activeTrigger","_templateFactory","_newContent","tip","_setListeners","_fixTitle","enable","disable","toggleEnabled","click","_leave","_enter","_hideModalHandler","_disposePopper","_isWithContent","shadowRoot","isInTheDom","ownerDocument","_getTipElement","_isWithActiveTrigger","_getTitle","_createTipElement","_getContentForTemplate","_getTemplateFactory","tipId","setContent","_initializeOnDelegatedTarget","_getDelegateConfig","attachment","phase","state","triggers","eventIn","eventOut","_setTimeout","timeout","dataAttributes","dataAttribute","SELECTOR_TITLE","SELECTOR_CONTENT","Popover","_getContent","EVENT_ACTIVATE","CLASS_NAME_DROPDOWN_ITEM","SELECTOR_DATA_SPY","SELECTOR_TARGET_LINKS","SELECTOR_NAV_LIST_GROUP","SELECTOR_NAV_LINKS","SELECTOR_NAV_ITEMS","SELECTOR_LIST_ITEMS","SELECTOR_LINK_ITEMS","SELECTOR_DROPDOWN","SELECTOR_DROPDOWN_TOGGLE","rootMargin","smoothScroll","threshold","ScrollSpy","_targetLinks","_observableSections","_rootElement","_activeTarget","_observer","_previousScrollData","visibleEntryTop","parentScrollTop","refresh","_initializeTargetsAndObservables","_maybeEnableSmoothScroll","disconnect","_getNewObserver","section","observe","observableSection","hash","height","offsetTop","scrollTo","top","behavior","IntersectionObserver","_observerCallback","targetElement","_process","userScrollsDown","isIntersecting","_clearActiveClass","entryIsLowerThanPrevious","targetLinks","anchor","decodeURI","_activateParents","listGroup","item","activeNodes","node","spy","HOME_KEY","END_KEY","CLASS_DROPDOWN","SELECTOR_DROPDOWN_MENU","NOT_SELECTOR_DROPDOWN_TOGGLE","SELECTOR_TAB_PANEL","SELECTOR_OUTER","SELECTOR_INNER","SELECTOR_INNER_ELEM","SELECTOR_DATA_TOGGLE_ACTIVE","Tab","_setInitialAttributes","_getChildren","innerElem","_elemIsActive","active","_getActiveElem","_deactivate","_activate","relatedElem","_toggleDropDown","nextActiveElement","preventScroll","_setAttributeIfNotExists","_setInitialAttributesOnChild","_getInnerElement","isActive","outerElem","_getOuterElement","_setInitialAttributesOnTargetPanel","open","EVENT_MOUSEOVER","EVENT_MOUSEOUT","CLASS_NAME_HIDE","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","isShown","_onInteraction","isInteracting"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"bootstrap.js","sources":["../../js/src/dom/data.js","../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/manipulator.js","../../js/src/util/config.js","../../js/src/base-component.js","../../js/src/dom/selector-engine.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/util/swipe.js","../../js/src/carousel.js","../../js/src/collapse.js","../../js/src/dropdown.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/util/scrollbar.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/util/template-factory.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1_000_000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`)\n }\n\n return selector\n}\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`\n }\n\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = object => {\n if (!object || typeof object !== 'object') {\n return false\n }\n\n if (typeof object.jquery !== 'undefined') {\n object = object[0]\n }\n\n return typeof object.nodeType !== 'undefined'\n}\n\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (isElement(object)) {\n return object.jquery ? object[0] : object\n }\n\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object))\n }\n\n return null\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])')\n\n if (!closedDetails) {\n return elementIsVisible\n }\n\n if (closedDetails !== element) {\n const summary = element.closest('summary')\n if (summary && summary.parentNode !== closedDetails) {\n return false\n }\n\n if (summary === null) {\n return false\n }\n }\n\n return elementIsVisible\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.harrytheo.com/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight // eslint-disable-line no-unused-expressions\n}\n\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback()\n }\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback.call(...args) : defaultValue\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]\n }\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n defineJQueryPlugin,\n execute,\n executeAfterTransition,\n findShadowRoot,\n getElement,\n getjQuery,\n getNextActiveElement,\n getTransitionDurationFromElement,\n getUID,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n onDOMContentLoaded,\n parseSelector,\n reflow,\n triggerTransitionEnd,\n toType\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index.js'\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\n\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getElementEvents(element) {\n const uid = makeEventUid(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, { delegateTarget: element })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue\n }\n\n hydrateObj(event, { delegateTarget: target })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n}\n\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events)\n .find(event => event.callable === callable && event.delegationSelector === delegationSelector)\n}\n\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string'\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : (handler || delegationFunction)\n let typeEvent = getTypeEvent(originalTypeEvent)\n\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent\n }\n\n return [isDelegated, callable, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n callable = wrapFunction(callable)\n }\n\n const events = getElementEvents(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)\n\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff\n\n return\n }\n\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = isDelegated ?\n bootstrapDelegationHandler(element, handler, callable) :\n bootstrapHandler(element, callable)\n\n fn.delegationSelector = isDelegated ? handler : null\n fn.callable = callable\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, isDelegated)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false)\n },\n\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getElementEvents(element)\n const storeElementEvent = events[typeEvent] || {}\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return\n }\n\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)\n return\n }\n\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n }\n }\n\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n\n let jQueryEvent = null\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value\n } catch {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value\n }\n })\n }\n }\n\n return obj\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true\n }\n\n if (value === 'false') {\n return false\n }\n\n if (value === Number(value).toString()) {\n return Number(value)\n }\n\n if (value === '' || value === 'null') {\n return null\n }\n\n if (typeof value !== 'string') {\n return value\n }\n\n try {\n return JSON.parse(decodeURIComponent(value))\n } catch {\n return value\n }\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))\n\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1)\n attributes[pureKey] = normalizeData(element.dataset[key])\n }\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport { isElement, toType } from './index.js'\n\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {}\n }\n\n static get DefaultType() {\n return {}\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n return config\n }\n\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n }\n }\n\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property]\n const valueType = isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n }\n }\n}\n\nexport default Config\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data.js'\nimport EventHandler from './dom/event-handler.js'\nimport Config from './util/config.js'\nimport { executeAfterTransition, getElement } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.8'\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super()\n\n element = getElement(element)\n if (!element) {\n return\n }\n\n this._element = element\n this._config = this._getConfig(config)\n\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null\n }\n }\n\n // Private\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible, parseSelector } from '../util/index.js'\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`\n }\n\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null\n }\n\n return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null\n}\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n let ancestor = element.parentNode.closest(selector)\n\n while (ancestor) {\n parents.push(ancestor)\n ancestor = ancestor.parentNode.closest(selector)\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n },\n\n getSelectorFromElement(element) {\n const selector = getSelector(element)\n\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null\n }\n\n return null\n },\n\n getElementFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.findOne(selector) : null\n },\n\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.find(selector) : []\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isDisabled } from './index.js'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport { execute } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'swipe'\nconst EVENT_KEY = '.bs.swipe'\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n}\n\nconst DefaultType = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n}\n\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super()\n this._element = element\n\n if (!element || !Swipe.isSupported()) {\n return\n }\n\n this._config = this._getConfig(config)\n this._deltaX = 0\n this._supportPointerEvents = Boolean(window.PointerEvent)\n this._initEvents()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY)\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX\n\n return\n }\n\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX\n }\n }\n\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX\n }\n\n this._handleSwipe()\n execute(this._config.endCallback)\n }\n\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this._deltaX\n }\n\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX)\n\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltaX / this._deltaX\n\n this._deltaX = 0\n\n if (!direction) {\n return\n }\n\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)\n }\n\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))\n }\n }\n\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n }\n}\n\nexport default Swipe\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getNextActiveElement,\n isRTL,\n isVisible,\n reflow,\n triggerTransitionEnd\n} from './util/index.js'\nimport Swipe from './util/swipe.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)', // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._interval = null\n this._activeElement = null\n this._isSliding = false\n this.touchTimeout = null\n this._swipeHelper = null\n\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._addEventListeners()\n\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element)\n }\n\n this._clearInterval()\n }\n\n cycle() {\n this._clearInterval()\n this._updateInterval()\n\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval)\n }\n\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle())\n return\n }\n\n this.cycle()\n }\n\n to(index) {\n const items = this._getItems()\n if (index > items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n const activeIndex = this._getItemIndex(this._getActive())\n if (activeIndex === index) {\n return\n }\n\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV\n\n this._slide(order, items[index])\n }\n\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose()\n }\n\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval\n return config\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause())\n EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle())\n }\n\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault())\n }\n\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n }\n\n this._swipeHelper = new Swipe(this._element, swipeConfig)\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(this._directionToOrder(direction))\n }\n }\n\n _getItemIndex(element) {\n return this._getItems().indexOf(element)\n }\n\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return\n }\n\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement)\n\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE)\n newActiveIndicator.setAttribute('aria-current', 'true')\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || this._getActive()\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n this._config.interval = elementInterval || this._config.defaultInterval\n }\n\n _slide(order, element = null) {\n if (this._isSliding) {\n return\n }\n\n const activeElement = this._getActive()\n const isNext = order === ORDER_NEXT\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap)\n\n if (nextElement === activeElement) {\n return\n }\n\n const nextElementIndex = this._getItemIndex(nextElement)\n\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n })\n }\n\n const slideEvent = triggerEvent(EVENT_SLIDE)\n\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return\n }\n\n const isCycling = Boolean(this._interval)\n this.pause()\n\n this._isSliding = true\n\n this._setActiveIndicatorElement(nextElementIndex)\n this._activeElement = nextElement\n\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n triggerEvent(EVENT_SLID)\n }\n\n this._queueCallback(completeCallBack, activeElement, this._isAnimated())\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE)\n }\n\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n }\n\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element)\n }\n\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n }\n\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config)\n\n if (typeof config === 'number') {\n data.to(config)\n return\n }\n\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n event.preventDefault()\n\n const carousel = Carousel.getOrCreateInstance(target)\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n carousel.to(slideIndex)\n carousel._maybeEnableCycle()\n return\n }\n\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next()\n carousel._maybeEnableCycle()\n return\n }\n\n carousel.prev()\n carousel._maybeEnableCycle()\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getElement,\n reflow\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\nconst Default = {\n parent: null,\n toggle: true\n}\n\nconst DefaultType = {\n parent: '(null|element)',\n toggle: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isTransitioning = false\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElement => foundElement === this._element)\n\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let activeChildren = []\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)\n .filter(element => element !== this._element)\n .map(element => Collapse.getOrCreateInstance(element, { toggle: false }))\n }\n\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n for (const activeInstance of activeChildren) {\n activeInstance.hide()\n }\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger)\n\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n // Private\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)\n\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n }\n }\n\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element))\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen)\n element.setAttribute('aria-expanded', isOpen)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n execute,\n getElement,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center'\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)'\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR = '.navbar'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\nconst PLACEMENT_TOPCENTER = 'top'\nconst PLACEMENT_BOTTOMCENTER = 'bottom'\n\nconst Default = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n}\n\nconst DefaultType = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n}\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._popper = null\n this._parent = this._element.parentNode // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.findOne(SELECTOR_MENU, this._parent)\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._createPopper()\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = super._getConfig(config)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org/docs/v2/)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = this._parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n }\n\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getPlacement() {\n const parentDropdown = this._parent\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig])\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {\n return\n }\n\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)\n\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle)\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n const relatedTarget = { relatedTarget: context._element }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName)\n const isEscapeEvent = event.key === ESCAPE_KEY\n const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)\n\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return\n }\n\n if (isInput && !isEscapeEvent) {\n return\n }\n\n event.preventDefault()\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?\n this :\n (SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode))\n\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (isUpOrDownEvent) {\n event.stopPropagation()\n instance.show()\n instance._selectMenuItem(event)\n return\n }\n\n if (instance._isShown()) { // else is escape and we check if it is shown\n event.stopPropagation()\n instance.hide()\n getToggleButton.focus()\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport {\n execute, executeAfterTransition, getElement, reflow\n} from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nconst Default = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n}\n\nconst DefaultType = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n}\n\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n const element = this._getElement()\n if (this._config.isAnimated) {\n reflow(element)\n }\n\n element.classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n const element = this._getElement()\n this._config.rootElement.append(element)\n\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nconst Default = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n}\n\nconst DefaultType = {\n autofocus: 'boolean',\n trapElement: 'element'\n}\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return\n }\n\n if (this._config.autofocus) {\n this._config.trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n _handleFocusin(event) {\n const { trapElement } = this._config\n\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\nconst PROPERTY_PADDING = 'padding-right'\nconst PROPERTY_MARGIN = 'margin-right'\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProperty)\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty)\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty)\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty)\n return\n }\n\n Manipulator.removeDataAttribute(element, styleProperty)\n element.style.setProperty(styleProperty, value)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n return\n }\n\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel)\n }\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin, isRTL, isVisible, reflow\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\nconst Default = {\n backdrop: true,\n focus: true,\n keyboard: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._isTransitioning = true\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._backdrop.show(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n this._isTransitioning = true\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated())\n }\n\n dispose() {\n EventHandler.off(window, EVENT_KEY)\n EventHandler.off(this._dialog, EVENT_KEY)\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated())\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n this._triggerBackdropTransition()\n })\n\n EventHandler.on(window, EVENT_RESIZE, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog()\n }\n })\n\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return\n }\n\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n return\n }\n\n if (this._config.backdrop) {\n this.hide()\n }\n })\n })\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const initialOverflowY = this._element.style.overflowY\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden'\n }\n\n this._element.classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY\n }, this._dialog)\n }, this._dialog)\n\n this._element.focus()\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin,\n isDisabled,\n isVisible\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\nconst CLASS_NAME_HIDING = 'hiding'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate()\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.add(CLASS_NAME_HIDING)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n return\n }\n\n this.hide()\n }\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop)\n\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n })\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show()\n }\n})\n\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide()\n }\n }\n})\n\nenableDismissTrigger(Offcanvas)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n dd: [],\n div: [],\n dl: [],\n dt: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n// js-docs-end allow-list\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n .some(regex => regex.test(attributeName))\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n }\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\nimport { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'\nimport { execute, getElement, isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'TemplateFactory'\n\nconst Default = {\n allowList: DefaultAllowlist,\n content: {}, // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '<div></div>'\n}\n\nconst DefaultType = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n}\n\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n}\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content)\n .map(config => this._resolvePossibleFunction(config))\n .filter(Boolean)\n }\n\n hasContent() {\n return this.getContent().length > 0\n }\n\n changeContent(content) {\n this._checkContent(content)\n this._config.content = { ...this._config.content, ...content }\n return this\n }\n\n toHtml() {\n const templateWrapper = document.createElement('div')\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template)\n\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector)\n }\n\n const template = templateWrapper.children[0]\n const extraClass = this._resolvePossibleFunction(this._config.extraClass)\n\n if (extraClass) {\n template.classList.add(...extraClass.split(' '))\n }\n\n return template\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config)\n this._checkContent(config.content)\n }\n\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({ selector, entry: content }, DefaultContentType)\n }\n }\n\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!templateElement) {\n return\n }\n\n content = this._resolvePossibleFunction(content)\n\n if (!content) {\n templateElement.remove()\n return\n }\n\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement)\n return\n }\n\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content)\n return\n }\n\n templateElement.textContent = content\n }\n\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [undefined, this])\n }\n\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = ''\n templateElement.append(element)\n return\n }\n\n templateElement.textContent = element.textContent\n }\n}\n\nexport default TemplateFactory\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport {\n defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop\n} from './util/index.js'\nimport { DefaultAllowlist } from './util/sanitizer.js'\nimport TemplateFactory from './util/template-factory.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\nconst EVENT_HIDE = 'hide'\nconst EVENT_HIDDEN = 'hidden'\nconst EVENT_SHOW = 'show'\nconst EVENT_SHOWN = 'shown'\nconst EVENT_INSERTED = 'inserted'\nconst EVENT_CLICK = 'click'\nconst EVENT_FOCUSIN = 'focusin'\nconst EVENT_FOCUSOUT = 'focusout'\nconst EVENT_MOUSEENTER = 'mouseenter'\nconst EVENT_MOUSELEAVE = 'mouseleave'\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '<div class=\"tooltip\" role=\"tooltip\">' +\n '<div class=\"tooltip-arrow\"></div>' +\n '<div class=\"tooltip-inner\"></div>' +\n '</div>',\n title: '',\n trigger: 'hover focus'\n}\n\nconst DefaultType = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n}\n\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org/docs/v2/)')\n }\n\n super(element, config)\n\n // Private\n this._isEnabled = true\n this._timeout = 0\n this._isHovered = null\n this._activeTrigger = {}\n this._popper = null\n this._templateFactory = null\n this._newContent = null\n\n // Protected\n this.tip = null\n\n this._setListeners()\n\n if (!this._config.selector) {\n this._fixTitle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle() {\n if (!this._isEnabled) {\n return\n }\n\n if (this._isShown()) {\n this._leave()\n return\n }\n\n this._enter()\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'))\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this._isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW))\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper()\n\n const tip = this._getTipElement()\n\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'))\n\n const { container } = this._config\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))\n }\n\n this._popper = this._createPopper(tip)\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN))\n\n if (this._isHovered === false) {\n this._leave()\n }\n\n this._isHovered = false\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n hide() {\n if (!this._isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE))\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const tip = this._getTipElement()\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n this._isHovered = null // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (!this._isHovered) {\n this._disposePopper()\n }\n\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN))\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n update() {\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle())\n }\n\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())\n }\n\n return this.tip\n }\n\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml()\n\n // TODO: remove this check in v6\n if (!tip) {\n return null\n }\n\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`)\n\n const tipId = getUID(this.constructor.NAME).toString()\n\n tip.setAttribute('id', tipId)\n\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n return tip\n }\n\n setContent(content) {\n this._newContent = content\n if (this._isShown()) {\n this._disposePopper()\n this.show()\n }\n }\n\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content)\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n })\n }\n\n return this._templateFactory\n }\n\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n }\n }\n\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title')\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _isAnimated() {\n return this._config.animation || (this.tip && this.tip.classList.contains(CLASS_NAME_FADE))\n }\n\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW)\n }\n\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element])\n const attachment = AttachmentMap[placement.toUpperCase()]\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element, this._element])\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement)\n }\n }\n ]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig])\n }\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[TRIGGER_CLICK] = !(context._isShown() && context._activeTrigger[TRIGGER_CLICK])\n context.toggle()\n })\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSEENTER) :\n this.constructor.eventName(EVENT_FOCUSIN)\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSELEAVE) :\n this.constructor.eventName(EVENT_FOCUSOUT)\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true\n context._enter()\n })\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] =\n context._element.contains(event.relatedTarget)\n\n context._leave()\n })\n }\n }\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n\n if (!title) {\n return\n }\n\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('data-bs-original-title', title) // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title')\n }\n\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true\n return\n }\n\n this._isHovered = true\n\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show()\n }\n }, this._config.delay.show)\n }\n\n _leave() {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n this._isHovered = false\n\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide()\n }\n }, this._config.delay.hide)\n }\n\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout)\n this._timeout = setTimeout(handler, timeout)\n }\n\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true)\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute]\n }\n }\n\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value\n }\n }\n\n config.selector = false\n config.trigger = 'manual'\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n\n if (this.tip) {\n this.tip.remove()\n this.tip = null\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Tooltip from './tooltip.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'popover'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Default = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>',\n trigger: 'click'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n}\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent()\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n }\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin, getElement, isDisabled, isVisible\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_CLICK = `click${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_TARGET_LINKS = '[href]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst Default = {\n offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n}\n\nconst DefaultType = {\n offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n}\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map()\n this._observableSections = new Map()\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element\n this._activeTarget = null\n this._observer = null\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n }\n this.refresh() // initialize\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables()\n this._maybeEnableSmoothScroll()\n\n if (this._observer) {\n this._observer.disconnect()\n } else {\n this._observer = this._getNewObserver()\n }\n\n for (const section of this._observableSections.values()) {\n this._observer.observe(section)\n }\n }\n\n dispose() {\n this._observer.disconnect()\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin\n\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))\n }\n\n return config\n }\n\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK)\n\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash)\n if (observableSection) {\n event.preventDefault()\n const root = this._rootElement || window\n const height = observableSection.offsetTop - this._element.offsetTop\n if (root.scrollTo) {\n root.scrollTo({ top: height, behavior: 'smooth' })\n return\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height\n }\n })\n }\n\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n }\n\n return new IntersectionObserver(entries => this._observerCallback(entries), options)\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop\n this._process(targetElement(entry))\n }\n\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop\n this._previousScrollData.parentScrollTop = parentScrollTop\n\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null\n this._clearActiveClass(targetElement(entry))\n\n continue\n }\n\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry)\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return\n }\n\n continue\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry)\n }\n }\n }\n\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map()\n this._observableSections = new Map()\n\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)\n\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue\n }\n\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor)\n this._observableSections.set(anchor.hash, observableSection)\n }\n }\n }\n\n _process(target) {\n if (this._activeTarget === target) {\n return\n }\n\n this._clearActiveClass(this._config.target)\n this._activeTarget = target\n target.classList.add(CLASS_NAME_ACTIVE)\n this._activateParents(target)\n\n EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })\n }\n\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n return\n }\n\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {\n item.classList.add(CLASS_NAME_ACTIVE)\n }\n }\n }\n\n _clearActiveClass(parent) {\n parent.classList.remove(CLASS_NAME_ACTIVE)\n\n const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent)\n for (const node of activeNodes) {\n node.classList.remove(CLASS_NAME_ACTIVE)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = ScrollSpy.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {\n ScrollSpy.getOrCreateInstance(spy)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(ScrollSpy)\n\nexport default ScrollSpy\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tab.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tab'\nconst DATA_KEY = 'bs.tab'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}`\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst HOME_KEY = 'Home'\nconst END_KEY = 'End'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_DROPDOWN = 'dropdown'\n\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\nconst SELECTOR_DROPDOWN_MENU = '.dropdown-menu'\nconst NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`\n\nconst SELECTOR_TAB_PANEL = '.list-group, .nav, [role=\"tablist\"]'\nconst SELECTOR_OUTER = '.nav-item, .list-group-item'\nconst SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role=\"tab\"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]' // TODO: could only be `tab` in v6\nconst SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`\n\nconst SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle=\"tab\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"pill\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"list\"]`\n\n/**\n * Class definition\n */\n\nclass Tab extends BaseComponent {\n constructor(element) {\n super(element)\n this._parent = this._element.closest(SELECTOR_TAB_PANEL)\n\n if (!this._parent) {\n return\n // TODO: should throw exception in v6\n // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)\n }\n\n // Set up initial aria attributes\n this._setInitialAttributes(this._parent, this._getChildren())\n\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n show() { // Shows this elem and deactivate the active sibling if exists\n const innerElem = this._element\n if (this._elemIsActive(innerElem)) {\n return\n }\n\n // Search for active tab on same parent to deactivate it\n const active = this._getActiveElem()\n\n const hideEvent = active ?\n EventHandler.trigger(active, EVENT_HIDE, { relatedTarget: innerElem }) :\n null\n\n const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, { relatedTarget: active })\n\n if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {\n return\n }\n\n this._deactivate(active, innerElem)\n this._activate(innerElem, active)\n }\n\n // Private\n _activate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.add(CLASS_NAME_ACTIVE)\n\n this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.add(CLASS_NAME_SHOW)\n return\n }\n\n element.removeAttribute('tabindex')\n element.setAttribute('aria-selected', true)\n this._toggleDropDown(element, true)\n EventHandler.trigger(element, EVENT_SHOWN, {\n relatedTarget: relatedElem\n })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _deactivate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.remove(CLASS_NAME_ACTIVE)\n element.blur()\n\n this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.remove(CLASS_NAME_SHOW)\n return\n }\n\n element.setAttribute('aria-selected', false)\n element.setAttribute('tabindex', '-1')\n this._toggleDropDown(element, false)\n EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _keydown(event) {\n if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key))) {\n return\n }\n\n event.stopPropagation()// stopPropagation/preventDefault both added to support up/down keys without scrolling the page\n event.preventDefault()\n\n const children = this._getChildren().filter(element => !isDisabled(element))\n let nextActiveElement\n\n if ([HOME_KEY, END_KEY].includes(event.key)) {\n nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]\n } else {\n const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)\n nextActiveElement = getNextActiveElement(children, event.target, isNext, true)\n }\n\n if (nextActiveElement) {\n nextActiveElement.focus({ preventScroll: true })\n Tab.getOrCreateInstance(nextActiveElement).show()\n }\n }\n\n _getChildren() { // collection of inner elements\n return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent)\n }\n\n _getActiveElem() {\n return this._getChildren().find(child => this._elemIsActive(child)) || null\n }\n\n _setInitialAttributes(parent, children) {\n this._setAttributeIfNotExists(parent, 'role', 'tablist')\n\n for (const child of children) {\n this._setInitialAttributesOnChild(child)\n }\n }\n\n _setInitialAttributesOnChild(child) {\n child = this._getInnerElement(child)\n const isActive = this._elemIsActive(child)\n const outerElem = this._getOuterElement(child)\n child.setAttribute('aria-selected', isActive)\n\n if (outerElem !== child) {\n this._setAttributeIfNotExists(outerElem, 'role', 'presentation')\n }\n\n if (!isActive) {\n child.setAttribute('tabindex', '-1')\n }\n\n this._setAttributeIfNotExists(child, 'role', 'tab')\n\n // set attributes to the related panel too\n this._setInitialAttributesOnTargetPanel(child)\n }\n\n _setInitialAttributesOnTargetPanel(child) {\n const target = SelectorEngine.getElementFromSelector(child)\n\n if (!target) {\n return\n }\n\n this._setAttributeIfNotExists(target, 'role', 'tabpanel')\n\n if (child.id) {\n this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)\n }\n }\n\n _toggleDropDown(element, open) {\n const outerElem = this._getOuterElement(element)\n if (!outerElem.classList.contains(CLASS_DROPDOWN)) {\n return\n }\n\n const toggle = (selector, className) => {\n const element = SelectorEngine.findOne(selector, outerElem)\n if (element) {\n element.classList.toggle(className, open)\n }\n }\n\n toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)\n toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)\n outerElem.setAttribute('aria-expanded', open)\n }\n\n _setAttributeIfNotExists(element, attribute, value) {\n if (!element.hasAttribute(attribute)) {\n element.setAttribute(attribute, value)\n }\n }\n\n _elemIsActive(elem) {\n return elem.classList.contains(CLASS_NAME_ACTIVE)\n }\n\n // Try to get the inner element (usually the .nav-link)\n _getInnerElement(elem) {\n return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem)\n }\n\n // Try to get the outer element (usually the .nav-item)\n _getOuterElement(elem) {\n return elem.closest(SELECTOR_OUTER) || elem\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tab.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n Tab.getOrCreateInstance(this).show()\n})\n\n/**\n * Initialize on focus\n */\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {\n Tab.getOrCreateInstance(element)\n }\n})\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tab)\n\nexport default Tab\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap toast.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin, reflow } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'toast'\nconst DATA_KEY = 'bs.toast'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\n\nconst DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n}\n\nconst Default = {\n animation: true,\n autohide: true,\n delay: 5000\n}\n\n/**\n * Class definition\n */\n\nclass Toast extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._timeout = null\n this._hasMouseInteraction = false\n this._hasKeyboardInteraction = false\n this._setListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show() {\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._clearTimeout()\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE)\n }\n\n const complete = () => {\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN)\n\n this._maybeScheduleHide()\n }\n\n this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\n reflow(this._element)\n this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)\n\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n hide() {\n if (!this.isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const complete = () => {\n this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\n this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.classList.add(CLASS_NAME_SHOWING)\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n dispose() {\n this._clearTimeout()\n\n if (this.isShown()) {\n this._element.classList.remove(CLASS_NAME_SHOW)\n }\n\n super.dispose()\n }\n\n isShown() {\n return this._element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n _maybeScheduleHide() {\n if (!this._config.autohide) {\n return\n }\n\n if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\n return\n }\n\n this._timeout = setTimeout(() => {\n this.hide()\n }, this._config.delay)\n }\n\n _onInteraction(event, isInteracting) {\n switch (event.type) {\n case 'mouseover':\n case 'mouseout': {\n this._hasMouseInteraction = isInteracting\n break\n }\n\n case 'focusin':\n case 'focusout': {\n this._hasKeyboardInteraction = isInteracting\n break\n }\n\n default: {\n break\n }\n }\n\n if (isInteracting) {\n this._clearTimeout()\n return\n }\n\n const nextElement = event.relatedTarget\n if (this._element === nextElement || this._element.contains(nextElement)) {\n return\n }\n\n this._maybeScheduleHide()\n }\n\n _setListeners() {\n EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\n EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\n }\n\n _clearTimeout() {\n clearTimeout(this._timeout)\n this._timeout = null\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Toast.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Toast)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Toast)\n\nexport default Toast\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap index.umd.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './src/alert.js'\nimport Button from './src/button.js'\nimport Carousel from './src/carousel.js'\nimport Collapse from './src/collapse.js'\nimport Dropdown from './src/dropdown.js'\nimport Modal from './src/modal.js'\nimport Offcanvas from './src/offcanvas.js'\nimport Popover from './src/popover.js'\nimport ScrollSpy from './src/scrollspy.js'\nimport Tab from './src/tab.js'\nimport Toast from './src/toast.js'\nimport Tooltip from './src/tooltip.js'\n\nexport default {\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Offcanvas,\n Popover,\n ScrollSpy,\n Tab,\n Toast,\n Tooltip\n}\n"],"names":["elementMap","Map","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete","MAX_UID","MILLISECONDS_MULTIPLIER","TRANSITION_END","parseSelector","selector","window","CSS","escape","replace","match","id","toType","object","undefined","Object","prototype","toString","call","toLowerCase","getUID","prefix","Math","floor","random","document","getElementById","getTransitionDurationFromElement","transitionDuration","transitionDelay","getComputedStyle","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","split","triggerTransitionEnd","dispatchEvent","Event","isElement","jquery","nodeType","getElement","length","querySelector","isVisible","getClientRects","elementIsVisible","getPropertyValue","closedDetails","closest","summary","parentNode","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","getAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","noop","reflow","offsetHeight","getjQuery","jQuery","body","DOMContentLoadedCallbacks","onDOMContentLoaded","callback","readyState","addEventListener","push","isRTL","dir","defineJQueryPlugin","plugin","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","execute","possibleCallback","args","defaultValue","executeAfterTransition","transitionElement","waitForTransition","durationPadding","emulatedDuration","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","listLength","index","indexOf","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","nativeEvents","Set","makeEventUid","uid","getElementEvents","bootstrapHandler","event","hydrateObj","delegateTarget","oneOff","EventHandler","off","type","apply","bootstrapDelegationHandler","domElements","querySelectorAll","domElement","findHandler","events","callable","delegationSelector","values","find","normalizeParameters","originalTypeEvent","delegationFunction","isDelegated","typeEvent","getTypeEvent","addHandler","wrapFunction","relatedTarget","handlers","previousFunction","removeHandler","Boolean","removeNamespacedHandlers","namespace","storeElementEvent","handlerKey","entries","includes","on","one","inNamespace","isNamespace","startsWith","elementEvent","slice","keyHandlers","trigger","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","evt","cancelable","preventDefault","obj","meta","value","_unused","defineProperty","configurable","normalizeData","JSON","parse","decodeURIComponent","normalizeDataKey","chr","Manipulator","setDataAttribute","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","dataset","filter","pureKey","charAt","getDataAttribute","Config","Default","DefaultType","Error","_getConfig","config","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","jsonConfig","constructor","configTypes","property","expectedTypes","valueType","RegExp","test","TypeError","toUpperCase","VERSION","BaseComponent","_element","_config","Data","DATA_KEY","dispose","EVENT_KEY","propertyName","getOwnPropertyNames","_queueCallback","isAnimated","getInstance","getOrCreateInstance","eventName","getSelector","hrefAttribute","trim","map","sel","join","SelectorEngine","concat","Element","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","el","getSelectorFromElement","getElementFromSelector","getMultipleElementsFromSelector","enableDismissTrigger","component","method","clickEvent","tagName","EVENT_CLOSE","EVENT_CLOSED","CLASS_NAME_FADE","CLASS_NAME_SHOW","Alert","close","closeEvent","_destroyElement","each","data","DATA_API_KEY","CLASS_NAME_ACTIVE","SELECTOR_DATA_TOGGLE","EVENT_CLICK_DATA_API","Button","toggle","button","EVENT_TOUCHSTART","EVENT_TOUCHMOVE","EVENT_TOUCHEND","EVENT_POINTERDOWN","EVENT_POINTERUP","POINTER_TYPE_TOUCH","POINTER_TYPE_PEN","CLASS_NAME_POINTER_EVENT","SWIPE_THRESHOLD","endCallback","leftCallback","rightCallback","Swipe","isSupported","_deltaX","_supportPointerEvents","PointerEvent","_initEvents","_start","touches","clientX","_eventIsPointerPenTouch","_end","_handleSwipe","_move","absDeltaX","abs","direction","add","pointerType","navigator","maxTouchPoints","ARROW_LEFT_KEY","ARROW_RIGHT_KEY","TOUCHEVENT_COMPAT_WAIT","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","EVENT_SLIDE","EVENT_SLID","EVENT_KEYDOWN","EVENT_MOUSEENTER","EVENT_MOUSELEAVE","EVENT_DRAG_START","EVENT_LOAD_DATA_API","CLASS_NAME_CAROUSEL","CLASS_NAME_SLIDE","CLASS_NAME_END","CLASS_NAME_START","CLASS_NAME_NEXT","CLASS_NAME_PREV","SELECTOR_ACTIVE","SELECTOR_ITEM","SELECTOR_ACTIVE_ITEM","SELECTOR_ITEM_IMG","SELECTOR_INDICATORS","SELECTOR_DATA_SLIDE","SELECTOR_DATA_RIDE","KEY_TO_DIRECTION","interval","keyboard","pause","ride","touch","wrap","Carousel","_interval","_activeElement","_isSliding","touchTimeout","_swipeHelper","_indicatorsElement","_addEventListeners","cycle","_slide","nextWhenVisible","hidden","_clearInterval","_updateInterval","setInterval","_maybeEnableCycle","to","items","_getItems","activeIndex","_getItemIndex","_getActive","order","defaultInterval","_keydown","_addTouchEventListeners","img","endCallBack","clearTimeout","swipeConfig","_directionToOrder","_setActiveIndicatorElement","activeIndicator","newActiveIndicator","elementInterval","parseInt","isNext","nextElement","nextElementIndex","triggerEvent","_orderToDirection","slideEvent","isCycling","directionalClassName","orderClassName","completeCallBack","_isAnimated","clearInterval","carousel","slideIndex","carousels","EVENT_SHOW","EVENT_SHOWN","EVENT_HIDE","EVENT_HIDDEN","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_COLLAPSED","CLASS_NAME_DEEPER_CHILDREN","CLASS_NAME_HORIZONTAL","WIDTH","HEIGHT","SELECTOR_ACTIVES","parent","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElement","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activeChildren","_getFirstLevelChildren","startEvent","activeInstance","dimension","_getDimension","style","complete","capitalizedDimension","scrollSize","getBoundingClientRect","selected","triggerArray","isOpen","ESCAPE_KEY","TAB_KEY","ARROW_UP_KEY","ARROW_DOWN_KEY","RIGHT_MOUSE_BUTTON","EVENT_KEYDOWN_DATA_API","EVENT_KEYUP_DATA_API","CLASS_NAME_DROPUP","CLASS_NAME_DROPEND","CLASS_NAME_DROPSTART","CLASS_NAME_DROPUP_CENTER","CLASS_NAME_DROPDOWN_CENTER","SELECTOR_DATA_TOGGLE_SHOWN","SELECTOR_MENU","SELECTOR_NAVBAR","SELECTOR_NAVBAR_NAV","SELECTOR_VISIBLE_ITEMS","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","PLACEMENT_TOPCENTER","PLACEMENT_BOTTOMCENTER","autoClose","boundary","display","offset","popperConfig","reference","Dropdown","_popper","_parent","_menu","_inNavbar","_detectNavbar","showEvent","_createPopper","focus","_completeHide","destroy","update","hideEvent","Popper","referenceElement","_getPopperConfig","createPopper","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","placement","modifiers","options","enabled","_selectMenuItem","clearMenus","openToggles","context","composedPath","isMenuTarget","dataApiKeydownHandler","isInput","isEscapeEvent","isUpOrDownEvent","getToggleButton","stopPropagation","EVENT_MOUSEDOWN","className","clickCallback","rootElement","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","EVENT_FOCUSIN","EVENT_KEYDOWN_TAB","TAB_NAV_FORWARD","TAB_NAV_BACKWARD","autofocus","trapElement","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","elements","shiftKey","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","PROPERTY_PADDING","PROPERTY_MARGIN","ScrollBarHelper","getWidth","documentWidth","clientWidth","innerWidth","width","_disableOverFlow","_setElementAttributes","calculatedValue","reset","_resetElementAttributes","isOverflowing","_saveInitialAttribute","overflow","styleProperty","scrollbarWidth","manipulationCallBack","setProperty","_applyManipulationCallback","actualValue","removeProperty","callBack","EVENT_HIDE_PREVENTED","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_MOUSEDOWN_DISMISS","EVENT_KEYDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","OPEN_SELECTOR","SELECTOR_DIALOG","SELECTOR_MODAL_BODY","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_scrollBar","_adjustDialog","_showElement","_hideModal","handleUpdate","scrollTop","modalBody","transitionComplete","_triggerBackdropTransition","event2","_resetAdjustments","isModalOverflowing","scrollHeight","clientHeight","initialOverflowY","overflowY","isBodyOverflowing","paddingLeft","paddingRight","alreadyOpen","CLASS_NAME_SHOWING","CLASS_NAME_HIDING","CLASS_NAME_BACKDROP","scroll","Offcanvas","blur","completeCallback","position","ARIA_ATTRIBUTE_PATTERN","DefaultAllowlist","a","area","b","br","col","code","dd","div","dl","dt","em","hr","h1","h2","h3","h4","h5","h6","i","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","uriAttributes","SAFE_URL_PATTERN","allowedAttribute","attribute","allowedAttributeList","attributeName","nodeName","nodeValue","attributeRegex","some","regex","sanitizeHtml","unsafeHtml","allowList","sanitizeFunction","domParser","DOMParser","createdDocument","parseFromString","elementName","attributeList","allowedAttributes","innerHTML","content","extraClass","html","sanitize","sanitizeFn","template","DefaultContentType","entry","TemplateFactory","getContent","_resolvePossibleFunction","hasContent","changeContent","_checkContent","toHtml","templateWrapper","_maybeSanitize","text","_setContent","arg","templateElement","_putElementInTemplate","textContent","DISALLOWED_ATTRIBUTES","CLASS_NAME_MODAL","SELECTOR_TOOLTIP_INNER","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","TRIGGER_CLICK","TRIGGER_MANUAL","EVENT_INSERTED","EVENT_CLICK","EVENT_FOCUSOUT","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","animation","container","customClass","delay","fallbackPlacements","title","Tooltip","_isEnabled","_timeout","_isHovered","_activeTrigger","_templateFactory","_newContent","tip","_setListeners","_fixTitle","enable","disable","toggleEnabled","_leave","_enter","_hideModalHandler","_disposePopper","_isWithContent","shadowRoot","isInTheDom","ownerDocument","_getTipElement","_isWithActiveTrigger","_getTitle","_createTipElement","_getContentForTemplate","_getTemplateFactory","tipId","setContent","_initializeOnDelegatedTarget","_getDelegateConfig","attachment","phase","state","triggers","eventIn","eventOut","_setTimeout","timeout","dataAttributes","dataAttribute","SELECTOR_TITLE","SELECTOR_CONTENT","Popover","_getContent","EVENT_ACTIVATE","CLASS_NAME_DROPDOWN_ITEM","SELECTOR_DATA_SPY","SELECTOR_TARGET_LINKS","SELECTOR_NAV_LIST_GROUP","SELECTOR_NAV_LINKS","SELECTOR_NAV_ITEMS","SELECTOR_LIST_ITEMS","SELECTOR_LINK_ITEMS","SELECTOR_DROPDOWN","SELECTOR_DROPDOWN_TOGGLE","rootMargin","smoothScroll","threshold","ScrollSpy","_targetLinks","_observableSections","_rootElement","_activeTarget","_observer","_previousScrollData","visibleEntryTop","parentScrollTop","refresh","_initializeTargetsAndObservables","_maybeEnableSmoothScroll","disconnect","_getNewObserver","section","observe","observableSection","hash","height","offsetTop","scrollTo","top","behavior","IntersectionObserver","_observerCallback","targetElement","_process","userScrollsDown","isIntersecting","_clearActiveClass","entryIsLowerThanPrevious","targetLinks","anchor","decodeURI","_activateParents","listGroup","item","activeNodes","node","spy","HOME_KEY","END_KEY","CLASS_DROPDOWN","SELECTOR_DROPDOWN_MENU","NOT_SELECTOR_DROPDOWN_TOGGLE","SELECTOR_TAB_PANEL","SELECTOR_OUTER","SELECTOR_INNER","SELECTOR_INNER_ELEM","SELECTOR_DATA_TOGGLE_ACTIVE","Tab","_setInitialAttributes","_getChildren","innerElem","_elemIsActive","active","_getActiveElem","_deactivate","_activate","relatedElem","_toggleDropDown","nextActiveElement","preventScroll","_setAttributeIfNotExists","_setInitialAttributesOnChild","_getInnerElement","isActive","outerElem","_getOuterElement","_setInitialAttributesOnTargetPanel","open","EVENT_MOUSEOVER","EVENT_MOUSEOUT","CLASS_NAME_HIDE","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","isShown","_onInteraction","isInteracting"],"mappings":"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"} \ No newline at end of file diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.min.js b/extensions/pagetop-bootsier/static/js/bootstrap.min.js index d5dc5ea1..7f2bc627 100644 --- a/extensions/pagetop-bootsier/static/js/bootstrap.min.js +++ b/extensions/pagetop-bootsier/static/js/bootstrap.min.js @@ -1,7 +1,7 @@ /*! - * Bootstrap v5.3.3 (https://getbootstrap.com/) - * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Bootstrap v5.3.8 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e(t.Popper)}(this,(function(t){"use strict";function e(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t)for(const i in t)if("default"!==i){const s=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,s.get?s:{enumerable:!0,get:()=>t[i]})}return e.default=t,Object.freeze(e)}const i=e(t),s=new Map,n={set(t,e,i){s.has(t)||s.set(t,new Map);const n=s.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>s.has(t)&&s.get(t).get(e)||null,remove(t,e){if(!s.has(t))return;const i=s.get(t);i.delete(e),0===i.size&&s.delete(t)}},o="transitionend",r=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),a=t=>{t.dispatchEvent(new Event(o))},l=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),c=t=>l(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(r(t)):null,h=t=>{if(!l(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},d=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),u=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?u(t.parentNode):null},_=()=>{},g=t=>{t.offsetHeight},f=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,m=[],p=()=>"rtl"===document.documentElement.dir,b=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,s=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=s,t.jQueryInterface)}},"loading"===document.readyState?(m.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of m)t()})),m.push(e)):e()},v=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,y=(t,e,i=!0)=>{if(!i)return void v(t);const s=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const s=Number.parseFloat(e),n=Number.parseFloat(i);return s||n?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let n=!1;const r=({target:i})=>{i===e&&(n=!0,e.removeEventListener(o,r),v(t))};e.addEventListener(o,r),setTimeout((()=>{n||a(e)}),s)},w=(t,e,i,s)=>{const n=t.length;let o=t.indexOf(e);return-1===o?!i&&s?t[n-1]:t[0]:(o+=i?1:-1,s&&(o=(o+n)%n),t[Math.max(0,Math.min(o,n-1))])},A=/[^.]*(?=\..*)\.|.*/,E=/\..*/,C=/::\d+$/,T={};let k=1;const $={mouseenter:"mouseover",mouseleave:"mouseout"},S=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${k++}`||t.uidEvent||k++}function O(t){const e=L(t);return t.uidEvent=e,T[e]=T[e]||{},T[e]}function I(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function D(t,e,i){const s="string"==typeof e,n=s?i:e||i;let o=M(t);return S.has(o)||(o=t),[s,n,o]}function N(t,e,i,s,n){if("string"!=typeof e||!t)return;let[o,r,a]=D(e,i,s);if(e in $){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=O(t),c=l[a]||(l[a]={}),h=I(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&n);const d=L(r,e.replace(A,"")),u=o?function(t,e,i){return function s(n){const o=t.querySelectorAll(e);for(let{target:r}=n;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return F(n,{delegateTarget:r}),s.oneOff&&j.off(t,n.type,e,i),i.apply(r,[n])}}(t,i,r):function(t,e){return function i(s){return F(s,{delegateTarget:t}),i.oneOff&&j.off(t,s.type,e),e.apply(t,[s])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=n,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function P(t,e,i,s,n){const o=I(e[i],s,n);o&&(t.removeEventListener(i,o,Boolean(n)),delete e[i][o.uidEvent])}function x(t,e,i,s){const n=e[i]||{};for(const[o,r]of Object.entries(n))o.includes(s)&&P(t,e,i,r.callable,r.delegationSelector)}function M(t){return t=t.replace(E,""),$[t]||t}const j={on(t,e,i,s){N(t,e,i,s,!1)},one(t,e,i,s){N(t,e,i,s,!0)},off(t,e,i,s){if("string"!=typeof e||!t)return;const[n,o,r]=D(e,i,s),a=r!==e,l=O(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))x(t,l,i,e.slice(1));for(const[i,s]of Object.entries(c)){const n=i.replace(C,"");a&&!e.includes(n)||P(t,l,r,s.callable,s.delegationSelector)}}else{if(!Object.keys(c).length)return;P(t,l,r,o,n?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const s=f();let n=null,o=!0,r=!0,a=!1;e!==M(e)&&s&&(n=s.Event(e,i),s(t).trigger(n),o=!n.isPropagationStopped(),r=!n.isImmediatePropagationStopped(),a=n.isDefaultPrevented());const l=F(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&n&&n.preventDefault(),l}};function F(t,e={}){for(const[i,s]of Object.entries(e))try{t[i]=s}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>s})}return t}function z(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function H(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const B={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${H(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${H(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const s of i){let i=s.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=z(t.dataset[s])}return e},getDataAttribute:(t,e)=>z(t.getAttribute(`data-bs-${H(e)}`))};class q{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=l(e)?B.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...l(e)?B.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[s,n]of Object.entries(e)){const e=t[s],o=l(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(n).test(o))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${s}" provided type "${o}" but expected type "${n}".`)}var i}}class W extends q{constructor(t,e){super(),(t=c(t))&&(this._element=t,this._config=this._getConfig(e),n.set(this._element,this.constructor.DATA_KEY,this))}dispose(){n.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){y(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return n.get(c(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.3"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const R=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map((t=>r(t))).join(","):null},K={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let s=t.parentNode.closest(e);for(;s;)i.push(s),s=s.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!d(t)&&h(t)))},getSelectorFromElement(t){const e=R(t);return e&&K.findOne(e)?e:null},getElementFromSelector(t){const e=R(t);return e?K.findOne(e):null},getMultipleElementsFromSelector(t){const e=R(t);return e?K.find(e):[]}},V=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),d(this))return;const n=K.getElementFromSelector(this)||this.closest(`.${s}`);t.getOrCreateInstance(n)[e]()}))},Q=".bs.alert",X=`close${Q}`,Y=`closed${Q}`;class U extends W{static get NAME(){return"alert"}close(){if(j.trigger(this._element,X).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,Y),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=U.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}V(U,"close"),b(U);const G='[data-bs-toggle="button"]';class J extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=J.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}j.on(document,"click.bs.button.data-api",G,(t=>{t.preventDefault();const e=t.target.closest(G);J.getOrCreateInstance(e).toggle()})),b(J);const Z=".bs.swipe",tt=`touchstart${Z}`,et=`touchmove${Z}`,it=`touchend${Z}`,st=`pointerdown${Z}`,nt=`pointerup${Z}`,ot={endCallback:null,leftCallback:null,rightCallback:null},rt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class at extends q{constructor(t,e){super(),this._element=t,t&&at.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return ot}static get DefaultType(){return rt}static get NAME(){return"swipe"}dispose(){j.off(this._element,Z)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),v(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&v(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(j.on(this._element,st,(t=>this._start(t))),j.on(this._element,nt,(t=>this._end(t))),this._element.classList.add("pointer-event")):(j.on(this._element,tt,(t=>this._start(t))),j.on(this._element,et,(t=>this._move(t))),j.on(this._element,it,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const lt=".bs.carousel",ct=".data-api",ht="next",dt="prev",ut="left",_t="right",gt=`slide${lt}`,ft=`slid${lt}`,mt=`keydown${lt}`,pt=`mouseenter${lt}`,bt=`mouseleave${lt}`,vt=`dragstart${lt}`,yt=`load${lt}${ct}`,wt=`click${lt}${ct}`,At="carousel",Et="active",Ct=".active",Tt=".carousel-item",kt=Ct+Tt,$t={ArrowLeft:_t,ArrowRight:ut},St={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Lt={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class Ot extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=K.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===At&&this.cycle()}static get Default(){return St}static get DefaultType(){return Lt}static get NAME(){return"carousel"}next(){this._slide(ht)}nextWhenVisible(){!document.hidden&&h(this._element)&&this.next()}prev(){this._slide(dt)}pause(){this._isSliding&&a(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?j.one(this._element,ft,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,ft,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const s=t>i?ht:dt;this._slide(s,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&j.on(this._element,mt,(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,pt,(()=>this.pause())),j.on(this._element,bt,(()=>this._maybeEnableCycle()))),this._config.touch&&at.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of K.find(".carousel-item img",this._element))j.on(t,vt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ut)),rightCallback:()=>this._slide(this._directionToOrder(_t)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new at(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=$t[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=K.findOne(Ct,this._indicatorsElement);e.classList.remove(Et),e.removeAttribute("aria-current");const i=K.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(Et),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),s=t===ht,n=e||w(this._getItems(),i,s,this._config.wrap);if(n===i)return;const o=this._getItemIndex(n),r=e=>j.trigger(this._element,e,{relatedTarget:n,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(gt).defaultPrevented)return;if(!i||!n)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=n;const l=s?"carousel-item-start":"carousel-item-end",c=s?"carousel-item-next":"carousel-item-prev";n.classList.add(c),g(n),i.classList.add(l),n.classList.add(l),this._queueCallback((()=>{n.classList.remove(l,c),n.classList.add(Et),i.classList.remove(Et,c,l),this._isSliding=!1,r(ft)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return K.findOne(kt,this._element)}_getItems(){return K.find(Tt,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ut?dt:ht:t===ut?ht:dt}_orderToDirection(t){return p()?t===dt?ut:_t:t===dt?_t:ut}static jQueryInterface(t){return this.each((function(){const e=Ot.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}j.on(document,wt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=K.getElementFromSelector(this);if(!e||!e.classList.contains(At))return;t.preventDefault();const i=Ot.getOrCreateInstance(e),s=this.getAttribute("data-bs-slide-to");return s?(i.to(s),void i._maybeEnableCycle()):"next"===B.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),j.on(window,yt,(()=>{const t=K.find('[data-bs-ride="carousel"]');for(const e of t)Ot.getOrCreateInstance(e)})),b(Ot);const It=".bs.collapse",Dt=`show${It}`,Nt=`shown${It}`,Pt=`hide${It}`,xt=`hidden${It}`,Mt=`click${It}.data-api`,jt="show",Ft="collapse",zt="collapsing",Ht=`:scope .${Ft} .${Ft}`,Bt='[data-bs-toggle="collapse"]',qt={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Rt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=K.find(Bt);for(const t of i){const e=K.getSelectorFromElement(t),i=K.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return qt}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Rt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(j.trigger(this._element,Dt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Ft),this._element.classList.add(zt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(zt),this._element.classList.add(Ft,jt),this._element.style[e]="",j.trigger(this._element,Nt)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,Pt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,g(this._element),this._element.classList.add(zt),this._element.classList.remove(Ft,jt);for(const t of this._triggerArray){const e=K.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(zt),this._element.classList.add(Ft),j.trigger(this._element,xt)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(jt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=c(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Bt);for(const e of t){const t=K.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=K.find(Ht,this._config.parent);return K.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Rt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,Mt,Bt,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of K.getMultipleElementsFromSelector(this))Rt.getOrCreateInstance(t,{toggle:!1}).toggle()})),b(Rt);const Kt="dropdown",Vt=".bs.dropdown",Qt=".data-api",Xt="ArrowUp",Yt="ArrowDown",Ut=`hide${Vt}`,Gt=`hidden${Vt}`,Jt=`show${Vt}`,Zt=`shown${Vt}`,te=`click${Vt}${Qt}`,ee=`keydown${Vt}${Qt}`,ie=`keyup${Vt}${Qt}`,se="show",ne='[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)',oe=`${ne}.${se}`,re=".dropdown-menu",ae=p()?"top-end":"top-start",le=p()?"top-start":"top-end",ce=p()?"bottom-end":"bottom-start",he=p()?"bottom-start":"bottom-end",de=p()?"left-start":"right-start",ue=p()?"right-start":"left-start",_e={autoClose:!0,boundary:"clippingParents",display:"dynamic",offset:[0,2],popperConfig:null,reference:"toggle"},ge={autoClose:"(boolean|string)",boundary:"(string|element)",display:"string",offset:"(array|string|function)",popperConfig:"(null|object|function)",reference:"(string|element|object)"};class fe extends W{constructor(t,e){super(t,e),this._popper=null,this._parent=this._element.parentNode,this._menu=K.next(this._element,re)[0]||K.prev(this._element,re)[0]||K.findOne(re,this._parent),this._inNavbar=this._detectNavbar()}static get Default(){return _e}static get DefaultType(){return ge}static get NAME(){return Kt}toggle(){return this._isShown()?this.hide():this.show()}show(){if(d(this._element)||this._isShown())return;const t={relatedTarget:this._element};if(!j.trigger(this._element,Jt,t).defaultPrevented){if(this._createPopper(),"ontouchstart"in document.documentElement&&!this._parent.closest(".navbar-nav"))for(const t of[].concat(...document.body.children))j.on(t,"mouseover",_);this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(se),this._element.classList.add(se),j.trigger(this._element,Zt,t)}}hide(){if(d(this._element)||!this._isShown())return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){if(!j.trigger(this._element,Ut,t).defaultPrevented){if("ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))j.off(t,"mouseover",_);this._popper&&this._popper.destroy(),this._menu.classList.remove(se),this._element.classList.remove(se),this._element.setAttribute("aria-expanded","false"),B.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,Gt,t)}}_getConfig(t){if("object"==typeof(t=super._getConfig(t)).reference&&!l(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Kt.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(){if(void 0===i)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let t=this._element;"parent"===this._config.reference?t=this._parent:l(this._config.reference)?t=c(this._config.reference):"object"==typeof this._config.reference&&(t=this._config.reference);const e=this._getPopperConfig();this._popper=i.createPopper(t,this._menu,e)}_isShown(){return this._menu.classList.contains(se)}_getPlacement(){const t=this._parent;if(t.classList.contains("dropend"))return de;if(t.classList.contains("dropstart"))return ue;if(t.classList.contains("dropup-center"))return"top";if(t.classList.contains("dropdown-center"))return"bottom";const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?le:ae:e?he:ce}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(B.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...v(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=K.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>h(t)));i.length&&w(i,e,t===Yt,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=fe.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=K.find(oe);for(const i of e){const e=fe.getInstance(i);if(!e||!1===e._config.autoClose)continue;const s=t.composedPath(),n=s.includes(e._menu);if(s.includes(e._element)||"inside"===e._config.autoClose&&!n||"outside"===e._config.autoClose&&n)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,s=[Xt,Yt].includes(t.key);if(!s&&!i)return;if(e&&!i)return;t.preventDefault();const n=this.matches(ne)?this:K.prev(this,ne)[0]||K.next(this,ne)[0]||K.findOne(ne,t.delegateTarget.parentNode),o=fe.getOrCreateInstance(n);if(s)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),n.focus())}}j.on(document,ee,ne,fe.dataApiKeydownHandler),j.on(document,ee,re,fe.dataApiKeydownHandler),j.on(document,te,fe.clearMenus),j.on(document,ie,fe.clearMenus),j.on(document,te,ne,(function(t){t.preventDefault(),fe.getOrCreateInstance(this).toggle()})),b(fe);const me="backdrop",pe="show",be=`mousedown.bs.${me}`,ve={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},ye={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class we extends q{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return ve}static get DefaultType(){return ye}static get NAME(){return me}show(t){if(!this._config.isVisible)return void v(t);this._append();const e=this._getElement();this._config.isAnimated&&g(e),e.classList.add(pe),this._emulateAnimation((()=>{v(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(pe),this._emulateAnimation((()=>{this.dispose(),v(t)}))):v(t)}dispose(){this._isAppended&&(j.off(this._element,be),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=c(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),j.on(t,be,(()=>{v(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){y(t,this._getElement(),this._config.isAnimated)}}const Ae=".bs.focustrap",Ee=`focusin${Ae}`,Ce=`keydown.tab${Ae}`,Te="backward",ke={autofocus:!0,trapElement:null},$e={autofocus:"boolean",trapElement:"element"};class Se extends q{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return ke}static get DefaultType(){return $e}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),j.off(document,Ae),j.on(document,Ee,(t=>this._handleFocusin(t))),j.on(document,Ce,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,Ae))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=K.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===Te?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Te:"forward")}}const Le=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",Oe=".sticky-top",Ie="padding-right",De="margin-right";class Ne{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,Ie,(e=>e+t)),this._setElementAttributes(Le,Ie,(e=>e+t)),this._setElementAttributes(Oe,De,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,Ie),this._resetElementAttributes(Le,Ie),this._resetElementAttributes(Oe,De)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const s=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+s)return;this._saveInitialAttribute(t,e);const n=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(n))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&B.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=B.getDataAttribute(t,e);null!==i?(B.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(l(t))e(t);else for(const i of K.find(t,this._element))e(i)}}const Pe=".bs.modal",xe=`hide${Pe}`,Me=`hidePrevented${Pe}`,je=`hidden${Pe}`,Fe=`show${Pe}`,ze=`shown${Pe}`,He=`resize${Pe}`,Be=`click.dismiss${Pe}`,qe=`mousedown.dismiss${Pe}`,We=`keydown.dismiss${Pe}`,Re=`click${Pe}.data-api`,Ke="modal-open",Ve="show",Qe="modal-static",Xe={backdrop:!0,focus:!0,keyboard:!0},Ye={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class Ue extends W{constructor(t,e){super(t,e),this._dialog=K.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new Ne,this._addEventListeners()}static get Default(){return Xe}static get DefaultType(){return Ye}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,Fe,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Ke),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(j.trigger(this._element,xe).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(Ve),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){j.off(window,Pe),j.off(this._dialog,Pe),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new we({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Se({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=K.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),g(this._element),this._element.classList.add(Ve),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,ze,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){j.on(this._element,We,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),j.on(window,He,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),j.on(this._element,qe,(t=>{j.one(this._element,Be,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Ke),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,je)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,Me).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(Qe)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(Qe),this._queueCallback((()=>{this._element.classList.remove(Qe),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Ue.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,Re,'[data-bs-toggle="modal"]',(function(t){const e=K.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,Fe,(t=>{t.defaultPrevented||j.one(e,je,(()=>{h(this)&&this.focus()}))}));const i=K.findOne(".modal.show");i&&Ue.getInstance(i).hide(),Ue.getOrCreateInstance(e).toggle(this)})),V(Ue),b(Ue);const Ge=".bs.offcanvas",Je=".data-api",Ze=`load${Ge}${Je}`,ti="show",ei="showing",ii="hiding",si=".offcanvas.show",ni=`show${Ge}`,oi=`shown${Ge}`,ri=`hide${Ge}`,ai=`hidePrevented${Ge}`,li=`hidden${Ge}`,ci=`resize${Ge}`,hi=`click${Ge}${Je}`,di=`keydown.dismiss${Ge}`,ui={backdrop:!0,keyboard:!0,scroll:!1},_i={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class gi extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return ui}static get DefaultType(){return _i}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,ni,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new Ne).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(ei),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(ti),this._element.classList.remove(ei),j.trigger(this._element,oi,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,ri).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(ii),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(ti,ii),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new Ne).reset(),j.trigger(this._element,li)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new we({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():j.trigger(this._element,ai)}:null})}_initializeFocusTrap(){return new Se({trapElement:this._element})}_addEventListeners(){j.on(this._element,di,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():j.trigger(this._element,ai))}))}static jQueryInterface(t){return this.each((function(){const e=gi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,hi,'[data-bs-toggle="offcanvas"]',(function(t){const e=K.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),d(this))return;j.one(e,li,(()=>{h(this)&&this.focus()}));const i=K.findOne(si);i&&i!==e&&gi.getInstance(i).hide(),gi.getOrCreateInstance(e).toggle(this)})),j.on(window,Ze,(()=>{for(const t of K.find(si))gi.getOrCreateInstance(t).show()})),j.on(window,ci,(()=>{for(const t of K.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&gi.getOrCreateInstance(t).hide()})),V(gi),b(gi);const fi={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},mi=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),pi=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,bi=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!mi.has(i)||Boolean(pi.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},vi={allowList:fi,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"<div></div>"},yi={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},wi={entry:"(string|element|function|null)",selector:"(string|element)"};class Ai extends q{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return vi}static get DefaultType(){return yi}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},wi)}_setContent(t,e,i){const s=K.findOne(i,t);s&&((e=this._resolvePossibleFunction(e))?l(e)?this._putElementInTemplate(c(e),s):this._config.html?s.innerHTML=this._maybeSanitize(e):s.textContent=e:s.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const s=(new window.DOMParser).parseFromString(t,"text/html"),n=[].concat(...s.body.querySelectorAll("*"));for(const t of n){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const s=[].concat(...t.attributes),n=[].concat(e["*"]||[],e[i]||[]);for(const e of s)bi(e,n)||t.removeAttribute(e.nodeName)}return s.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return v(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Ei=new Set(["sanitize","allowList","sanitizeFn"]),Ci="fade",Ti="show",ki=".modal",$i="hide.bs.modal",Si="hover",Li="focus",Oi={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},Ii={allowList:fi,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',title:"",trigger:"hover focus"},Di={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class Ni extends W{constructor(t,e){if(void 0===i)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return Ii}static get DefaultType(){return Di}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ki),$i,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.eventName("show")),e=(u(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:s}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(s.append(i),j.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(Ti),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))j.on(t,"mouseover",_);this._queueCallback((()=>{j.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!j.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(Ti),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))j.off(t,"mouseover",_);this._activeTrigger.click=!1,this._activeTrigger[Li]=!1,this._activeTrigger[Si]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(Ci,Ti),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(Ci),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Ai({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(Ci)}_isShown(){return this.tip&&this.tip.classList.contains(Ti)}_createPopper(t){const e=v(this._config.placement,[this,t,this._element]),s=Oi[e.toUpperCase()];return i.createPopper(this._element,t,this._getPopperConfig(s))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return v(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...v(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)j.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===Si?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===Si?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");j.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?Li:Si]=!0,e._enter()})),j.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?Li:Si]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ki),$i,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=B.getDataAttributes(this._element);for(const t of Object.keys(e))Ei.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:c(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=Ni.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}b(Ni);const Pi={...Ni.Default,content:"",offset:[0,8],placement:"right",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>',trigger:"click"},xi={...Ni.DefaultType,content:"(null|string|element|function)"};class Mi extends Ni{static get Default(){return Pi}static get DefaultType(){return xi}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=Mi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}b(Mi);const ji=".bs.scrollspy",Fi=`activate${ji}`,zi=`click${ji}`,Hi=`load${ji}.data-api`,Bi="active",qi="[href]",Wi=".nav-link",Ri=`${Wi}, .nav-item > ${Wi}, .list-group-item`,Ki={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},Vi={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Qi extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return Ki}static get DefaultType(){return Vi}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=c(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(j.off(this._config.target,zi),j.on(this._config.target,zi,qi,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,s=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:s,behavior:"smooth"});i.scrollTop=s}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},s=(this._rootElement||document.documentElement).scrollTop,n=s>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=s;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(n&&t){if(i(o),!s)return}else n||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=K.find(qi,this._config.target);for(const e of t){if(!e.hash||d(e))continue;const t=K.findOne(decodeURI(e.hash),this._element);h(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(Bi),this._activateParents(t),j.trigger(this._element,Fi,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))K.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(Bi);else for(const e of K.parents(t,".nav, .list-group"))for(const t of K.prev(e,Ri))t.classList.add(Bi)}_clearActiveClass(t){t.classList.remove(Bi);const e=K.find(`${qi}.${Bi}`,t);for(const t of e)t.classList.remove(Bi)}static jQueryInterface(t){return this.each((function(){const e=Qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,Hi,(()=>{for(const t of K.find('[data-bs-spy="scroll"]'))Qi.getOrCreateInstance(t)})),b(Qi);const Xi=".bs.tab",Yi=`hide${Xi}`,Ui=`hidden${Xi}`,Gi=`show${Xi}`,Ji=`shown${Xi}`,Zi=`click${Xi}`,ts=`keydown${Xi}`,es=`load${Xi}`,is="ArrowLeft",ss="ArrowRight",ns="ArrowUp",os="ArrowDown",rs="Home",as="End",ls="active",cs="fade",hs="show",ds=".dropdown-toggle",us=`:not(${ds})`,_s='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',gs=`.nav-link${us}, .list-group-item${us}, [role="tab"]${us}, ${_s}`,fs=`.${ls}[data-bs-toggle="tab"], .${ls}[data-bs-toggle="pill"], .${ls}[data-bs-toggle="list"]`;class ms extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),j.on(this._element,ts,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?j.trigger(e,Yi,{relatedTarget:t}):null;j.trigger(t,Gi,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(ls),this._activate(K.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),j.trigger(t,Ji,{relatedTarget:e})):t.classList.add(hs)}),t,t.classList.contains(cs)))}_deactivate(t,e){t&&(t.classList.remove(ls),t.blur(),this._deactivate(K.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),j.trigger(t,Ui,{relatedTarget:e})):t.classList.remove(hs)}),t,t.classList.contains(cs)))}_keydown(t){if(![is,ss,ns,os,rs,as].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!d(t)));let i;if([rs,as].includes(t.key))i=e[t.key===rs?0:e.length-1];else{const s=[ss,os].includes(t.key);i=w(e,t.target,s,!0)}i&&(i.focus({preventScroll:!0}),ms.getOrCreateInstance(i).show())}_getChildren(){return K.find(gs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=K.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const s=(t,s)=>{const n=K.findOne(t,i);n&&n.classList.toggle(s,e)};s(ds,ls),s(".dropdown-menu",hs),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(ls)}_getInnerElement(t){return t.matches(gs)?t:K.findOne(gs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=ms.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,Zi,_s,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),d(this)||ms.getOrCreateInstance(this).show()})),j.on(window,es,(()=>{for(const t of K.find(fs))ms.getOrCreateInstance(t)})),b(ms);const ps=".bs.toast",bs=`mouseover${ps}`,vs=`mouseout${ps}`,ys=`focusin${ps}`,ws=`focusout${ps}`,As=`hide${ps}`,Es=`hidden${ps}`,Cs=`show${ps}`,Ts=`shown${ps}`,ks="hide",$s="show",Ss="showing",Ls={animation:"boolean",autohide:"boolean",delay:"number"},Os={animation:!0,autohide:!0,delay:5e3};class Is extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return Os}static get DefaultType(){return Ls}static get NAME(){return"toast"}show(){j.trigger(this._element,Cs).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(ks),g(this._element),this._element.classList.add($s,Ss),this._queueCallback((()=>{this._element.classList.remove(Ss),j.trigger(this._element,Ts),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(j.trigger(this._element,As).defaultPrevented||(this._element.classList.add(Ss),this._queueCallback((()=>{this._element.classList.add(ks),this._element.classList.remove(Ss,$s),j.trigger(this._element,Es)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove($s),super.dispose()}isShown(){return this._element.classList.contains($s)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,bs,(t=>this._onInteraction(t,!0))),j.on(this._element,vs,(t=>this._onInteraction(t,!1))),j.on(this._element,ys,(t=>this._onInteraction(t,!0))),j.on(this._element,ws,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Is.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return V(Is),b(Is),{Alert:U,Button:J,Carousel:Ot,Collapse:Rt,Dropdown:fe,Modal:Ue,Offcanvas:gi,Popover:Mi,ScrollSpy:Qi,Tab:ms,Toast:Is,Tooltip:Ni}})); +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e(t.Popper)}(this,function(t){"use strict";function e(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t)for(const i in t)if("default"!==i){const s=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,s.get?s:{enumerable:!0,get:()=>t[i]})}return e.default=t,Object.freeze(e)}const i=e(t),s=new Map,n={set(t,e,i){s.has(t)||s.set(t,new Map);const n=s.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>s.has(t)&&s.get(t).get(e)||null,remove(t,e){if(!s.has(t))return;const i=s.get(t);i.delete(e),0===i.size&&s.delete(t)}},o="transitionend",r=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,(t,e)=>`#${CSS.escape(e)}`)),t),a=t=>null==t?`${t}`:Object.prototype.toString.call(t).match(/\s([a-z]+)/i)[1].toLowerCase(),l=t=>{t.dispatchEvent(new Event(o))},c=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),h=t=>c(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(r(t)):null,d=t=>{if(!c(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},u=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),_=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?_(t.parentNode):null},g=()=>{},f=t=>{t.offsetHeight},m=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,p=[],b=()=>"rtl"===document.documentElement.dir,v=t=>{var e;e=()=>{const e=m();if(e){const i=t.NAME,s=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=s,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",()=>{for(const t of p)t()}),p.push(e)):e()},y=(t,e=[],i=t)=>"function"==typeof t?t.call(...e):i,w=(t,e,i=!0)=>{if(!i)return void y(t);const s=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const s=Number.parseFloat(e),n=Number.parseFloat(i);return s||n?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let n=!1;const r=({target:i})=>{i===e&&(n=!0,e.removeEventListener(o,r),y(t))};e.addEventListener(o,r),setTimeout(()=>{n||l(e)},s)},A=(t,e,i,s)=>{const n=t.length;let o=t.indexOf(e);return-1===o?!i&&s?t[n-1]:t[0]:(o+=i?1:-1,s&&(o=(o+n)%n),t[Math.max(0,Math.min(o,n-1))])},E=/[^.]*(?=\..*)\.|.*/,C=/\..*/,T=/::\d+$/,k={};let $=1;const S={mouseenter:"mouseover",mouseleave:"mouseout"},L=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${$++}`||t.uidEvent||$++}function I(t){const e=O(t);return t.uidEvent=e,k[e]=k[e]||{},k[e]}function D(t,e,i=null){return Object.values(t).find(t=>t.callable===e&&t.delegationSelector===i)}function N(t,e,i){const s="string"==typeof e,n=s?i:e||i;let o=j(t);return L.has(o)||(o=t),[s,n,o]}function P(t,e,i,s,n){if("string"!=typeof e||!t)return;let[o,r,a]=N(e,i,s);if(e in S){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=I(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&n);const d=O(r,e.replace(E,"")),u=o?function(t,e,i){return function s(n){const o=t.querySelectorAll(e);for(let{target:r}=n;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return z(n,{delegateTarget:r}),s.oneOff&&F.off(t,n.type,e,i),i.apply(r,[n])}}(t,i,r):function(t,e){return function i(s){return z(s,{delegateTarget:t}),i.oneOff&&F.off(t,s.type,e),e.apply(t,[s])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=n,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function x(t,e,i,s,n){const o=D(e[i],s,n);o&&(t.removeEventListener(i,o,Boolean(n)),delete e[i][o.uidEvent])}function M(t,e,i,s){const n=e[i]||{};for(const[o,r]of Object.entries(n))o.includes(s)&&x(t,e,i,r.callable,r.delegationSelector)}function j(t){return t=t.replace(C,""),S[t]||t}const F={on(t,e,i,s){P(t,e,i,s,!1)},one(t,e,i,s){P(t,e,i,s,!0)},off(t,e,i,s){if("string"!=typeof e||!t)return;const[n,o,r]=N(e,i,s),a=r!==e,l=I(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))M(t,l,i,e.slice(1));for(const[i,s]of Object.entries(c)){const n=i.replace(T,"");a&&!e.includes(n)||x(t,l,r,s.callable,s.delegationSelector)}}else{if(!Object.keys(c).length)return;x(t,l,r,o,n?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const s=m();let n=null,o=!0,r=!0,a=!1;e!==j(e)&&s&&(n=s.Event(e,i),s(t).trigger(n),o=!n.isPropagationStopped(),r=!n.isImmediatePropagationStopped(),a=n.isDefaultPrevented());const l=z(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&n&&n.preventDefault(),l}};function z(t,e={}){for(const[i,s]of Object.entries(e))try{t[i]=s}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>s})}return t}function H(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function B(t){return t.replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`)}const q={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${B(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${B(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter(t=>t.startsWith("bs")&&!t.startsWith("bsConfig"));for(const s of i){let i=s.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1),e[i]=H(t.dataset[s])}return e},getDataAttribute:(t,e)=>H(t.getAttribute(`data-bs-${B(e)}`))};class W{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=c(e)?q.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...c(e)?q.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[i,s]of Object.entries(e)){const e=t[i],n=c(e)?"element":a(e);if(!new RegExp(s).test(n))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${i}" provided type "${n}" but expected type "${s}".`)}}}class R extends W{constructor(t,e){super(),(t=h(t))&&(this._element=t,this._config=this._getConfig(e),n.set(this._element,this.constructor.DATA_KEY,this))}dispose(){n.remove(this._element,this.constructor.DATA_KEY),F.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){w(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return n.get(h(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.8"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const K=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map(t=>r(t)).join(","):null},V={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter(t=>t.matches(e)),parents(t,e){const i=[];let s=t.parentNode.closest(e);for(;s;)i.push(s),s=s.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map(t=>`${t}:not([tabindex^="-"])`).join(",");return this.find(e,t).filter(t=>!u(t)&&d(t))},getSelectorFromElement(t){const e=K(t);return e&&V.findOne(e)?e:null},getElementFromSelector(t){const e=K(t);return e?V.findOne(e):null},getMultipleElementsFromSelector(t){const e=K(t);return e?V.find(e):[]}},Q=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;F.on(document,i,`[data-bs-dismiss="${s}"]`,function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),u(this))return;const n=V.getElementFromSelector(this)||this.closest(`.${s}`);t.getOrCreateInstance(n)[e]()})},X=".bs.alert",Y=`close${X}`,U=`closed${X}`;class G extends R{static get NAME(){return"alert"}close(){if(F.trigger(this._element,Y).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback(()=>this._destroyElement(),this._element,t)}_destroyElement(){this._element.remove(),F.trigger(this._element,U),this.dispose()}static jQueryInterface(t){return this.each(function(){const e=G.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}})}}Q(G,"close"),v(G);const J='[data-bs-toggle="button"]';class Z extends R{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each(function(){const e=Z.getOrCreateInstance(this);"toggle"===t&&e[t]()})}}F.on(document,"click.bs.button.data-api",J,t=>{t.preventDefault();const e=t.target.closest(J);Z.getOrCreateInstance(e).toggle()}),v(Z);const tt=".bs.swipe",et=`touchstart${tt}`,it=`touchmove${tt}`,st=`touchend${tt}`,nt=`pointerdown${tt}`,ot=`pointerup${tt}`,rt={endCallback:null,leftCallback:null,rightCallback:null},at={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class lt extends W{constructor(t,e){super(),this._element=t,t&&lt.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return rt}static get DefaultType(){return at}static get NAME(){return"swipe"}dispose(){F.off(this._element,tt)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),y(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&y(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(F.on(this._element,nt,t=>this._start(t)),F.on(this._element,ot,t=>this._end(t)),this._element.classList.add("pointer-event")):(F.on(this._element,et,t=>this._start(t)),F.on(this._element,it,t=>this._move(t)),F.on(this._element,st,t=>this._end(t)))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ct=".bs.carousel",ht=".data-api",dt="ArrowLeft",ut="ArrowRight",_t="next",gt="prev",ft="left",mt="right",pt=`slide${ct}`,bt=`slid${ct}`,vt=`keydown${ct}`,yt=`mouseenter${ct}`,wt=`mouseleave${ct}`,At=`dragstart${ct}`,Et=`load${ct}${ht}`,Ct=`click${ct}${ht}`,Tt="carousel",kt="active",$t=".active",St=".carousel-item",Lt=$t+St,Ot={[dt]:mt,[ut]:ft},It={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Dt={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class Nt extends R{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===Tt&&this.cycle()}static get Default(){return It}static get DefaultType(){return Dt}static get NAME(){return"carousel"}next(){this._slide(_t)}nextWhenVisible(){!document.hidden&&d(this._element)&&this.next()}prev(){this._slide(gt)}pause(){this._isSliding&&l(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval(()=>this.nextWhenVisible(),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?F.one(this._element,bt,()=>this.cycle()):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void F.one(this._element,bt,()=>this.to(t));const i=this._getItemIndex(this._getActive());if(i===t)return;const s=t>i?_t:gt;this._slide(s,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&F.on(this._element,vt,t=>this._keydown(t)),"hover"===this._config.pause&&(F.on(this._element,yt,()=>this.pause()),F.on(this._element,wt,()=>this._maybeEnableCycle())),this._config.touch&&lt.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of V.find(".carousel-item img",this._element))F.on(t,At,t=>t.preventDefault());const t={leftCallback:()=>this._slide(this._directionToOrder(ft)),rightCallback:()=>this._slide(this._directionToOrder(mt)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout(()=>this._maybeEnableCycle(),500+this._config.interval))}};this._swipeHelper=new lt(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Ot[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=V.findOne($t,this._indicatorsElement);e.classList.remove(kt),e.removeAttribute("aria-current");const i=V.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(kt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),s=t===_t,n=e||A(this._getItems(),i,s,this._config.wrap);if(n===i)return;const o=this._getItemIndex(n),r=e=>F.trigger(this._element,e,{relatedTarget:n,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(pt).defaultPrevented)return;if(!i||!n)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=n;const l=s?"carousel-item-start":"carousel-item-end",c=s?"carousel-item-next":"carousel-item-prev";n.classList.add(c),f(n),i.classList.add(l),n.classList.add(l),this._queueCallback(()=>{n.classList.remove(l,c),n.classList.add(kt),i.classList.remove(kt,c,l),this._isSliding=!1,r(bt)},i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return V.findOne(Lt,this._element)}_getItems(){return V.find(St,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return b()?t===ft?gt:_t:t===ft?_t:gt}_orderToDirection(t){return b()?t===gt?ft:mt:t===gt?mt:ft}static jQueryInterface(t){return this.each(function(){const e=Nt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)})}}F.on(document,Ct,"[data-bs-slide], [data-bs-slide-to]",function(t){const e=V.getElementFromSelector(this);if(!e||!e.classList.contains(Tt))return;t.preventDefault();const i=Nt.getOrCreateInstance(e),s=this.getAttribute("data-bs-slide-to");return s?(i.to(s),void i._maybeEnableCycle()):"next"===q.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())}),F.on(window,Et,()=>{const t=V.find('[data-bs-ride="carousel"]');for(const e of t)Nt.getOrCreateInstance(e)}),v(Nt);const Pt=".bs.collapse",xt=`show${Pt}`,Mt=`shown${Pt}`,jt=`hide${Pt}`,Ft=`hidden${Pt}`,zt=`click${Pt}.data-api`,Ht="show",Bt="collapse",qt="collapsing",Wt=`:scope .${Bt} .${Bt}`,Rt='[data-bs-toggle="collapse"]',Kt={parent:null,toggle:!0},Vt={parent:"(null|element)",toggle:"boolean"};class Qt extends R{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=V.find(Rt);for(const t of i){const e=V.getSelectorFromElement(t),i=V.find(e).filter(t=>t===this._element);null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Kt}static get DefaultType(){return Vt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter(t=>t!==this._element).map(t=>Qt.getOrCreateInstance(t,{toggle:!1}))),t.length&&t[0]._isTransitioning)return;if(F.trigger(this._element,xt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Bt),this._element.classList.add(qt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback(()=>{this._isTransitioning=!1,this._element.classList.remove(qt),this._element.classList.add(Bt,Ht),this._element.style[e]="",F.trigger(this._element,Mt)},this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(F.trigger(this._element,jt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,f(this._element),this._element.classList.add(qt),this._element.classList.remove(Bt,Ht);for(const t of this._triggerArray){const e=V.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback(()=>{this._isTransitioning=!1,this._element.classList.remove(qt),this._element.classList.add(Bt),F.trigger(this._element,Ft)},this._element,!0)}_isShown(t=this._element){return t.classList.contains(Ht)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=h(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Rt);for(const e of t){const t=V.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=V.find(Wt,this._config.parent);return V.find(t,this._config.parent).filter(t=>!e.includes(t))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each(function(){const i=Qt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}})}}F.on(document,zt,Rt,function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of V.getMultipleElementsFromSelector(this))Qt.getOrCreateInstance(t,{toggle:!1}).toggle()}),v(Qt);const Xt="dropdown",Yt=".bs.dropdown",Ut=".data-api",Gt="ArrowUp",Jt="ArrowDown",Zt=`hide${Yt}`,te=`hidden${Yt}`,ee=`show${Yt}`,ie=`shown${Yt}`,se=`click${Yt}${Ut}`,ne=`keydown${Yt}${Ut}`,oe=`keyup${Yt}${Ut}`,re="show",ae='[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)',le=`${ae}.${re}`,ce=".dropdown-menu",he=b()?"top-end":"top-start",de=b()?"top-start":"top-end",ue=b()?"bottom-end":"bottom-start",_e=b()?"bottom-start":"bottom-end",ge=b()?"left-start":"right-start",fe=b()?"right-start":"left-start",me={autoClose:!0,boundary:"clippingParents",display:"dynamic",offset:[0,2],popperConfig:null,reference:"toggle"},pe={autoClose:"(boolean|string)",boundary:"(string|element)",display:"string",offset:"(array|string|function)",popperConfig:"(null|object|function)",reference:"(string|element|object)"};class be extends R{constructor(t,e){super(t,e),this._popper=null,this._parent=this._element.parentNode,this._menu=V.next(this._element,ce)[0]||V.prev(this._element,ce)[0]||V.findOne(ce,this._parent),this._inNavbar=this._detectNavbar()}static get Default(){return me}static get DefaultType(){return pe}static get NAME(){return Xt}toggle(){return this._isShown()?this.hide():this.show()}show(){if(u(this._element)||this._isShown())return;const t={relatedTarget:this._element};if(!F.trigger(this._element,ee,t).defaultPrevented){if(this._createPopper(),"ontouchstart"in document.documentElement&&!this._parent.closest(".navbar-nav"))for(const t of[].concat(...document.body.children))F.on(t,"mouseover",g);this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(re),this._element.classList.add(re),F.trigger(this._element,ie,t)}}hide(){if(u(this._element)||!this._isShown())return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){if(!F.trigger(this._element,Zt,t).defaultPrevented){if("ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))F.off(t,"mouseover",g);this._popper&&this._popper.destroy(),this._menu.classList.remove(re),this._element.classList.remove(re),this._element.setAttribute("aria-expanded","false"),q.removeDataAttribute(this._menu,"popper"),F.trigger(this._element,te,t)}}_getConfig(t){if("object"==typeof(t=super._getConfig(t)).reference&&!c(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Xt.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(){if(void 0===i)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org/docs/v2/)");let t=this._element;"parent"===this._config.reference?t=this._parent:c(this._config.reference)?t=h(this._config.reference):"object"==typeof this._config.reference&&(t=this._config.reference);const e=this._getPopperConfig();this._popper=i.createPopper(t,this._menu,e)}_isShown(){return this._menu.classList.contains(re)}_getPlacement(){const t=this._parent;if(t.classList.contains("dropend"))return ge;if(t.classList.contains("dropstart"))return fe;if(t.classList.contains("dropup-center"))return"top";if(t.classList.contains("dropdown-center"))return"bottom";const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?de:he:e?_e:ue}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(q.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...y(this._config.popperConfig,[void 0,t])}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(t=>d(t));i.length&&A(i,e,t===Jt,!i.includes(e)).focus()}static jQueryInterface(t){return this.each(function(){const e=be.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}})}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=V.find(le);for(const i of e){const e=be.getInstance(i);if(!e||!1===e._config.autoClose)continue;const s=t.composedPath(),n=s.includes(e._menu);if(s.includes(e._element)||"inside"===e._config.autoClose&&!n||"outside"===e._config.autoClose&&n)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,s=[Gt,Jt].includes(t.key);if(!s&&!i)return;if(e&&!i)return;t.preventDefault();const n=this.matches(ae)?this:V.prev(this,ae)[0]||V.next(this,ae)[0]||V.findOne(ae,t.delegateTarget.parentNode),o=be.getOrCreateInstance(n);if(s)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),n.focus())}}F.on(document,ne,ae,be.dataApiKeydownHandler),F.on(document,ne,ce,be.dataApiKeydownHandler),F.on(document,se,be.clearMenus),F.on(document,oe,be.clearMenus),F.on(document,se,ae,function(t){t.preventDefault(),be.getOrCreateInstance(this).toggle()}),v(be);const ve="backdrop",ye="show",we=`mousedown.bs.${ve}`,Ae={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Ee={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ce extends W{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Ae}static get DefaultType(){return Ee}static get NAME(){return ve}show(t){if(!this._config.isVisible)return void y(t);this._append();const e=this._getElement();this._config.isAnimated&&f(e),e.classList.add(ye),this._emulateAnimation(()=>{y(t)})}hide(t){this._config.isVisible?(this._getElement().classList.remove(ye),this._emulateAnimation(()=>{this.dispose(),y(t)})):y(t)}dispose(){this._isAppended&&(F.off(this._element,we),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=h(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),F.on(t,we,()=>{y(this._config.clickCallback)}),this._isAppended=!0}_emulateAnimation(t){w(t,this._getElement(),this._config.isAnimated)}}const Te=".bs.focustrap",ke=`focusin${Te}`,$e=`keydown.tab${Te}`,Se="backward",Le={autofocus:!0,trapElement:null},Oe={autofocus:"boolean",trapElement:"element"};class Ie extends W{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return Le}static get DefaultType(){return Oe}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),F.off(document,Te),F.on(document,ke,t=>this._handleFocusin(t)),F.on(document,$e,t=>this._handleKeydown(t)),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,F.off(document,Te))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=V.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===Se?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Se:"forward")}}const De=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",Ne=".sticky-top",Pe="padding-right",xe="margin-right";class Me{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,Pe,e=>e+t),this._setElementAttributes(De,Pe,e=>e+t),this._setElementAttributes(Ne,xe,e=>e-t)}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,Pe),this._resetElementAttributes(De,Pe),this._resetElementAttributes(Ne,xe)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const s=this.getWidth();this._applyManipulationCallback(t,t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+s)return;this._saveInitialAttribute(t,e);const n=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(n))}px`)})}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&q.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,t=>{const i=q.getDataAttribute(t,e);null!==i?(q.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)})}_applyManipulationCallback(t,e){if(c(t))e(t);else for(const i of V.find(t,this._element))e(i)}}const je=".bs.modal",Fe=`hide${je}`,ze=`hidePrevented${je}`,He=`hidden${je}`,Be=`show${je}`,qe=`shown${je}`,We=`resize${je}`,Re=`click.dismiss${je}`,Ke=`mousedown.dismiss${je}`,Ve=`keydown.dismiss${je}`,Qe=`click${je}.data-api`,Xe="modal-open",Ye="show",Ue="modal-static",Ge={backdrop:!0,focus:!0,keyboard:!0},Je={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class Ze extends R{constructor(t,e){super(t,e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new Me,this._addEventListeners()}static get Default(){return Ge}static get DefaultType(){return Je}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||F.trigger(this._element,Be,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Xe),this._adjustDialog(),this._backdrop.show(()=>this._showElement(t)))}hide(){this._isShown&&!this._isTransitioning&&(F.trigger(this._element,Fe).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(Ye),this._queueCallback(()=>this._hideModal(),this._element,this._isAnimated())))}dispose(){F.off(window,je),F.off(this._dialog,je),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ce({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ie({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=V.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),f(this._element),this._element.classList.add(Ye),this._queueCallback(()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,F.trigger(this._element,qe,{relatedTarget:t})},this._dialog,this._isAnimated())}_addEventListeners(){F.on(this._element,Ve,t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())}),F.on(window,We,()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()}),F.on(this._element,Ke,t=>{F.one(this._element,Re,e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())})})}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide(()=>{document.body.classList.remove(Xe),this._resetAdjustments(),this._scrollBar.reset(),F.trigger(this._element,He)})}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(F.trigger(this._element,ze).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(Ue)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(Ue),this._queueCallback(()=>{this._element.classList.remove(Ue),this._queueCallback(()=>{this._element.style.overflowY=e},this._dialog)},this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=b()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=b()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each(function(){const i=Ze.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}})}}F.on(document,Qe,'[data-bs-toggle="modal"]',function(t){const e=V.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),F.one(e,Be,t=>{t.defaultPrevented||F.one(e,He,()=>{d(this)&&this.focus()})});const i=V.findOne(".modal.show");i&&Ze.getInstance(i).hide(),Ze.getOrCreateInstance(e).toggle(this)}),Q(Ze),v(Ze);const ti=".bs.offcanvas",ei=".data-api",ii=`load${ti}${ei}`,si="show",ni="showing",oi="hiding",ri=".offcanvas.show",ai=`show${ti}`,li=`shown${ti}`,ci=`hide${ti}`,hi=`hidePrevented${ti}`,di=`hidden${ti}`,ui=`resize${ti}`,_i=`click${ti}${ei}`,gi=`keydown.dismiss${ti}`,fi={backdrop:!0,keyboard:!0,scroll:!1},mi={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class pi extends R{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return fi}static get DefaultType(){return mi}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||F.trigger(this._element,ai,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new Me).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(ni),this._queueCallback(()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(si),this._element.classList.remove(ni),F.trigger(this._element,li,{relatedTarget:t})},this._element,!0))}hide(){this._isShown&&(F.trigger(this._element,ci).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(oi),this._backdrop.hide(),this._queueCallback(()=>{this._element.classList.remove(si,oi),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new Me).reset(),F.trigger(this._element,di)},this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ce({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():F.trigger(this._element,hi)}:null})}_initializeFocusTrap(){return new Ie({trapElement:this._element})}_addEventListeners(){F.on(this._element,gi,t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():F.trigger(this._element,hi))})}static jQueryInterface(t){return this.each(function(){const e=pi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}})}}F.on(document,_i,'[data-bs-toggle="offcanvas"]',function(t){const e=V.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),u(this))return;F.one(e,di,()=>{d(this)&&this.focus()});const i=V.findOne(ri);i&&i!==e&&pi.getInstance(i).hide(),pi.getOrCreateInstance(e).toggle(this)}),F.on(window,ii,()=>{for(const t of V.find(ri))pi.getOrCreateInstance(t).show()}),F.on(window,ui,()=>{for(const t of V.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&pi.getOrCreateInstance(t).hide()}),Q(pi),v(pi);const bi={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},vi=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),yi=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,wi=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!vi.has(i)||Boolean(yi.test(t.nodeValue)):e.filter(t=>t instanceof RegExp).some(t=>t.test(i))},Ai={allowList:bi,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"<div></div>"},Ei={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Ci={entry:"(string|element|function|null)",selector:"(string|element)"};class Ti extends W{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Ai}static get DefaultType(){return Ei}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map(t=>this._resolvePossibleFunction(t)).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Ci)}_setContent(t,e,i){const s=V.findOne(i,t);s&&((e=this._resolvePossibleFunction(e))?c(e)?this._putElementInTemplate(h(e),s):this._config.html?s.innerHTML=this._maybeSanitize(e):s.textContent=e:s.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const s=(new window.DOMParser).parseFromString(t,"text/html"),n=[].concat(...s.body.querySelectorAll("*"));for(const t of n){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const s=[].concat(...t.attributes),n=[].concat(e["*"]||[],e[i]||[]);for(const e of s)wi(e,n)||t.removeAttribute(e.nodeName)}return s.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return y(t,[void 0,this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const ki=new Set(["sanitize","allowList","sanitizeFn"]),$i="fade",Si="show",Li=".tooltip-inner",Oi=".modal",Ii="hide.bs.modal",Di="hover",Ni="focus",Pi="click",xi={AUTO:"auto",TOP:"top",RIGHT:b()?"left":"right",BOTTOM:"bottom",LEFT:b()?"right":"left"},Mi={allowList:bi,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',title:"",trigger:"hover focus"},ji={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class Fi extends R{constructor(t,e){if(void 0===i)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org/docs/v2/)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return Mi}static get DefaultType(){return ji}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),F.off(this._element.closest(Oi),Ii,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=F.trigger(this._element,this.constructor.eventName("show")),e=(_(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:s}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(s.append(i),F.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(Si),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))F.on(t,"mouseover",g);this._queueCallback(()=>{F.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1},this.tip,this._isAnimated())}hide(){if(this._isShown()&&!F.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(Si),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))F.off(t,"mouseover",g);this._activeTrigger[Pi]=!1,this._activeTrigger[Ni]=!1,this._activeTrigger[Di]=!1,this._isHovered=null,this._queueCallback(()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),F.trigger(this._element,this.constructor.eventName("hidden")))},this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove($i,Si),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add($i),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Ti({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{[Li]:this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains($i)}_isShown(){return this.tip&&this.tip.classList.contains(Si)}_createPopper(t){const e=y(this._config.placement,[this,t,this._element]),s=xi[e.toUpperCase()];return i.createPopper(this._element,t,this._getPopperConfig(s))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return y(t,[this._element,this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...y(this._config.popperConfig,[void 0,e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)F.on(this._element,this.constructor.eventName("click"),this._config.selector,t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger[Pi]=!(e._isShown()&&e._activeTrigger[Pi]),e.toggle()});else if("manual"!==e){const t=e===Di?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===Di?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");F.on(this._element,t,this._config.selector,t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?Ni:Di]=!0,e._enter()}),F.on(this._element,i,this._config.selector,t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?Ni:Di]=e._element.contains(t.relatedTarget),e._leave()})}this._hideModalHandler=()=>{this._element&&this.hide()},F.on(this._element.closest(Oi),Ii,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout(()=>{this._isHovered&&this.show()},this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout(()=>{this._isHovered||this.hide()},this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=q.getDataAttributes(this._element);for(const t of Object.keys(e))ki.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:h(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each(function(){const e=Fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}})}}v(Fi);const zi=".popover-header",Hi=".popover-body",Bi={...Fi.Default,content:"",offset:[0,8],placement:"right",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>',trigger:"click"},qi={...Fi.DefaultType,content:"(null|string|element|function)"};class Wi extends Fi{static get Default(){return Bi}static get DefaultType(){return qi}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{[zi]:this._getTitle(),[Hi]:this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each(function(){const e=Wi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}})}}v(Wi);const Ri=".bs.scrollspy",Ki=`activate${Ri}`,Vi=`click${Ri}`,Qi=`load${Ri}.data-api`,Xi="active",Yi="[href]",Ui=".nav-link",Gi=`${Ui}, .nav-item > ${Ui}, .list-group-item`,Ji={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},Zi={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class ts extends R{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return Ji}static get DefaultType(){return Zi}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=h(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map(t=>Number.parseFloat(t))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(F.off(this._config.target,Vi),F.on(this._config.target,Vi,Yi,t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,s=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:s,behavior:"smooth"});i.scrollTop=s}}))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver(t=>this._observerCallback(t),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},s=(this._rootElement||document.documentElement).scrollTop,n=s>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=s;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(n&&t){if(i(o),!s)return}else n||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=V.find(Yi,this._config.target);for(const e of t){if(!e.hash||u(e))continue;const t=V.findOne(decodeURI(e.hash),this._element);d(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(Xi),this._activateParents(t),F.trigger(this._element,Ki,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))V.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(Xi);else for(const e of V.parents(t,".nav, .list-group"))for(const t of V.prev(e,Gi))t.classList.add(Xi)}_clearActiveClass(t){t.classList.remove(Xi);const e=V.find(`${Yi}.${Xi}`,t);for(const t of e)t.classList.remove(Xi)}static jQueryInterface(t){return this.each(function(){const e=ts.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}})}}F.on(window,Qi,()=>{for(const t of V.find('[data-bs-spy="scroll"]'))ts.getOrCreateInstance(t)}),v(ts);const es=".bs.tab",is=`hide${es}`,ss=`hidden${es}`,ns=`show${es}`,os=`shown${es}`,rs=`click${es}`,as=`keydown${es}`,ls=`load${es}`,cs="ArrowLeft",hs="ArrowRight",ds="ArrowUp",us="ArrowDown",_s="Home",gs="End",fs="active",ms="fade",ps="show",bs=".dropdown-toggle",vs=`:not(${bs})`,ys='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',ws=`.nav-link${vs}, .list-group-item${vs}, [role="tab"]${vs}, ${ys}`,As=`.${fs}[data-bs-toggle="tab"], .${fs}[data-bs-toggle="pill"], .${fs}[data-bs-toggle="list"]`;class Es extends R{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),F.on(this._element,as,t=>this._keydown(t)))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?F.trigger(e,is,{relatedTarget:t}):null;F.trigger(t,ns,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(fs),this._activate(V.getElementFromSelector(t)),this._queueCallback(()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),F.trigger(t,os,{relatedTarget:e})):t.classList.add(ps)},t,t.classList.contains(ms)))}_deactivate(t,e){t&&(t.classList.remove(fs),t.blur(),this._deactivate(V.getElementFromSelector(t)),this._queueCallback(()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),F.trigger(t,ss,{relatedTarget:e})):t.classList.remove(ps)},t,t.classList.contains(ms)))}_keydown(t){if(![cs,hs,ds,us,_s,gs].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter(t=>!u(t));let i;if([_s,gs].includes(t.key))i=e[t.key===_s?0:e.length-1];else{const s=[hs,us].includes(t.key);i=A(e,t.target,s,!0)}i&&(i.focus({preventScroll:!0}),Es.getOrCreateInstance(i).show())}_getChildren(){return V.find(ws,this._parent)}_getActiveElem(){return this._getChildren().find(t=>this._elemIsActive(t))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=V.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const s=(t,s)=>{const n=V.findOne(t,i);n&&n.classList.toggle(s,e)};s(bs,fs),s(".dropdown-menu",ps),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(fs)}_getInnerElement(t){return t.matches(ws)?t:V.findOne(ws,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each(function(){const e=Es.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}})}}F.on(document,rs,ys,function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),u(this)||Es.getOrCreateInstance(this).show()}),F.on(window,ls,()=>{for(const t of V.find(As))Es.getOrCreateInstance(t)}),v(Es);const Cs=".bs.toast",Ts=`mouseover${Cs}`,ks=`mouseout${Cs}`,$s=`focusin${Cs}`,Ss=`focusout${Cs}`,Ls=`hide${Cs}`,Os=`hidden${Cs}`,Is=`show${Cs}`,Ds=`shown${Cs}`,Ns="hide",Ps="show",xs="showing",Ms={animation:"boolean",autohide:"boolean",delay:"number"},js={animation:!0,autohide:!0,delay:5e3};class Fs extends R{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return js}static get DefaultType(){return Ms}static get NAME(){return"toast"}show(){F.trigger(this._element,Is).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Ns),f(this._element),this._element.classList.add(Ps,xs),this._queueCallback(()=>{this._element.classList.remove(xs),F.trigger(this._element,Ds),this._maybeScheduleHide()},this._element,this._config.animation))}hide(){this.isShown()&&(F.trigger(this._element,Ls).defaultPrevented||(this._element.classList.add(xs),this._queueCallback(()=>{this._element.classList.add(Ns),this._element.classList.remove(xs,Ps),F.trigger(this._element,Os)},this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(Ps),super.dispose()}isShown(){return this._element.classList.contains(Ps)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout(()=>{this.hide()},this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){F.on(this._element,Ts,t=>this._onInteraction(t,!0)),F.on(this._element,ks,t=>this._onInteraction(t,!1)),F.on(this._element,$s,t=>this._onInteraction(t,!0)),F.on(this._element,Ss,t=>this._onInteraction(t,!1))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each(function(){const e=Fs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}})}}return Q(Fs),v(Fs),{Alert:G,Button:Z,Carousel:Nt,Collapse:Qt,Dropdown:be,Modal:Ze,Offcanvas:pi,Popover:Wi,ScrollSpy:ts,Tab:Es,Toast:Fs,Tooltip:Fi}}); //# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.min.js.map b/extensions/pagetop-bootsier/static/js/bootstrap.min.js.map index 4d437152..df4b8491 100644 --- a/extensions/pagetop-bootsier/static/js/bootstrap.min.js.map +++ b/extensions/pagetop-bootsier/static/js/bootstrap.min.js.map @@ -1 +1 @@ -{"version":3,"names":["elementMap","Map","Data","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete","TRANSITION_END","parseSelector","selector","window","CSS","escape","replace","match","id","triggerTransitionEnd","dispatchEvent","Event","isElement","object","jquery","nodeType","getElement","length","document","querySelector","isVisible","getClientRects","elementIsVisible","getComputedStyle","getPropertyValue","closedDetails","closest","summary","parentNode","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","getAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","noop","reflow","offsetHeight","getjQuery","jQuery","body","DOMContentLoadedCallbacks","isRTL","dir","defineJQueryPlugin","plugin","callback","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","readyState","addEventListener","push","execute","possibleCallback","args","defaultValue","executeAfterTransition","transitionElement","waitForTransition","emulatedDuration","transitionDuration","transitionDelay","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","split","getTransitionDurationFromElement","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","listLength","index","indexOf","Math","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","nativeEvents","Set","makeEventUid","uid","getElementEvents","findHandler","events","callable","delegationSelector","Object","values","find","event","normalizeParameters","originalTypeEvent","delegationFunction","isDelegated","typeEvent","getTypeEvent","addHandler","oneOff","wrapFunction","relatedTarget","delegateTarget","call","this","handlers","previousFunction","domElements","querySelectorAll","domElement","hydrateObj","EventHandler","off","type","apply","bootstrapDelegationHandler","bootstrapHandler","removeHandler","Boolean","removeNamespacedHandlers","namespace","storeElementEvent","handlerKey","entries","includes","on","one","inNamespace","isNamespace","startsWith","elementEvent","slice","keyHandlers","trigger","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","evt","cancelable","preventDefault","obj","meta","value","_unused","defineProperty","configurable","normalizeData","toString","JSON","parse","decodeURIComponent","normalizeDataKey","chr","toLowerCase","Manipulator","setDataAttribute","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","dataset","filter","pureKey","charAt","getDataAttribute","Config","Default","DefaultType","Error","_getConfig","config","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","jsonConfig","constructor","configTypes","property","expectedTypes","valueType","prototype","RegExp","test","TypeError","toUpperCase","BaseComponent","super","_element","_config","DATA_KEY","dispose","EVENT_KEY","propertyName","getOwnPropertyNames","_queueCallback","isAnimated","getInstance","getOrCreateInstance","VERSION","eventName","getSelector","hrefAttribute","trim","map","sel","join","SelectorEngine","concat","Element","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","el","getSelectorFromElement","getElementFromSelector","getMultipleElementsFromSelector","enableDismissTrigger","component","method","clickEvent","tagName","EVENT_CLOSE","EVENT_CLOSED","Alert","close","_destroyElement","each","data","undefined","SELECTOR_DATA_TOGGLE","Button","toggle","button","EVENT_TOUCHSTART","EVENT_TOUCHMOVE","EVENT_TOUCHEND","EVENT_POINTERDOWN","EVENT_POINTERUP","endCallback","leftCallback","rightCallback","Swipe","isSupported","_deltaX","_supportPointerEvents","PointerEvent","_initEvents","_start","_eventIsPointerPenTouch","clientX","touches","_end","_handleSwipe","_move","absDeltaX","abs","direction","add","pointerType","navigator","maxTouchPoints","DATA_API_KEY","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","EVENT_SLIDE","EVENT_SLID","EVENT_KEYDOWN","EVENT_MOUSEENTER","EVENT_MOUSELEAVE","EVENT_DRAG_START","EVENT_LOAD_DATA_API","EVENT_CLICK_DATA_API","CLASS_NAME_CAROUSEL","CLASS_NAME_ACTIVE","SELECTOR_ACTIVE","SELECTOR_ITEM","SELECTOR_ACTIVE_ITEM","KEY_TO_DIRECTION","ArrowLeft","ArrowRight","interval","keyboard","pause","ride","touch","wrap","Carousel","_interval","_activeElement","_isSliding","touchTimeout","_swipeHelper","_indicatorsElement","_addEventListeners","cycle","_slide","nextWhenVisible","hidden","_clearInterval","_updateInterval","setInterval","_maybeEnableCycle","to","items","_getItems","activeIndex","_getItemIndex","_getActive","order","defaultInterval","_keydown","_addTouchEventListeners","img","swipeConfig","_directionToOrder","endCallBack","clearTimeout","_setActiveIndicatorElement","activeIndicator","newActiveIndicator","elementInterval","parseInt","isNext","nextElement","nextElementIndex","triggerEvent","_orderToDirection","isCycling","directionalClassName","orderClassName","completeCallBack","_isAnimated","clearInterval","carousel","slideIndex","carousels","EVENT_SHOW","EVENT_SHOWN","EVENT_HIDE","EVENT_HIDDEN","CLASS_NAME_SHOW","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_DEEPER_CHILDREN","parent","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElement","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activeChildren","_getFirstLevelChildren","activeInstance","dimension","_getDimension","style","scrollSize","complete","getBoundingClientRect","selected","triggerArray","isOpen","ARROW_UP_KEY","ARROW_DOWN_KEY","EVENT_KEYDOWN_DATA_API","EVENT_KEYUP_DATA_API","SELECTOR_DATA_TOGGLE_SHOWN","SELECTOR_MENU","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","autoClose","boundary","display","offset","popperConfig","reference","Dropdown","_popper","_parent","_menu","_inNavbar","_detectNavbar","_createPopper","focus","_completeHide","destroy","update","Popper","referenceElement","_getPopperConfig","createPopper","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","placement","modifiers","options","enabled","_selectMenuItem","clearMenus","openToggles","context","composedPath","isMenuTarget","dataApiKeydownHandler","isInput","isEscapeEvent","isUpOrDownEvent","getToggleButton","stopPropagation","EVENT_MOUSEDOWN","className","clickCallback","rootElement","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","EVENT_FOCUSIN","EVENT_KEYDOWN_TAB","TAB_NAV_BACKWARD","autofocus","trapElement","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","elements","shiftKey","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","PROPERTY_PADDING","PROPERTY_MARGIN","ScrollBarHelper","getWidth","documentWidth","clientWidth","innerWidth","width","_disableOverFlow","_setElementAttributes","calculatedValue","reset","_resetElementAttributes","isOverflowing","_saveInitialAttribute","overflow","styleProperty","scrollbarWidth","_applyManipulationCallback","setProperty","actualValue","removeProperty","callBack","EVENT_HIDE_PREVENTED","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_MOUSEDOWN_DISMISS","EVENT_KEYDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_scrollBar","_adjustDialog","_showElement","_hideModal","handleUpdate","scrollTop","modalBody","transitionComplete","_triggerBackdropTransition","event2","_resetAdjustments","isModalOverflowing","scrollHeight","clientHeight","initialOverflowY","overflowY","isBodyOverflowing","paddingLeft","paddingRight","showEvent","alreadyOpen","CLASS_NAME_SHOWING","CLASS_NAME_HIDING","OPEN_SELECTOR","scroll","Offcanvas","blur","completeCallback","position","DefaultAllowlist","a","area","b","br","col","code","dd","div","dl","dt","em","hr","h1","h2","h3","h4","h5","h6","i","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","uriAttributes","SAFE_URL_PATTERN","allowedAttribute","attribute","allowedAttributeList","attributeName","nodeName","nodeValue","attributeRegex","some","regex","allowList","content","extraClass","html","sanitize","sanitizeFn","template","DefaultContentType","entry","TemplateFactory","getContent","_resolvePossibleFunction","hasContent","changeContent","_checkContent","toHtml","templateWrapper","innerHTML","_maybeSanitize","text","_setContent","arg","templateElement","_putElementInTemplate","textContent","unsafeHtml","sanitizeFunction","createdDocument","DOMParser","parseFromString","elementName","attributeList","allowedAttributes","sanitizeHtml","DISALLOWED_ATTRIBUTES","CLASS_NAME_FADE","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","animation","container","customClass","delay","fallbackPlacements","title","Tooltip","_isEnabled","_timeout","_isHovered","_activeTrigger","_templateFactory","_newContent","tip","_setListeners","_fixTitle","enable","disable","toggleEnabled","click","_leave","_enter","_hideModalHandler","_disposePopper","_isWithContent","isInTheDom","ownerDocument","_getTipElement","_isWithActiveTrigger","_getTitle","_createTipElement","_getContentForTemplate","_getTemplateFactory","tipId","prefix","floor","random","getElementById","getUID","setContent","_initializeOnDelegatedTarget","_getDelegateConfig","attachment","phase","state","triggers","eventIn","eventOut","_setTimeout","timeout","dataAttributes","dataAttribute","Popover","_getContent","EVENT_ACTIVATE","EVENT_CLICK","SELECTOR_TARGET_LINKS","SELECTOR_NAV_LINKS","SELECTOR_LINK_ITEMS","rootMargin","smoothScroll","threshold","ScrollSpy","_targetLinks","_observableSections","_rootElement","_activeTarget","_observer","_previousScrollData","visibleEntryTop","parentScrollTop","refresh","_initializeTargetsAndObservables","_maybeEnableSmoothScroll","disconnect","_getNewObserver","section","observe","observableSection","hash","height","offsetTop","scrollTo","top","behavior","IntersectionObserver","_observerCallback","targetElement","_process","userScrollsDown","isIntersecting","_clearActiveClass","entryIsLowerThanPrevious","targetLinks","anchor","decodeURI","_activateParents","listGroup","item","activeNodes","node","spy","ARROW_LEFT_KEY","ARROW_RIGHT_KEY","HOME_KEY","END_KEY","SELECTOR_DROPDOWN_TOGGLE","NOT_SELECTOR_DROPDOWN_TOGGLE","SELECTOR_INNER_ELEM","SELECTOR_DATA_TOGGLE_ACTIVE","Tab","_setInitialAttributes","_getChildren","innerElem","_elemIsActive","active","_getActiveElem","hideEvent","_deactivate","_activate","relatedElem","_toggleDropDown","nextActiveElement","preventScroll","_setAttributeIfNotExists","_setInitialAttributesOnChild","_getInnerElement","isActive","outerElem","_getOuterElement","_setInitialAttributesOnTargetPanel","open","EVENT_MOUSEOVER","EVENT_MOUSEOUT","EVENT_FOCUSOUT","CLASS_NAME_HIDE","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","isShown","_onInteraction","isInteracting"],"sources":["../../js/src/dom/data.js","../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/manipulator.js","../../js/src/util/config.js","../../js/src/base-component.js","../../js/src/dom/selector-engine.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/util/swipe.js","../../js/src/carousel.js","../../js/src/collapse.js","../../js/src/dropdown.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/util/scrollbar.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/util/template-factory.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1_000_000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`)\n }\n\n return selector\n}\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`\n }\n\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = object => {\n if (!object || typeof object !== 'object') {\n return false\n }\n\n if (typeof object.jquery !== 'undefined') {\n object = object[0]\n }\n\n return typeof object.nodeType !== 'undefined'\n}\n\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (isElement(object)) {\n return object.jquery ? object[0] : object\n }\n\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object))\n }\n\n return null\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])')\n\n if (!closedDetails) {\n return elementIsVisible\n }\n\n if (closedDetails !== element) {\n const summary = element.closest('summary')\n if (summary && summary.parentNode !== closedDetails) {\n return false\n }\n\n if (summary === null) {\n return false\n }\n }\n\n return elementIsVisible\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight // eslint-disable-line no-unused-expressions\n}\n\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback()\n }\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]\n }\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n defineJQueryPlugin,\n execute,\n executeAfterTransition,\n findShadowRoot,\n getElement,\n getjQuery,\n getNextActiveElement,\n getTransitionDurationFromElement,\n getUID,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n onDOMContentLoaded,\n parseSelector,\n reflow,\n triggerTransitionEnd,\n toType\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index.js'\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\n\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getElementEvents(element) {\n const uid = makeEventUid(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, { delegateTarget: element })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue\n }\n\n hydrateObj(event, { delegateTarget: target })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n}\n\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events)\n .find(event => event.callable === callable && event.delegationSelector === delegationSelector)\n}\n\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string'\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : (handler || delegationFunction)\n let typeEvent = getTypeEvent(originalTypeEvent)\n\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent\n }\n\n return [isDelegated, callable, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n callable = wrapFunction(callable)\n }\n\n const events = getElementEvents(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)\n\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff\n\n return\n }\n\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = isDelegated ?\n bootstrapDelegationHandler(element, handler, callable) :\n bootstrapHandler(element, callable)\n\n fn.delegationSelector = isDelegated ? handler : null\n fn.callable = callable\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, isDelegated)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false)\n },\n\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getElementEvents(element)\n const storeElementEvent = events[typeEvent] || {}\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return\n }\n\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)\n return\n }\n\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n }\n }\n\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n\n let jQueryEvent = null\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value\n } catch {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value\n }\n })\n }\n }\n\n return obj\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true\n }\n\n if (value === 'false') {\n return false\n }\n\n if (value === Number(value).toString()) {\n return Number(value)\n }\n\n if (value === '' || value === 'null') {\n return null\n }\n\n if (typeof value !== 'string') {\n return value\n }\n\n try {\n return JSON.parse(decodeURIComponent(value))\n } catch {\n return value\n }\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))\n\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)\n attributes[pureKey] = normalizeData(element.dataset[key])\n }\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport { isElement, toType } from './index.js'\n\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {}\n }\n\n static get DefaultType() {\n return {}\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n return config\n }\n\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n }\n }\n\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property]\n const valueType = isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n }\n }\n}\n\nexport default Config\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data.js'\nimport EventHandler from './dom/event-handler.js'\nimport Config from './util/config.js'\nimport { executeAfterTransition, getElement } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.3'\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super()\n\n element = getElement(element)\n if (!element) {\n return\n }\n\n this._element = element\n this._config = this._getConfig(config)\n\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null\n }\n }\n\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible, parseSelector } from '../util/index.js'\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`\n }\n\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null\n }\n\n return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null\n}\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n let ancestor = element.parentNode.closest(selector)\n\n while (ancestor) {\n parents.push(ancestor)\n ancestor = ancestor.parentNode.closest(selector)\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n },\n\n getSelectorFromElement(element) {\n const selector = getSelector(element)\n\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null\n }\n\n return null\n },\n\n getElementFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.findOne(selector) : null\n },\n\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.find(selector) : []\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isDisabled } from './index.js'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport { execute } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'swipe'\nconst EVENT_KEY = '.bs.swipe'\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n}\n\nconst DefaultType = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n}\n\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super()\n this._element = element\n\n if (!element || !Swipe.isSupported()) {\n return\n }\n\n this._config = this._getConfig(config)\n this._deltaX = 0\n this._supportPointerEvents = Boolean(window.PointerEvent)\n this._initEvents()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY)\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX\n\n return\n }\n\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX\n }\n }\n\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX\n }\n\n this._handleSwipe()\n execute(this._config.endCallback)\n }\n\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this._deltaX\n }\n\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX)\n\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltaX / this._deltaX\n\n this._deltaX = 0\n\n if (!direction) {\n return\n }\n\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)\n }\n\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))\n }\n }\n\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n }\n}\n\nexport default Swipe\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getNextActiveElement,\n isRTL,\n isVisible,\n reflow,\n triggerTransitionEnd\n} from './util/index.js'\nimport Swipe from './util/swipe.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)', // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._interval = null\n this._activeElement = null\n this._isSliding = false\n this.touchTimeout = null\n this._swipeHelper = null\n\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._addEventListeners()\n\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element)\n }\n\n this._clearInterval()\n }\n\n cycle() {\n this._clearInterval()\n this._updateInterval()\n\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval)\n }\n\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle())\n return\n }\n\n this.cycle()\n }\n\n to(index) {\n const items = this._getItems()\n if (index > items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n const activeIndex = this._getItemIndex(this._getActive())\n if (activeIndex === index) {\n return\n }\n\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV\n\n this._slide(order, items[index])\n }\n\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose()\n }\n\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval\n return config\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause())\n EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle())\n }\n\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault())\n }\n\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n }\n\n this._swipeHelper = new Swipe(this._element, swipeConfig)\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(this._directionToOrder(direction))\n }\n }\n\n _getItemIndex(element) {\n return this._getItems().indexOf(element)\n }\n\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return\n }\n\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement)\n\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE)\n newActiveIndicator.setAttribute('aria-current', 'true')\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || this._getActive()\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n this._config.interval = elementInterval || this._config.defaultInterval\n }\n\n _slide(order, element = null) {\n if (this._isSliding) {\n return\n }\n\n const activeElement = this._getActive()\n const isNext = order === ORDER_NEXT\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap)\n\n if (nextElement === activeElement) {\n return\n }\n\n const nextElementIndex = this._getItemIndex(nextElement)\n\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n })\n }\n\n const slideEvent = triggerEvent(EVENT_SLIDE)\n\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return\n }\n\n const isCycling = Boolean(this._interval)\n this.pause()\n\n this._isSliding = true\n\n this._setActiveIndicatorElement(nextElementIndex)\n this._activeElement = nextElement\n\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n triggerEvent(EVENT_SLID)\n }\n\n this._queueCallback(completeCallBack, activeElement, this._isAnimated())\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE)\n }\n\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n }\n\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element)\n }\n\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n }\n\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config)\n\n if (typeof config === 'number') {\n data.to(config)\n return\n }\n\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n event.preventDefault()\n\n const carousel = Carousel.getOrCreateInstance(target)\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n carousel.to(slideIndex)\n carousel._maybeEnableCycle()\n return\n }\n\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next()\n carousel._maybeEnableCycle()\n return\n }\n\n carousel.prev()\n carousel._maybeEnableCycle()\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getElement,\n reflow\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\nconst Default = {\n parent: null,\n toggle: true\n}\n\nconst DefaultType = {\n parent: '(null|element)',\n toggle: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isTransitioning = false\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElement => foundElement === this._element)\n\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let activeChildren = []\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)\n .filter(element => element !== this._element)\n .map(element => Collapse.getOrCreateInstance(element, { toggle: false }))\n }\n\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n for (const activeInstance of activeChildren) {\n activeInstance.hide()\n }\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger)\n\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)\n\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n }\n }\n\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element))\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen)\n element.setAttribute('aria-expanded', isOpen)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n execute,\n getElement,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center'\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)'\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR = '.navbar'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\nconst PLACEMENT_TOPCENTER = 'top'\nconst PLACEMENT_BOTTOMCENTER = 'bottom'\n\nconst Default = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n}\n\nconst DefaultType = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n}\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._popper = null\n this._parent = this._element.parentNode // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.findOne(SELECTOR_MENU, this._parent)\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._createPopper()\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = super._getConfig(config)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = this._parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n }\n\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getPlacement() {\n const parentDropdown = this._parent\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {\n return\n }\n\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)\n\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle)\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n const relatedTarget = { relatedTarget: context._element }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName)\n const isEscapeEvent = event.key === ESCAPE_KEY\n const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)\n\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return\n }\n\n if (isInput && !isEscapeEvent) {\n return\n }\n\n event.preventDefault()\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?\n this :\n (SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode))\n\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (isUpOrDownEvent) {\n event.stopPropagation()\n instance.show()\n instance._selectMenuItem(event)\n return\n }\n\n if (instance._isShown()) { // else is escape and we check if it is shown\n event.stopPropagation()\n instance.hide()\n getToggleButton.focus()\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport {\n execute, executeAfterTransition, getElement, reflow\n} from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nconst Default = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n}\n\nconst DefaultType = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n}\n\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n const element = this._getElement()\n if (this._config.isAnimated) {\n reflow(element)\n }\n\n element.classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n const element = this._getElement()\n this._config.rootElement.append(element)\n\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nconst Default = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n}\n\nconst DefaultType = {\n autofocus: 'boolean',\n trapElement: 'element'\n}\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return\n }\n\n if (this._config.autofocus) {\n this._config.trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n _handleFocusin(event) {\n const { trapElement } = this._config\n\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\nconst PROPERTY_PADDING = 'padding-right'\nconst PROPERTY_MARGIN = 'margin-right'\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProperty)\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty)\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty)\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty)\n return\n }\n\n Manipulator.removeDataAttribute(element, styleProperty)\n element.style.setProperty(styleProperty, value)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n return\n }\n\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel)\n }\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin, isRTL, isVisible, reflow\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\nconst Default = {\n backdrop: true,\n focus: true,\n keyboard: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._isTransitioning = true\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._backdrop.show(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n this._isTransitioning = true\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated())\n }\n\n dispose() {\n EventHandler.off(window, EVENT_KEY)\n EventHandler.off(this._dialog, EVENT_KEY)\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated())\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n this._triggerBackdropTransition()\n })\n\n EventHandler.on(window, EVENT_RESIZE, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog()\n }\n })\n\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return\n }\n\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n return\n }\n\n if (this._config.backdrop) {\n this.hide()\n }\n })\n })\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const initialOverflowY = this._element.style.overflowY\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden'\n }\n\n this._element.classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY\n }, this._dialog)\n }, this._dialog)\n\n this._element.focus()\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin,\n isDisabled,\n isVisible\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\nconst CLASS_NAME_HIDING = 'hiding'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate()\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.add(CLASS_NAME_HIDING)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n return\n }\n\n this.hide()\n }\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop)\n\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n })\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show()\n }\n})\n\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide()\n }\n }\n})\n\nenableDismissTrigger(Offcanvas)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n dd: [],\n div: [],\n dl: [],\n dt: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n// js-docs-end allow-list\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\n// eslint-disable-next-line unicorn/better-regex\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n .some(regex => regex.test(attributeName))\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n }\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\nimport { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'\nimport { execute, getElement, isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'TemplateFactory'\n\nconst Default = {\n allowList: DefaultAllowlist,\n content: {}, // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '<div></div>'\n}\n\nconst DefaultType = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n}\n\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n}\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content)\n .map(config => this._resolvePossibleFunction(config))\n .filter(Boolean)\n }\n\n hasContent() {\n return this.getContent().length > 0\n }\n\n changeContent(content) {\n this._checkContent(content)\n this._config.content = { ...this._config.content, ...content }\n return this\n }\n\n toHtml() {\n const templateWrapper = document.createElement('div')\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template)\n\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector)\n }\n\n const template = templateWrapper.children[0]\n const extraClass = this._resolvePossibleFunction(this._config.extraClass)\n\n if (extraClass) {\n template.classList.add(...extraClass.split(' '))\n }\n\n return template\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config)\n this._checkContent(config.content)\n }\n\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({ selector, entry: content }, DefaultContentType)\n }\n }\n\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!templateElement) {\n return\n }\n\n content = this._resolvePossibleFunction(content)\n\n if (!content) {\n templateElement.remove()\n return\n }\n\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement)\n return\n }\n\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content)\n return\n }\n\n templateElement.textContent = content\n }\n\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this])\n }\n\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = ''\n templateElement.append(element)\n return\n }\n\n templateElement.textContent = element.textContent\n }\n}\n\nexport default TemplateFactory\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport {\n defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop\n} from './util/index.js'\nimport { DefaultAllowlist } from './util/sanitizer.js'\nimport TemplateFactory from './util/template-factory.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\nconst EVENT_HIDE = 'hide'\nconst EVENT_HIDDEN = 'hidden'\nconst EVENT_SHOW = 'show'\nconst EVENT_SHOWN = 'shown'\nconst EVENT_INSERTED = 'inserted'\nconst EVENT_CLICK = 'click'\nconst EVENT_FOCUSIN = 'focusin'\nconst EVENT_FOCUSOUT = 'focusout'\nconst EVENT_MOUSEENTER = 'mouseenter'\nconst EVENT_MOUSELEAVE = 'mouseleave'\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '<div class=\"tooltip\" role=\"tooltip\">' +\n '<div class=\"tooltip-arrow\"></div>' +\n '<div class=\"tooltip-inner\"></div>' +\n '</div>',\n title: '',\n trigger: 'hover focus'\n}\n\nconst DefaultType = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n}\n\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org)')\n }\n\n super(element, config)\n\n // Private\n this._isEnabled = true\n this._timeout = 0\n this._isHovered = null\n this._activeTrigger = {}\n this._popper = null\n this._templateFactory = null\n this._newContent = null\n\n // Protected\n this.tip = null\n\n this._setListeners()\n\n if (!this._config.selector) {\n this._fixTitle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle() {\n if (!this._isEnabled) {\n return\n }\n\n this._activeTrigger.click = !this._activeTrigger.click\n if (this._isShown()) {\n this._leave()\n return\n }\n\n this._enter()\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'))\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this._isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW))\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper()\n\n const tip = this._getTipElement()\n\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'))\n\n const { container } = this._config\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))\n }\n\n this._popper = this._createPopper(tip)\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN))\n\n if (this._isHovered === false) {\n this._leave()\n }\n\n this._isHovered = false\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n hide() {\n if (!this._isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE))\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const tip = this._getTipElement()\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n this._isHovered = null // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (!this._isHovered) {\n this._disposePopper()\n }\n\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN))\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n update() {\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle())\n }\n\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())\n }\n\n return this.tip\n }\n\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml()\n\n // TODO: remove this check in v6\n if (!tip) {\n return null\n }\n\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`)\n\n const tipId = getUID(this.constructor.NAME).toString()\n\n tip.setAttribute('id', tipId)\n\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n return tip\n }\n\n setContent(content) {\n this._newContent = content\n if (this._isShown()) {\n this._disposePopper()\n this.show()\n }\n }\n\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content)\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n })\n }\n\n return this._templateFactory\n }\n\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n }\n }\n\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title')\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _isAnimated() {\n return this._config.animation || (this.tip && this.tip.classList.contains(CLASS_NAME_FADE))\n }\n\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW)\n }\n\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element])\n const attachment = AttachmentMap[placement.toUpperCase()]\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element])\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement)\n }\n }\n ]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n }\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context.toggle()\n })\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSEENTER) :\n this.constructor.eventName(EVENT_FOCUSIN)\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSELEAVE) :\n this.constructor.eventName(EVENT_FOCUSOUT)\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true\n context._enter()\n })\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] =\n context._element.contains(event.relatedTarget)\n\n context._leave()\n })\n }\n }\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n\n if (!title) {\n return\n }\n\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('data-bs-original-title', title) // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title')\n }\n\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true\n return\n }\n\n this._isHovered = true\n\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show()\n }\n }, this._config.delay.show)\n }\n\n _leave() {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n this._isHovered = false\n\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide()\n }\n }, this._config.delay.hide)\n }\n\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout)\n this._timeout = setTimeout(handler, timeout)\n }\n\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true)\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute]\n }\n }\n\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value\n }\n }\n\n config.selector = false\n config.trigger = 'manual'\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n\n if (this.tip) {\n this.tip.remove()\n this.tip = null\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Tooltip from './tooltip.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'popover'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Default = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>',\n trigger: 'click'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n}\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent()\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n }\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin, getElement, isDisabled, isVisible\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_CLICK = `click${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_TARGET_LINKS = '[href]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst Default = {\n offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n}\n\nconst DefaultType = {\n offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n}\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map()\n this._observableSections = new Map()\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element\n this._activeTarget = null\n this._observer = null\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n }\n this.refresh() // initialize\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables()\n this._maybeEnableSmoothScroll()\n\n if (this._observer) {\n this._observer.disconnect()\n } else {\n this._observer = this._getNewObserver()\n }\n\n for (const section of this._observableSections.values()) {\n this._observer.observe(section)\n }\n }\n\n dispose() {\n this._observer.disconnect()\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin\n\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))\n }\n\n return config\n }\n\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK)\n\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash)\n if (observableSection) {\n event.preventDefault()\n const root = this._rootElement || window\n const height = observableSection.offsetTop - this._element.offsetTop\n if (root.scrollTo) {\n root.scrollTo({ top: height, behavior: 'smooth' })\n return\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height\n }\n })\n }\n\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n }\n\n return new IntersectionObserver(entries => this._observerCallback(entries), options)\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop\n this._process(targetElement(entry))\n }\n\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop\n this._previousScrollData.parentScrollTop = parentScrollTop\n\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null\n this._clearActiveClass(targetElement(entry))\n\n continue\n }\n\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry)\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return\n }\n\n continue\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry)\n }\n }\n }\n\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map()\n this._observableSections = new Map()\n\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)\n\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue\n }\n\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor)\n this._observableSections.set(anchor.hash, observableSection)\n }\n }\n }\n\n _process(target) {\n if (this._activeTarget === target) {\n return\n }\n\n this._clearActiveClass(this._config.target)\n this._activeTarget = target\n target.classList.add(CLASS_NAME_ACTIVE)\n this._activateParents(target)\n\n EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })\n }\n\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n return\n }\n\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {\n item.classList.add(CLASS_NAME_ACTIVE)\n }\n }\n }\n\n _clearActiveClass(parent) {\n parent.classList.remove(CLASS_NAME_ACTIVE)\n\n const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent)\n for (const node of activeNodes) {\n node.classList.remove(CLASS_NAME_ACTIVE)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = ScrollSpy.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {\n ScrollSpy.getOrCreateInstance(spy)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(ScrollSpy)\n\nexport default ScrollSpy\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tab.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tab'\nconst DATA_KEY = 'bs.tab'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}`\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst HOME_KEY = 'Home'\nconst END_KEY = 'End'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_DROPDOWN = 'dropdown'\n\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\nconst SELECTOR_DROPDOWN_MENU = '.dropdown-menu'\nconst NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`\n\nconst SELECTOR_TAB_PANEL = '.list-group, .nav, [role=\"tablist\"]'\nconst SELECTOR_OUTER = '.nav-item, .list-group-item'\nconst SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role=\"tab\"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]' // TODO: could only be `tab` in v6\nconst SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`\n\nconst SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle=\"tab\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"pill\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"list\"]`\n\n/**\n * Class definition\n */\n\nclass Tab extends BaseComponent {\n constructor(element) {\n super(element)\n this._parent = this._element.closest(SELECTOR_TAB_PANEL)\n\n if (!this._parent) {\n return\n // TODO: should throw exception in v6\n // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)\n }\n\n // Set up initial aria attributes\n this._setInitialAttributes(this._parent, this._getChildren())\n\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n show() { // Shows this elem and deactivate the active sibling if exists\n const innerElem = this._element\n if (this._elemIsActive(innerElem)) {\n return\n }\n\n // Search for active tab on same parent to deactivate it\n const active = this._getActiveElem()\n\n const hideEvent = active ?\n EventHandler.trigger(active, EVENT_HIDE, { relatedTarget: innerElem }) :\n null\n\n const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, { relatedTarget: active })\n\n if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {\n return\n }\n\n this._deactivate(active, innerElem)\n this._activate(innerElem, active)\n }\n\n // Private\n _activate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.add(CLASS_NAME_ACTIVE)\n\n this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.add(CLASS_NAME_SHOW)\n return\n }\n\n element.removeAttribute('tabindex')\n element.setAttribute('aria-selected', true)\n this._toggleDropDown(element, true)\n EventHandler.trigger(element, EVENT_SHOWN, {\n relatedTarget: relatedElem\n })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _deactivate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.remove(CLASS_NAME_ACTIVE)\n element.blur()\n\n this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.remove(CLASS_NAME_SHOW)\n return\n }\n\n element.setAttribute('aria-selected', false)\n element.setAttribute('tabindex', '-1')\n this._toggleDropDown(element, false)\n EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _keydown(event) {\n if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key))) {\n return\n }\n\n event.stopPropagation()// stopPropagation/preventDefault both added to support up/down keys without scrolling the page\n event.preventDefault()\n\n const children = this._getChildren().filter(element => !isDisabled(element))\n let nextActiveElement\n\n if ([HOME_KEY, END_KEY].includes(event.key)) {\n nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]\n } else {\n const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)\n nextActiveElement = getNextActiveElement(children, event.target, isNext, true)\n }\n\n if (nextActiveElement) {\n nextActiveElement.focus({ preventScroll: true })\n Tab.getOrCreateInstance(nextActiveElement).show()\n }\n }\n\n _getChildren() { // collection of inner elements\n return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent)\n }\n\n _getActiveElem() {\n return this._getChildren().find(child => this._elemIsActive(child)) || null\n }\n\n _setInitialAttributes(parent, children) {\n this._setAttributeIfNotExists(parent, 'role', 'tablist')\n\n for (const child of children) {\n this._setInitialAttributesOnChild(child)\n }\n }\n\n _setInitialAttributesOnChild(child) {\n child = this._getInnerElement(child)\n const isActive = this._elemIsActive(child)\n const outerElem = this._getOuterElement(child)\n child.setAttribute('aria-selected', isActive)\n\n if (outerElem !== child) {\n this._setAttributeIfNotExists(outerElem, 'role', 'presentation')\n }\n\n if (!isActive) {\n child.setAttribute('tabindex', '-1')\n }\n\n this._setAttributeIfNotExists(child, 'role', 'tab')\n\n // set attributes to the related panel too\n this._setInitialAttributesOnTargetPanel(child)\n }\n\n _setInitialAttributesOnTargetPanel(child) {\n const target = SelectorEngine.getElementFromSelector(child)\n\n if (!target) {\n return\n }\n\n this._setAttributeIfNotExists(target, 'role', 'tabpanel')\n\n if (child.id) {\n this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)\n }\n }\n\n _toggleDropDown(element, open) {\n const outerElem = this._getOuterElement(element)\n if (!outerElem.classList.contains(CLASS_DROPDOWN)) {\n return\n }\n\n const toggle = (selector, className) => {\n const element = SelectorEngine.findOne(selector, outerElem)\n if (element) {\n element.classList.toggle(className, open)\n }\n }\n\n toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)\n toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)\n outerElem.setAttribute('aria-expanded', open)\n }\n\n _setAttributeIfNotExists(element, attribute, value) {\n if (!element.hasAttribute(attribute)) {\n element.setAttribute(attribute, value)\n }\n }\n\n _elemIsActive(elem) {\n return elem.classList.contains(CLASS_NAME_ACTIVE)\n }\n\n // Try to get the inner element (usually the .nav-link)\n _getInnerElement(elem) {\n return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem)\n }\n\n // Try to get the outer element (usually the .nav-item)\n _getOuterElement(elem) {\n return elem.closest(SELECTOR_OUTER) || elem\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tab.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n Tab.getOrCreateInstance(this).show()\n})\n\n/**\n * Initialize on focus\n */\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {\n Tab.getOrCreateInstance(element)\n }\n})\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tab)\n\nexport default Tab\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap toast.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin, reflow } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'toast'\nconst DATA_KEY = 'bs.toast'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\n\nconst DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n}\n\nconst Default = {\n animation: true,\n autohide: true,\n delay: 5000\n}\n\n/**\n * Class definition\n */\n\nclass Toast extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._timeout = null\n this._hasMouseInteraction = false\n this._hasKeyboardInteraction = false\n this._setListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show() {\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._clearTimeout()\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE)\n }\n\n const complete = () => {\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN)\n\n this._maybeScheduleHide()\n }\n\n this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\n reflow(this._element)\n this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)\n\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n hide() {\n if (!this.isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const complete = () => {\n this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\n this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.classList.add(CLASS_NAME_SHOWING)\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n dispose() {\n this._clearTimeout()\n\n if (this.isShown()) {\n this._element.classList.remove(CLASS_NAME_SHOW)\n }\n\n super.dispose()\n }\n\n isShown() {\n return this._element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n\n _maybeScheduleHide() {\n if (!this._config.autohide) {\n return\n }\n\n if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\n return\n }\n\n this._timeout = setTimeout(() => {\n this.hide()\n }, this._config.delay)\n }\n\n _onInteraction(event, isInteracting) {\n switch (event.type) {\n case 'mouseover':\n case 'mouseout': {\n this._hasMouseInteraction = isInteracting\n break\n }\n\n case 'focusin':\n case 'focusout': {\n this._hasKeyboardInteraction = isInteracting\n break\n }\n\n default: {\n break\n }\n }\n\n if (isInteracting) {\n this._clearTimeout()\n return\n }\n\n const nextElement = event.relatedTarget\n if (this._element === nextElement || this._element.contains(nextElement)) {\n return\n }\n\n this._maybeScheduleHide()\n }\n\n _setListeners() {\n EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\n EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\n }\n\n _clearTimeout() {\n clearTimeout(this._timeout)\n this._timeout = null\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Toast.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Toast)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Toast)\n\nexport default Toast\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap index.umd.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './src/alert.js'\nimport Button from './src/button.js'\nimport Carousel from './src/carousel.js'\nimport Collapse from './src/collapse.js'\nimport Dropdown from './src/dropdown.js'\nimport Modal from './src/modal.js'\nimport Offcanvas from './src/offcanvas.js'\nimport Popover from './src/popover.js'\nimport ScrollSpy from './src/scrollspy.js'\nimport Tab from './src/tab.js'\nimport Toast from './src/toast.js'\nimport Tooltip from './src/tooltip.js'\n\nexport default {\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Offcanvas,\n Popover,\n ScrollSpy,\n Tab,\n Toast,\n Tooltip\n}\n"],"mappings":"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"} \ No newline at end of file +{"version":3,"names":["elementMap","Map","Data","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete","TRANSITION_END","parseSelector","selector","window","CSS","escape","replace","match","id","toType","object","Object","prototype","toString","call","toLowerCase","triggerTransitionEnd","dispatchEvent","Event","isElement","jquery","nodeType","getElement","length","document","querySelector","isVisible","getClientRects","elementIsVisible","getComputedStyle","getPropertyValue","closedDetails","closest","summary","parentNode","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","getAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","noop","reflow","offsetHeight","getjQuery","jQuery","body","DOMContentLoadedCallbacks","isRTL","dir","defineJQueryPlugin","plugin","callback","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","readyState","addEventListener","push","execute","possibleCallback","args","defaultValue","executeAfterTransition","transitionElement","waitForTransition","emulatedDuration","transitionDuration","transitionDelay","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","split","getTransitionDurationFromElement","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","listLength","index","indexOf","Math","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","nativeEvents","Set","makeEventUid","uid","getElementEvents","findHandler","events","callable","delegationSelector","values","find","event","normalizeParameters","originalTypeEvent","delegationFunction","isDelegated","typeEvent","getTypeEvent","addHandler","oneOff","wrapFunction","relatedTarget","delegateTarget","this","handlers","previousFunction","domElements","querySelectorAll","domElement","hydrateObj","EventHandler","off","type","apply","bootstrapDelegationHandler","bootstrapHandler","removeHandler","Boolean","removeNamespacedHandlers","namespace","storeElementEvent","handlerKey","entries","includes","on","one","inNamespace","isNamespace","startsWith","elementEvent","slice","keyHandlers","trigger","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","evt","cancelable","preventDefault","obj","meta","value","_unused","defineProperty","configurable","normalizeData","JSON","parse","decodeURIComponent","normalizeDataKey","chr","Manipulator","setDataAttribute","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","dataset","filter","pureKey","charAt","getDataAttribute","Config","Default","DefaultType","Error","_getConfig","config","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","jsonConfig","constructor","configTypes","property","expectedTypes","valueType","RegExp","test","TypeError","toUpperCase","BaseComponent","super","_element","_config","DATA_KEY","dispose","EVENT_KEY","propertyName","getOwnPropertyNames","_queueCallback","isAnimated","getInstance","getOrCreateInstance","VERSION","eventName","getSelector","hrefAttribute","trim","map","sel","join","SelectorEngine","concat","Element","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","el","getSelectorFromElement","getElementFromSelector","getMultipleElementsFromSelector","enableDismissTrigger","component","method","clickEvent","tagName","EVENT_CLOSE","EVENT_CLOSED","Alert","close","_destroyElement","each","data","undefined","SELECTOR_DATA_TOGGLE","Button","toggle","button","EVENT_TOUCHSTART","EVENT_TOUCHMOVE","EVENT_TOUCHEND","EVENT_POINTERDOWN","EVENT_POINTERUP","endCallback","leftCallback","rightCallback","Swipe","isSupported","_deltaX","_supportPointerEvents","PointerEvent","_initEvents","_start","_eventIsPointerPenTouch","clientX","touches","_end","_handleSwipe","_move","absDeltaX","abs","direction","add","pointerType","navigator","maxTouchPoints","DATA_API_KEY","ARROW_LEFT_KEY","ARROW_RIGHT_KEY","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","EVENT_SLIDE","EVENT_SLID","EVENT_KEYDOWN","EVENT_MOUSEENTER","EVENT_MOUSELEAVE","EVENT_DRAG_START","EVENT_LOAD_DATA_API","EVENT_CLICK_DATA_API","CLASS_NAME_CAROUSEL","CLASS_NAME_ACTIVE","SELECTOR_ACTIVE","SELECTOR_ITEM","SELECTOR_ACTIVE_ITEM","KEY_TO_DIRECTION","ARROW_LEFT_KEY$1","ARROW_RIGHT_KEY$1","interval","keyboard","pause","ride","touch","wrap","Carousel","_interval","_activeElement","_isSliding","touchTimeout","_swipeHelper","_indicatorsElement","_addEventListeners","cycle","_slide","nextWhenVisible","hidden","_clearInterval","_updateInterval","setInterval","_maybeEnableCycle","to","items","_getItems","activeIndex","_getItemIndex","_getActive","order","defaultInterval","_keydown","_addTouchEventListeners","img","swipeConfig","_directionToOrder","endCallBack","clearTimeout","_setActiveIndicatorElement","activeIndicator","newActiveIndicator","elementInterval","parseInt","isNext","nextElement","nextElementIndex","triggerEvent","_orderToDirection","isCycling","directionalClassName","orderClassName","completeCallBack","_isAnimated","clearInterval","carousel","slideIndex","carousels","EVENT_SHOW","EVENT_SHOWN","EVENT_HIDE","EVENT_HIDDEN","CLASS_NAME_SHOW","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_DEEPER_CHILDREN","parent","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElement","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activeChildren","_getFirstLevelChildren","activeInstance","dimension","_getDimension","style","scrollSize","complete","getBoundingClientRect","selected","triggerArray","isOpen","ARROW_UP_KEY","ARROW_DOWN_KEY","EVENT_KEYDOWN_DATA_API","EVENT_KEYUP_DATA_API","SELECTOR_DATA_TOGGLE_SHOWN","SELECTOR_MENU","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","autoClose","boundary","display","offset","popperConfig","reference","Dropdown","_popper","_parent","_menu","_inNavbar","_detectNavbar","_createPopper","focus","_completeHide","destroy","update","Popper","referenceElement","_getPopperConfig","createPopper","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","placement","modifiers","options","enabled","_selectMenuItem","clearMenus","openToggles","context","composedPath","isMenuTarget","dataApiKeydownHandler","isInput","isEscapeEvent","isUpOrDownEvent","getToggleButton","stopPropagation","EVENT_MOUSEDOWN","className","clickCallback","rootElement","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","EVENT_FOCUSIN","EVENT_KEYDOWN_TAB","TAB_NAV_BACKWARD","autofocus","trapElement","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","elements","shiftKey","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","PROPERTY_PADDING","PROPERTY_MARGIN","ScrollBarHelper","getWidth","documentWidth","clientWidth","innerWidth","width","_disableOverFlow","_setElementAttributes","calculatedValue","reset","_resetElementAttributes","isOverflowing","_saveInitialAttribute","overflow","styleProperty","scrollbarWidth","_applyManipulationCallback","setProperty","actualValue","removeProperty","callBack","EVENT_HIDE_PREVENTED","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_MOUSEDOWN_DISMISS","EVENT_KEYDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_scrollBar","_adjustDialog","_showElement","_hideModal","handleUpdate","scrollTop","modalBody","transitionComplete","_triggerBackdropTransition","event2","_resetAdjustments","isModalOverflowing","scrollHeight","clientHeight","initialOverflowY","overflowY","isBodyOverflowing","paddingLeft","paddingRight","showEvent","alreadyOpen","CLASS_NAME_SHOWING","CLASS_NAME_HIDING","OPEN_SELECTOR","scroll","Offcanvas","blur","completeCallback","position","DefaultAllowlist","a","area","b","br","col","code","dd","div","dl","dt","em","hr","h1","h2","h3","h4","h5","h6","i","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","uriAttributes","SAFE_URL_PATTERN","allowedAttribute","attribute","allowedAttributeList","attributeName","nodeName","nodeValue","attributeRegex","some","regex","allowList","content","extraClass","html","sanitize","sanitizeFn","template","DefaultContentType","entry","TemplateFactory","getContent","_resolvePossibleFunction","hasContent","changeContent","_checkContent","toHtml","templateWrapper","innerHTML","_maybeSanitize","text","_setContent","arg","templateElement","_putElementInTemplate","textContent","unsafeHtml","sanitizeFunction","createdDocument","DOMParser","parseFromString","elementName","attributeList","allowedAttributes","sanitizeHtml","DISALLOWED_ATTRIBUTES","CLASS_NAME_FADE","SELECTOR_TOOLTIP_INNER","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","TRIGGER_CLICK","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","animation","container","customClass","delay","fallbackPlacements","title","Tooltip","_isEnabled","_timeout","_isHovered","_activeTrigger","_templateFactory","_newContent","tip","_setListeners","_fixTitle","enable","disable","toggleEnabled","_leave","_enter","_hideModalHandler","_disposePopper","_isWithContent","isInTheDom","ownerDocument","_getTipElement","_isWithActiveTrigger","_getTitle","_createTipElement","_getContentForTemplate","_getTemplateFactory","tipId","prefix","floor","random","getElementById","getUID","setContent","_initializeOnDelegatedTarget","_getDelegateConfig","attachment","phase","state","triggers","eventIn","eventOut","_setTimeout","timeout","dataAttributes","dataAttribute","SELECTOR_TITLE","SELECTOR_CONTENT","Popover","_getContent","EVENT_ACTIVATE","EVENT_CLICK","SELECTOR_TARGET_LINKS","SELECTOR_NAV_LINKS","SELECTOR_LINK_ITEMS","rootMargin","smoothScroll","threshold","ScrollSpy","_targetLinks","_observableSections","_rootElement","_activeTarget","_observer","_previousScrollData","visibleEntryTop","parentScrollTop","refresh","_initializeTargetsAndObservables","_maybeEnableSmoothScroll","disconnect","_getNewObserver","section","observe","observableSection","hash","height","offsetTop","scrollTo","top","behavior","IntersectionObserver","_observerCallback","targetElement","_process","userScrollsDown","isIntersecting","_clearActiveClass","entryIsLowerThanPrevious","targetLinks","anchor","decodeURI","_activateParents","listGroup","item","activeNodes","node","spy","HOME_KEY","END_KEY","SELECTOR_DROPDOWN_TOGGLE","NOT_SELECTOR_DROPDOWN_TOGGLE","SELECTOR_INNER_ELEM","SELECTOR_DATA_TOGGLE_ACTIVE","Tab","_setInitialAttributes","_getChildren","innerElem","_elemIsActive","active","_getActiveElem","hideEvent","_deactivate","_activate","relatedElem","_toggleDropDown","nextActiveElement","preventScroll","_setAttributeIfNotExists","_setInitialAttributesOnChild","_getInnerElement","isActive","outerElem","_getOuterElement","_setInitialAttributesOnTargetPanel","open","EVENT_MOUSEOVER","EVENT_MOUSEOUT","EVENT_FOCUSOUT","CLASS_NAME_HIDE","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","isShown","_onInteraction","isInteracting"],"sources":["../../js/src/dom/data.js","../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/manipulator.js","../../js/src/util/config.js","../../js/src/base-component.js","../../js/src/dom/selector-engine.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/util/swipe.js","../../js/src/carousel.js","../../js/src/collapse.js","../../js/src/dropdown.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/util/scrollbar.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/util/template-factory.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1_000_000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`)\n }\n\n return selector\n}\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`\n }\n\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = object => {\n if (!object || typeof object !== 'object') {\n return false\n }\n\n if (typeof object.jquery !== 'undefined') {\n object = object[0]\n }\n\n return typeof object.nodeType !== 'undefined'\n}\n\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (isElement(object)) {\n return object.jquery ? object[0] : object\n }\n\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object))\n }\n\n return null\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])')\n\n if (!closedDetails) {\n return elementIsVisible\n }\n\n if (closedDetails !== element) {\n const summary = element.closest('summary')\n if (summary && summary.parentNode !== closedDetails) {\n return false\n }\n\n if (summary === null) {\n return false\n }\n }\n\n return elementIsVisible\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.harrytheo.com/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight // eslint-disable-line no-unused-expressions\n}\n\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback()\n }\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback.call(...args) : defaultValue\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]\n }\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n defineJQueryPlugin,\n execute,\n executeAfterTransition,\n findShadowRoot,\n getElement,\n getjQuery,\n getNextActiveElement,\n getTransitionDurationFromElement,\n getUID,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n onDOMContentLoaded,\n parseSelector,\n reflow,\n triggerTransitionEnd,\n toType\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index.js'\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\n\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getElementEvents(element) {\n const uid = makeEventUid(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, { delegateTarget: element })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue\n }\n\n hydrateObj(event, { delegateTarget: target })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n}\n\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events)\n .find(event => event.callable === callable && event.delegationSelector === delegationSelector)\n}\n\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string'\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : (handler || delegationFunction)\n let typeEvent = getTypeEvent(originalTypeEvent)\n\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent\n }\n\n return [isDelegated, callable, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n callable = wrapFunction(callable)\n }\n\n const events = getElementEvents(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)\n\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff\n\n return\n }\n\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = isDelegated ?\n bootstrapDelegationHandler(element, handler, callable) :\n bootstrapHandler(element, callable)\n\n fn.delegationSelector = isDelegated ? handler : null\n fn.callable = callable\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, isDelegated)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false)\n },\n\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getElementEvents(element)\n const storeElementEvent = events[typeEvent] || {}\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return\n }\n\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)\n return\n }\n\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n }\n }\n\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n\n let jQueryEvent = null\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value\n } catch {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value\n }\n })\n }\n }\n\n return obj\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true\n }\n\n if (value === 'false') {\n return false\n }\n\n if (value === Number(value).toString()) {\n return Number(value)\n }\n\n if (value === '' || value === 'null') {\n return null\n }\n\n if (typeof value !== 'string') {\n return value\n }\n\n try {\n return JSON.parse(decodeURIComponent(value))\n } catch {\n return value\n }\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))\n\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1)\n attributes[pureKey] = normalizeData(element.dataset[key])\n }\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport { isElement, toType } from './index.js'\n\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {}\n }\n\n static get DefaultType() {\n return {}\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n return config\n }\n\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n }\n }\n\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property]\n const valueType = isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n }\n }\n}\n\nexport default Config\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data.js'\nimport EventHandler from './dom/event-handler.js'\nimport Config from './util/config.js'\nimport { executeAfterTransition, getElement } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.8'\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super()\n\n element = getElement(element)\n if (!element) {\n return\n }\n\n this._element = element\n this._config = this._getConfig(config)\n\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null\n }\n }\n\n // Private\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible, parseSelector } from '../util/index.js'\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`\n }\n\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null\n }\n\n return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null\n}\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n let ancestor = element.parentNode.closest(selector)\n\n while (ancestor) {\n parents.push(ancestor)\n ancestor = ancestor.parentNode.closest(selector)\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n },\n\n getSelectorFromElement(element) {\n const selector = getSelector(element)\n\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null\n }\n\n return null\n },\n\n getElementFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.findOne(selector) : null\n },\n\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.find(selector) : []\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isDisabled } from './index.js'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport { execute } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'swipe'\nconst EVENT_KEY = '.bs.swipe'\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n}\n\nconst DefaultType = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n}\n\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super()\n this._element = element\n\n if (!element || !Swipe.isSupported()) {\n return\n }\n\n this._config = this._getConfig(config)\n this._deltaX = 0\n this._supportPointerEvents = Boolean(window.PointerEvent)\n this._initEvents()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY)\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX\n\n return\n }\n\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX\n }\n }\n\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX\n }\n\n this._handleSwipe()\n execute(this._config.endCallback)\n }\n\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this._deltaX\n }\n\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX)\n\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltaX / this._deltaX\n\n this._deltaX = 0\n\n if (!direction) {\n return\n }\n\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)\n }\n\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))\n }\n }\n\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n }\n}\n\nexport default Swipe\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getNextActiveElement,\n isRTL,\n isVisible,\n reflow,\n triggerTransitionEnd\n} from './util/index.js'\nimport Swipe from './util/swipe.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)', // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._interval = null\n this._activeElement = null\n this._isSliding = false\n this.touchTimeout = null\n this._swipeHelper = null\n\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._addEventListeners()\n\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element)\n }\n\n this._clearInterval()\n }\n\n cycle() {\n this._clearInterval()\n this._updateInterval()\n\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval)\n }\n\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle())\n return\n }\n\n this.cycle()\n }\n\n to(index) {\n const items = this._getItems()\n if (index > items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n const activeIndex = this._getItemIndex(this._getActive())\n if (activeIndex === index) {\n return\n }\n\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV\n\n this._slide(order, items[index])\n }\n\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose()\n }\n\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval\n return config\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause())\n EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle())\n }\n\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault())\n }\n\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n }\n\n this._swipeHelper = new Swipe(this._element, swipeConfig)\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(this._directionToOrder(direction))\n }\n }\n\n _getItemIndex(element) {\n return this._getItems().indexOf(element)\n }\n\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return\n }\n\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement)\n\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE)\n newActiveIndicator.setAttribute('aria-current', 'true')\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || this._getActive()\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n this._config.interval = elementInterval || this._config.defaultInterval\n }\n\n _slide(order, element = null) {\n if (this._isSliding) {\n return\n }\n\n const activeElement = this._getActive()\n const isNext = order === ORDER_NEXT\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap)\n\n if (nextElement === activeElement) {\n return\n }\n\n const nextElementIndex = this._getItemIndex(nextElement)\n\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n })\n }\n\n const slideEvent = triggerEvent(EVENT_SLIDE)\n\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return\n }\n\n const isCycling = Boolean(this._interval)\n this.pause()\n\n this._isSliding = true\n\n this._setActiveIndicatorElement(nextElementIndex)\n this._activeElement = nextElement\n\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n triggerEvent(EVENT_SLID)\n }\n\n this._queueCallback(completeCallBack, activeElement, this._isAnimated())\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE)\n }\n\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n }\n\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element)\n }\n\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n }\n\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config)\n\n if (typeof config === 'number') {\n data.to(config)\n return\n }\n\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n event.preventDefault()\n\n const carousel = Carousel.getOrCreateInstance(target)\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n carousel.to(slideIndex)\n carousel._maybeEnableCycle()\n return\n }\n\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next()\n carousel._maybeEnableCycle()\n return\n }\n\n carousel.prev()\n carousel._maybeEnableCycle()\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getElement,\n reflow\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\nconst Default = {\n parent: null,\n toggle: true\n}\n\nconst DefaultType = {\n parent: '(null|element)',\n toggle: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isTransitioning = false\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElement => foundElement === this._element)\n\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let activeChildren = []\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)\n .filter(element => element !== this._element)\n .map(element => Collapse.getOrCreateInstance(element, { toggle: false }))\n }\n\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n for (const activeInstance of activeChildren) {\n activeInstance.hide()\n }\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger)\n\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n // Private\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)\n\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n }\n }\n\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element))\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen)\n element.setAttribute('aria-expanded', isOpen)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n execute,\n getElement,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center'\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)'\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR = '.navbar'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\nconst PLACEMENT_TOPCENTER = 'top'\nconst PLACEMENT_BOTTOMCENTER = 'bottom'\n\nconst Default = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n}\n\nconst DefaultType = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n}\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._popper = null\n this._parent = this._element.parentNode // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.findOne(SELECTOR_MENU, this._parent)\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._createPopper()\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = super._getConfig(config)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org/docs/v2/)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = this._parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n }\n\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getPlacement() {\n const parentDropdown = this._parent\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig])\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {\n return\n }\n\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)\n\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle)\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n const relatedTarget = { relatedTarget: context._element }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName)\n const isEscapeEvent = event.key === ESCAPE_KEY\n const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)\n\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return\n }\n\n if (isInput && !isEscapeEvent) {\n return\n }\n\n event.preventDefault()\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?\n this :\n (SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode))\n\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (isUpOrDownEvent) {\n event.stopPropagation()\n instance.show()\n instance._selectMenuItem(event)\n return\n }\n\n if (instance._isShown()) { // else is escape and we check if it is shown\n event.stopPropagation()\n instance.hide()\n getToggleButton.focus()\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport {\n execute, executeAfterTransition, getElement, reflow\n} from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nconst Default = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n}\n\nconst DefaultType = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n}\n\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n const element = this._getElement()\n if (this._config.isAnimated) {\n reflow(element)\n }\n\n element.classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n const element = this._getElement()\n this._config.rootElement.append(element)\n\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nconst Default = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n}\n\nconst DefaultType = {\n autofocus: 'boolean',\n trapElement: 'element'\n}\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return\n }\n\n if (this._config.autofocus) {\n this._config.trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n _handleFocusin(event) {\n const { trapElement } = this._config\n\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\nconst PROPERTY_PADDING = 'padding-right'\nconst PROPERTY_MARGIN = 'margin-right'\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProperty)\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty)\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty)\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty)\n return\n }\n\n Manipulator.removeDataAttribute(element, styleProperty)\n element.style.setProperty(styleProperty, value)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n return\n }\n\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel)\n }\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin, isRTL, isVisible, reflow\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\nconst Default = {\n backdrop: true,\n focus: true,\n keyboard: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._isTransitioning = true\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._backdrop.show(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n this._isTransitioning = true\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated())\n }\n\n dispose() {\n EventHandler.off(window, EVENT_KEY)\n EventHandler.off(this._dialog, EVENT_KEY)\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated())\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n this._triggerBackdropTransition()\n })\n\n EventHandler.on(window, EVENT_RESIZE, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog()\n }\n })\n\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return\n }\n\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n return\n }\n\n if (this._config.backdrop) {\n this.hide()\n }\n })\n })\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const initialOverflowY = this._element.style.overflowY\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden'\n }\n\n this._element.classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY\n }, this._dialog)\n }, this._dialog)\n\n this._element.focus()\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin,\n isDisabled,\n isVisible\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\nconst CLASS_NAME_HIDING = 'hiding'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate()\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.add(CLASS_NAME_HIDING)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n return\n }\n\n this.hide()\n }\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop)\n\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n })\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show()\n }\n})\n\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide()\n }\n }\n})\n\nenableDismissTrigger(Offcanvas)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n dd: [],\n div: [],\n dl: [],\n dt: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n// js-docs-end allow-list\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n .some(regex => regex.test(attributeName))\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n }\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\nimport { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'\nimport { execute, getElement, isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'TemplateFactory'\n\nconst Default = {\n allowList: DefaultAllowlist,\n content: {}, // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '<div></div>'\n}\n\nconst DefaultType = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n}\n\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n}\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content)\n .map(config => this._resolvePossibleFunction(config))\n .filter(Boolean)\n }\n\n hasContent() {\n return this.getContent().length > 0\n }\n\n changeContent(content) {\n this._checkContent(content)\n this._config.content = { ...this._config.content, ...content }\n return this\n }\n\n toHtml() {\n const templateWrapper = document.createElement('div')\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template)\n\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector)\n }\n\n const template = templateWrapper.children[0]\n const extraClass = this._resolvePossibleFunction(this._config.extraClass)\n\n if (extraClass) {\n template.classList.add(...extraClass.split(' '))\n }\n\n return template\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config)\n this._checkContent(config.content)\n }\n\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({ selector, entry: content }, DefaultContentType)\n }\n }\n\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!templateElement) {\n return\n }\n\n content = this._resolvePossibleFunction(content)\n\n if (!content) {\n templateElement.remove()\n return\n }\n\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement)\n return\n }\n\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content)\n return\n }\n\n templateElement.textContent = content\n }\n\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [undefined, this])\n }\n\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = ''\n templateElement.append(element)\n return\n }\n\n templateElement.textContent = element.textContent\n }\n}\n\nexport default TemplateFactory\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport {\n defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop\n} from './util/index.js'\nimport { DefaultAllowlist } from './util/sanitizer.js'\nimport TemplateFactory from './util/template-factory.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\nconst EVENT_HIDE = 'hide'\nconst EVENT_HIDDEN = 'hidden'\nconst EVENT_SHOW = 'show'\nconst EVENT_SHOWN = 'shown'\nconst EVENT_INSERTED = 'inserted'\nconst EVENT_CLICK = 'click'\nconst EVENT_FOCUSIN = 'focusin'\nconst EVENT_FOCUSOUT = 'focusout'\nconst EVENT_MOUSEENTER = 'mouseenter'\nconst EVENT_MOUSELEAVE = 'mouseleave'\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '<div class=\"tooltip\" role=\"tooltip\">' +\n '<div class=\"tooltip-arrow\"></div>' +\n '<div class=\"tooltip-inner\"></div>' +\n '</div>',\n title: '',\n trigger: 'hover focus'\n}\n\nconst DefaultType = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n}\n\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org/docs/v2/)')\n }\n\n super(element, config)\n\n // Private\n this._isEnabled = true\n this._timeout = 0\n this._isHovered = null\n this._activeTrigger = {}\n this._popper = null\n this._templateFactory = null\n this._newContent = null\n\n // Protected\n this.tip = null\n\n this._setListeners()\n\n if (!this._config.selector) {\n this._fixTitle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle() {\n if (!this._isEnabled) {\n return\n }\n\n if (this._isShown()) {\n this._leave()\n return\n }\n\n this._enter()\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'))\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this._isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW))\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper()\n\n const tip = this._getTipElement()\n\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'))\n\n const { container } = this._config\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))\n }\n\n this._popper = this._createPopper(tip)\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN))\n\n if (this._isHovered === false) {\n this._leave()\n }\n\n this._isHovered = false\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n hide() {\n if (!this._isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE))\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const tip = this._getTipElement()\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n this._isHovered = null // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (!this._isHovered) {\n this._disposePopper()\n }\n\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN))\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n update() {\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle())\n }\n\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())\n }\n\n return this.tip\n }\n\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml()\n\n // TODO: remove this check in v6\n if (!tip) {\n return null\n }\n\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`)\n\n const tipId = getUID(this.constructor.NAME).toString()\n\n tip.setAttribute('id', tipId)\n\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n return tip\n }\n\n setContent(content) {\n this._newContent = content\n if (this._isShown()) {\n this._disposePopper()\n this.show()\n }\n }\n\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content)\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n })\n }\n\n return this._templateFactory\n }\n\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n }\n }\n\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title')\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _isAnimated() {\n return this._config.animation || (this.tip && this.tip.classList.contains(CLASS_NAME_FADE))\n }\n\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW)\n }\n\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element])\n const attachment = AttachmentMap[placement.toUpperCase()]\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element, this._element])\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement)\n }\n }\n ]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig])\n }\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[TRIGGER_CLICK] = !(context._isShown() && context._activeTrigger[TRIGGER_CLICK])\n context.toggle()\n })\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSEENTER) :\n this.constructor.eventName(EVENT_FOCUSIN)\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSELEAVE) :\n this.constructor.eventName(EVENT_FOCUSOUT)\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true\n context._enter()\n })\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] =\n context._element.contains(event.relatedTarget)\n\n context._leave()\n })\n }\n }\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n\n if (!title) {\n return\n }\n\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('data-bs-original-title', title) // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title')\n }\n\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true\n return\n }\n\n this._isHovered = true\n\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show()\n }\n }, this._config.delay.show)\n }\n\n _leave() {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n this._isHovered = false\n\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide()\n }\n }, this._config.delay.hide)\n }\n\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout)\n this._timeout = setTimeout(handler, timeout)\n }\n\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true)\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute]\n }\n }\n\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value\n }\n }\n\n config.selector = false\n config.trigger = 'manual'\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n\n if (this.tip) {\n this.tip.remove()\n this.tip = null\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Tooltip from './tooltip.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'popover'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Default = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>',\n trigger: 'click'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n}\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent()\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n }\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin, getElement, isDisabled, isVisible\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_CLICK = `click${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_TARGET_LINKS = '[href]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst Default = {\n offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n}\n\nconst DefaultType = {\n offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n}\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map()\n this._observableSections = new Map()\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element\n this._activeTarget = null\n this._observer = null\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n }\n this.refresh() // initialize\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables()\n this._maybeEnableSmoothScroll()\n\n if (this._observer) {\n this._observer.disconnect()\n } else {\n this._observer = this._getNewObserver()\n }\n\n for (const section of this._observableSections.values()) {\n this._observer.observe(section)\n }\n }\n\n dispose() {\n this._observer.disconnect()\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin\n\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))\n }\n\n return config\n }\n\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK)\n\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash)\n if (observableSection) {\n event.preventDefault()\n const root = this._rootElement || window\n const height = observableSection.offsetTop - this._element.offsetTop\n if (root.scrollTo) {\n root.scrollTo({ top: height, behavior: 'smooth' })\n return\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height\n }\n })\n }\n\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n }\n\n return new IntersectionObserver(entries => this._observerCallback(entries), options)\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop\n this._process(targetElement(entry))\n }\n\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop\n this._previousScrollData.parentScrollTop = parentScrollTop\n\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null\n this._clearActiveClass(targetElement(entry))\n\n continue\n }\n\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry)\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return\n }\n\n continue\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry)\n }\n }\n }\n\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map()\n this._observableSections = new Map()\n\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)\n\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue\n }\n\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor)\n this._observableSections.set(anchor.hash, observableSection)\n }\n }\n }\n\n _process(target) {\n if (this._activeTarget === target) {\n return\n }\n\n this._clearActiveClass(this._config.target)\n this._activeTarget = target\n target.classList.add(CLASS_NAME_ACTIVE)\n this._activateParents(target)\n\n EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })\n }\n\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n return\n }\n\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {\n item.classList.add(CLASS_NAME_ACTIVE)\n }\n }\n }\n\n _clearActiveClass(parent) {\n parent.classList.remove(CLASS_NAME_ACTIVE)\n\n const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent)\n for (const node of activeNodes) {\n node.classList.remove(CLASS_NAME_ACTIVE)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = ScrollSpy.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {\n ScrollSpy.getOrCreateInstance(spy)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(ScrollSpy)\n\nexport default ScrollSpy\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tab.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tab'\nconst DATA_KEY = 'bs.tab'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}`\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst HOME_KEY = 'Home'\nconst END_KEY = 'End'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_DROPDOWN = 'dropdown'\n\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\nconst SELECTOR_DROPDOWN_MENU = '.dropdown-menu'\nconst NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`\n\nconst SELECTOR_TAB_PANEL = '.list-group, .nav, [role=\"tablist\"]'\nconst SELECTOR_OUTER = '.nav-item, .list-group-item'\nconst SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role=\"tab\"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]' // TODO: could only be `tab` in v6\nconst SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`\n\nconst SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle=\"tab\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"pill\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"list\"]`\n\n/**\n * Class definition\n */\n\nclass Tab extends BaseComponent {\n constructor(element) {\n super(element)\n this._parent = this._element.closest(SELECTOR_TAB_PANEL)\n\n if (!this._parent) {\n return\n // TODO: should throw exception in v6\n // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)\n }\n\n // Set up initial aria attributes\n this._setInitialAttributes(this._parent, this._getChildren())\n\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n show() { // Shows this elem and deactivate the active sibling if exists\n const innerElem = this._element\n if (this._elemIsActive(innerElem)) {\n return\n }\n\n // Search for active tab on same parent to deactivate it\n const active = this._getActiveElem()\n\n const hideEvent = active ?\n EventHandler.trigger(active, EVENT_HIDE, { relatedTarget: innerElem }) :\n null\n\n const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, { relatedTarget: active })\n\n if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {\n return\n }\n\n this._deactivate(active, innerElem)\n this._activate(innerElem, active)\n }\n\n // Private\n _activate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.add(CLASS_NAME_ACTIVE)\n\n this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.add(CLASS_NAME_SHOW)\n return\n }\n\n element.removeAttribute('tabindex')\n element.setAttribute('aria-selected', true)\n this._toggleDropDown(element, true)\n EventHandler.trigger(element, EVENT_SHOWN, {\n relatedTarget: relatedElem\n })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _deactivate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.remove(CLASS_NAME_ACTIVE)\n element.blur()\n\n this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.remove(CLASS_NAME_SHOW)\n return\n }\n\n element.setAttribute('aria-selected', false)\n element.setAttribute('tabindex', '-1')\n this._toggleDropDown(element, false)\n EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _keydown(event) {\n if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key))) {\n return\n }\n\n event.stopPropagation()// stopPropagation/preventDefault both added to support up/down keys without scrolling the page\n event.preventDefault()\n\n const children = this._getChildren().filter(element => !isDisabled(element))\n let nextActiveElement\n\n if ([HOME_KEY, END_KEY].includes(event.key)) {\n nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]\n } else {\n const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)\n nextActiveElement = getNextActiveElement(children, event.target, isNext, true)\n }\n\n if (nextActiveElement) {\n nextActiveElement.focus({ preventScroll: true })\n Tab.getOrCreateInstance(nextActiveElement).show()\n }\n }\n\n _getChildren() { // collection of inner elements\n return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent)\n }\n\n _getActiveElem() {\n return this._getChildren().find(child => this._elemIsActive(child)) || null\n }\n\n _setInitialAttributes(parent, children) {\n this._setAttributeIfNotExists(parent, 'role', 'tablist')\n\n for (const child of children) {\n this._setInitialAttributesOnChild(child)\n }\n }\n\n _setInitialAttributesOnChild(child) {\n child = this._getInnerElement(child)\n const isActive = this._elemIsActive(child)\n const outerElem = this._getOuterElement(child)\n child.setAttribute('aria-selected', isActive)\n\n if (outerElem !== child) {\n this._setAttributeIfNotExists(outerElem, 'role', 'presentation')\n }\n\n if (!isActive) {\n child.setAttribute('tabindex', '-1')\n }\n\n this._setAttributeIfNotExists(child, 'role', 'tab')\n\n // set attributes to the related panel too\n this._setInitialAttributesOnTargetPanel(child)\n }\n\n _setInitialAttributesOnTargetPanel(child) {\n const target = SelectorEngine.getElementFromSelector(child)\n\n if (!target) {\n return\n }\n\n this._setAttributeIfNotExists(target, 'role', 'tabpanel')\n\n if (child.id) {\n this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)\n }\n }\n\n _toggleDropDown(element, open) {\n const outerElem = this._getOuterElement(element)\n if (!outerElem.classList.contains(CLASS_DROPDOWN)) {\n return\n }\n\n const toggle = (selector, className) => {\n const element = SelectorEngine.findOne(selector, outerElem)\n if (element) {\n element.classList.toggle(className, open)\n }\n }\n\n toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)\n toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)\n outerElem.setAttribute('aria-expanded', open)\n }\n\n _setAttributeIfNotExists(element, attribute, value) {\n if (!element.hasAttribute(attribute)) {\n element.setAttribute(attribute, value)\n }\n }\n\n _elemIsActive(elem) {\n return elem.classList.contains(CLASS_NAME_ACTIVE)\n }\n\n // Try to get the inner element (usually the .nav-link)\n _getInnerElement(elem) {\n return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem)\n }\n\n // Try to get the outer element (usually the .nav-item)\n _getOuterElement(elem) {\n return elem.closest(SELECTOR_OUTER) || elem\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tab.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n Tab.getOrCreateInstance(this).show()\n})\n\n/**\n * Initialize on focus\n */\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {\n Tab.getOrCreateInstance(element)\n }\n})\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tab)\n\nexport default Tab\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap toast.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin, reflow } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'toast'\nconst DATA_KEY = 'bs.toast'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\n\nconst DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n}\n\nconst Default = {\n animation: true,\n autohide: true,\n delay: 5000\n}\n\n/**\n * Class definition\n */\n\nclass Toast extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._timeout = null\n this._hasMouseInteraction = false\n this._hasKeyboardInteraction = false\n this._setListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show() {\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._clearTimeout()\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE)\n }\n\n const complete = () => {\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN)\n\n this._maybeScheduleHide()\n }\n\n this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\n reflow(this._element)\n this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)\n\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n hide() {\n if (!this.isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const complete = () => {\n this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\n this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.classList.add(CLASS_NAME_SHOWING)\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n dispose() {\n this._clearTimeout()\n\n if (this.isShown()) {\n this._element.classList.remove(CLASS_NAME_SHOW)\n }\n\n super.dispose()\n }\n\n isShown() {\n return this._element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n _maybeScheduleHide() {\n if (!this._config.autohide) {\n return\n }\n\n if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\n return\n }\n\n this._timeout = setTimeout(() => {\n this.hide()\n }, this._config.delay)\n }\n\n _onInteraction(event, isInteracting) {\n switch (event.type) {\n case 'mouseover':\n case 'mouseout': {\n this._hasMouseInteraction = isInteracting\n break\n }\n\n case 'focusin':\n case 'focusout': {\n this._hasKeyboardInteraction = isInteracting\n break\n }\n\n default: {\n break\n }\n }\n\n if (isInteracting) {\n this._clearTimeout()\n return\n }\n\n const nextElement = event.relatedTarget\n if (this._element === nextElement || this._element.contains(nextElement)) {\n return\n }\n\n this._maybeScheduleHide()\n }\n\n _setListeners() {\n EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\n EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\n }\n\n _clearTimeout() {\n clearTimeout(this._timeout)\n this._timeout = null\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Toast.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Toast)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Toast)\n\nexport default Toast\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap index.umd.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './src/alert.js'\nimport Button from './src/button.js'\nimport Carousel from './src/carousel.js'\nimport Collapse from './src/collapse.js'\nimport Dropdown from './src/dropdown.js'\nimport Modal from './src/modal.js'\nimport Offcanvas from './src/offcanvas.js'\nimport Popover from './src/popover.js'\nimport ScrollSpy from './src/scrollspy.js'\nimport Tab from './src/tab.js'\nimport Toast from './src/toast.js'\nimport Tooltip from './src/tooltip.js'\n\nexport default {\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Offcanvas,\n Popover,\n ScrollSpy,\n Tab,\n Toast,\n Tooltip\n}\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file From bcde17cb9e789ad75ed255fc8ad381cefe2b200d Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 12 Oct 2025 20:37:38 +0200 Subject: [PATCH 211/244] =?UTF-8?q?=F0=9F=8E=A8=20(bootsier):=20Ajusta=20e?= =?UTF-8?q?stilos=20para=20personalizar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extensions/pagetop-bootsier/.gitattributes | 1 + extensions/pagetop-bootsier/Cargo.toml | 2 +- extensions/pagetop-bootsier/README.md | 2 +- extensions/pagetop-bootsier/build.rs | 6 +- extensions/pagetop-bootsier/src/lib.rs | 4 +- .../static/scss/_customs.scss | 108 ++++++++++++++++++ .../static/scss/bootsier.scss | 55 +++++++++ .../bootstrap-5.3.8}/_accordion.scss | 0 .../bootstrap-5.3.8}/_alert.scss | 0 .../bootstrap-5.3.8}/_badge.scss | 0 .../bootstrap-5.3.8}/_breadcrumb.scss | 0 .../bootstrap-5.3.8}/_button-group.scss | 0 .../bootstrap-5.3.8}/_buttons.scss | 0 .../bootstrap-5.3.8}/_card.scss | 0 .../bootstrap-5.3.8}/_carousel.scss | 0 .../bootstrap-5.3.8}/_close.scss | 0 .../bootstrap-5.3.8}/_containers.scss | 0 .../bootstrap-5.3.8}/_dropdown.scss | 0 .../bootstrap-5.3.8}/_forms.scss | 0 .../bootstrap-5.3.8}/_functions.scss | 0 .../bootstrap-5.3.8}/_grid.scss | 0 .../bootstrap-5.3.8}/_helpers.scss | 0 .../bootstrap-5.3.8}/_images.scss | 0 .../bootstrap-5.3.8}/_list-group.scss | 0 .../bootstrap-5.3.8}/_maps.scss | 0 .../bootstrap-5.3.8}/_mixins.scss | 0 .../bootstrap-5.3.8}/_modal.scss | 0 .../bootstrap-5.3.8}/_nav.scss | 0 .../bootstrap-5.3.8}/_navbar.scss | 0 .../bootstrap-5.3.8}/_offcanvas.scss | 0 .../bootstrap-5.3.8}/_pagination.scss | 0 .../bootstrap-5.3.8}/_placeholders.scss | 0 .../bootstrap-5.3.8}/_popover.scss | 0 .../bootstrap-5.3.8}/_progress.scss | 0 .../bootstrap-5.3.8}/_reboot.scss | 0 .../bootstrap-5.3.8}/_root.scss | 0 .../bootstrap-5.3.8}/_spinners.scss | 0 .../bootstrap-5.3.8}/_tables.scss | 0 .../bootstrap-5.3.8}/_toasts.scss | 0 .../bootstrap-5.3.8}/_tooltip.scss | 0 .../bootstrap-5.3.8}/_transitions.scss | 0 .../bootstrap-5.3.8}/_type.scss | 0 .../bootstrap-5.3.8}/_utilities.scss | 0 .../bootstrap-5.3.8}/_variables-dark.scss | 0 .../bootstrap-5.3.8}/_variables.scss | 0 .../bootstrap-5.3.8}/bootstrap-grid.scss | 0 .../bootstrap-5.3.8}/bootstrap-reboot.scss | 0 .../bootstrap-5.3.8}/bootstrap-utilities.scss | 0 .../bootstrap-5.3.8}/bootstrap.scss | 0 .../forms/_floating-labels.scss | 0 .../bootstrap-5.3.8}/forms/_form-check.scss | 0 .../bootstrap-5.3.8}/forms/_form-control.scss | 0 .../bootstrap-5.3.8}/forms/_form-range.scss | 0 .../bootstrap-5.3.8}/forms/_form-select.scss | 0 .../bootstrap-5.3.8}/forms/_form-text.scss | 0 .../bootstrap-5.3.8}/forms/_input-group.scss | 0 .../bootstrap-5.3.8}/forms/_labels.scss | 0 .../bootstrap-5.3.8}/forms/_validation.scss | 0 .../bootstrap-5.3.8}/helpers/_clearfix.scss | 0 .../bootstrap-5.3.8}/helpers/_color-bg.scss | 0 .../helpers/_colored-links.scss | 0 .../bootstrap-5.3.8}/helpers/_focus-ring.scss | 0 .../bootstrap-5.3.8}/helpers/_icon-link.scss | 0 .../bootstrap-5.3.8}/helpers/_position.scss | 0 .../bootstrap-5.3.8}/helpers/_ratio.scss | 0 .../bootstrap-5.3.8}/helpers/_stacks.scss | 0 .../helpers/_stretched-link.scss | 0 .../helpers/_text-truncation.scss | 0 .../helpers/_visually-hidden.scss | 0 .../bootstrap-5.3.8}/helpers/_vr.scss | 0 .../bootstrap-5.3.8}/mixins/_alert.scss | 0 .../bootstrap-5.3.8}/mixins/_backdrop.scss | 0 .../bootstrap-5.3.8}/mixins/_banner.scss | 0 .../mixins/_border-radius.scss | 0 .../bootstrap-5.3.8}/mixins/_box-shadow.scss | 0 .../bootstrap-5.3.8}/mixins/_breakpoints.scss | 0 .../bootstrap-5.3.8}/mixins/_buttons.scss | 0 .../bootstrap-5.3.8}/mixins/_caret.scss | 0 .../bootstrap-5.3.8}/mixins/_clearfix.scss | 0 .../bootstrap-5.3.8}/mixins/_color-mode.scss | 0 .../mixins/_color-scheme.scss | 0 .../bootstrap-5.3.8}/mixins/_container.scss | 0 .../bootstrap-5.3.8}/mixins/_deprecate.scss | 0 .../bootstrap-5.3.8}/mixins/_forms.scss | 0 .../bootstrap-5.3.8}/mixins/_gradients.scss | 0 .../bootstrap-5.3.8}/mixins/_grid.scss | 0 .../bootstrap-5.3.8}/mixins/_image.scss | 0 .../bootstrap-5.3.8}/mixins/_list-group.scss | 0 .../bootstrap-5.3.8}/mixins/_lists.scss | 0 .../bootstrap-5.3.8}/mixins/_pagination.scss | 0 .../bootstrap-5.3.8}/mixins/_reset-text.scss | 0 .../bootstrap-5.3.8}/mixins/_resize.scss | 0 .../mixins/_table-variants.scss | 0 .../mixins/_text-truncate.scss | 0 .../bootstrap-5.3.8}/mixins/_transition.scss | 0 .../bootstrap-5.3.8}/mixins/_utilities.scss | 0 .../mixins/_visually-hidden.scss | 0 .../bootstrap-5.3.8}/tests/jasmine.js | 0 .../_auto-import-of-variables-dark.test.scss | 0 .../tests/mixins/_box-shadow.test.scss | 0 .../tests/mixins/_color-contrast.test.scss | 0 .../tests/mixins/_color-modes.test.scss | 0 .../_media-query-color-mode-full.test.scss | 0 .../tests/mixins/_utilities.test.scss | 0 .../tests/sass-true/register.js | 0 .../tests/sass-true/runner.js | 0 .../tests/utilities/_api.test.scss | 0 .../bootstrap-5.3.8}/utilities/_api.scss | 0 .../bootstrap-5.3.8}/vendor/_rfs.scss | 0 109 files changed, 171 insertions(+), 7 deletions(-) create mode 100644 extensions/pagetop-bootsier/.gitattributes create mode 100644 extensions/pagetop-bootsier/static/scss/_customs.scss create mode 100644 extensions/pagetop-bootsier/static/scss/bootsier.scss rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_accordion.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_alert.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_badge.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_breadcrumb.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_button-group.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_buttons.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_card.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_carousel.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_close.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_containers.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_dropdown.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_forms.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_functions.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_grid.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_helpers.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_images.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_list-group.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_maps.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_mixins.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_modal.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_nav.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_navbar.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_offcanvas.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_pagination.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_placeholders.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_popover.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_progress.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_reboot.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_root.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_spinners.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_tables.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_toasts.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_tooltip.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_transitions.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_type.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_utilities.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_variables-dark.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/_variables.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/bootstrap-grid.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/bootstrap-reboot.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/bootstrap-utilities.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/bootstrap.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/forms/_floating-labels.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/forms/_form-check.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/forms/_form-control.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/forms/_form-range.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/forms/_form-select.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/forms/_form-text.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/forms/_input-group.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/forms/_labels.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/forms/_validation.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/helpers/_clearfix.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/helpers/_color-bg.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/helpers/_colored-links.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/helpers/_focus-ring.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/helpers/_icon-link.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/helpers/_position.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/helpers/_ratio.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/helpers/_stacks.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/helpers/_stretched-link.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/helpers/_text-truncation.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/helpers/_visually-hidden.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/helpers/_vr.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_alert.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_backdrop.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_banner.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_border-radius.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_box-shadow.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_breakpoints.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_buttons.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_caret.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_clearfix.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_color-mode.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_color-scheme.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_container.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_deprecate.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_forms.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_gradients.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_grid.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_image.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_list-group.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_lists.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_pagination.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_reset-text.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_resize.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_table-variants.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_text-truncate.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_transition.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_utilities.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/mixins/_visually-hidden.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/tests/jasmine.js (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/tests/mixins/_auto-import-of-variables-dark.test.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/tests/mixins/_box-shadow.test.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/tests/mixins/_color-contrast.test.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/tests/mixins/_color-modes.test.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/tests/mixins/_media-query-color-mode-full.test.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/tests/mixins/_utilities.test.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/tests/sass-true/register.js (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/tests/sass-true/runner.js (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/tests/utilities/_api.test.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/utilities/_api.scss (100%) rename extensions/pagetop-bootsier/static/{bootstrap => scss/bootstrap-5.3.8}/vendor/_rfs.scss (100%) diff --git a/extensions/pagetop-bootsier/.gitattributes b/extensions/pagetop-bootsier/.gitattributes new file mode 100644 index 00000000..940d6a84 --- /dev/null +++ b/extensions/pagetop-bootsier/.gitattributes @@ -0,0 +1 @@ +static/** linguist-vendored diff --git a/extensions/pagetop-bootsier/Cargo.toml b/extensions/pagetop-bootsier/Cargo.toml index 8945e5a8..11306b63 100644 --- a/extensions/pagetop-bootsier/Cargo.toml +++ b/extensions/pagetop-bootsier/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.18" edition = "2021" description = """ - Tema de PageTop basado en Bootstrap para ofrecer su catálogo de estilos y componentes flexibles. + Tema de PageTop basado en Bootstrap para dar vida a tus diseños web. """ categories = ["web-programming", "gui"] keywords = ["pagetop", "theme", "bootstrap", "css", "js"] diff --git a/extensions/pagetop-bootsier/README.md b/extensions/pagetop-bootsier/README.md index 1a33b4ea..7495bc22 100644 --- a/extensions/pagetop-bootsier/README.md +++ b/extensions/pagetop-bootsier/README.md @@ -2,7 +2,7 @@ <h1>PageTop Bootsier</h1> -<p>Tema de <strong>PageTop</strong> basado en Bootstrap para ofrecer su catálogo de estilos y componentes flexibles.</p> +<p>Tema de <strong>PageTop</strong> basado en Bootstrap para dar vida a tus diseños web.</p> [![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier) [![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier) diff --git a/extensions/pagetop-bootsier/build.rs b/extensions/pagetop-bootsier/build.rs index f2d0f794..5945660a 100644 --- a/extensions/pagetop-bootsier/build.rs +++ b/extensions/pagetop-bootsier/build.rs @@ -4,8 +4,8 @@ use std::env; use std::path::Path; fn main() -> std::io::Result<()> { - StaticFilesBundle::from_scss("./static/bootstrap/bootstrap.scss", "bootstrap.min.css") - .with_name("bootsier") + StaticFilesBundle::from_scss("./static/scss/bootsier.scss", "bootstrap.min.css") + .with_name("bootsier_bs") .build()?; StaticFilesBundle::from_dir("./static/js", Some(bootstrap_js_files)) .with_name("bootsier_js") @@ -13,7 +13,7 @@ fn main() -> std::io::Result<()> { } fn bootstrap_js_files(path: &Path) -> bool { - // No filtering during development, only on "release" compilation. + // No filtra durante el desarrollo, solo en la compilación "release". env::var("PROFILE").unwrap_or_else(|_| "release".to_string()) != "release" || path.file_name().map_or(false, |n| n == "bootstrap.min.js") } diff --git a/extensions/pagetop-bootsier/src/lib.rs b/extensions/pagetop-bootsier/src/lib.rs index fecf1273..a6583333 100644 --- a/extensions/pagetop-bootsier/src/lib.rs +++ b/extensions/pagetop-bootsier/src/lib.rs @@ -100,7 +100,7 @@ impl Extension for Bootsier { } fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { - static_files_service!(scfg, [bootsier] => "/bootsier/css"); + static_files_service!(scfg, [bootsier_bs] => "/bootsier/bs"); static_files_service!(scfg, [bootsier_js] => "/bootsier/js"); } } @@ -108,7 +108,7 @@ impl Extension for Bootsier { impl Theme for Bootsier { fn after_render_page_body(&self, page: &mut Page) { page.alter_assets(ContextOp::AddStyleSheet( - StyleSheet::from("/bootsier/css/bootstrap.min.css") + StyleSheet::from("/bootsier/bs/bootstrap.min.css") .with_version(BOOTSTRAP_VERSION) .with_weight(-90), )) diff --git a/extensions/pagetop-bootsier/static/scss/_customs.scss b/extensions/pagetop-bootsier/static/scss/_customs.scss new file mode 100644 index 00000000..988d7055 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/_customs.scss @@ -0,0 +1,108 @@ +// Enable CSS Grid +$enable-grid-classes: false; +$enable-cssgrid: true; + +// Opacity +.bg-opacity-0 { + --bs-bg-opacity: 0; +} + +.border-opacity-0 { + --bs-border-opacity: 0; +} + +.text-opacity-0 { + --bs-text-opacity: 0; +} +.text-opacity-10 { + --bs-text-opacity: 0.1; +} + +// Extending utilities +$utilities: map-merge( + $utilities, + ( + // Individual border widths + "border-top": ( + property: border-top-width, + class: border-top, + values: $border-widths + ), + "border-end": ( + property: border-right-width, + class: border-end, + values: $border-widths + ), + "border-bottom": ( + property: border-bottom-width, + class: border-bottom, + values: $border-widths + ), + "border-start": ( + property: border-left-width, + class: border-start, + values: $border-widths + ), + // Individual rounded values + "rounded-top-start": ( + property: border-top-left-radius, + class: rounded-top-start, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-top-end": ( + property: border-top-right-radius, + class: rounded-top-end, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-bottom-start": ( + property: border-bottom-left-radius, + class: rounded-bottom-start, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-bottom-end": ( + property: border-bottom-right-radius, + class: rounded-bottom-end, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + ) +); diff --git a/extensions/pagetop-bootsier/static/scss/bootsier.scss b/extensions/pagetop-bootsier/static/scss/bootsier.scss new file mode 100644 index 00000000..0d52046a --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootsier.scss @@ -0,0 +1,55 @@ +@import "bootstrap-5.3.8/mixins/banner"; +@include bsBanner(""); + + +// scss-docs-start import-stack +// Configuration +@import "bootstrap-5.3.8/functions"; +@import "bootstrap-5.3.8/variables"; +@import "bootstrap-5.3.8/variables-dark"; +@import "bootstrap-5.3.8/maps"; +@import "bootstrap-5.3.8/mixins"; +@import "bootstrap-5.3.8/utilities"; + +// Layout & components +@import "bootstrap-5.3.8/root"; +@import "bootstrap-5.3.8/reboot"; +@import "bootstrap-5.3.8/type"; +@import "bootstrap-5.3.8/images"; +@import "bootstrap-5.3.8/containers"; +@import "bootstrap-5.3.8/grid"; +@import "bootstrap-5.3.8/tables"; +@import "bootstrap-5.3.8/forms"; +@import "bootstrap-5.3.8/buttons"; +@import "bootstrap-5.3.8/transitions"; +@import "bootstrap-5.3.8/dropdown"; +@import "bootstrap-5.3.8/button-group"; +@import "bootstrap-5.3.8/nav"; +@import "bootstrap-5.3.8/navbar"; +@import "bootstrap-5.3.8/card"; +@import "bootstrap-5.3.8/accordion"; +@import "bootstrap-5.3.8/breadcrumb"; +@import "bootstrap-5.3.8/pagination"; +@import "bootstrap-5.3.8/badge"; +@import "bootstrap-5.3.8/alert"; +@import "bootstrap-5.3.8/progress"; +@import "bootstrap-5.3.8/list-group"; +@import "bootstrap-5.3.8/close"; +@import "bootstrap-5.3.8/toasts"; +@import "bootstrap-5.3.8/modal"; +@import "bootstrap-5.3.8/tooltip"; +@import "bootstrap-5.3.8/popover"; +@import "bootstrap-5.3.8/carousel"; +@import "bootstrap-5.3.8/spinners"; +@import "bootstrap-5.3.8/offcanvas"; +@import "bootstrap-5.3.8/placeholders"; + +// Helpers +@import "bootstrap-5.3.8/helpers"; + +// Custom definitions +@import "customs"; + +// Utilities +@import "bootstrap-5.3.8/utilities/api"; +// scss-docs-end import-stack diff --git a/extensions/pagetop-bootsier/static/bootstrap/_accordion.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_accordion.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_accordion.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_accordion.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_alert.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_alert.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_alert.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_alert.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_badge.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_badge.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_badge.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_badge.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_breadcrumb.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_breadcrumb.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_breadcrumb.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_breadcrumb.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_button-group.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_button-group.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_button-group.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_button-group.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_buttons.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_buttons.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_buttons.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_buttons.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_card.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_card.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_card.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_card.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_carousel.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_carousel.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_carousel.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_carousel.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_close.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_close.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_close.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_close.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_containers.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_containers.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_containers.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_containers.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_dropdown.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_dropdown.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_dropdown.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_dropdown.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_forms.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_forms.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_forms.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_forms.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_functions.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_functions.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_functions.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_functions.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_grid.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_grid.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_grid.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_grid.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_helpers.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_helpers.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_helpers.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_helpers.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_images.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_images.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_images.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_images.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_list-group.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_list-group.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_list-group.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_list-group.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_maps.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_maps.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_maps.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_maps.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_mixins.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_mixins.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_mixins.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_mixins.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_modal.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_modal.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_modal.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_modal.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_nav.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_nav.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_nav.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_nav.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_navbar.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_navbar.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_navbar.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_navbar.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_offcanvas.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_offcanvas.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_offcanvas.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_offcanvas.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_pagination.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_pagination.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_pagination.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_pagination.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_placeholders.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_placeholders.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_placeholders.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_placeholders.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_popover.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_popover.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_popover.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_popover.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_progress.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_progress.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_progress.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_progress.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_reboot.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_reboot.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_reboot.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_reboot.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_root.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_root.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_root.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_root.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_spinners.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_spinners.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_spinners.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_spinners.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_tables.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_tables.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_tables.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_tables.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_toasts.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_toasts.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_toasts.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_toasts.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_tooltip.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_tooltip.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_tooltip.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_tooltip.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_transitions.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_transitions.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_transitions.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_transitions.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_type.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_type.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_type.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_type.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_utilities.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_utilities.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_utilities.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_utilities.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_variables-dark.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_variables-dark.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_variables-dark.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_variables-dark.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/_variables.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_variables.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/_variables.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_variables.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/bootstrap-grid.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-grid.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/bootstrap-grid.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-grid.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/bootstrap-reboot.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-reboot.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/bootstrap-reboot.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-reboot.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/bootstrap-utilities.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-utilities.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/bootstrap-utilities.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-utilities.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/bootstrap.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/bootstrap.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/forms/_floating-labels.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_floating-labels.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/forms/_floating-labels.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_floating-labels.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/forms/_form-check.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-check.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/forms/_form-check.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-check.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/forms/_form-control.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-control.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/forms/_form-control.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-control.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/forms/_form-range.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-range.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/forms/_form-range.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-range.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/forms/_form-select.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-select.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/forms/_form-select.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-select.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/forms/_form-text.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-text.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/forms/_form-text.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-text.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/forms/_input-group.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_input-group.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/forms/_input-group.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_input-group.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/forms/_labels.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_labels.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/forms/_labels.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_labels.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/forms/_validation.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_validation.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/forms/_validation.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_validation.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/helpers/_clearfix.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_clearfix.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/helpers/_clearfix.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_clearfix.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/helpers/_color-bg.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_color-bg.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/helpers/_color-bg.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_color-bg.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/helpers/_colored-links.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_colored-links.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/helpers/_colored-links.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_colored-links.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/helpers/_focus-ring.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_focus-ring.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/helpers/_focus-ring.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_focus-ring.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/helpers/_icon-link.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_icon-link.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/helpers/_icon-link.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_icon-link.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/helpers/_position.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_position.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/helpers/_position.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_position.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/helpers/_ratio.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_ratio.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/helpers/_ratio.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_ratio.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/helpers/_stacks.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_stacks.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/helpers/_stacks.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_stacks.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/helpers/_stretched-link.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_stretched-link.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/helpers/_stretched-link.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_stretched-link.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/helpers/_text-truncation.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_text-truncation.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/helpers/_text-truncation.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_text-truncation.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/helpers/_visually-hidden.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_visually-hidden.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/helpers/_visually-hidden.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_visually-hidden.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/helpers/_vr.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_vr.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/helpers/_vr.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_vr.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_alert.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_alert.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_alert.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_alert.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_backdrop.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_backdrop.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_backdrop.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_backdrop.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_banner.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_banner.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_banner.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_banner.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_border-radius.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_border-radius.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_border-radius.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_border-radius.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_box-shadow.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_box-shadow.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_box-shadow.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_box-shadow.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_breakpoints.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_breakpoints.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_breakpoints.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_breakpoints.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_buttons.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_buttons.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_buttons.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_buttons.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_caret.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_caret.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_caret.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_caret.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_clearfix.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_clearfix.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_clearfix.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_clearfix.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_color-mode.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_color-mode.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_color-mode.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_color-mode.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_color-scheme.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_color-scheme.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_color-scheme.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_color-scheme.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_container.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_container.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_container.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_container.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_deprecate.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_deprecate.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_deprecate.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_deprecate.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_forms.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_forms.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_forms.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_forms.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_gradients.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_gradients.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_gradients.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_gradients.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_grid.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_grid.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_grid.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_grid.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_image.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_image.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_image.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_image.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_list-group.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_list-group.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_list-group.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_list-group.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_lists.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_lists.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_lists.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_lists.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_pagination.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_pagination.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_pagination.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_pagination.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_reset-text.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_reset-text.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_reset-text.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_reset-text.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_resize.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_resize.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_resize.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_resize.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_table-variants.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_table-variants.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_table-variants.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_table-variants.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_text-truncate.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_text-truncate.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_text-truncate.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_text-truncate.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_transition.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_transition.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_transition.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_transition.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_utilities.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_utilities.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_utilities.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_utilities.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/mixins/_visually-hidden.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_visually-hidden.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/mixins/_visually-hidden.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_visually-hidden.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/tests/jasmine.js b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/jasmine.js similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/tests/jasmine.js rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/jasmine.js diff --git a/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_auto-import-of-variables-dark.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_auto-import-of-variables-dark.test.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_auto-import-of-variables-dark.test.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_auto-import-of-variables-dark.test.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_box-shadow.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_box-shadow.test.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_box-shadow.test.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_box-shadow.test.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_color-contrast.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_color-contrast.test.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_color-contrast.test.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_color-contrast.test.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_color-modes.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_color-modes.test.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_color-modes.test.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_color-modes.test.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_media-query-color-mode-full.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_media-query-color-mode-full.test.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_media-query-color-mode-full.test.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_media-query-color-mode-full.test.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_utilities.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_utilities.test.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/tests/mixins/_utilities.test.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_utilities.test.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/tests/sass-true/register.js b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/sass-true/register.js similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/tests/sass-true/register.js rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/sass-true/register.js diff --git a/extensions/pagetop-bootsier/static/bootstrap/tests/sass-true/runner.js b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/sass-true/runner.js similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/tests/sass-true/runner.js rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/sass-true/runner.js diff --git a/extensions/pagetop-bootsier/static/bootstrap/tests/utilities/_api.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/utilities/_api.test.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/tests/utilities/_api.test.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/utilities/_api.test.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/utilities/_api.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/utilities/_api.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/utilities/_api.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/utilities/_api.scss diff --git a/extensions/pagetop-bootsier/static/bootstrap/vendor/_rfs.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/vendor/_rfs.scss similarity index 100% rename from extensions/pagetop-bootsier/static/bootstrap/vendor/_rfs.scss rename to extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/vendor/_rfs.scss From 39a3dabcfb5b9f62414816c9134b6fbd6f5d2365 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 13 Oct 2025 13:13:33 +0200 Subject: [PATCH 212/244] =?UTF-8?q?=E2=9C=A8=20(html):=20A=C3=B1ade=20sopo?= =?UTF-8?q?rte=20para=20unidades=20CSS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 9 +- Cargo.toml | 1 + src/html.rs | 5 + src/html/unit.rs | 259 ++++++++++++++++++++++++++++++++++ src/prelude.rs | 2 +- tests/{html.rs => html_pm.rs} | 0 tests/html_unit.rs | 223 +++++++++++++++++++++++++++++ 7 files changed, 494 insertions(+), 5 deletions(-) create mode 100644 src/html/unit.rs rename tests/{html.rs => html_pm.rs} (100%) create mode 100644 tests/html_unit.rs diff --git a/Cargo.lock b/Cargo.lock index ebcebd39..f1b09f9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1568,6 +1568,7 @@ dependencies = [ "parking_lot", "pastey", "serde", + "serde_json", "substring", "tempfile", "terminal_size", @@ -1914,9 +1915,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.3" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +checksum = "4a52d8d02cacdb176ef4678de6c052efb4b3da14b78e4db683a4252762be5433" dependencies = [ "aho-corasick", "memchr", @@ -1926,9 +1927,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +checksum = "722166aa0d7438abbaa4d5cc2c649dac844e8c56d82fb3d33e9c34b5cd268fc6" dependencies = [ "aho-corasick", "memchr", diff --git a/Cargo.toml b/Cargo.toml index 103f6a94..0d17082b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ testing = [] [dev-dependencies] tempfile = "3.23" +serde_json = "1.0" pagetop-aliner.workspace = true pagetop-bootsier.workspace = true diff --git a/src/html.rs b/src/html.rs index abc8e8cf..f85c24ed 100644 --- a/src/html.rs +++ b/src/html.rs @@ -84,6 +84,11 @@ use crate::{core, AutoDefault}; #[allow(type_alias_bounds)] pub type OptionComponent<C: core::component::Component> = core::component::Typed<C>; +mod unit; +pub use unit::UnitValue; + +// **< HTML PrepareMarkup >************************************************************************* + /// Prepara contenido HTML para su conversión a [`Markup`]. /// /// Este tipo encapsula distintos orígenes de contenido HTML (texto plano, HTML sin escapar o diff --git a/src/html/unit.rs b/src/html/unit.rs new file mode 100644 index 00000000..b6a9bc76 --- /dev/null +++ b/src/html/unit.rs @@ -0,0 +1,259 @@ +use crate::AutoDefault; + +use serde::{Deserialize, Deserializer}; + +use std::fmt; +use std::str::FromStr; + +/// Representa una **unidad CSS** lista para formatear o deserializar. +/// +/// ## Unidades soportadas +/// +/// - **Absolutas** *(valores enteros, `isize`)*: +/// - `Cm(isize)` - `cm` (centímetros) +/// - `In(isize)` - `in` (pulgadas; `1in = 96px = 2.54cm`) +/// - `Mm(isize)` - `mm` (milímetros) +/// - `Pc(isize)` - `pc` (picas; `1pc = 12pt`) +/// - `Pt(isize)` - `pt` (puntos; `1pt = 1/72in`) +/// - `Px(isize)` - `px` (píxeles; `1px = 1/96in`) +/// +/// - **Relativas** *(valores decimales, `f32`)*: +/// - `RelEm(f32)` - `em` (relativa al tamaño de fuente del elemento) +/// - `RelRem(f32)` - `rem` (relativa al tamaño de fuente de `:root`) +/// - `RelPct(f32)` - `%` (porcentaje relativo al elemento padre) +/// - `RelVh(f32)` - `vh` (1% de la **altura** del viewport) +/// - `RelVw(f32)` - `vw` (1% del **ancho** del viewport) +/// +/// ## Valores especiales +/// +/// - `None` - equivale a un texto vacío (`""`), útil para atributos opcionales. +/// - `Auto` - equivale a `"auto"`. +/// - `Zero` - equivale a `"0"` (cero sin unidad). +/// +/// ## Características +/// +/// - Soporta unidades **absolutas** (`cm`, `in`, `mm`, `pc`, `pt`, `px`) y **relativas** (`em`, +/// `rem`, `%`, `vh`, `vw`). +/// - `FromStr` para convertir desde texto (p.ej. `"12px"`, `"1.25rem"`, `"auto"`). +/// - `Display` para formatear a cadena (p.ej. `UnitValue::Px(12)` genera `"12px"`). +/// - `Deserialize` delega en `FromStr`, garantizando una gramática única. +/// +/// ## Ejemplos +/// +/// ```rust +/// # use pagetop::prelude::*; +/// use std::str::FromStr; +/// +/// assert_eq!(UnitValue::from_str("16px").unwrap(), UnitValue::Px(16)); +/// assert_eq!(UnitValue::from_str("1.25rem").unwrap(), UnitValue::RelRem(1.25)); +/// assert_eq!(UnitValue::from_str("33%").unwrap(), UnitValue::RelPct(33.0)); +/// assert_eq!(UnitValue::from_str("auto").unwrap(), UnitValue::Auto); +/// assert_eq!(UnitValue::from_str("").unwrap(), UnitValue::None); +/// assert_eq!(UnitValue::from_str("0").unwrap(), UnitValue::Zero); +/// ``` +/// +/// ## Notas +/// +/// - Las absolutas **no aceptan** decimales (p.ej., `"1.5px"` sería erróneo). +/// - Se aceptan signos `+`/`-` en todas las unidades (p.ej., `"-12px"`, `"+0.5em"`). +/// - La comparación de unidad es *case-insensitive* al interpretar el texto (`"PX"`, `"Px"`, …). +/// - **Sobre píxeles**: Los píxeles (px) son relativos al dispositivo de visualización. En +/// dispositivos con baja densidad de píxeles (dpi), 1px equivale a un píxel (punto) del +/// dispositivo. En impresoras y pantallas de alta resolución, 1px implica múltiples píxeles del +/// dispositivo. +/// - **Sobre `em` y `rem`**: +/// - `em` es **relativo al tamaño de fuente *del propio elemento***. Si el elemento hereda o +/// cambia su `font-size`, todos los valores en `em` dentro de él **se escalan en cascada**. +/// - `rem` es **relativo al tamaño de fuente del elemento raíz** (`:root`/`html`), **no se verá +/// afectado** por cambios de `font-size` en elementos anidados. +/// - Ejemplo: si `:root { font-size: 16px }` y un contenedor tiene `font-size: 20px`, entonces +/// dentro del contenedor `1em == 20px` pero `1rem == 16px`. +/// - Uso típico: `rem` para tipografía y espaciados globales (consistencia al cambiar la base del +/// sitio); `em` para tamaños que deban escalar **con el propio componente** (p.ej., +/// `padding: 0.5em` que crece si el componente aumenta su `font-size`). +/// - **Sobre el viewport**: Si el ancho de la ventana del navegador es de 50cm, 1vw equivale a +/// 0.5cm (1vw siempre es 1% del ancho del viewport, independientemente del zoom del navegador o +/// la densidad de píxeles del dispositivo). +#[rustfmt::skip] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum UnitValue { + #[default] + None, + Auto, + /// Cero sin unidad. + Zero, + /// Centímetros. + Cm(isize), + /// Pulgadas (1in = 96px = 2.54cm). + In(isize), + /// Milímetros. + Mm(isize), + /// Picas (1pc = 12pt). + Pc(isize), + /// Puntos (1pt = 1/72in). + Pt(isize), + /// Píxeles (1px = 1/96in). + Px(isize), + /// Relativo al tamaño de la fuente del elemento. + RelEm(f32), + /// Relativo al tamaño de la fuente del elemento raíz. + RelRem(f32), + /// Porcentaje relativo al elemento padre. + RelPct(f32), + /// Relativo al 1% de la altura del viewport. + RelVh(f32), + /// Relativo al 1% del ancho del viewport. + RelVw(f32), +} + +/// Formatea la unidad como cadena CSS. +/// +/// Reglas: +/// +/// - `None` - `""` (cadena vacía). +/// - `Auto` - `"auto"`. +/// - `Zero` - `"0"` (cero sin unidad). +/// - Absolutas - entero con su unidad: `Px(12)` a `"12px"`. +/// - Relativas - número en punto flotante; si es entero, se imprime sin decimales: +/// - `RelEm(2.0)` a `"2em"` +/// - `RelPct(33.5)` a `"33.5%"` +#[rustfmt::skip] +impl fmt::Display for UnitValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + UnitValue::None => write!(f, ""), + UnitValue::Auto => write!(f, "auto"), + UnitValue::Zero => write!(f, "0"), + // Valor absoluto. + UnitValue::Cm(av) => write!(f, "{av}cm"), + UnitValue::In(av) => write!(f, "{av}in"), + UnitValue::Mm(av) => write!(f, "{av}mm"), + UnitValue::Pc(av) => write!(f, "{av}pc"), + UnitValue::Pt(av) => write!(f, "{av}pt"), + UnitValue::Px(av) => write!(f, "{av}px"), + // Valor relativo. + UnitValue::RelEm(rv) => write!(f, "{rv}em"), + UnitValue::RelRem(rv) => write!(f, "{rv}rem"), + UnitValue::RelPct(rv) => write!(f, "{rv}%"), + UnitValue::RelVh(rv) => write!(f, "{rv}vh"), + UnitValue::RelVw(rv) => write!(f, "{rv}vw"), + } + } +} + +/// Convierte una cadena a [`UnitValue`] siguiendo una gramática CSS acotada. +/// +/// ## Acepta +/// +/// - `""` para `UnitValue::None` +/// - `"auto"` +/// - **Cero sin unidad**: `"0"`, `"+0"`, `"-0"`, `"0.0"`, `"0."`, `".0"` para `UnitValue::Zero` +/// - Porcentaje: `"<n>%"` (p.ej. `"33%"`, `"33 %"`) +/// - Absolutas enteras: `"<entero><unidad>"`, p.ej. `"12px"`, `"-5pt"` +/// - Relativas decimales: `"<float><unidad>"`, p.ej. `"1.25rem"`, `"-0.5vh"`, `".5em"`, `"1.rem"` +/// +/// (Se toleran espacios entre número y unidad: `"12 px"`, `"1.5 rem"`). +/// +/// ## Ejemplo +/// +/// ```rust +/// # use pagetop::prelude::*; +/// use std::str::FromStr; +/// +/// assert_eq!(UnitValue::from_str("12px").unwrap(), UnitValue::Px(12)); +/// assert!(UnitValue::from_str("12").is_err()); +/// ``` +/// +/// ## Errores de interpretación +/// +/// - Falta la unidad cuando es necesaria (p.ej. `"12"`, excepto para el valor cero). +/// - Decimales en valores que deben ser absolutos (p.ej. `"1.5px"`). +/// - Unidades desconocidas (p.ej. `"10ch"`, no soportada aún). +/// - Notación científica o bases no decimales: `"1e3vw"`, `"0x10px"` (no soportadas). Los ceros a +/// la izquierda (p. ej. `"020px"`) se interpretan en **base 10** (`20px`). +/// +/// La comparación de la unidad es *case-insensitive*. +impl FromStr for UnitValue { + type Err = String; + + fn from_str(input: &str) -> Result<Self, Self::Err> { + let s = input.trim(); + if s.is_empty() { + return Ok(UnitValue::None); + } + if s.eq_ignore_ascii_case("auto") { + return Ok(UnitValue::Auto); + } + + match s.find(|c: char| c.is_ascii_alphabetic() || c == '%') { + None => { + let n: f32 = s + .parse() + .map_err(|e| format!("Invalid number `{s}`: {e}"))?; + if n == 0.0 { + Ok(UnitValue::Zero) + } else { + Err( + "Missing unit (expected one of cm,in,mm,pc,pt,px,em,rem,vh,vw, or %)" + .to_string(), + ) + } + } + Some(split_pos) => { + let (num_str, unit_str) = s.split_at(split_pos); + let u = unit_str.trim(); + let n = num_str.trim(); + + let parse_abs = |n_s: &str| -> Result<isize, String> { + n_s.parse::<isize>() + .map_err(|e| format!("Invalid integer `{n_s}`: {e}")) + }; + let parse_rel = |n_s: &str| -> Result<f32, String> { + n_s.parse::<f32>() + .map_err(|e| format!("Invalid float `{n_s}`: {e}")) + }; + + match u.to_ascii_lowercase().as_str() { + // Unidades absolutas. + "cm" => Ok(UnitValue::Cm(parse_abs(n)?)), + "in" => Ok(UnitValue::In(parse_abs(n)?)), + "mm" => Ok(UnitValue::Mm(parse_abs(n)?)), + "pc" => Ok(UnitValue::Pc(parse_abs(n)?)), + "pt" => Ok(UnitValue::Pt(parse_abs(n)?)), + "px" => Ok(UnitValue::Px(parse_abs(n)?)), + // Unidades relativas. + "em" => Ok(UnitValue::RelEm(parse_rel(n)?)), + "rem" => Ok(UnitValue::RelRem(parse_rel(n)?)), + "vh" => Ok(UnitValue::RelVh(parse_rel(n)?)), + "vw" => Ok(UnitValue::RelVw(parse_rel(n)?)), + // Porcentaje como unidad. + "%" => Ok(UnitValue::RelPct(parse_rel(n)?)), + // Unidad desconocida. + _ => Err(format!("Unknown unit: `{u}`")), + } + } + } + } +} + +/// Deserializa desde una cadena usando la misma gramática que [`FromStr`]. +/// +/// ### Ejemplo con `serde_json` +/// ```rust +/// # use pagetop::prelude::*; +/// use serde::Deserialize; +/// +/// #[derive(Deserialize)] +/// struct Style { width: UnitValue } +/// +/// // "{\"width\":\"12px\"}" deserializa como `Style { width: UnitValue::Px(12) }` +/// ``` +impl<'de> Deserialize<'de> for UnitValue { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + let raw = String::deserialize(deserializer)?; + raw.parse().map_err(serde::de::Error::custom) + } +} diff --git a/src/prelude.rs b/src/prelude.rs index a71375e1..cd3191f6 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -34,7 +34,7 @@ pub use crate::trace; pub use crate::html::{ display, html_private, Asset, Assets, AttrClasses, AttrId, AttrL10n, AttrName, AttrValue, ClassesOp, Escaper, Favicon, JavaScript, Markup, PreEscaped, PrepareMarkup, StyleSheet, - TargetMedia, DOCTYPE, + TargetMedia, UnitValue, DOCTYPE, }; pub use crate::locale::*; diff --git a/tests/html.rs b/tests/html_pm.rs similarity index 100% rename from tests/html.rs rename to tests/html_pm.rs diff --git a/tests/html_unit.rs b/tests/html_unit.rs new file mode 100644 index 00000000..9316af89 --- /dev/null +++ b/tests/html_unit.rs @@ -0,0 +1,223 @@ +use pagetop::prelude::*; + +use std::str::FromStr; + +#[pagetop::test] +async fn unit_value_empty_and_auto_and_zero_without_unit() { + assert_eq!(UnitValue::from_str("").unwrap(), UnitValue::None); + assert_eq!(UnitValue::from_str("auto").unwrap(), UnitValue::Auto); + assert_eq!(UnitValue::from_str("AUTO").unwrap(), UnitValue::Auto); + + // Cero sin unidad. + assert_eq!(UnitValue::from_str("0").unwrap(), UnitValue::Zero); + assert_eq!(UnitValue::from_str("+0").unwrap(), UnitValue::Zero); + assert_eq!(UnitValue::from_str("-0").unwrap(), UnitValue::Zero); +} + +#[pagetop::test] +async fn unit_value_absolute_integers_with_signs_and_spaces_and_case() { + // Positivos, negativos y con espacios. + assert_eq!(UnitValue::from_str("12px").unwrap(), UnitValue::Px(12)); + assert_eq!(UnitValue::from_str("-5pt").unwrap(), UnitValue::Pt(-5)); + assert_eq!(UnitValue::from_str(" 7 cm ").unwrap(), UnitValue::Cm(7)); + assert_eq!(UnitValue::from_str("+9 in").unwrap(), UnitValue::In(9)); + assert_eq!(UnitValue::from_str(" 13 mm ").unwrap(), UnitValue::Mm(13)); + assert_eq!(UnitValue::from_str("4 pc").unwrap(), UnitValue::Pc(4)); + + // Insensibilidad a mayúsculas. + assert_eq!(UnitValue::from_str("10PX").unwrap(), UnitValue::Px(10)); + assert_eq!(UnitValue::from_str("15Pt").unwrap(), UnitValue::Pt(15)); +} + +#[pagetop::test] +async fn unit_value_relative_floats_with_signs_and_spaces_and_case() { + assert_eq!( + UnitValue::from_str("1.25rem").unwrap(), + UnitValue::RelRem(1.25) + ); + assert_eq!( + UnitValue::from_str("-0.5em").unwrap(), + UnitValue::RelEm(-0.5) + ); + assert_eq!( + UnitValue::from_str(" 33% ").unwrap(), + UnitValue::RelPct(33.0) + ); + assert_eq!( + UnitValue::from_str(" -12.5 vh").unwrap(), + UnitValue::RelVh(-12.5) + ); + assert_eq!( + UnitValue::from_str(" 8.0 VW ").unwrap(), + UnitValue::RelVw(8.0) + ); +} + +#[pagetop::test] +async fn unit_value_whitespace_between_number_and_unit_is_allowed() { + // Hay espacio entre número y unidad (la implementación actual lo admite). + assert_eq!(UnitValue::from_str("12 px").unwrap(), UnitValue::Px(12)); + assert_eq!( + UnitValue::from_str("1.5 rem").unwrap(), + UnitValue::RelRem(1.5) + ); + assert_eq!( + UnitValue::from_str("25 %").unwrap(), + UnitValue::RelPct(25.0) + ); +} + +#[pagetop::test] +async fn unit_value_roundtrip_display_keeps_expected_format() { + let cases = [ + ("", UnitValue::None, ""), + ("auto", UnitValue::Auto, "auto"), + ("0", UnitValue::Zero, "0"), + ("12px", UnitValue::Px(12), "12px"), + ("-5pt", UnitValue::Pt(-5), "-5pt"), + ("7cm", UnitValue::Cm(7), "7cm"), + ("33%", UnitValue::RelPct(33.0), "33%"), + ("1.25rem", UnitValue::RelRem(1.25), "1.25rem"), + ("2em", UnitValue::RelEm(2.0), "2em"), + ("-0.5vh", UnitValue::RelVh(-0.5), "-0.5vh"), + ("8vw", UnitValue::RelVw(8.0), "8vw"), + ]; + + for (input, expected_value, expected_display) in cases { + let parsed = UnitValue::from_str(input).unwrap(); + assert_eq!( + parsed, expected_value, + "parsed mismatch for input `{input}`" + ); + assert_eq!( + parsed.to_string(), + expected_display, + "display mismatch for input `{input}`" + ); + } +} + +#[pagetop::test] +async fn unit_value_percentage_trimming_and_signs() { + assert_eq!( + UnitValue::from_str(" 12.5 % ").unwrap(), + UnitValue::RelPct(12.5) + ); + assert_eq!( + UnitValue::from_str("-0.0%").unwrap(), + UnitValue::RelPct(-0.0) + ); + assert_eq!( + UnitValue::from_str("+15%").unwrap(), + UnitValue::RelPct(15.0) + ); +} + +// ERRORES ESPERADOS (no cambiar los mensajes; con is_err() basta). + +#[pagetop::test] +async fn unit_value_errors_missing_unit_for_non_zero() { + assert!( + UnitValue::from_str("12").is_err(), + "non-zero without unit must error" + ); + assert!( + UnitValue::from_str(" -3 ").is_err(), + "non-zero without unit must error" + ); +} + +#[pagetop::test] +async fn unit_value_errors_decimals_in_absolute_units() { + assert!(UnitValue::from_str("1.5px").is_err()); + assert!(UnitValue::from_str("-2.0pt").is_err()); + assert!(UnitValue::from_str("+0.1cm").is_err()); +} + +#[pagetop::test] +async fn unit_value_errors_unknown_units_or_bad_percentages() { + // Unidad no soportada. + assert!(UnitValue::from_str("10ch").is_err()); + assert!(UnitValue::from_str("2q").is_err()); + // Falta número. + assert!(UnitValue::from_str("%").is_err()); + assert!(UnitValue::from_str(" % ").is_err()); +} + +#[pagetop::test] +async fn unit_value_errors_non_numeric_numbers() { + assert!(UnitValue::from_str("NaNem").is_err()); + // Decimal no permitido por FromStr. + assert!(UnitValue::from_str("1,5rem").is_err()); +} + +#[pagetop::test] +async fn unit_value_serde_deserialize_struct_and_array() { + use serde::Deserialize; + + #[derive(Deserialize, Debug, PartialEq)] + struct BoxStyle { + width: UnitValue, + height: UnitValue, + margin: UnitValue, + } + + let json = r#"{ "width": "12px", "height": "1.5rem", "margin": "0" }"#; + let s: BoxStyle = serde_json::from_str(json).unwrap(); + assert_eq!(s.width, UnitValue::Px(12)); + assert_eq!(s.height, UnitValue::RelRem(1.5)); + assert_eq!(s.margin, UnitValue::Zero); + + #[derive(Deserialize, Debug, PartialEq)] + struct Many { + values: Vec<UnitValue>, + } + + let json_arr = r#"{ "values": ["", "auto", "33%", "8vw", "7 cm", "-5pt"] }"#; + let m: Many = serde_json::from_str(json_arr).unwrap(); + assert_eq!( + m.values, + vec![ + UnitValue::None, + UnitValue::Auto, + UnitValue::RelPct(33.0), + UnitValue::RelVw(8.0), + UnitValue::Cm(7), + UnitValue::Pt(-5), + ] + ); +} + +#[pagetop::test] +async fn unit_value_accepts_dot5_and_1dot_shorthand_for_relatives() { + // `.5` y `1.` se parsean correctamente en relativas. + assert_eq!(UnitValue::from_str(".5em").unwrap(), UnitValue::RelEm(0.5)); + assert_eq!( + UnitValue::from_str("1.rem").unwrap(), + UnitValue::RelRem(1.0) + ); + assert_eq!(UnitValue::from_str("1.vh").unwrap(), UnitValue::RelVh(1.0)); + // Sin unidad debe seguir fallando. + assert!(UnitValue::from_str("1.").is_err()); +} + +#[pagetop::test] +async fn unit_value_display_keeps_minus_zero_for_relatives() { + // Comportamiento actual: f32 Display muestra "-0" si el valor es -0.0. + let v = UnitValue::RelEm(-0.0); + // Se acepta cualquiera de los dos formatos como válidos. + let s = v.to_string(); + assert!( + s == "-0em" || s == "0em", + "current Display prints `{s}` for -0.0; both are acceptable in tests" + ); +} + +#[pagetop::test] +async fn unit_value_rejects_non_decimal_notations() { + // Octal, los ceros a la izquierda (p.ej. `"020px"`) se interpretan en **base 10** (`20px`). + assert_eq!(UnitValue::from_str("020px").unwrap(), UnitValue::Px(20)); + // Notación científica y bases no decimales (p.ej. `"1e3vw"`, `"0x10px"`) no están soportadas. + assert!(UnitValue::from_str("1e3vw").is_err()); + assert!(UnitValue::from_str("0x10px").is_err()); +} From d46de78367f96776b2ac90ca298706852bc2c891 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 13 Oct 2025 18:51:32 +0200 Subject: [PATCH 213/244] =?UTF-8?q?=E2=9C=A8=20(unit):=20A=C3=B1ade=20m?= =?UTF-8?q?=C3=A9todo=20`is=5Fnumeric`=20en=20`UnitValue`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html/unit.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/html/unit.rs b/src/html/unit.rs index b6a9bc76..b67e8b17 100644 --- a/src/html/unit.rs +++ b/src/html/unit.rs @@ -106,6 +106,31 @@ pub enum UnitValue { RelVw(f32), } +impl UnitValue { + /// Indica si el valor es **numérico**. + /// + /// Devuelve `true` para `Zero` y las unidades absolutas/relativas, y `false` para + /// [`UnitValue::None`] y [`UnitValue::Auto`]. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop::prelude::*; + /// // Numéricos (incluido el cero sin unidad). + /// assert!(UnitValue::Zero.is_numeric()); + /// assert!(UnitValue::Px(0).is_numeric()); + /// assert!(UnitValue::Px(10).is_numeric()); + /// assert!(UnitValue::RelPct(33.0).is_numeric()); + /// // No numéricos. + /// assert!(!UnitValue::None.is_numeric()); + /// assert!(!UnitValue::Auto.is_numeric()); + /// ``` + #[inline] + pub const fn is_numeric(&self) -> bool { + !matches!(self, UnitValue::None | UnitValue::Auto) + } +} + /// Formatea la unidad como cadena CSS. /// /// Reglas: From 6368e71413fce6cf42d037f95d44162da24a884b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 17 Oct 2025 18:14:20 +0200 Subject: [PATCH 214/244] =?UTF-8?q?=F0=9F=8E=A8=20(pagetop):=20Mejoras=20s?= =?UTF-8?q?encillas=20en=20doc.=20y=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component.rs | 2 +- src/config.rs | 18 +++++++-------- src/core/action/definition.rs | 3 ++- src/global.rs | 4 ++-- src/html/assets/favicon.rs | 4 ++-- src/html/unit.rs | 41 +++++++++++++++++------------------ src/locale.rs | 12 +++++----- tests/html_unit.rs | 4 ++-- 8 files changed, 43 insertions(+), 45 deletions(-) diff --git a/src/base/component.rs b/src/base/component.rs index 6c3b028f..8991d721 100644 --- a/src/base/component.rs +++ b/src/base/component.rs @@ -1,6 +1,6 @@ //! Componentes nativos proporcionados por PageTop. -use crate::AutoDefault; +use crate::prelude::*; use std::fmt; diff --git a/src/config.rs b/src/config.rs index f2fb9f7f..1607a874 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,9 +23,9 @@ //! * Si `PAGETOP_RUN_MODE` no está definida, se asume el valor `default`, y PageTop intentará //! cargar *config/default.toml* si el archivo existe. //! -//! * Útil para definir configuraciones específicas por entorno, garantizando que cada uno (p.ej. -//! *dev*, *staging* o *production*) disponga de sus propias opciones, como claves de API, -//! URLs o ajustes de rendimiento, sin afectar a los demás. +//! * Permite definir configuraciones específicas por entorno, garantizando que cada uno (p. ej., +//! *dev*, *staging* o *production*) disponga de sus propias opciones, como claves de API, URLs +//! o ajustes de rendimiento, sin afectar a los demás. //! //! 3. **config/local.{rm}.toml**, útil para configuraciones locales específicas de la máquina o de //! la ejecución: @@ -132,15 +132,15 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( let config_dir = util::resolve_absolute_dir(&dir).unwrap_or_else(|_| PathBuf::from(&dir)); // Modo de ejecución según la variable de entorno PAGETOP_RUN_MODE. Si no está definida, se usa - // por defecto, DEFAULT_RUN_MODE (p.ej.: PAGETOP_RUN_MODE=production). + // por defecto DEFAULT_RUN_MODE (p. ej. PAGETOP_RUN_MODE=production). let rm = env::var("PAGETOP_RUN_MODE").unwrap_or_else(|_| DEFAULT_RUN_MODE.into()); Config::builder() // 1. Configuración común para todos los entornos (common.toml). .add_source(File::from(config_dir.join("common.toml")).required(false)) - // 2. Configuración específica del entorno (p.ej.: default.toml, production.toml). + // 2. Configuración específica del entorno (p. ej. default.toml o production.toml). .add_source(File::from(config_dir.join(format!("{rm}.toml"))).required(false)) - // 3. Configuración local reservada para cada entorno (p.ej.: local.default.toml). + // 3. Configuración local reservada para cada entorno (p. ej. local.default.toml). .add_source(File::from(config_dir.join(format!("local.{rm}.toml"))).required(false)) // 4. Configuración local común (local.toml). .add_source(File::from(config_dir.join("local.toml")).required(false)) @@ -206,7 +206,7 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( /// * **Valores por defecto**. Declara un valor por defecto para cada clave obligatoria. Las claves /// opcionales pueden ser `Option<T>`. /// -/// * **Secciones únicas**. Agrupa tus claves dentro de una sección exclusiva (p.ej. `[blog]`) para +/// * **Secciones únicas**. Agrupa tus claves dentro de una sección exclusiva (p. ej. `[blog]`) para /// evitar colisiones con otras librerías. /// /// * **Solo lectura**. La variable generada es inmutable durante toda la vida del programa. Para @@ -229,9 +229,7 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( macro_rules! include_config { ( $SETTINGS_NAME:ident : $Settings_Type:ty => [ $( $k:literal => $v:expr ),* $(,)? ] ) => { #[doc = concat!( - "Referencia y valores por defecto de los ajustes de configuración para [`", - stringify!($Settings_Type), - "`]." + "Instancia los ajustes de configuración para [`", stringify!($Settings_Type), "`]." )] #[doc = ""] #[doc = "Valores por defecto:"] diff --git a/src/core/action/definition.rs b/src/core/action/definition.rs index 9ec9af1f..7ebe4104 100644 --- a/src/core/action/definition.rs +++ b/src/core/action/definition.rs @@ -24,7 +24,8 @@ impl ActionKey { /// - `action_type_id`: Tipo de la acción. /// - `theme_type_id`: Opcional, identificador de tipo ([`UniqueId`]) del tema asociado. /// - `referer_type_id`: Opcional, identificador de tipo ([`UniqueId`]) del componente referido. - /// - `referer_id`: Opcional, identificador de la instancia (p.ej. para un formulario concreto). + /// - `referer_id`: Opcional, identificador de la instancia (p. ej. para asociar la acción a un + /// componente concreto). /// /// Esta clave permitirá seleccionar las funciones a ejecutar para ese tipo de acción, con /// filtros opcionales por tema, componente, o una instancia concreta según su identificador. diff --git a/src/global.rs b/src/global.rs index c8805a30..ee07d818 100644 --- a/src/global.rs +++ b/src/global.rs @@ -30,7 +30,7 @@ include_config!(SETTINGS: Settings => [ ]); #[derive(Debug, Deserialize)] -/// Ajustes para las secciones globales [`[app]`](App), [`[dev]`](Dev), [`[log]`](Log) y +/// Tipos para las secciones globales [`[app]`](App), [`[dev]`](Dev), [`[log]`](Log) y /// [`[server]`](Server) de [`SETTINGS`]. pub struct Settings { pub app: App, @@ -105,7 +105,7 @@ pub struct Server { pub bind_address: String, /// Puerto de escucha del servidor web. pub bind_port: u16, - /// Duración de la cookie de sesión en segundos (p.ej. `604_800` para una semana). + /// Duración de la cookie de sesión en segundos (p. ej., `604_800` para una semana). /// /// El valor `0` indica que la cookie permanecerá activa hasta que se cierre el navegador. pub session_lifetime: i64, diff --git a/src/html/assets/favicon.rs b/src/html/assets/favicon.rs index dce3e1bd..7598603c 100644 --- a/src/html/assets/favicon.rs +++ b/src/html/assets/favicon.rs @@ -63,7 +63,7 @@ impl Favicon { /// Le añade un icono genérico con atributo `sizes`, útil para indicar resoluciones específicas. /// /// El atributo `sizes` informa al navegador de las dimensiones de la imagen para que seleccione - /// el recurso más adecuado. Puede enumerar varias dimensiones separadas por espacios, p.ej. + /// el recurso más adecuado. Puede enumerar varias dimensiones separadas por espacios, p. ej. /// `"16x16 32x32 48x48"` o usar `any` para iconos escalables (SVG). /// /// No es imprescindible, pero puede mejorar la selección del icono más adecuado. @@ -73,7 +73,7 @@ impl Favicon { /// Le añade un *Apple Touch Icon*, usado por dispositivos iOS para las pantallas de inicio. /// - /// Se recomienda indicar también el tamaño, p.ej. `"256x256"`. + /// Se recomienda indicar también el tamaño, p. ej. `"256x256"`. pub fn with_apple_touch_icon(self, image: impl Into<String>, sizes: impl Into<String>) -> Self { self.add_icon_item("apple-touch-icon", image.into(), Some(sizes.into()), None) } diff --git a/src/html/unit.rs b/src/html/unit.rs index b67e8b17..53319dc8 100644 --- a/src/html/unit.rs +++ b/src/html/unit.rs @@ -34,8 +34,8 @@ use std::str::FromStr; /// /// - Soporta unidades **absolutas** (`cm`, `in`, `mm`, `pc`, `pt`, `px`) y **relativas** (`em`, /// `rem`, `%`, `vh`, `vw`). -/// - `FromStr` para convertir desde texto (p.ej. `"12px"`, `"1.25rem"`, `"auto"`). -/// - `Display` para formatear a cadena (p.ej. `UnitValue::Px(12)` genera `"12px"`). +/// - `FromStr` para convertir desde texto (p. ej., `"12px"`, `"1.25rem"`, `"auto"`). +/// - `Display` para formatear a cadena (p. ej., `UnitValue::Px(12)` genera `"12px"`). /// - `Deserialize` delega en `FromStr`, garantizando una gramática única. /// /// ## Ejemplos @@ -54,8 +54,8 @@ use std::str::FromStr; /// /// ## Notas /// -/// - Las absolutas **no aceptan** decimales (p.ej., `"1.5px"` sería erróneo). -/// - Se aceptan signos `+`/`-` en todas las unidades (p.ej., `"-12px"`, `"+0.5em"`). +/// - Las absolutas **no aceptan** decimales (p. ej., `"1.5px"` sería erróneo). +/// - Se aceptan signos `+`/`-` en todas las unidades (p. ej., `"-12px"`, `"+0.5em"`). /// - La comparación de unidad es *case-insensitive* al interpretar el texto (`"PX"`, `"Px"`, …). /// - **Sobre píxeles**: Los píxeles (px) son relativos al dispositivo de visualización. En /// dispositivos con baja densidad de píxeles (dpi), 1px equivale a un píxel (punto) del @@ -69,7 +69,7 @@ use std::str::FromStr; /// - Ejemplo: si `:root { font-size: 16px }` y un contenedor tiene `font-size: 20px`, entonces /// dentro del contenedor `1em == 20px` pero `1rem == 16px`. /// - Uso típico: `rem` para tipografía y espaciados globales (consistencia al cambiar la base del -/// sitio); `em` para tamaños que deban escalar **con el propio componente** (p.ej., +/// sitio); `em` para tamaños que deban escalar **con el propio componente** (p. ej., /// `padding: 0.5em` que crece si el componente aumenta su `font-size`). /// - **Sobre el viewport**: Si el ancho de la ventana del navegador es de 50cm, 1vw equivale a /// 0.5cm (1vw siempre es 1% del ancho del viewport, independientemente del zoom del navegador o @@ -107,26 +107,25 @@ pub enum UnitValue { } impl UnitValue { - /// Indica si el valor es **numérico**. + /// Indica si el valor es **medible**, incluyendo `Zero` sin unidad. /// - /// Devuelve `true` para `Zero` y las unidades absolutas/relativas, y `false` para - /// [`UnitValue::None`] y [`UnitValue::Auto`]. + /// Devuelve `false` para [`UnitValue::None`] y [`UnitValue::Auto`]. /// /// # Ejemplos /// /// ```rust /// # use pagetop::prelude::*; /// // Numéricos (incluido el cero sin unidad). - /// assert!(UnitValue::Zero.is_numeric()); - /// assert!(UnitValue::Px(0).is_numeric()); - /// assert!(UnitValue::Px(10).is_numeric()); - /// assert!(UnitValue::RelPct(33.0).is_numeric()); + /// assert!(UnitValue::Zero.is_measurable()); + /// assert!(UnitValue::Px(0).is_measurable()); + /// assert!(UnitValue::Px(10).is_measurable()); + /// assert!(UnitValue::RelPct(33.0).is_measurable()); /// // No numéricos. - /// assert!(!UnitValue::None.is_numeric()); - /// assert!(!UnitValue::Auto.is_numeric()); + /// assert!(!UnitValue::None.is_measurable()); + /// assert!(!UnitValue::Auto.is_measurable()); /// ``` #[inline] - pub const fn is_numeric(&self) -> bool { + pub const fn is_measurable(&self) -> bool { !matches!(self, UnitValue::None | UnitValue::Auto) } } @@ -173,9 +172,9 @@ impl fmt::Display for UnitValue { /// - `""` para `UnitValue::None` /// - `"auto"` /// - **Cero sin unidad**: `"0"`, `"+0"`, `"-0"`, `"0.0"`, `"0."`, `".0"` para `UnitValue::Zero` -/// - Porcentaje: `"<n>%"` (p.ej. `"33%"`, `"33 %"`) -/// - Absolutas enteras: `"<entero><unidad>"`, p.ej. `"12px"`, `"-5pt"` -/// - Relativas decimales: `"<float><unidad>"`, p.ej. `"1.25rem"`, `"-0.5vh"`, `".5em"`, `"1.rem"` +/// - Porcentaje: `"<n>%"` (p. ej., `"33%"`, `"33 %"`) +/// - Absolutas enteras: `"<entero><unidad>"`, p. ej., `"12px"`, `"-5pt"` +/// - Relativas decimales: `"<float><unidad>"`, p. ej., `"1.25rem"`, `"-0.5vh"`, `".5em"`, `"1.rem"` /// /// (Se toleran espacios entre número y unidad: `"12 px"`, `"1.5 rem"`). /// @@ -191,9 +190,9 @@ impl fmt::Display for UnitValue { /// /// ## Errores de interpretación /// -/// - Falta la unidad cuando es necesaria (p.ej. `"12"`, excepto para el valor cero). -/// - Decimales en valores que deben ser absolutos (p.ej. `"1.5px"`). -/// - Unidades desconocidas (p.ej. `"10ch"`, no soportada aún). +/// - Falta la unidad cuando es necesaria (p. ej., `"12"`, excepto para el valor cero). +/// - Decimales en valores que deben ser absolutos (p. ej. `"1.5px"`). +/// - Unidades desconocidas (p. ej., `"10ch"`, no soportada aún). /// - Notación científica o bases no decimales: `"1e3vw"`, `"0x10px"` (no soportadas). Los ceros a /// la izquierda (p. ej. `"020px"`) se interpretan en **base 10** (`20px`). /// diff --git a/src/locale.rs b/src/locale.rs index 7c913ec9..5c000f7c 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -181,8 +181,8 @@ pub enum LangMatch { /// Cuando el identificador de idioma es una cadena vacía. Unspecified, /// Si encuentra un [`LanguageIdentifier`] en la lista de idiomas soportados por PageTop que - /// coincide exactamente con el identificador de idioma (p.ej. "es-ES"), o con el identificador - /// del idioma base (p.ej. "es"). + /// coincide exactamente con el identificador de idioma (p. ej. "es-ES"), o con el identificador + /// del idioma base (p. ej. "es"). Found(&'static LanguageIdentifier), /// Si el identificador de idioma no está entre los soportados por PageTop. Unsupported(String), @@ -205,13 +205,13 @@ impl LangMatch { return Self::Unspecified; } - // Intenta aplicar coincidencia exacta con el código completo (p.ej. "es-MX"). + // Intenta aplicar coincidencia exacta con el código completo (p. ej. "es-MX"). let lang = language.to_ascii_lowercase(); if let Some(langid) = LANGUAGES.get(lang.as_str()).map(|(langid, _)| langid) { return Self::Found(langid); } - // Si la variante regional no existe, retrocede al idioma base (p.ej. "es"). + // Si la variante regional no existe, retrocede al idioma base (p. ej. "es"). if let Some((base_lang, _)) = lang.split_once('-') { if let Some(langid) = LANGUAGES.get(base_lang).map(|(langid, _)| langid) { return Self::Found(langid); @@ -375,13 +375,13 @@ impl L10n { } } - /// Añade un argumento `{$arg}` → `value` a la traducción. + /// Añade un argumento `{$arg}` => `value` a la traducción. pub fn with_arg(mut self, arg: impl Into<String>, value: impl Into<String>) -> Self { self.args.insert(arg.into(), value.into()); self } - /// Añade varios argumentos a la traducción de una sola vez (p.ej. usando la macro [`hm!`], + /// Añade varios argumentos a la traducción de una sola vez (p. ej. usando la macro [`hm!`], /// también vec![("k", "v")], incluso un array de duplas u otras colecciones). pub fn with_args<I, K, V>(mut self, args: I) -> Self where diff --git a/tests/html_unit.rs b/tests/html_unit.rs index 9316af89..6acae935 100644 --- a/tests/html_unit.rs +++ b/tests/html_unit.rs @@ -215,9 +215,9 @@ async fn unit_value_display_keeps_minus_zero_for_relatives() { #[pagetop::test] async fn unit_value_rejects_non_decimal_notations() { - // Octal, los ceros a la izquierda (p.ej. `"020px"`) se interpretan en **base 10** (`20px`). + // Octal, los ceros a la izquierda (p. ej. `"020px"`) se interpretan en **base 10** (`20px`). assert_eq!(UnitValue::from_str("020px").unwrap(), UnitValue::Px(20)); - // Notación científica y bases no decimales (p.ej. `"1e3vw"`, `"0x10px"`) no están soportadas. + // Notación científica y bases no decimales (p. ej., `"1e3vw"`, `"0x10px"`) no están soportadas. assert!(UnitValue::from_str("1e3vw").is_err()); assert!(UnitValue::from_str("0x10px").is_err()); } From 5eab417b11a3e98f1cd7f4effcdd1de959c86f1e Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 18 Oct 2025 21:33:29 +0200 Subject: [PATCH 215/244] =?UTF-8?q?=F0=9F=9A=9A=20Renombra=20`add=5Fcompon?= =?UTF-8?q?ent`=20por=20`add=5Fchild`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- README.md | 2 +- examples/hello-name.rs | 2 +- examples/hello-world.rs | 2 +- extensions/pagetop-aliner/README.md | 4 ++-- extensions/pagetop-aliner/src/lib.rs | 4 ++-- src/base/component/block.rs | 2 +- src/base/component/intro.rs | 6 +++--- src/base/extension/welcome.rs | 10 +++++----- src/lib.rs | 2 +- src/response/page.rs | 23 +++++++++++------------ src/response/page/error.rs | 4 ++-- 12 files changed, 31 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2926a69..bfc9067a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ internos pueden omitirse si no afectan al uso del proyecto. - [context] Generaliza los parámetros de contexto - [context] Define un `trait` común de contexto - Modifica tipos para atributos HTML a minúsculas -- Renombra `with_component` por `add_component` +- Renombra `with_component` por `add_child` ### Corregido diff --git a/README.md b/README.md index be720910..986db58b 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ impl Extension for HelloWorld { async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(request) - .add_component(Html::with(move |_| html! { h1 { "Hello World!" } })) + .add_child(Html::with(|_| html! { h1 { "Hello World!" } })) .render() } diff --git a/examples/hello-name.rs b/examples/hello-name.rs index e1285d09..c6a82aaf 100644 --- a/examples/hello-name.rs +++ b/examples/hello-name.rs @@ -14,7 +14,7 @@ async fn hello_name( ) -> ResultPage<Markup, ErrorPage> { let name = path.into_inner(); Page::new(request) - .add_component(Html::with(move |_| html! { h1 { "Hello " (name) "!" } })) + .add_child(Html::with(move |_| html! { h1 { "Hello " (name) "!" } })) .render() } diff --git a/examples/hello-world.rs b/examples/hello-world.rs index d56f2105..64817466 100644 --- a/examples/hello-world.rs +++ b/examples/hello-world.rs @@ -10,7 +10,7 @@ impl Extension for HelloWorld { async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(request) - .add_component(Html::with(move |_| html! { h1 { "Hello World!" } })) + .add_child(Html::with(|_| html! { h1 { "Hello World!" } })) .render() } diff --git a/extensions/pagetop-aliner/README.md b/extensions/pagetop-aliner/README.md index 0560a067..43fb65a5 100644 --- a/extensions/pagetop-aliner/README.md +++ b/extensions/pagetop-aliner/README.md @@ -67,10 +67,10 @@ use pagetop::prelude::*; async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(request) .with_theme("Aliner") - .add_component( + .add_child( Block::new() .with_title(L10n::l("sample_title")) - .add_component(Html::with(|cx| html! { + .add_child(Html::with(|cx| html! { p { (L10n::l("sample_content").using(cx)) } })), ) diff --git a/extensions/pagetop-aliner/src/lib.rs b/extensions/pagetop-aliner/src/lib.rs index b51800c2..edbb5040 100644 --- a/extensions/pagetop-aliner/src/lib.rs +++ b/extensions/pagetop-aliner/src/lib.rs @@ -68,10 +68,10 @@ use pagetop::prelude::*; async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(request) .with_theme("Aliner") - .add_component( + .add_child( Block::new() .with_title(L10n::l("sample_title")) - .add_component(Html::with(|cx| html! { + .add_child(Html::with(|cx| html! { p { (L10n::l("sample_content").using(cx)) } })), ) diff --git a/src/base/component/block.rs b/src/base/component/block.rs index 9a04c4ea..17af50c2 100644 --- a/src/base/component/block.rs +++ b/src/base/component/block.rs @@ -71,7 +71,7 @@ impl Block { } /// Añade un nuevo componente hijo al bloque. - pub fn add_component(mut self, component: impl Component) -> Self { + pub fn add_child(mut self, component: impl Component) -> Self { self.children .alter_child(ChildOp::Add(Child::with(component))); self diff --git a/src/base/component/intro.rs b/src/base/component/intro.rs index 5d3440e9..7e5c3931 100644 --- a/src/base/component/intro.rs +++ b/src/base/component/intro.rs @@ -65,10 +65,10 @@ pub enum IntroOpening { /// ```rust /// # use pagetop::prelude::*; /// let intro = Intro::default() -/// .add_component( +/// .add_child( /// Block::new() /// .with_title(L10n::l("intro_custom_block_title")) -/// .add_component(Html::with(move |cx| { +/// .add_child(Html::with(move |cx| { /// html! { /// p { (L10n::l("intro_custom_paragraph_1").using(cx)) } /// p { (L10n::l("intro_custom_paragraph_2").using(cx)) } @@ -301,7 +301,7 @@ impl Intro { /// 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 { + pub fn add_child(mut self, component: impl Component) -> Self { self.children .alter_child(ChildOp::Add(Child::with(component))); self diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs index d94afad7..b875163b 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -26,22 +26,22 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(request) .with_title(L10n::l("welcome_title")) - .add_component( + .add_child( Intro::new() - .add_component( + .add_child( Block::new() .with_title(L10n::l("welcome_status_title")) - .add_component(Html::with(move |cx| { + .add_child(Html::with(move |cx| { html! { p { (L10n::l("welcome_status_1").using(cx)) } p { (L10n::l("welcome_status_2").using(cx)) } } })), ) - .add_component( + .add_child( Block::new() .with_title(L10n::l("welcome_support_title")) - .add_component(Html::with(move |cx| { + .add_child(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)) } diff --git a/src/lib.rs b/src/lib.rs index de6d9e68..a2683495 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,7 +61,7 @@ impl Extension for HelloWorld { async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(request) - .add_component(Html::with(move |_| html! { h1 { "Hello World!" } })) + .add_child(Html::with(|_| html! { h1 { "Hello World!" } })) .render() } diff --git a/src/response/page.rs b/src/response/page.rs index 1649d543..036c999c 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -93,29 +93,28 @@ impl Page { self } - /// **Obsoleto desde la versión 0.4.0**: usar [`add_component()`](Self::add_component) en su - /// lugar. - #[deprecated(since = "0.4.0", note = "Use `add_component()` instead")] + /// **Obsoleto desde la versión 0.4.0**: usar [`add_child()`](Self::add_child) en su lugar. + #[deprecated(since = "0.4.0", note = "Use `add_child()` instead")] pub fn with_component(self, component: impl Component) -> Self { - self.add_component(component) + self.add_child(component) } - /// **Obsoleto desde la versión 0.4.0**: usar [`add_component_in()`](Self::add_component_in) en - /// su lugar. - #[deprecated(since = "0.4.0", note = "Use `add_component_in()` instead")] + /// **Obsoleto desde la versión 0.4.0**: usar [`add_child_in()`](Self::add_child_in) en su + /// lugar. + #[deprecated(since = "0.4.0", note = "Use `add_child_in()` instead")] pub fn with_component_in(self, region_key: &'static str, component: impl Component) -> Self { - self.add_component_in(region_key, component) + self.add_child_in(region_key, component) } - /// Añade un componente a la región de contenido por defecto. - pub fn add_component(mut self, component: impl Component) -> Self { + /// Añade un componente hijo a la región de contenido por defecto. + pub fn add_child(mut self, component: impl Component) -> Self { self.context .alter_child_in(REGION_CONTENT, ChildOp::Add(Child::with(component))); self } - /// Añade un componente en una región (`region_key`) de la página. - pub fn add_component_in(mut self, region_key: &'static str, component: impl Component) -> Self { + /// Añade un componente hijo en una región (`region_key`) de la página. + pub fn add_child_in(mut self, region_key: &'static str, component: impl Component) -> Self { self.context .alter_child_in(region_key, ChildOp::Add(Child::with(component))); self diff --git a/src/response/page/error.rs b/src/response/page/error.rs index 50e1c77b..6fe6451f 100644 --- a/src/response/page/error.rs +++ b/src/response/page/error.rs @@ -34,7 +34,7 @@ impl Display for ErrorPage { if let Ok(page) = error_page .with_title(L10n::n("Error FORBIDDEN")) .with_layout("error") - .add_component(Html::with(move |_| error403.clone())) + .add_child(Html::with(move |_| error403.clone())) .render() { write!(f, "{}", page.into_string()) @@ -49,7 +49,7 @@ impl Display for ErrorPage { if let Ok(page) = error_page .with_title(L10n::n("Error RESOURCE NOT FOUND")) .with_layout("error") - .add_component(Html::with(move |_| error404.clone())) + .add_child(Html::with(move |_| error404.clone())) .render() { write!(f, "{}", page.into_string()) From 708dc9244b057dbe3a034e501f855636feb7ded1 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 19 Oct 2025 21:39:14 +0200 Subject: [PATCH 216/244] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Mejora=20macro=20`?= =?UTF-8?q?join=5Fopt!`=20y=20retoca=20documentaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/component.rs | 5 +++++ src/util.rs | 30 ++++++++++++++++-------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/core/component.rs b/src/core/component.rs index be9bbad1..a7faa2fb 100644 --- a/src/core/component.rs +++ b/src/core/component.rs @@ -10,4 +10,9 @@ pub use children::{Typed, TypedOp}; mod context; pub use context::{Context, ContextError, ContextOp, Contextual}; + +/// Alias de función (*callback*) para **resolver una URL** según el contexto de renderizado. +/// +/// Se usa para generar enlaces dinámicos en función del contexto (petición, idioma, etc.). Debe +/// devolver una referencia válida durante el renderizado. pub type FnPathByContext = fn(cx: &Context) -> &str; diff --git a/src/util.rs b/src/util.rs index f73cf78a..3d07361a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -70,14 +70,12 @@ macro_rules! join { }; } -/// Concatena los fragmentos no vacíos en un [`Option<String>`] con un separador opcional. +/// Concatena los fragmentos **no vacíos** en un [`Option<String>`] con un separador opcional. /// -/// Esta macro acepta cualquier número de fragmentos que implementen [`AsRef<str>`] para concatenar -/// todos los fragmentos no vacíos usando opcionalmente un separador. +/// Acepta cualquier número de fragmentos que implementen [`AsRef<str>`]. Si todos los fragmentos +/// están vacíos, devuelve `None`. /// -/// Si todos los fragmentos están vacíos, devuelve [`None`]. -/// -/// # Ejemplo +/// # Ejemplos /// /// ```rust /// # use pagetop::prelude::*; @@ -90,7 +88,7 @@ macro_rules! join { /// assert_eq!(result_without_separator, Some("HelloWorld".to_string())); /// /// // Devuelve `None` si todos los fragmentos están vacíos. -/// let result_empty = join_opt!(["", "", ""]); +/// let result_empty = join_opt!(["", "", ""]; ","); /// assert_eq!(result_empty, None); /// ``` #[macro_export] @@ -100,12 +98,16 @@ macro_rules! join_opt { (!s.is_empty()).then_some(s) }}; ([$($arg:expr),* $(,)?]; $separator:expr) => {{ - let s = [$($arg),*] - .iter() - .filter(|&item| !item.is_empty()) - .cloned() - .collect::<Vec<_>>() - .join($separator); + let sep = ($separator).as_ref(); + let mut s = String::new(); + for part in [ $( ($arg).as_ref() ),* ] { + if !(part as &str).is_empty() { + if !s.is_empty() { + s.push_str(sep); + } + s.push_str(part); + } + } (!s.is_empty()).then_some(s) }}; } @@ -153,7 +155,7 @@ macro_rules! join_pair { }}; } -/// Concatena varios fragmentos en un [`Option<String>`] si ninguno está vacío. +/// Concatena varios fragmentos en un [`Option<String>`] **si ninguno está vacío**. /// /// Si alguno de los fragmentos, que deben implementar [`AsRef<str>`], está vacío, devuelve /// [`None`]. Opcionalmente se puede indicar un separador entre los fragmentos concatenados. From 44ddfa4a5136897da3d3561592041caee7528d8e Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 19 Oct 2025 21:40:42 +0200 Subject: [PATCH 217/244] =?UTF-8?q?=E2=9C=A8=20Simplifica=20`Display`=20co?= =?UTF-8?q?n=20`f.write=5Fstr()`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html/unit.rs | 6 +++--- src/response/page/error.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/html/unit.rs b/src/html/unit.rs index 53319dc8..4a99de16 100644 --- a/src/html/unit.rs +++ b/src/html/unit.rs @@ -145,9 +145,9 @@ impl UnitValue { impl fmt::Display for UnitValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - UnitValue::None => write!(f, ""), - UnitValue::Auto => write!(f, "auto"), - UnitValue::Zero => write!(f, "0"), + UnitValue::None => Ok(()), + UnitValue::Auto => f.write_str("auto"), + UnitValue::Zero => f.write_str("0"), // Valor absoluto. UnitValue::Cm(av) => write!(f, "{av}cm"), UnitValue::In(av) => write!(f, "{av}in"), diff --git a/src/response/page/error.rs b/src/response/page/error.rs index 6fe6451f..9945a948 100644 --- a/src/response/page/error.rs +++ b/src/response/page/error.rs @@ -24,9 +24,9 @@ impl Display for ErrorPage { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { // Error 304. - ErrorPage::NotModified(_) => write!(f, "Not Modified"), + ErrorPage::NotModified(_) => f.write_str("Not Modified"), // Error 400. - ErrorPage::BadRequest(_) => write!(f, "Bad Client Data"), + ErrorPage::BadRequest(_) => f.write_str("Bad Client Data"), // Error 403. ErrorPage::AccessDenied(request) => { let mut error_page = Page::new(request.clone()); @@ -39,7 +39,7 @@ impl Display for ErrorPage { { write!(f, "{}", page.into_string()) } else { - write!(f, "Access Denied") + f.write_str("Access Denied") } } // Error 404. @@ -54,15 +54,15 @@ impl Display for ErrorPage { { write!(f, "{}", page.into_string()) } else { - write!(f, "Not Found") + f.write_str("Not Found") } } // Error 412. - ErrorPage::PreconditionFailed(_) => write!(f, "Precondition Failed"), + ErrorPage::PreconditionFailed(_) => f.write_str("Precondition Failed"), // Error 500. - ErrorPage::InternalError(_) => write!(f, "Internal Error"), + ErrorPage::InternalError(_) => f.write_str("Internal Error"), // Error 504. - ErrorPage::Timeout(_) => write!(f, "Timeout"), + ErrorPage::Timeout(_) => f.write_str("Timeout"), } } } From d6e176cc197d94d0c9d95222a9913551fe1033eb Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 19 Oct 2025 21:47:19 +0200 Subject: [PATCH 218/244] =?UTF-8?q?=E2=9E=95=20(bootsier):=20A=C3=B1ade=20?= =?UTF-8?q?dependencia=20`serde`=20y=20edita=20doc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 1 + Cargo.toml | 3 ++- README.md | 2 +- extensions/pagetop-bootsier/Cargo.toml | 3 ++- extensions/pagetop-bootsier/README.md | 6 +++--- extensions/pagetop-bootsier/src/lib.rs | 2 +- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f1b09f9d..2f9fa42e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1593,6 +1593,7 @@ version = "0.0.18" dependencies = [ "pagetop", "pagetop-build", + "serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0d17082b..b1bae0a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ actix-web = { workspace = true, default-features = true } actix-session = { version = "0.11", features = ["cookie-session"] } actix-web-files = { package = "actix-files", version = "0.6" } -serde = { version = "1.0", features = ["derive"] } +serde.workspace = true pagetop-macros.workspace = true pagetop-statics.workspace = true @@ -78,6 +78,7 @@ authors = ["Manuel Cillero <manuel@cillero.es>"] [workspace.dependencies] actix-web = { version = "4.11", default-features = false } +serde = { version = "1.0", features = ["derive"] } # Helpers pagetop-build = { version = "0.3", path = "helpers/pagetop-build" } pagetop-macros = { version = "0.2", path = "helpers/pagetop-macros" } diff --git a/README.md b/README.md index 986db58b..9a12c845 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ El código se organiza en un *workspace* donde actualmente se incluyen los sigui es un tema para demos y pruebas que muestra esquemáticamente la composición de las páginas HTML. * **[pagetop-bootsier](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-bootsier)**, - tema basado en [Bootstrap](https://getbootstrap.com) para ofrecer su catálogo de estilos y + tema basado en [Bootstrap](https://getbootstrap.com) para integrar su catálogo de estilos y componentes flexibles. diff --git a/extensions/pagetop-bootsier/Cargo.toml b/extensions/pagetop-bootsier/Cargo.toml index 11306b63..6df6cf69 100644 --- a/extensions/pagetop-bootsier/Cargo.toml +++ b/extensions/pagetop-bootsier/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.18" edition = "2021" description = """ - Tema de PageTop basado en Bootstrap para dar vida a tus diseños web. + Tema de PageTop basado en Bootstrap para aplicar su catálogo de estilos y componentes flexibles. """ categories = ["web-programming", "gui"] keywords = ["pagetop", "theme", "bootstrap", "css", "js"] @@ -16,6 +16,7 @@ authors.workspace = true [dependencies] pagetop.workspace = true +serde.workspace = true [build-dependencies] pagetop-build.workspace = true diff --git a/extensions/pagetop-bootsier/README.md b/extensions/pagetop-bootsier/README.md index 7495bc22..84e11b57 100644 --- a/extensions/pagetop-bootsier/README.md +++ b/extensions/pagetop-bootsier/README.md @@ -2,7 +2,7 @@ <h1>PageTop Bootsier</h1> -<p>Tema de <strong>PageTop</strong> basado en Bootstrap para dar vida a tus diseños web.</p> +<p>Tema de <strong>PageTop</strong> basado en Bootstrap para aplicar su catálogo de estilos y componentes flexibles.</p> [![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier) [![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier) @@ -67,10 +67,10 @@ use pagetop::prelude::*; async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(request) .with_theme("Bootsier") - .add_component( + .add_child( Block::new() .with_title(L10n::l("sample_title")) - .add_component(Html::with(|cx| html! { + .add_child(Html::with(|cx| html! { p { (L10n::l("sample_content").using(cx)) } })), ) diff --git a/extensions/pagetop-bootsier/src/lib.rs b/extensions/pagetop-bootsier/src/lib.rs index a6583333..777f71e1 100644 --- a/extensions/pagetop-bootsier/src/lib.rs +++ b/extensions/pagetop-bootsier/src/lib.rs @@ -3,7 +3,7 @@ <h1>PageTop Bootsier</h1> -<p>Tema de <strong>PageTop</strong> basado en Bootstrap para ofrecer su catálogo de estilos y componentes flexibles.</p> +<p>Tema de <strong>PageTop</strong> basado en Bootstrap para aplicar su catálogo de estilos y componentes flexibles.</p> [![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier) [![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier) From 8978506c39b8eee428875c9766c5d2460d30aa09 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 19 Oct 2025 21:57:15 +0200 Subject: [PATCH 219/244] =?UTF-8?q?=E2=9C=A8=20(bootsier):=20A=C3=B1ade=20?= =?UTF-8?q?m=C3=A1s=20componentes=20y=20repasa=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Se incorpora nuevo componente Dropdown. - Se crea un componente Navbar con soporte para marca, elementos de navegación. - Se implementa el componente Offcanvas con opciones de posición, visibilidad y fondo personalizables. - Mejora el manejo de imágenes con un nuevo componente de Image. - Se reorganizan los componentes del tema para una mejor estructura y usabilidad. --- extensions/pagetop-bootsier/build.rs | 2 +- extensions/pagetop-bootsier/src/config.rs | 41 +++ extensions/pagetop-bootsier/src/lib.rs | 30 +- .../src/locale/en-US/bootsier.ftl | 5 + .../src/locale/en-US/components.ftl | 5 + .../src/locale/en-US/regions.ftl | 9 + .../src/locale/es-ES/bootsier.ftl | 5 + .../src/locale/es-ES/components.ftl | 5 + .../src/locale/es-ES/regions.ftl | 9 + extensions/pagetop-bootsier/src/theme.rs | 27 ++ extensions/pagetop-bootsier/src/theme/aux.rs | 18 ++ .../pagetop-bootsier/src/theme/aux/border.rs | 202 ++++++++++++ .../src/theme/aux/breakpoint.rs | 127 ++++++++ .../pagetop-bootsier/src/theme/aux/color.rs | 155 +++++++++ .../pagetop-bootsier/src/theme/aux/opacity.rs | 109 +++++++ .../pagetop-bootsier/src/theme/aux/rounded.rs | 214 +++++++++++++ .../pagetop-bootsier/src/theme/container.rs | 269 ++++++++++++++++ .../pagetop-bootsier/src/theme/dropdown.rs | 5 + .../src/theme/dropdown/component.rs | 99 ++++++ .../src/theme/dropdown/item.rs | 109 +++++++ .../pagetop-bootsier/src/theme/image.rs | 186 +++++++++++ .../pagetop-bootsier/src/theme/navbar.rs | 17 + .../src/theme/navbar/brand.rs | 104 ++++++ .../src/theme/navbar/button_toggler.rs | 73 +++++ .../src/theme/navbar/component.rs | 233 ++++++++++++++ .../src/theme/navbar/content.rs | 69 ++++ .../pagetop-bootsier/src/theme/navbar/item.rs | 113 +++++++ .../pagetop-bootsier/src/theme/navbar/nav.rs | 75 +++++ .../pagetop-bootsier/src/theme/offcanvas.rs | 302 ++++++++++++++++++ 29 files changed, 2608 insertions(+), 9 deletions(-) create mode 100644 extensions/pagetop-bootsier/src/config.rs create mode 100644 extensions/pagetop-bootsier/src/locale/en-US/bootsier.ftl create mode 100644 extensions/pagetop-bootsier/src/locale/en-US/components.ftl create mode 100644 extensions/pagetop-bootsier/src/locale/en-US/regions.ftl create mode 100644 extensions/pagetop-bootsier/src/locale/es-ES/bootsier.ftl create mode 100644 extensions/pagetop-bootsier/src/locale/es-ES/components.ftl create mode 100644 extensions/pagetop-bootsier/src/locale/es-ES/regions.ftl create mode 100644 extensions/pagetop-bootsier/src/theme.rs create mode 100644 extensions/pagetop-bootsier/src/theme/aux.rs create mode 100644 extensions/pagetop-bootsier/src/theme/aux/border.rs create mode 100644 extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs create mode 100644 extensions/pagetop-bootsier/src/theme/aux/color.rs create mode 100644 extensions/pagetop-bootsier/src/theme/aux/opacity.rs create mode 100644 extensions/pagetop-bootsier/src/theme/aux/rounded.rs create mode 100644 extensions/pagetop-bootsier/src/theme/container.rs create mode 100644 extensions/pagetop-bootsier/src/theme/dropdown.rs create mode 100644 extensions/pagetop-bootsier/src/theme/dropdown/component.rs create mode 100644 extensions/pagetop-bootsier/src/theme/dropdown/item.rs create mode 100644 extensions/pagetop-bootsier/src/theme/image.rs create mode 100644 extensions/pagetop-bootsier/src/theme/navbar.rs create mode 100644 extensions/pagetop-bootsier/src/theme/navbar/brand.rs create mode 100644 extensions/pagetop-bootsier/src/theme/navbar/button_toggler.rs create mode 100644 extensions/pagetop-bootsier/src/theme/navbar/component.rs create mode 100644 extensions/pagetop-bootsier/src/theme/navbar/content.rs create mode 100644 extensions/pagetop-bootsier/src/theme/navbar/item.rs create mode 100644 extensions/pagetop-bootsier/src/theme/navbar/nav.rs create mode 100644 extensions/pagetop-bootsier/src/theme/offcanvas.rs diff --git a/extensions/pagetop-bootsier/build.rs b/extensions/pagetop-bootsier/build.rs index 5945660a..a96301c5 100644 --- a/extensions/pagetop-bootsier/build.rs +++ b/extensions/pagetop-bootsier/build.rs @@ -15,5 +15,5 @@ fn main() -> std::io::Result<()> { fn bootstrap_js_files(path: &Path) -> bool { // No filtra durante el desarrollo, solo en la compilación "release". env::var("PROFILE").unwrap_or_else(|_| "release".to_string()) != "release" - || path.file_name().map_or(false, |n| n == "bootstrap.min.js") + || path.file_name().is_some_and(|n| n == "bootstrap.min.js") } diff --git a/extensions/pagetop-bootsier/src/config.rs b/extensions/pagetop-bootsier/src/config.rs new file mode 100644 index 00000000..6c2365ba --- /dev/null +++ b/extensions/pagetop-bootsier/src/config.rs @@ -0,0 +1,41 @@ +//! Opciones de configuración del tema. +//! +//! Ejemplo: +//! +//! ```toml +//! [bootsier] +//! max_width = "90rem" +//! ``` +//! +//! Uso: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! use pagetop_bootsier::config; +//! +//! assert_eq!(config::SETTINGS.bootsier.max_width, UnitValue::Px(1440)); +//! ``` +//! +//! Consulta [`pagetop::config`] para ver cómo PageTop lee los archivos de configuración y aplica +//! los valores a los ajustes. + +use pagetop::prelude::*; + +use serde::Deserialize; + +include_config!(SETTINGS: Settings => [ + // [bootsier] + "bootsier.max_width" => "1440px", +]); + +#[derive(Debug, Deserialize)] +/// Tipos para la sección [`[bootsier]`](Bootsier) de [`SETTINGS`]. +pub struct Settings { + pub bootsier: Bootsier, +} +#[derive(Debug, Deserialize)] +/// Sección `[bootsier]` de la configuración. Forma parte de [`Settings`]. +pub struct Bootsier { + /// Ancho máximo predeterminado para la página, por ejemplo "100%" o "90rem". + pub max_width: UnitValue, +} diff --git a/extensions/pagetop-bootsier/src/lib.rs b/extensions/pagetop-bootsier/src/lib.rs index 777f71e1..a0e6c703 100644 --- a/extensions/pagetop-bootsier/src/lib.rs +++ b/extensions/pagetop-bootsier/src/lib.rs @@ -68,10 +68,10 @@ use pagetop::prelude::*; async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(request) .with_theme("Bootsier") - .add_component( + .add_child( Block::new() .with_title(L10n::l("sample_title")) - .add_component(Html::with(|cx| html! { + .add_child(Html::with(|cx| html! { p { (L10n::l("sample_content").using(cx)) } })), ) @@ -80,18 +80,32 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { ``` */ +#![doc( + html_favicon_url = "https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/favicon.ico" +)] + use pagetop::prelude::*; -/// El tema usa las mismas regiones predefinidas por [`ThemeRegion`]. -pub type BootsierRegion = ThemeRegion; +include_locales!(LOCALES_BOOTSIER); // Versión de la librería Bootstrap. const BOOTSTRAP_VERSION: &str = "5.3.8"; -/// Tema basado en [Bootstrap](https://getbootstrap.com/) para los componentes base de PageTop. -/// -/// Ofrece composición de páginas *responsive*, utilidades y componentes listos para usar, con -/// estilos coherentes y enfoque en accesibilidad. +pub mod config; + +pub mod theme; + +/// *Prelude* del tema. +pub mod prelude { + pub use crate::config::*; + pub use crate::theme::aux::*; + pub use crate::theme::*; +} + +/// El tema usa las mismas regiones predefinidas por [`ThemeRegion`]. +pub type BootsierRegion = ThemeRegion; + +/// Implementa el tema. pub struct Bootsier; impl Extension for Bootsier { diff --git a/extensions/pagetop-bootsier/src/locale/en-US/bootsier.ftl b/extensions/pagetop-bootsier/src/locale/en-US/bootsier.ftl new file mode 100644 index 00000000..0e8969cd --- /dev/null +++ b/extensions/pagetop-bootsier/src/locale/en-US/bootsier.ftl @@ -0,0 +1,5 @@ +e404-description = Oops! Page Not Found +e404-message = The page you are looking for may have been removed, had its name changed, or is temporarily unavailable. +e500-description = Oops! Unexpected Error +e500-message = We're having an issue. Please report this error to an administrator. +back-homepage = Back to homepage diff --git a/extensions/pagetop-bootsier/src/locale/en-US/components.ftl b/extensions/pagetop-bootsier/src/locale/en-US/components.ftl new file mode 100644 index 00000000..83dde396 --- /dev/null +++ b/extensions/pagetop-bootsier/src/locale/en-US/components.ftl @@ -0,0 +1,5 @@ +# Offcanvas +close = Close + +# Navbar +toggle = Toggle navigation diff --git a/extensions/pagetop-bootsier/src/locale/en-US/regions.ftl b/extensions/pagetop-bootsier/src/locale/en-US/regions.ftl new file mode 100644 index 00000000..f3b76e22 --- /dev/null +++ b/extensions/pagetop-bootsier/src/locale/en-US/regions.ftl @@ -0,0 +1,9 @@ +header = Header +nav_branding = Navigation branding region +nav_main = Main navigation region +nav_additional = Additional navigation region (eg search form, social icons, etc) +breadcrumb = Breadcrumb +content = Main content +sidebar_first = Sidebar first +sidebar_second = Sidebar second +footer = Footer diff --git a/extensions/pagetop-bootsier/src/locale/es-ES/bootsier.ftl b/extensions/pagetop-bootsier/src/locale/es-ES/bootsier.ftl new file mode 100644 index 00000000..998b54f2 --- /dev/null +++ b/extensions/pagetop-bootsier/src/locale/es-ES/bootsier.ftl @@ -0,0 +1,5 @@ +e404-description = ¡Vaya! Página No Encontrada +e404-message = La página que está buscando puede haber sido eliminada, cambiada de nombre o no está disponible temporalmente. +e500-description = ¡Vaya! Error Inesperado +e500-message = Está ocurriendo una incidencia. Por favor, informe de este error a un administrador. +back-homepage = Volver al inicio diff --git a/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl b/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl new file mode 100644 index 00000000..1ae97888 --- /dev/null +++ b/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl @@ -0,0 +1,5 @@ +# Offcanvas +close = Cerrar + +# Navbar +toggle = Mostrar/ocultar navegación diff --git a/extensions/pagetop-bootsier/src/locale/es-ES/regions.ftl b/extensions/pagetop-bootsier/src/locale/es-ES/regions.ftl new file mode 100644 index 00000000..674fc4b1 --- /dev/null +++ b/extensions/pagetop-bootsier/src/locale/es-ES/regions.ftl @@ -0,0 +1,9 @@ +header = Cabecera +nav_branding = Navegación y marca +nav_main = Navegación principal +nav_additional = Navegación adicional (p.e. formulario de búsqueda, iconos sociales, etc.) +breadcrumb = Ruta de posicionamiento +content = Contenido principal +sidebar_first = Barra lateral primera +sidebar_second = Barra lateral segunda +footer = Pie diff --git a/extensions/pagetop-bootsier/src/theme.rs b/extensions/pagetop-bootsier/src/theme.rs new file mode 100644 index 00000000..51073d43 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme.rs @@ -0,0 +1,27 @@ +//! Definiciones y componentes del tema. + +pub mod aux; + +// Container. +mod container; +pub use container::{Container, ContainerType}; + +// Dropdown. +pub mod dropdown; +#[doc(inline)] +pub use dropdown::Dropdown; + +// Image. +mod image; +pub use image::{Image, ImageSize}; + +// Navbar. +pub mod navbar; +#[doc(inline)] +pub use navbar::{Navbar, NavbarToggler}; + +// Offcanvas. +mod offcanvas; +pub use offcanvas::{ + Offcanvas, OffcanvasBackdrop, OffcanvasBodyScroll, OffcanvasPlacement, OffcanvasVisibility, +}; diff --git a/extensions/pagetop-bootsier/src/theme/aux.rs b/extensions/pagetop-bootsier/src/theme/aux.rs new file mode 100644 index 00000000..72ebf066 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux.rs @@ -0,0 +1,18 @@ +//! Coleción de elementos auxiliares de Bootstrap para Bootsier. + +mod breakpoint; +pub use breakpoint::BreakPoint; + +mod color; +pub use color::Color; +pub use color::{BgColor, BorderColor, TextColor}; + +mod opacity; +pub use opacity::Opacity; +pub use opacity::{BgOpacity, BorderOpacity, TextOpacity}; + +mod border; +pub use border::{Border, BorderSize}; + +mod rounded; +pub use rounded::{Rounded, RoundedRadius}; diff --git a/extensions/pagetop-bootsier/src/theme/aux/border.rs b/extensions/pagetop-bootsier/src/theme/aux/border.rs new file mode 100644 index 00000000..840f03c7 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/border.rs @@ -0,0 +1,202 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +use std::fmt; + +// **< BorderSize >********************************************************************************* + +/// Tamaño (**ancho**) para los bordes ([`Border`]). +/// +/// Mapea a `border`, `border-0` y `border-{1..5}`: +/// +/// - `None` no añade clase (devuelve `""`). +/// - `Default` genera `border` (borde por defecto del tema). +/// - `Zero` genera `border-0` (sin borde). +/// - `Scale{1..5}` genera `border-{1..5}` (ancho creciente). +#[derive(AutoDefault)] +pub enum BorderSize { + #[default] + None, + Default, + Zero, + Scale1, + Scale2, + Scale3, + Scale4, + Scale5, +} + +impl BorderSize { + #[rustfmt::skip] + fn to_class(&self, prefix: impl AsRef<str>) -> String { + match self { + Self::None => String::new(), + Self::Default => String::from(prefix.as_ref()), + Self::Zero => join!(prefix, "-0"), + Self::Scale1 => join!(prefix, "-1"), + Self::Scale2 => join!(prefix, "-2"), + Self::Scale3 => join!(prefix, "-3"), + Self::Scale4 => join!(prefix, "-4"), + Self::Scale5 => join!(prefix, "-5"), + } + } +} + +impl fmt::Display for BorderSize { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.to_class("border")) + } +} + +// **< Border >************************************************************************************* + +/// Agrupa propiedades para crear **bordes**. +/// +/// Permite: +/// +/// - Definir un tamaño **global** para todo el borde (`size`). +/// - Ajustar el tamaño de cada **lado lógico** (`top`, `end`, `bottom`, `start`, **en este orden**, +/// respetando LTR/RTL). +/// - Aplicar un **color** al borde (`BorderColor`). +/// - Aplicar un nivel de **opacidad** (`BorderOpacity`). +/// +/// # Comportamiento aditivo / sustractivo +/// +/// - **Aditivo**: basta con crear un borde sin tamaño con `Border::new()` para ir añadiendo cada +/// lado lógico con el tamaño deseado usando `BorderSize::Scale{1..5}`. +/// +/// - **Sustractivo**: se crea un borde con tamaño predefinido, p. ej. utilizando +/// `Border::with(BorderSize::Scale2)` y eliminar los lados deseados con `BorderSize::Zero`. +/// +/// - **Anchos diferentes por lado**: usando `BorderSize::Scale{1..5}` en cada lado deseado. +/// +/// # Ejemplos +/// +/// **Borde global:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = Border::with(BorderSize::Scale2); +/// assert_eq!(b.to_string(), "border-2"); +/// ``` +/// +/// **Aditivo (solo borde superior):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = Border::new().with_top(BorderSize::Scale1); +/// assert_eq!(b.to_string(), "border-top-1"); +/// ``` +/// +/// **Sustractivo (borde global menos el superior):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = Border::with(BorderSize::Default).with_top(BorderSize::Zero); +/// assert_eq!(b.to_string(), "border border-top-0"); +/// ``` +/// +/// **Ancho por lado (lado lógico inicial a 2 y final a 4):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = Border::new().with_start(BorderSize::Scale2).with_end(BorderSize::Scale4); +/// assert_eq!(b.to_string(), "border-end-4 border-start-2"); +/// ``` +/// +/// **Combinado (ejemplo completo):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = Border::with(BorderSize::Default) // Borde global por defecto. +/// .with_top(BorderSize::Zero) // Quita borde superior. +/// .with_end(BorderSize::Scale3) // Ancho 3 para el lado lógico final. +/// .with_color(BorderColor::Theme(Color::Primary)) +/// .with_opacity(BorderOpacity::Theme(Opacity::Half)); +/// +/// assert_eq!(b.to_string(), "border border-top-0 border-end-3 border-primary border-opacity-50"); +/// ``` +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Border { + size : BorderSize, + top : BorderSize, + end : BorderSize, + bottom : BorderSize, + start : BorderSize, + color : BorderColor, + opacity: BorderOpacity, +} + +impl Border { + /// Prepara un borde **sin tamaño global** de partida. + pub fn new() -> Self { + Self::default() + } + + /// Crea un borde **con tamaño global** (`size`). + pub fn with(size: BorderSize) -> Self { + Self::default().with_size(size) + } + + // **< Border BUILDER >************************************************************************* + + /// Establece el tamaño global del borde (`border*`). + pub fn with_size(mut self, size: BorderSize) -> Self { + self.size = size; + self + } + + /// Establece el tamaño del borde superior (`border-top-*`). + pub fn with_top(mut self, size: BorderSize) -> Self { + self.top = size; + self + } + + /// Establece el tamaño del borde en el lado lógico final (`border-end-*`). Respeta LTR/RTL. + pub fn with_end(mut self, size: BorderSize) -> Self { + self.end = size; + self + } + + /// Establece el tamaño del borde inferior (`border-bottom-*`). + pub fn with_bottom(mut self, size: BorderSize) -> Self { + self.bottom = size; + self + } + + /// Establece el tamaño del borde en el lado lógico inicial (`border-start-*`). Respeta LTR/RTL. + pub fn with_start(mut self, size: BorderSize) -> Self { + self.start = size; + self + } + + /// Establece el **color** del borde. + pub fn with_color(mut self, color: BorderColor) -> Self { + self.color = color; + self + } + + /// Establece la **opacidad** del borde. + pub fn with_opacity(mut self, opacity: BorderOpacity) -> Self { + self.opacity = opacity; + self + } +} + +impl fmt::Display for Border { + /// Concatena cada definición en el orden: *global*, `top`, `end`, `bottom`, `start`, *color* y + /// *opacidad*; respetando LTR/RTL y omitiendo las definiciones vacías. + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + join_opt!([ + self.size.to_string(), + self.top.to_class("border-top"), + self.end.to_class("border-end"), + self.bottom.to_class("border-bottom"), + self.start.to_class("border-start"), + self.color.to_string(), + self.opacity.to_string(), + ]; " ") + .unwrap_or_default() + ) + } +} diff --git a/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs b/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs new file mode 100644 index 00000000..963bb3b5 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs @@ -0,0 +1,127 @@ +use pagetop::prelude::*; + +use std::fmt; + +/// Define los puntos de ruptura (*breakpoints*) para aplicar diseño *responsive*. +/// +/// - `"sm"`, `"md"`, `"lg"`, `"xl"` o `"xxl"` para los puntos de ruptura `SM`, `MD`, `LG`, `XL` o +/// `XXL`, respectivamente. +/// - `""` (cadena vacía) para `None`. +/// - `"fluid"` para las variantes `Fluid` y `FluidMax(_)`, útil para modelar `container-fluid` en +/// [`Container`](crate::theme::Container). Se debe tener en cuenta que `"fluid"` **no** es un +/// sufijo de *breakpoint*. Para construir clases válidas con prefijo (p. ej., `"col-md"`), se +/// recomienda usar `to_class()` (Self::to_class) o `try_class()` (Self::try_class). +/// +/// # Ejemplos +/// +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// assert_eq!(BreakPoint::MD.to_string(), "md"); +/// assert_eq!(BreakPoint::None.to_string(), ""); +/// assert_eq!(BreakPoint::Fluid.to_string(), "fluid"); +/// +/// // Forma correcta para clases con prefijo: +/// //assert_eq!(BreakPoint::MD.to_class("col"), "col-md"); +/// //assert_eq!(BreakPoint::Fluid.to_class("offcanvas"), "offcanvas"); +/// ``` +#[rustfmt::skip] +#[derive(AutoDefault)] +pub enum BreakPoint { + /// **Menos de 576px**. Dispositivos muy pequeños: teléfonos en modo vertical. + #[default] + None, + /// **576px o más** - Dispositivos pequeños: teléfonos en modo horizontal. + SM, + /// **768px o más** - Dispositivos medianos: tabletas. + MD, + /// **992px o más** - Dispositivos grandes: puestos de escritorio. + LG, + /// **1200px o más** - Dispositivos muy grandes: puestos de escritorio grandes. + XL, + /// **1400px o más** - Dispositivos extragrandes: puestos de escritorio más grandes. + XXL, + /// Para [`Container`](crate::theme::Container), ocupa el 100% del ancho del dispositivo. + Fluid, + /// Para [`Container`](crate::theme::Container), ocupa el 100% del ancho del dispositivo hasta + /// un ancho máximo indicado. + FluidMax(UnitValue) +} + +impl BreakPoint { + /// Comprueba si es un punto de ruptura efectivo. + /// + /// Devuelve `true` si el valor es `SM`, `MD`, `LG`, `XL` o `XXL`; y `false` en otro caso. + #[inline] + pub const fn is_breakpoint(&self) -> bool { + matches!(self, Self::SM | Self::MD | Self::LG | Self::XL | Self::XXL) + } + + /// Genera un nombre de clase CSS basado en el punto de ruptura. + /// + /// Si es un punto de ruptura efectivo (ver [`is_breakpoint()`](Self::is_breakpoint), concatena + /// el prefijo, un guion (`-`) y el sufijo asociado. En otro caso devuelve únicamente el + /// prefijo. + /// + /// # Ejemplo + /// + /// ```rust + /// let breakpoint = BreakPoint::MD; + /// let class = breakpoint.to_class("col"); + /// assert_eq!(class, "col-md".to_string()); + /// + /// let breakpoint = BreakPoint::Fluid; + /// let class = breakpoint.to_class("offcanvas"); + /// assert_eq!(class, "offcanvas".to_string()); + /// ``` + #[inline] + pub fn to_class(&self, prefix: impl AsRef<str>) -> String { + if self.is_breakpoint() { + join!(prefix, "-", self.to_string()) + } else { + String::from(prefix.as_ref()) + } + } + + /// Intenta generar un nombre de clase CSS basado en el punto de ruptura. + /// + /// Si es un punto de ruptura efectivo (ver [`is_breakpoint()`](Self::is_breakpoint), devuelve + /// `Some(String)` concatenando el prefijo, un guion (`-`) y el sufijo asociado. En otro caso + /// devuelve `None`. + /// + /// # Ejemplo + /// + /// ```rust + /// let breakpoint = BreakPoint::MD; + /// let class = breakpoint.try_class("col"); + /// assert_eq!(class, Some("col-md".to_string())); + /// + /// let breakpoint = BreakPoint::Fluid; + /// let class = breakpoint.try_class("navbar-expanded"); + /// assert_eq!(class, None); + /// ``` + #[inline] + pub fn try_class(&self, prefix: impl AsRef<str>) -> Option<String> { + if self.is_breakpoint() { + Some(join!(prefix, "-", self.to_string())) + } else { + None + } + } +} + +#[rustfmt::skip] +impl fmt::Display for BreakPoint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::None => Ok(()), + Self::SM => f.write_str("sm"), + Self::MD => f.write_str("md"), + Self::LG => f.write_str("lg"), + Self::XL => f.write_str("xl"), + Self::XXL => f.write_str("xxl"), + // Devuelven "fluid" (para modelar `container-fluid`). + Self::Fluid => f.write_str("fluid"), + Self::FluidMax(_) => f.write_str("fluid"), + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/aux/color.rs b/extensions/pagetop-bootsier/src/theme/aux/color.rs new file mode 100644 index 00000000..3a288550 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/color.rs @@ -0,0 +1,155 @@ +use pagetop::prelude::*; + +use std::fmt; + +// **< Color >************************************************************************************** + +/// Paleta de colores **temáticos**. +/// +/// Equivalente a los nombres estándar de Bootstrap (`primary`, `secondary`, `success`, etc.). Sirve +/// como base para componer clases de fondo ([`BgColor`]), borde ([`BorderColor`]) y texto +/// ([`TextColor`]). +#[derive(AutoDefault)] +pub enum Color { + #[default] + Primary, + Secondary, + Success, + Info, + Warning, + Danger, + Light, + Dark, +} + +#[rustfmt::skip] +impl fmt::Display for Color { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Primary => f.write_str("primary"), + Self::Secondary => f.write_str("secondary"), + Self::Success => f.write_str("success"), + Self::Info => f.write_str("info"), + Self::Warning => f.write_str("warning"), + Self::Danger => f.write_str("danger"), + Self::Light => f.write_str("light"), + Self::Dark => f.write_str("dark"), + } + } +} + +// **< BgColor >************************************************************************************ + +/// Colores de fondo (`bg-*`). +/// +/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). +/// - `Body*` usa fondos predefinidos del tema (`bg-body`, `bg-body-secondary`, `bg-body-tertiary`). +/// - `Theme(Color)` genera `bg-{color}` (p. ej., `bg-primary`). +/// - `Subtle(Color)` genera `bg-{color}-subtle` (tono suave). +/// - `Black` y `White` son colores explícitos. +/// - `Transparent` no aplica color de fondo (`bg-transparent`). +#[derive(AutoDefault)] +pub enum BgColor { + #[default] + Default, + Body, + BodySecondary, + BodyTertiary, + Theme(Color), + Subtle(Color), + Black, + White, + Transparent, +} + +#[rustfmt::skip] +impl fmt::Display for BgColor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Body => f.write_str("bg-body"), + Self::BodySecondary => f.write_str("bg-body-secondary"), + Self::BodyTertiary => f.write_str("bg-body-tertiary"), + Self::Theme(c) => write!(f, "bg-{c}"), + Self::Subtle(c) => write!(f, "bg-{c}-subtle"), + Self::Black => f.write_str("bg-black"), + Self::White => f.write_str("bg-white"), + Self::Transparent => f.write_str("bg-transparent"), + } + } +} + +// **< BorderColor >******************************************************************************** + +/// Colores (`border-*`) para los bordes ([`Border`](crate::theme::aux::Border)). +/// +/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). +/// - `Theme(Color)` genera `border-{color}`. +/// - `Subtle(Color)` genera `border-{color}-subtle` (versión suavizada). +/// - `Black` y `White` son colores explícitos. +#[derive(AutoDefault)] +pub enum BorderColor { + #[default] + Default, + Theme(Color), + Subtle(Color), + Black, + White, +} + +#[rustfmt::skip] +impl fmt::Display for BorderColor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Theme(c) => write!(f, "border-{c}"), + Self::Subtle(c) => write!(f, "border-{c}-subtle"), + Self::Black => f.write_str("border-black"), + Self::White => f.write_str("border-white"), + } + } +} + +// **< TextColor >********************************************************************************** + +/// Colores de texto y fondos de texto (`text-*`). +/// +/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). +/// - `Body*` aplica colores predefinidos del tema (`text-body`, `text-body-emphasis`, +/// `text-body-secondary`, `text-body-tertiary`). +/// - `Theme(Color)` genera `text-{color}`. +/// - `Emphasis(Color)` genera `text-{color}-emphasis` (contraste mayor acorde al tema). +/// - `Background(Color)` genera `text-bg-{color}` (para color de fondo del texto). +/// - `Black` y `White` son colores explícitos. +#[derive(AutoDefault)] +pub enum TextColor { + #[default] + Default, + Body, + BodyEmphasis, + BodySecondary, + BodyTertiary, + Theme(Color), + Emphasis(Color), + Background(Color), + Black, + White, +} + +#[rustfmt::skip] +impl fmt::Display for TextColor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Body => f.write_str("text-body"), + Self::BodyEmphasis => f.write_str("text-body-emphasis"), + Self::BodySecondary => f.write_str("text-body-secondary"), + Self::BodyTertiary => f.write_str("text-body-tertiary"), + Self::Theme(c) => write!(f, "text-{c}"), + Self::Emphasis(c) => write!(f, "text-{c}-emphasis"), + Self::Background(c) => write!(f, "text-bg-{c}"), + Self::Black => f.write_str("text-black"), + Self::White => f.write_str("text-white"), + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/aux/opacity.rs b/extensions/pagetop-bootsier/src/theme/aux/opacity.rs new file mode 100644 index 00000000..96724d91 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/opacity.rs @@ -0,0 +1,109 @@ +use pagetop::prelude::*; + +use std::fmt; + +// **< Opacity >************************************************************************************ + +/// Niveles de **opacidad** (`opacity-*`). +/// +/// Se usa para modular la transparencia del color de fondo `bg-opacity-*` ([`BgOpacity`]), borde +/// `border-opacity-*` ([`BorderOpacity`]) o texto `text-opacity-*` ([`TextOpacity`]), según las +/// siguientes equivalencias: +/// +/// - `Opaque` => `opacity-100` (100% de opacidad). +/// - `SemiOpaque` => `opacity-75` (75%). +/// - `Half` => `opacity-50` (50%). +/// - `SemiTransparent` => `opacity-25` (25%). +/// - `AlmostTransparent` => `opacity-10` (10%). +/// - `Transparent` => `opacity-0` (0%, totalmente transparente). +#[rustfmt::skip] +#[derive(AutoDefault)] +pub enum Opacity { + #[default] + Opaque, // 100% + SemiOpaque, // 75% + Half, // 50% + SemiTransparent, // 25% + AlmostTransparent, // 10% + Transparent, // 0% +} + +#[rustfmt::skip] +impl fmt::Display for Opacity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Opaque => f.write_str("opacity-100"), + Self::SemiOpaque => f.write_str("opacity-75"), + Self::Half => f.write_str("opacity-50"), + Self::SemiTransparent => f.write_str("opacity-25"), + Self::AlmostTransparent => f.write_str("opacity-10"), + Self::Transparent => f.write_str("opacity-0"), + } + } +} + +// **< BgOpacity >********************************************************************************** + +/// Opacidad para el fondo (`bg-opacity-*`). +/// +/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). +/// - `Theme(Opacity)` genera `bg-{opacity}` (p. ej., `bg-opacity-50`). +#[derive(AutoDefault)] +pub enum BgOpacity { + #[default] + Default, + Theme(Opacity), +} + +impl fmt::Display for BgOpacity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Theme(o) => write!(f, "bg-{o}"), + } + } +} + +// **< BorderOpacity >****************************************************************************** + +/// Opacidad (`border-opacity-*`) para los bordes ([`Border`](crate::theme::aux::Border)). +/// +/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). +/// - `Theme(Opacity)` genera `border-{opacity}` (p. ej., `border-opacity-25`). +#[derive(AutoDefault)] +pub enum BorderOpacity { + #[default] + Default, + Theme(Opacity), +} + +impl fmt::Display for BorderOpacity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Theme(o) => write!(f, "border-{o}"), + } + } +} + +// **< TextOpacity >******************************************************************************** + +/// Opacidad para el texto (`text-opacity-*`). +/// +/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). +/// - `Theme(Opacity)` genera `text-{opacity}` (p. ej., `text-opacity-100`). +#[derive(AutoDefault)] +pub enum TextOpacity { + #[default] + Default, + Theme(Opacity), +} + +impl fmt::Display for TextOpacity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Theme(o) => write!(f, "text-{o}"), + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/aux/rounded.rs b/extensions/pagetop-bootsier/src/theme/aux/rounded.rs new file mode 100644 index 00000000..f7f6e3fe --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/rounded.rs @@ -0,0 +1,214 @@ +use pagetop::prelude::*; + +use std::fmt; + +// **< RoundedRadius >****************************************************************************** + +/// Radio (**redondeo**) para las esquinas ([`Rounded`]). +/// +/// Mapea a `rounded`, `rounded-0`, `rounded-{1..5}`, `rounded-circle` y `rounded-pill`. +/// +/// - `None` no añade clase (devuelve `""`). +/// - `Default` genera `rounded` (radio por defecto del tema). +/// - `Zero` genera `rounded-0` (sin redondeo). +/// - `Scale{1..5}` genera `rounded-{1..5}` (radio creciente). +/// - `Circle` genera `rounded-circle`. +/// - `Pill` genera `rounded-pill`. +#[derive(AutoDefault)] +pub enum RoundedRadius { + #[default] + None, + Default, + Zero, + Scale1, + Scale2, + Scale3, + Scale4, + Scale5, + Circle, + Pill, +} + +impl RoundedRadius { + #[rustfmt::skip] + fn to_class(&self, base: impl AsRef<str>) -> String { + match self { + RoundedRadius::None => String::new(), + RoundedRadius::Default => String::from(base.as_ref()), + RoundedRadius::Zero => join!(base, "-0"), + RoundedRadius::Scale1 => join!(base, "-1"), + RoundedRadius::Scale2 => join!(base, "-2"), + RoundedRadius::Scale3 => join!(base, "-3"), + RoundedRadius::Scale4 => join!(base, "-4"), + RoundedRadius::Scale5 => join!(base, "-5"), + RoundedRadius::Circle => join!(base, "-circle"), + RoundedRadius::Pill => join!(base, "-pill"), + } + } +} + +impl fmt::Display for RoundedRadius { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.to_class("rounded")) + } +} + +// **< Rounded >************************************************************************************ + +/// Agrupa propiedades para crear **esquinas redondeadas**. +/// +/// Permite: +/// +/// - Definir un radio **global para todas las esquinas** (`radius`). +/// - Ajustar el radio asociado a las **esquinas de cada lado lógico** (`top`, `end`, `bottom`, +/// `start`, **en este orden**, respetando LTR/RTL). +/// - Ajustar el radio de las **esquinas concretas** (`top-start`, `top-end`, `bottom-start`, +/// `bottom-end`, **en este orden**, respetando LTR/RTL). +/// +/// # Ejemplos +/// +/// **Radio global:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = Rounded::with(RoundedRadius::Default); +/// assert_eq!(r.to_string(), "rounded"); +/// ``` +/// +/// **Sin redondeo:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = Rounded::new(); +/// assert_eq!(r.to_string(), ""); +/// ``` +/// +/// **Radio en las esquinas de un lado lógico:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = Rounded::new().with_end(RoundedRadius::Scale2); +/// assert_eq!(r.to_string(), "rounded-end-2"); +/// ``` +/// +/// **Radio en una esquina concreta:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = Rounded::new().with_top_start(RoundedRadius::Scale3); +/// assert_eq!(r.to_string(), "rounded-top-start-3"); +/// ``` +/// +/// **Combinado (ejemplo completo):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = Rounded::new() +/// .with_top(RoundedRadius::Default) // Añade redondeo arriba. +/// .with_bottom_start(RoundedRadius::Scale4) // Añade una esquina redondeada concreta. +/// .with_bottom_end(RoundedRadius::Circle); // Añade redondeo extremo en otra esquina. +/// +/// assert_eq!(r.to_string(), "rounded-top rounded-bottom-start-4 rounded-bottom-end-circle"); +/// ``` +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Rounded { + radius : RoundedRadius, + top : RoundedRadius, + end : RoundedRadius, + bottom : RoundedRadius, + start : RoundedRadius, + top_start : RoundedRadius, + top_end : RoundedRadius, + bottom_start: RoundedRadius, + bottom_end : RoundedRadius, +} + +impl Rounded { + /// Prepara las esquinas **sin redondeo global** de partida. + pub fn new() -> Self { + Self::default() + } + + /// Crea las esquinas **con redondeo global** (`radius`). + pub fn with(radius: RoundedRadius) -> Self { + Self::default().with_radius(radius) + } + + // **< Rounded BUILDER >************************************************************************ + + /// Establece el radio global de las esquinas (`rounded*`). + pub fn with_radius(mut self, radius: RoundedRadius) -> Self { + self.radius = radius; + self + } + + /// Establece el radio en las esquinas del lado superior (`rounded-top-*`). + pub fn with_top(mut self, radius: RoundedRadius) -> Self { + self.top = radius; + self + } + + /// Establece el radio en las esquinas del lado lógico final (`rounded-end-*`). Respeta LTR/RTL. + pub fn with_end(mut self, radius: RoundedRadius) -> Self { + self.end = radius; + self + } + + /// Establece el radio en las esquinas del lado inferior (`rounded-bottom-*`). + pub fn with_bottom(mut self, radius: RoundedRadius) -> Self { + self.bottom = radius; + self + } + + /// Establece el radio en las esquinas del lado lógico inicial (`rounded-start-*`). Respeta + /// LTR/RTL. + pub fn with_start(mut self, radius: RoundedRadius) -> Self { + self.start = radius; + self + } + + /// Establece el radio en la esquina superior-inicial (`rounded-top-start-*`). Respeta LTR/RTL. + pub fn with_top_start(mut self, radius: RoundedRadius) -> Self { + self.top_start = radius; + self + } + + /// Establece el radio en la esquina superior-final (`rounded-top-end-*`). Respeta LTR/RTL. + pub fn with_top_end(mut self, radius: RoundedRadius) -> Self { + self.top_end = radius; + self + } + + /// Establece el radio en la esquina inferior-inicial (`rounded-bottom-start-*`). Respeta + /// LTR/RTL. + pub fn with_bottom_start(mut self, radius: RoundedRadius) -> Self { + self.bottom_start = radius; + self + } + + /// Establece el radio en la esquina inferior-final (`rounded-bottom-end-*`). Respeta LTR/RTL. + pub fn with_bottom_end(mut self, radius: RoundedRadius) -> Self { + self.bottom_end = radius; + self + } +} + +impl fmt::Display for Rounded { + /// Concatena cada definición en el orden: *global*, `top`, `end`, `bottom`, `start`, + /// `top-start`, `top-end`, `bottom-start` y `bottom-end`; respetando LTR/RTL y omitiendo las + /// definiciones vacías. + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + join_opt!([ + self.radius.to_string(), + self.top.to_class("rounded-top"), + self.end.to_class("rounded-end"), + self.bottom.to_class("rounded-bottom"), + self.start.to_class("rounded-start"), + self.top_start.to_class("rounded-top-start"), + self.top_end.to_class("rounded-top-end"), + self.bottom_start.to_class("rounded-bottom-start"), + self.bottom_end.to_class("rounded-bottom-end"), + ]; " ") + .unwrap_or_default() + ) + } +} diff --git a/extensions/pagetop-bootsier/src/theme/container.rs b/extensions/pagetop-bootsier/src/theme/container.rs new file mode 100644 index 00000000..65ce9230 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/container.rs @@ -0,0 +1,269 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +/// Tipo de contenedor ([`Container`]). +/// +/// Permite aplicar la etiqueta HTML apropiada (`<main>`, `<header>`, etc.) manteniendo una API +/// común a todos los contenedores. +#[rustfmt::skip] +#[derive(AutoDefault)] +pub enum ContainerType { + /// Contenedor genérico (`<div>`). + #[default] + Default, + /// Contenido principal de la página (`<main>`). + Main, + /// Encabezado de la página o de sección (`<header>`). + Header, + /// Pie de la página o de sección (`<footer>`). + Footer, + /// Sección de contenido (`<section>`). + Section, + /// Artículo de contenido (`<article>`). + Article, +} + +/// Componente genérico para crear un contenedor de componentes. +/// +/// Envuelve el contenido con la etiqueta HTML indicada por [`ContainerType`]. Sólo se renderiza si +/// existen componentes hijos (*children*). +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Container { + id : AttrId, + classes : AttrClasses, + container_type: ContainerType, + breakpoint : BreakPoint, + children : Children, + bg_color : BgColor, + text_color : TextColor, + border : Border, + rounded : Rounded, +} + +impl Component for Container { + fn new() -> Self { + Container::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes( + ClassesOp::Prepend, + [ + join_pair!("container", "-", self.breakpoint().to_string()), + self.bg_color().to_string(), + self.text_color().to_string(), + self.border().to_string(), + self.rounded().to_string(), + ] + .join(" "), + ); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let output = self.children().render(cx); + if output.is_empty() { + return PrepareMarkup::None; + } + let style = match self.breakpoint() { + BreakPoint::FluidMax(w) if w.is_measurable() => { + Some(join!("max-width: ", w.to_string(), ";")) + } + _ => None, + }; + match self.container_type() { + ContainerType::Default => PrepareMarkup::With(html! { + div id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + ContainerType::Main => PrepareMarkup::With(html! { + main id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + ContainerType::Header => PrepareMarkup::With(html! { + header id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + ContainerType::Footer => PrepareMarkup::With(html! { + footer id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + ContainerType::Section => PrepareMarkup::With(html! { + section id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + ContainerType::Article => PrepareMarkup::With(html! { + article id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + } + } +} + +impl Container { + /// Crea un contenedor de tipo `Main` (`<main>`). + pub fn main() -> Self { + Container { + container_type: ContainerType::Main, + ..Default::default() + } + } + + /// Crea un contenedor de tipo `Header` (`<header>`). + pub fn header() -> Self { + Container { + container_type: ContainerType::Header, + ..Default::default() + } + } + + /// Crea un contenedor de tipo `Footer` (`<footer>`). + pub fn footer() -> Self { + Container { + container_type: ContainerType::Footer, + ..Default::default() + } + } + + /// Crea un contenedor de tipo `Section` (`<section>`). + pub fn section() -> Self { + Container { + container_type: ContainerType::Section, + ..Default::default() + } + } + + /// Crea un contenedor de tipo `Article` (`<article>`). + pub fn article() -> Self { + Container { + container_type: ContainerType::Article, + ..Default::default() + } + } + + // **< Container BUILDER >********************************************************************** + + /// Establece el identificador único (`id`) del contenedor. + #[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 contenedor. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + /// Establece el *punto de ruptura* del contenedor. + #[builder_fn] + pub fn with_breakpoint(mut self, bp: BreakPoint) -> Self { + self.breakpoint = bp; + self + } + + /// Añade un nuevo componente hijo al contenedor. + pub fn add_child(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 + } + + /// Establece el color de fondo ([`BgColor`]). + #[builder_fn] + pub fn with_bg_color(mut self, color: BgColor) -> Self { + self.bg_color = color; + self + } + + /// Establece el color del texto ([`TextColor`]). + #[builder_fn] + pub fn with_text_color(mut self, color: TextColor) -> Self { + self.text_color = color; + self + } + + /// Atajo para definir los colores de fondo y texto a la vez. + #[builder_fn] + pub fn with_colors(mut self, bg_color: BgColor, text_color: TextColor) -> Self { + self.bg_color = bg_color; + self.text_color = text_color; + self + } + + /// Establece el borde del contenedor ([`Border`]). + #[builder_fn] + pub fn with_border(mut self, border: Border) -> Self { + self.border = border; + self + } + + /// Establece esquinas redondeadas para el contenedor. + #[builder_fn] + pub fn with_rounded(mut self, rounded: Rounded) -> Self { + self.rounded = rounded; + self + } + + // **< Container GETTERS >********************************************************************** + + /// Devuelve las clases CSS asociadas al contenedor. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el tipo semántico del contenedor. + pub fn container_type(&self) -> &ContainerType { + &self.container_type + } + + /// Devuelve el *punto de ruptura* actualmente configurado. + pub fn breakpoint(&self) -> &BreakPoint { + &self.breakpoint + } + + /// Devuelve la lista de hijos (`children`) del contenedor. + pub fn children(&self) -> &Children { + &self.children + } + + /// Devuelve el color de fondo del contenedor. + pub fn bg_color(&self) -> &BgColor { + &self.bg_color + } + + /// Devuelve el color del texto del contenedor. + pub fn text_color(&self) -> &TextColor { + &self.text_color + } + + /// Devuelve el borde del contenedor. + pub fn border(&self) -> &Border { + &self.border + } + + /// Devuelve las esquinas redondeadas del contenedor. + pub fn rounded(&self) -> &Rounded { + &self.rounded + } +} diff --git a/extensions/pagetop-bootsier/src/theme/dropdown.rs b/extensions/pagetop-bootsier/src/theme/dropdown.rs new file mode 100644 index 00000000..a04f8dd6 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/dropdown.rs @@ -0,0 +1,5 @@ +mod component; +pub use component::Dropdown; + +mod item; +pub use item::Item; diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs new file mode 100644 index 00000000..2e0ea700 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs @@ -0,0 +1,99 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Dropdown { + id : AttrId, + classes: AttrClasses, + items : Children, +} + +impl Component for Dropdown { + fn new() -> Self { + Dropdown::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes(ClassesOp::Prepend, "dropdown"); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let items = self.items().render(cx); + if items.is_empty() { + return PrepareMarkup::None; + } + + PrepareMarkup::With(html! { + div id=[self.id()] class=[self.classes().get()] { + button + type="button" + class="btn btn-secondary dropdown-toggle" + data-bs-toggle="dropdown" + aria-expanded="false" + { + ("Dropdown button") + } + ul class="dropdown-menu" { + li { + a class="dropdown-item" href="#" { + ("Action") + } + } + li { + a class="dropdown-item" href="#" { + ("Another action") + } + } + li { + a class="dropdown-item" href="#" { + ("Something else here") + } + } + } + } + }) + } +} + +impl Dropdown { + // **< Dropdown BUILDER >*********************************************************************** + + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + pub fn add_item(mut self, item: dropdown::Item) -> Self { + self.items.add(Child::with(item)); + self + } + + #[builder_fn] + pub fn with_items(mut self, op: TypedOp<dropdown::Item>) -> Self { + self.items.alter_typed(op); + self + } + + // **< Dropdown GETTERS >*********************************************************************** + + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + pub fn items(&self) -> &Children { + &self.items + } +} diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/item.rs b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs new file mode 100644 index 00000000..1edd64b1 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs @@ -0,0 +1,109 @@ +use pagetop::prelude::*; + +// **< ItemType >*********************************************************************************** + +#[derive(AutoDefault)] +pub enum ItemType { + #[default] + Void, + Label(L10n), + Link(L10n, FnPathByContext), + LinkBlank(L10n, FnPathByContext), +} + +// **< Item >*************************************************************************************** + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Item { + item_type: ItemType, +} + +impl Component for Item { + fn new() -> Self { + Item::default() + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let description: Option<String> = None; + + // Obtiene la URL actual desde `cx.request`. + let current_path = cx.request().map(|request| request.path()); + + match self.item_type() { + ItemType::Void => PrepareMarkup::None, + ItemType::Label(label) => PrepareMarkup::With(html! { + li class="dropdown-item" { + span title=[description] { + //(left_icon) + (label.using(cx)) + //(right_icon) + } + } + }), + ItemType::Link(label, path) => { + let item_path = path(cx); + let (class, aria) = if current_path == Some(item_path) { + ("dropdown-item active", Some("page")) + } else { + ("dropdown-item", None) + }; + PrepareMarkup::With(html! { + li class=(class) aria-current=[aria] { + a class="nav-link" href=(item_path) title=[description] { + //(left_icon) + (label.using(cx)) + //(right_icon) + } + } + }) + } + ItemType::LinkBlank(label, path) => { + let item_path = path(cx); + let (class, aria) = if current_path == Some(item_path) { + ("dropdown-item active", Some("page")) + } else { + ("dropdown-item", None) + }; + PrepareMarkup::With(html! { + li class=(class) aria-current=[aria] { + a class="nav-link" href=(item_path) title=[description] target="_blank" { + //(left_icon) + (label.using(cx)) + //(right_icon) + } + } + }) + } + } + } +} + +impl Item { + pub fn label(label: L10n) -> Self { + Item { + item_type: ItemType::Label(label), + ..Default::default() + } + } + + pub fn link(label: L10n, path: FnPathByContext) -> Self { + Item { + item_type: ItemType::Link(label, path), + ..Default::default() + } + } + + pub fn link_blank(label: L10n, path: FnPathByContext) -> Self { + Item { + item_type: ItemType::LinkBlank(label, path), + ..Default::default() + } + } + + // Item GETTERS. + + pub fn item_type(&self) -> &ItemType { + &self.item_type + } +} diff --git a/extensions/pagetop-bootsier/src/theme/image.rs b/extensions/pagetop-bootsier/src/theme/image.rs new file mode 100644 index 00000000..6c602780 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/image.rs @@ -0,0 +1,186 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +#[derive(AutoDefault)] +pub enum ImageSource { + #[default] + //Logo(PageTopLogo), + Responsive(String), + Thumbnail(String), + Static(String), +} + +#[derive(AutoDefault)] +pub enum ImageSize { + #[default] + Auto, + Dimensions(UnitValue, UnitValue), + Width(UnitValue), + Height(UnitValue), + Both(UnitValue), +} + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Image { + id : AttrId, + classes: AttrClasses, + source : ImageSource, + alt : AttrL10n, + size : ImageSize, + border : Border, + rounded: Rounded, +} + +impl Component for Image { + fn new() -> Self { + Image::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes( + ClassesOp::Prepend, + [ + String::from(match self.source() { + //ImageSource::Logo(_) => "img-fluid", + ImageSource::Responsive(_) => "img-fluid", + ImageSource::Thumbnail(_) => "img-thumbnail", + _ => "", + }), + self.border().to_string(), + self.rounded().to_string(), + ] + .join(" "), + ); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let dimensions = match self.size() { + ImageSize::Auto => None, + ImageSize::Dimensions(w, h) => { + let w = w.to_string(); + let h = h.to_string(); + Some(join!("width: ", w, "; height: ", h, ";")) + } + ImageSize::Width(w) => { + let w = w.to_string(); + Some(join!("width: ", w, ";")) + } + ImageSize::Height(h) => { + let h = h.to_string(); + Some(join!("height: ", h, ";")) + } + ImageSize::Both(v) => { + let v = v.to_string(); + Some(join!("width: ", v, "; height: ", v, ";")) + } + }; + let source = match self.source() { + /* + ImageSource::Logo(logo) => { + return PrepareMarkup::With(html! { + span + id=[self.id()] + class=[self.classes().get()] + style=[dimensions] + { + (logo.render(cx)) + } + }) + } + */ + ImageSource::Responsive(source) => Some(source), + ImageSource::Thumbnail(source) => Some(source), + ImageSource::Static(source) => Some(source), + }; + PrepareMarkup::With(html! { + img + src=[source] + alt=[self.alternative().lookup(cx)] + id=[self.id()] + class=[self.classes().get()] + style=[dimensions] {} + }) + } +} + +impl Image { + pub fn with(source: ImageSource) -> Self { + Image::default().with_source(source) + } + + // **< Image BUILDER >************************************************************************** + + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + #[builder_fn] + pub fn with_source(mut self, source: ImageSource) -> Self { + self.source = source; + self + } + + #[builder_fn] + pub fn with_alternative(mut self, alt: L10n) -> Self { + self.alt.alter_value(alt); + self + } + + #[builder_fn] + pub fn with_size(mut self, size: ImageSize) -> Self { + self.size = size; + self + } + + #[builder_fn] + pub fn with_border(mut self, border: Border) -> Self { + self.border = border; + self + } + + #[builder_fn] + pub fn with_rounded(mut self, rounded: Rounded) -> Self { + self.rounded = rounded; + self + } + + // **< Image GETTERS >************************************************************************** + + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + pub fn source(&self) -> &ImageSource { + &self.source + } + + pub fn alternative(&self) -> &AttrL10n { + &self.alt + } + + pub fn size(&self) -> &ImageSize { + &self.size + } + + pub fn border(&self) -> &Border { + &self.border + } + + pub fn rounded(&self) -> &Rounded { + &self.rounded + } +} diff --git a/extensions/pagetop-bootsier/src/theme/navbar.rs b/extensions/pagetop-bootsier/src/theme/navbar.rs new file mode 100644 index 00000000..3745b116 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar.rs @@ -0,0 +1,17 @@ +mod component; +pub use component::{Navbar, NavbarToggler, NavbarType}; + +mod button_toggler; +pub use button_toggler::ButtonToggler; + +mod content; +pub use content::{Content, ContentType}; + +mod brand; +pub use brand::Brand; + +mod nav; +pub use nav::Nav; + +mod item; +pub use item::{Item, ItemType}; diff --git a/extensions/pagetop-bootsier/src/theme/navbar/brand.rs b/extensions/pagetop-bootsier/src/theme/navbar/brand.rs new file mode 100644 index 00000000..cfeb45aa --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar/brand.rs @@ -0,0 +1,104 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Brand { + id : AttrId, + #[default(_code = "global::SETTINGS.app.name.to_owned()")] + app_name : String, + slogan : AttrL10n, + logo : Typed<Image>, + #[default(_code = "|_| \"/\"")] + home : FnPathByContext, +} + +impl Component for Brand { + fn new() -> Self { + Brand::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let logo = self.logo().render(cx); + let home = self.home()(cx); + let title = &L10n::l("site_home").lookup(cx); + PrepareMarkup::With(html! { + div id=[self.id()] class="branding__container" { + div class="branding__content" { + @if !logo.is_empty() { + a class="branding__logo" href=(home) title=[title] rel="home" { + (logo) + } + } + div class="branding__text" { + a class="branding__name" href=(home) title=[title] rel="home" { + (self.app_name()) + } + @if let Some(slogan) = self.slogan().lookup(cx) { + div class="branding__slogan" { + (slogan) + } + } + } + } + } + }) + } +} + +impl Brand { + // Brand BUILDER. + + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + #[builder_fn] + pub fn with_app_name(mut self, app_name: impl Into<String>) -> Self { + self.app_name = app_name.into(); + self + } + + #[builder_fn] + pub fn with_slogan(mut self, slogan: L10n) -> Self { + self.slogan.alter_value(slogan); + self + } + + #[builder_fn] + pub fn with_logo(mut self, logo: Option<Image>) -> Self { + self.logo.alter_component(logo); + self + } + + #[builder_fn] + pub fn with_home(mut self, home: FnPathByContext) -> Self { + self.home = home; + self + } + + // Brand GETTERS. + + pub fn app_name(&self) -> &String { + &self.app_name + } + + pub fn slogan(&self) -> &AttrL10n { + &self.slogan + } + + pub fn logo(&self) -> &Typed<Image> { + &self.logo + } + + pub fn home(&self) -> &FnPathByContext { + &self.home + } +} diff --git a/extensions/pagetop-bootsier/src/theme/navbar/button_toggler.rs b/extensions/pagetop-bootsier/src/theme/navbar/button_toggler.rs new file mode 100644 index 00000000..036182a7 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar/button_toggler.rs @@ -0,0 +1,73 @@ +use pagetop::prelude::*; + +use crate::LOCALES_BOOTSIER; + +use std::fmt; + +#[derive(AutoDefault, PartialEq)] +pub(crate) enum Toggle { + #[default] + Collapse, + Offcanvas, +} + +#[rustfmt::skip] +impl fmt::Display for Toggle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Toggle::Collapse => write!(f, "collapse"), + Toggle::Offcanvas => write!(f, "offcanvas"), + } + } +} + +#[derive(AutoDefault)] +pub struct ButtonToggler; + +impl Component for ButtonToggler { + fn new() -> Self { + ButtonToggler::default() + } + + fn prepare_component(&self, _cx: &mut Context) -> PrepareMarkup { + PrepareMarkup::With(html! { + button + type="button" + class="navbar-toggler" + { + span class="navbar-toggler-icon" {} + } + }) + } +} + +impl ButtonToggler { + // ButtonToggler PRIVATE RENDER. + + pub(crate) fn render( + &self, + cx: &mut Context, + id_content: String, + data_bs_toggle: Toggle, + ) -> Markup { + let id_content_target = join!("#", id_content); + let aria_expanded = if data_bs_toggle == Toggle::Collapse { + Some("false") + } else { + None + }; + html! { + button + type="button" + class="navbar-toggler" + data-bs-toggle=(data_bs_toggle) + data-bs-target=(id_content_target) + aria-controls=(id_content) + aria-expanded=[aria_expanded] + aria-label=[L10n::t("toggle", &LOCALES_BOOTSIER).lookup(cx)] + { + span class="navbar-toggler-icon" {} + } + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/navbar/component.rs b/extensions/pagetop-bootsier/src/theme/navbar/component.rs new file mode 100644 index 00000000..4a203c3f --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar/component.rs @@ -0,0 +1,233 @@ +use pagetop::prelude::*; + +use crate::prelude::*; +use crate::LOCALES_BOOTSIER; + +const TOGGLE_COLLAPSE: &str = "collapse"; +const TOGGLE_OFFCANVAS: &str = "offcanvas"; + +#[derive(AutoDefault)] +pub enum NavbarToggler { + #[default] + Enabled, + Disabled, +} + +#[derive(AutoDefault)] +pub enum NavbarType { + #[default] + None, + Nav(Typed<navbar::Nav>), + Offcanvas(Typed<Offcanvas>), + Text(L10n), +} + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Navbar { + id : AttrId, + classes : AttrClasses, + expand : BreakPoint, + toggler : NavbarToggler, + navbar_type: NavbarType, + contents : Children, + brand : Typed<navbar::Brand>, +} + +impl Component for Navbar { + fn new() -> Self { + Navbar::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes( + ClassesOp::Prepend, + [ + "navbar".to_string(), + self.expand().try_class("navbar-expand").unwrap_or_default(), + ] + .join(" "), + ); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let id = cx.required_id::<Self>(self.id()); + + let navbar_type = match self.navbar_type() { + NavbarType::None => return PrepareMarkup::None, + NavbarType::Nav(nav) => { + let id_content = join!(id, "-content"); + match self.toggler() { + NavbarToggler::Enabled => self.toggler_wrapper( + TOGGLE_COLLAPSE, + L10n::t("toggle", &LOCALES_BOOTSIER).lookup(cx), + id_content, + self.brand().render(cx), + nav.render(cx), + ), + NavbarToggler::Disabled => nav.render(cx), + } + } + NavbarType::Offcanvas(oc) => { + let id_content = oc.id().unwrap_or_default(); + self.toggler_wrapper( + TOGGLE_OFFCANVAS, + L10n::t("toggle", &LOCALES_BOOTSIER).lookup(cx), + id_content, + self.brand().render(cx), + oc.render(cx), + ) + } + NavbarType::Text(text) => html! { + span class="navbar-text" { + (text.using(cx)) + } + }, + }; + + self.nav_wrapper(id, self.brand().render(cx), navbar_type) + } +} + +impl Navbar { + pub fn with_nav(nav: navbar::Nav) -> Self { + Navbar::default().with_navbar_type(NavbarType::Nav(Typed::with(nav))) + } + + pub fn with_offcanvas(offcanvas: Offcanvas) -> Self { + Navbar::default().with_navbar_type(NavbarType::Offcanvas(Typed::with(offcanvas))) + } + + // Navbar BUILDER. + + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + #[builder_fn] + pub fn with_expand(mut self, bp: BreakPoint) -> Self { + self.expand = bp; + self + } + + #[builder_fn] + pub fn with_toggler(mut self, toggler: NavbarToggler) -> Self { + self.toggler = toggler; + self + } + + #[builder_fn] + pub fn with_navbar_type(mut self, navbar_type: NavbarType) -> Self { + self.navbar_type = navbar_type; + self + } + + pub fn with_content(mut self, content: navbar::Content) -> Self { + self.contents.add(Child::with(content)); + self + } + + #[builder_fn] + pub fn with_contents(mut self, op: TypedOp<navbar::Content>) -> Self { + self.contents.alter_typed(op); + self + } + + #[builder_fn] + pub fn with_brand(mut self, brand: Option<navbar::Brand>) -> Self { + self.brand.alter_component(brand); + self + } + + // Navbar GETTERS. + + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + pub fn expand(&self) -> &BreakPoint { + &self.expand + } + + pub fn toggler(&self) -> &NavbarToggler { + &self.toggler + } + + pub fn navbar_type(&self) -> &NavbarType { + &self.navbar_type + } + + pub fn contents(&self) -> &Children { + &self.contents + } + + pub fn brand(&self) -> &Typed<navbar::Brand> { + &self.brand + } + + // Navbar HELPERS. + + fn nav_wrapper(&self, id: String, brand: Markup, content: Markup) -> PrepareMarkup { + if content.is_empty() { + PrepareMarkup::None + } else { + PrepareMarkup::With(html! { + (brand) + nav id=(id) class=[self.classes().get()] { + div class="container-fluid" { + (content) + } + } + }) + } + } + + fn toggler_wrapper( + &self, + data_bs_toggle: &str, + aria_label: Option<String>, + id_content: String, + brand: Markup, + content: Markup, + ) -> Markup { + if content.is_empty() { + html! {} + } else { + let id_content_target = join!("#", id_content); + let aria_expanded = if data_bs_toggle == TOGGLE_COLLAPSE { + Some("false") + } else { + None + }; + html! { + (brand) + button + type="button" + class="navbar-toggler" + data-bs-toggle=(data_bs_toggle) + data-bs-target=(id_content_target) + aria-controls=(id_content) + aria-expanded=[aria_expanded] + aria-label=[aria_label] + { + span class="navbar-toggler-icon" {} + } + div id=(id_content) class="collapse navbar-collapse" { + (content) + } + } + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/navbar/content.rs b/extensions/pagetop-bootsier/src/theme/navbar/content.rs new file mode 100644 index 00000000..2efb4a05 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar/content.rs @@ -0,0 +1,69 @@ +use pagetop::prelude::*; + +use crate::theme::navbar; + +#[derive(AutoDefault)] +pub enum ContentType { + #[default] + None, + Brand(Typed<navbar::Brand>), + Nav(Typed<navbar::Nav>), + Text(L10n), +} + +// Item. + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Content { + content: ContentType, +} + +impl Component for Content { + fn new() -> Self { + Content::default() + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + match self.content() { + ContentType::None => PrepareMarkup::None, + ContentType::Brand(brand) => PrepareMarkup::With(html! { + (brand.render(cx)) + }), + ContentType::Nav(nav) => PrepareMarkup::With(html! { + (nav.render(cx)) + }), + ContentType::Text(text) => PrepareMarkup::With(html! { + span class="navbar-text" { + (text.using(cx)) + } + }), + } + } +} + +impl Content { + pub fn brand(content: navbar::Brand) -> Self { + Content { + content: ContentType::Brand(Typed::with(content)), + } + } + + pub fn nav(content: navbar::Nav) -> Self { + Content { + content: ContentType::Nav(Typed::with(content)), + } + } + + pub fn text(content: L10n) -> Self { + Content { + content: ContentType::Text(content), + } + } + + // Content GETTERS. + + pub fn content(&self) -> &ContentType { + &self.content + } +} diff --git a/extensions/pagetop-bootsier/src/theme/navbar/item.rs b/extensions/pagetop-bootsier/src/theme/navbar/item.rs new file mode 100644 index 00000000..08a2aeee --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar/item.rs @@ -0,0 +1,113 @@ +use pagetop::prelude::*; + +use crate::theme::Dropdown; + +type Label = L10n; + +#[derive(AutoDefault)] +pub enum ItemType { + #[default] + Void, + Label(Label), + Link(Label, FnPathByContext), + LinkBlank(Label, FnPathByContext), + Dropdown(Typed<Dropdown>), +} + +// Item. + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Item { + item_type: ItemType, +} + +impl Component for Item { + fn new() -> Self { + Item::default() + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let description: Option<String> = None; + + // Obtiene la URL actual desde `cx.request`. + let current_path = cx.request().map(|request| request.path()); + + match self.item_type() { + ItemType::Void => PrepareMarkup::None, + ItemType::Label(label) => PrepareMarkup::With(html! { + li class="nav-item" { + span title=[description] { + //(left_icon) + (label.using(cx)) + //(right_icon) + } + } + }), + ItemType::Link(label, path) => { + let item_path = path(cx); + let (class, aria) = if current_path == Some(item_path) { + ("nav-item active", Some("page")) + } else { + ("nav-item", None) + }; + PrepareMarkup::With(html! { + li class=(class) aria-current=[aria] { + a class="nav-link" href=(item_path) title=[description] { + //(left_icon) + (label.using(cx)) + //(right_icon) + } + } + }) + } + ItemType::LinkBlank(label, path) => { + let item_path = path(cx); + let (class, aria) = if current_path == Some(item_path) { + ("nav-item active", Some("page")) + } else { + ("nav-item", None) + }; + PrepareMarkup::With(html! { + li class=(class) aria-current=[aria] { + a class="nav-link" href=(item_path) title=[description] target="_blank" { + //(left_icon) + (label.using(cx)) + //(right_icon) + } + } + }) + } + ItemType::Dropdown(menu) => PrepareMarkup::With(html! { (menu.render(cx)) }), + } + } +} + +impl Item { + pub fn label(label: L10n) -> Self { + Item { + item_type: ItemType::Label(label), + ..Default::default() + } + } + + pub fn link(label: L10n, path: FnPathByContext) -> Self { + Item { + item_type: ItemType::Link(label, path), + ..Default::default() + } + } + + pub fn link_blank(label: L10n, path: FnPathByContext) -> Self { + Item { + item_type: ItemType::LinkBlank(label, path), + ..Default::default() + } + } + + // Item GETTERS. + + pub fn item_type(&self) -> &ItemType { + &self.item_type + } +} diff --git a/extensions/pagetop-bootsier/src/theme/navbar/nav.rs b/extensions/pagetop-bootsier/src/theme/navbar/nav.rs new file mode 100644 index 00000000..bc03a291 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar/nav.rs @@ -0,0 +1,75 @@ +use pagetop::prelude::*; + +use crate::theme::navbar; + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Nav { + id : AttrId, + classes: AttrClasses, + items : Children, +} + +impl Component for Nav { + fn new() -> Self { + Nav::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes(ClassesOp::Prepend, "navbar-nav"); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let items = self.items().render(cx); + if items.is_empty() { + return PrepareMarkup::None; + } + + PrepareMarkup::With(html! { + ul id=[self.id()] class=[self.classes().get()] { + (items) + } + }) + } +} + +impl Nav { + // Nav BUILDER. + + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + pub fn with_item(mut self, item: navbar::Item) -> Self { + self.items.add(Child::with(item)); + self + } + + #[builder_fn] + pub fn with_items(mut self, op: TypedOp<navbar::Item>) -> Self { + self.items.alter_typed(op); + self + } + + // Nav GETTERS. + + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + pub fn items(&self) -> &Children { + &self.items + } +} diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas.rs b/extensions/pagetop-bootsier/src/theme/offcanvas.rs new file mode 100644 index 00000000..b790522b --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/offcanvas.rs @@ -0,0 +1,302 @@ +use pagetop::prelude::*; + +use crate::prelude::*; +use crate::LOCALES_BOOTSIER; + +use std::fmt; + +// **< OffcanvasPlacement >************************************************************************* + +/// Posición de aparición del panel **deslizante** ([`Offcanvas`]). +/// +/// Define desde qué borde de la ventana entra y se ancla el panel. +#[derive(AutoDefault)] +pub enum OffcanvasPlacement { + /// Opción por defecto, desde el borde inicial según dirección de lectura (respetando LTR/RTL). + #[default] + Start, + /// Desde el borde final según dirección de lectura (respetando LTR/RTL). + End, + /// Desde la parte superior. + Top, + /// Desde la parte inferior. + Bottom, +} + +#[rustfmt::skip] +impl fmt::Display for OffcanvasPlacement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + OffcanvasPlacement::Start => f.write_str("offcanvas-start"), + OffcanvasPlacement::End => f.write_str("offcanvas-end"), + OffcanvasPlacement::Top => f.write_str("offcanvas-top"), + OffcanvasPlacement::Bottom => f.write_str("offcanvas-bottom"), + } + } +} + +// **< OffcanvasVisibility >************************************************************************ + +/// Estado inicial del panel ([`Offcanvas`]). +#[derive(AutoDefault)] +pub enum OffcanvasVisibility { + /// El panel **permanece oculto** desde el principio. + #[default] + Default, + /// El panel **se muestra abierto** al cargar. + Show, +} + +impl fmt::Display for OffcanvasVisibility { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + OffcanvasVisibility::Default => Ok(()), + OffcanvasVisibility::Show => f.write_str("show"), + } + } +} + +// **< OffcanvasBodyScroll >************************************************************************ + +/// Controla si la página principal puede **desplazarse** al abrir el panel ([`Offcanvas`]). +#[derive(AutoDefault)] +pub enum OffcanvasBodyScroll { + /// Opción por defecto, la página principal se **bloquea** centrando la interacción en el panel. + #[default] + Disabled, + /// **Permite** el desplazamiento de la página principal. + Enabled, +} + +// **< OffcanvasBackdrop >************************************************************************** + +/// Comportamiento de la **capa de fondo** (*backdrop*) del panel ([`Offcanvas`]) al desplegarse. +#[derive(AutoDefault)] +pub enum OffcanvasBackdrop { + /// **Sin capa** de fondo; la página principal permanece visible e interactiva. + Disabled, + /// Opción por defecto, se **oscurece** el fondo; un clic fuera del panel suele cerrarlo. + #[default] + Enabled, + /// Se muestra capa de fondo pero **no** se cierra al pulsar fuera (útil cuando se requiere + /// completar una acción antes de salir). + Static, +} + +// **< Offcanvas >********************************************************************************** + +/// Panel lateral **deslizante** para contenido complementario. +/// +/// Útil para navegación, filtros, formularios o menús contextuales. Incluye las siguientes +/// características principales: +/// +/// - **Entrada configurable desde un borde** de la ventana. +/// - **Encabezado con título** y **botón de cierre** integrado. +/// - **Accesibilidad**: asocia título y controles a un identificador único y expone atributos +/// adecuados para lectores de pantalla y navegación por teclado. +/// - **Opcionalmente** bloquea el desplazamiento del documento y/o muestra una capa de fondo para +/// centrar la atención del usuario. +/// - **Responsive**: puede cambiar su comportamiento según el punto de ruptura indicado. +/// - **No se renderiza** si no tiene contenido. +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Offcanvas { + id : AttrId, + classes : AttrClasses, + title : L10n, + breakpoint: BreakPoint, + placement : OffcanvasPlacement, + visibility: OffcanvasVisibility, + scrolling : OffcanvasBodyScroll, + backdrop : OffcanvasBackdrop, + children : Children, +} + +impl Component for Offcanvas { + fn new() -> Self { + Offcanvas::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes( + ClassesOp::Prepend, + [ + self.breakpoint().to_class("offcanvas"), + self.placement().to_string(), + self.visibility().to_string(), + ] + .join(" "), + ); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let body = self.children().render(cx); + if body.is_empty() { + return PrepareMarkup::None; + } + + let id = cx.required_id::<Self>(self.id()); + let id_label = join!(id, "-label"); + let id_target = join!("#", id); + + let body_scroll = match self.body_scroll() { + OffcanvasBodyScroll::Disabled => None, + OffcanvasBodyScroll::Enabled => Some("true"), + }; + + let backdrop = match self.backdrop() { + OffcanvasBackdrop::Disabled => Some("false"), + OffcanvasBackdrop::Enabled => None, + OffcanvasBackdrop::Static => Some("static"), + }; + + let title = self.title().using(cx); + + PrepareMarkup::With(html! { + div + id=(id) + class=[self.classes().get()] + tabindex="-1" + data-bs-scroll=[body_scroll] + data-bs-backdrop=[backdrop] + aria-labelledby=(id_label) + { + div class="offcanvas-header" { + @if !title.is_empty() { + h5 class="offcanvas-title" id=(id_label) { (title) } + } + button + type="button" + class="btn-close" + data-bs-dismiss="offcanvas" + data-bs-target=(id_target) + aria-label=[L10n::t("close", &LOCALES_BOOTSIER).lookup(cx)] + {} + } + div class="offcanvas-body" { + (body) + } + } + }) + } +} + +impl Offcanvas { + // **< Offcanvas BUILDER >********************************************************************** + + /// Establece el identificador único (`id`) del panel. + #[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 panel. + #[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 encabezado. + #[builder_fn] + pub fn with_title(mut self, title: L10n) -> Self { + self.title = title; + self + } + + /// Configura el **punto de ruptura** para activar el comportamiento responsive del panel. + #[builder_fn] + pub fn with_breakpoint(mut self, bp: BreakPoint) -> Self { + self.breakpoint = bp; + self + } + + /// Indica la **posición** desde la que entra el panel. + #[builder_fn] + pub fn with_placement(mut self, placement: OffcanvasPlacement) -> Self { + self.placement = placement; + self + } + + /// Fija el **estado inicial** del panel (oculto o visible al cargar). + #[builder_fn] + pub fn with_visibility(mut self, visibility: OffcanvasVisibility) -> Self { + self.visibility = visibility; + self + } + + /// Permite o bloquea el **desplazamiento** de la página principal mientras el panel está + /// abierto. + #[builder_fn] + pub fn with_body_scroll(mut self, scrolling: OffcanvasBodyScroll) -> Self { + self.scrolling = scrolling; + self + } + + /// Ajusta la **capa de fondo** del panel para definir su comportamiento al interactuar fuera. + #[builder_fn] + pub fn with_backdrop(mut self, backdrop: OffcanvasBackdrop) -> Self { + self.backdrop = backdrop; + self + } + + /// Añade un nuevo componente hijo al panel. + pub fn add_child(mut self, child: impl Component) -> Self { + self.children.add(Child::with(child)); + self + } + + /// Modifica la lista de hijos (`children`) aplicando una operación [`ChildOp`]. + #[builder_fn] + pub fn with_children(mut self, op: ChildOp) -> Self { + self.children.alter_child(op); + self + } + + // **< Offcanvas GETTERS >********************************************************************** + + /// Devuelve las clases CSS asociadas al panel. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el título del panel como [`L10n`]. + pub fn title(&self) -> &L10n { + &self.title + } + + /// Devuelve el punto de ruptura configurado. + pub fn breakpoint(&self) -> &BreakPoint { + &self.breakpoint + } + + /// Devuelve la posición del panel. + pub fn placement(&self) -> &OffcanvasPlacement { + &self.placement + } + + /// Devuelve el estado inicial del panel. + pub fn visibility(&self) -> &OffcanvasVisibility { + &self.visibility + } + + /// Indica si la página principal puede desplazarse mientras el panel está abierto. + pub fn body_scroll(&self) -> &OffcanvasBodyScroll { + &self.scrolling + } + + /// Devuelve la configuración de la capa de fondo. + pub fn backdrop(&self) -> &OffcanvasBackdrop { + &self.backdrop + } + + /// Devuelve la lista de hijos (`children`) del panel. + pub fn children(&self) -> &Children { + &self.children + } +} From bf310bec7e59a148f0c834b6bf182bdd46209fcd Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 25 Oct 2025 07:03:14 +0200 Subject: [PATCH 220/244] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Mejora=20adici?= =?UTF-8?q?=C3=B3n=20de=20componentes=20hijos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component/block.rs | 8 ++++---- src/base/component/intro.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/base/component/block.rs b/src/base/component/block.rs index 17af50c2..76d094ff 100644 --- a/src/base/component/block.rs +++ b/src/base/component/block.rs @@ -71,13 +71,13 @@ impl Block { } /// Añade un nuevo componente hijo al bloque. + #[inline] pub fn add_child(mut self, component: impl Component) -> Self { - self.children - .alter_child(ChildOp::Add(Child::with(component))); + self.children.add(Child::with(component)); self } - /// Modifica la lista de hijos (`children`) aplicando una operación [`ChildOp`]. + /// Modifica la lista de componentes (`children`) aplicando una operación [`ChildOp`]. #[builder_fn] pub fn with_child(mut self, op: ChildOp) -> Self { self.children.alter_child(op); @@ -96,7 +96,7 @@ impl Block { &self.title } - /// Devuelve la lista de hijos (`children`) del bloque. + /// Devuelve la lista de componentes (`children`) del bloque. pub fn children(&self) -> &Children { &self.children } diff --git a/src/base/component/intro.rs b/src/base/component/intro.rs index 7e5c3931..6fd4521e 100644 --- a/src/base/component/intro.rs +++ b/src/base/component/intro.rs @@ -301,13 +301,13 @@ impl Intro { /// Añade un nuevo componente hijo a la intro. /// /// Si es un bloque ([`Block`]) aplica estilos específicos para destacarlo. + #[inline] pub fn add_child(mut self, component: impl Component) -> Self { - self.children - .alter_child(ChildOp::Add(Child::with(component))); + self.children.add(Child::with(component)); self } - /// Modifica la lista de hijos (`children`) aplicando una operación [`ChildOp`]. + /// Modifica la lista de componentes (`children`) aplicando una operación [`ChildOp`]. #[builder_fn] pub fn with_child(mut self, op: ChildOp) -> Self { self.children.alter_child(op); @@ -336,7 +336,7 @@ impl Intro { self.opening } - /// Devuelve la lista de hijos (`children`) de la intro. + /// Devuelve la lista de componentes (`children`) de la intro. pub fn children(&self) -> &Children { &self.children } From d21e1a21682ed87c758d25856259e6bbd1be886c Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 25 Oct 2025 07:13:15 +0200 Subject: [PATCH 221/244] =?UTF-8?q?=F0=9F=94=92=20Mejora=20seguridad=20de?= =?UTF-8?q?=20enlaces=20con=20`noopener`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component/intro.rs | 8 ++++---- src/base/component/poweredby.rs | 2 +- src/locale/en-US/welcome.ftl | 2 +- src/locale/es-ES/welcome.ftl | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/base/component/intro.rs b/src/base/component/intro.rs index 6fd4521e..a20d6232 100644 --- a/src/base/component/intro.rs +++ b/src/base/component/intro.rs @@ -166,7 +166,7 @@ impl Component for Intro { class="intro-button__link" href=((lnk)(cx)) target="_blank" - rel="noreferrer" + rel="noopener noreferrer" { span {} span {} span {} div class="intro-button__text" { @@ -216,9 +216,9 @@ impl Component for Intro { } } 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)) } + a href="https://crates.io/crates/pagetop" target="_blank" rel="noopener noreferrer" { ("Crates.io") } + a href="https://docs.rs/pagetop" target="_blank" rel="noopener noreferrer" { ("Docs.rs") } + a href="https://git.cillero.es/manuelcillero/pagetop" target="_blank" rel="noopener noreferrer" { (L10n::l("intro_code").using(cx)) } em { (L10n::l("intro_have_fun").using(cx)) } } } diff --git a/src/base/component/poweredby.rs b/src/base/component/poweredby.rs index d77d65c6..51ab79d8 100644 --- a/src/base/component/poweredby.rs +++ b/src/base/component/poweredby.rs @@ -1,7 +1,7 @@ use crate::prelude::*; // Enlace a la página oficial de PageTop. -const LINK: &str = "<a href=\"https://pagetop.cillero.es\" rel=\"noreferrer\">PageTop</a>"; +const LINK: &str = "<a href=\"https://pagetop.cillero.es\" rel=\"noopener noreferrer\">PageTop</a>"; /// Componente que renderiza la sección 'Powered by' (*Funciona con*) típica del pie de página. /// diff --git a/src/locale/en-US/welcome.ftl b/src/locale/en-US/welcome.ftl index 34028804..ec691d1b 100644 --- a/src/locale/en-US/welcome.ftl +++ b/src/locale/en-US/welcome.ftl @@ -8,5 +8,5 @@ welcome_status_1 = If you can see this page, it means the <strong>PageTop</stron 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://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_1 = To report issues with the <strong>PageTop</strong> framework, use <a href="https://github.com/manuelcillero/pagetop/issues" target="_blank" rel="noopener 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. diff --git a/src/locale/es-ES/welcome.ftl b/src/locale/es-ES/welcome.ftl index 605d1e2c..a3e3a184 100644 --- a/src/locale/es-ES/welcome.ftl +++ b/src/locale/es-ES/welcome.ftl @@ -8,5 +8,5 @@ welcome_status_1 = Si puedes ver esta página, es porque el servidor de <strong> 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://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_1 = Para comunicar incidencias del propio entorno <strong>PageTop</strong>, utiliza <a href="https://github.com/manuelcillero/pagetop/issues" target="_blank" rel="noopener 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. From 3841d1d3f3fcb9a427ac1b14d9dab9ae910e93d2 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 25 Oct 2025 09:02:58 +0200 Subject: [PATCH 222/244] =?UTF-8?q?=F0=9F=8E=A8=20(bootsier):=20Mejora=20m?= =?UTF-8?q?en=C3=BAs=20desplegables=20`Dropdown`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/locale/en-US/components.ftl | 3 + .../src/locale/es-ES/components.ftl | 3 + extensions/pagetop-bootsier/src/theme/aux.rs | 7 +- .../pagetop-bootsier/src/theme/aux/color.rs | 29 ++ .../pagetop-bootsier/src/theme/aux/size.rs | 31 ++ .../pagetop-bootsier/src/theme/dropdown.rs | 15 +- .../src/theme/dropdown/component.rs | 378 ++++++++++++++++-- .../src/theme/dropdown/item.rs | 260 ++++++++++-- 8 files changed, 654 insertions(+), 72 deletions(-) create mode 100644 extensions/pagetop-bootsier/src/theme/aux/size.rs diff --git a/extensions/pagetop-bootsier/src/locale/en-US/components.ftl b/extensions/pagetop-bootsier/src/locale/en-US/components.ftl index 83dde396..0bb7fba6 100644 --- a/extensions/pagetop-bootsier/src/locale/en-US/components.ftl +++ b/extensions/pagetop-bootsier/src/locale/en-US/components.ftl @@ -1,3 +1,6 @@ +# Dropdown +dropdown_toggle = Toggle Dropdown + # Offcanvas close = Close diff --git a/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl b/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl index 1ae97888..045191e3 100644 --- a/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl +++ b/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl @@ -1,3 +1,6 @@ +# Dropdown +dropdown_toggle = Mostrar/ocultar menú + # Offcanvas close = Cerrar diff --git a/extensions/pagetop-bootsier/src/theme/aux.rs b/extensions/pagetop-bootsier/src/theme/aux.rs index 72ebf066..f3cc127d 100644 --- a/extensions/pagetop-bootsier/src/theme/aux.rs +++ b/extensions/pagetop-bootsier/src/theme/aux.rs @@ -1,11 +1,11 @@ -//! Coleción de elementos auxiliares de Bootstrap para Bootsier. +//! Colección de elementos auxiliares de Bootstrap para Bootsier. mod breakpoint; pub use breakpoint::BreakPoint; mod color; pub use color::Color; -pub use color::{BgColor, BorderColor, TextColor}; +pub use color::{BgColor, BorderColor, ButtonColor, TextColor}; mod opacity; pub use opacity::Opacity; @@ -16,3 +16,6 @@ pub use border::{Border, BorderSize}; mod rounded; pub use rounded::{Rounded, RoundedRadius}; + +mod size; +pub use size::ButtonSize; diff --git a/extensions/pagetop-bootsier/src/theme/aux/color.rs b/extensions/pagetop-bootsier/src/theme/aux/color.rs index 3a288550..c071e407 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/color.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/color.rs @@ -110,6 +110,35 @@ impl fmt::Display for BorderColor { } } +// **< ButtonColor >******************************************************************************** + +/// Variantes de color (`btn-*`) para **botones**. +/// +/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). +/// - `Background(Color)` genera `btn-{color}` (botón relleno). +/// - `Outline(Color)` genera `btn-outline-{color}` (contorno: texto y borde, fondo transparente). +/// - `Link` aplica estilo de enlace (`btn-link`), sin caja ni fondo, heredando el color de texto. +#[derive(AutoDefault)] +pub enum ButtonColor { + #[default] + Default, + Background(Color), + Outline(Color), + Link, +} + +#[rustfmt::skip] +impl fmt::Display for ButtonColor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Background(c) => write!(f, "btn-{c}"), + Self::Outline(c) => write!(f, "btn-outline-{c}"), + Self::Link => f.write_str("btn-link"), + } + } +} + // **< TextColor >********************************************************************************** /// Colores de texto y fondos de texto (`text-*`). diff --git a/extensions/pagetop-bootsier/src/theme/aux/size.rs b/extensions/pagetop-bootsier/src/theme/aux/size.rs new file mode 100644 index 00000000..e5cff63c --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/size.rs @@ -0,0 +1,31 @@ +use pagetop::prelude::*; + +use std::fmt; + +// **< ButtonSize >********************************************************************************* + +/// Tamaño visual de un botón. +/// +/// Controla la escala del botón según el diseño del tema: +/// +/// - `Default`, tamaño por defecto del tema (no añade clase). +/// - `Small`, botón compacto. +/// - `Large`, botón destacado/grande. +#[derive(AutoDefault)] +pub enum ButtonSize { + #[default] + Default, + Small, + Large, +} + +#[rustfmt::skip] +impl fmt::Display for ButtonSize { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Small => f.write_str("btn-sm"), + Self::Large => f.write_str("btn-lg"), + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/dropdown.rs b/extensions/pagetop-bootsier/src/theme/dropdown.rs index a04f8dd6..9e81c7a3 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown.rs @@ -1,5 +1,18 @@ +//! Definiciones para crear menús desplegables [`Dropdown`]. +//! +//! Cada [`dropdown::Item`](crate::theme::dropdown::Item) representa un elemento individual del +//! desplegable [`Dropdown`], con distintos comportamientos según su finalidad: enlaces de +//! navegación, botones de acción, encabezados o divisores visuales. +//! +//! Los ítems pueden estar activos, deshabilitados o abrirse en nueva ventana según su contexto y +//! configuración, y permiten incluir etiquetas localizables usando [`L10n`](pagetop::locale::L10n). +//! +//! Su propósito es ofrecer una base uniforme sobre la que construir menús consistentes, adaptados +//! al contexto de cada aplicación. + mod component; pub use component::Dropdown; +pub use component::{AutoClose, Direction, MenuAlign, MenuPosition}; mod item; -pub use item::Item; +pub use item::{Item, ItemKind}; diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs index 2e0ea700..9aef2562 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs @@ -1,13 +1,134 @@ use pagetop::prelude::*; use crate::prelude::*; +use crate::LOCALES_BOOTSIER; +// **< AutoClose >********************************************************************************** + +/// Estrategia para el cierre automático de un menú [`Dropdown`]. +/// +/// Define cuándo se cierra el menú desplegado según la interacción del usuario. +#[derive(AutoDefault)] +pub enum AutoClose { + /// Comportamiento por defecto, se cierra con clics dentro y fuera del menú, o pulsando `Esc`. + #[default] + Default, + /// Sólo se cierra con clics dentro del menú. + ClickableInside, + /// Sólo se cierra con clics fuera del menú. + ClickableOutside, + /// Cierre manual, no se cierra con clics; sólo al pulsar nuevamente el botón del menú + /// (*toggle*), o pulsando `Esc`. + ManualClose, +} + +// **< Direction >********************************************************************************** + +/// Dirección de despliegue de un menú [`Dropdown`]. +/// +/// Controla desde qué posición se muestra el menú respecto al botón. +#[derive(AutoDefault)] +pub enum Direction { + /// Comportamiento por defecto (despliega el menú hacia abajo desde la posición inicial, + /// respetando LTR/RTL). + #[default] + Default, + /// Centra horizontalmente el menú respecto al botón. + Centered, + /// Despliega el menú hacia arriba. + Dropup, + /// Despliega el menú hacia arriba y centrado. + DropupCentered, + /// Despliega el menú desde el lateral final, respetando LTR/RTL. + Dropend, + /// Despliega el menú desde el lateral inicial, respetando LTR/RTL. + Dropstart, +} + +// **< MenuAlign >********************************************************************************** + +/// Alineación horizontal del menú desplegable [`Dropdown`]. +/// +/// Permite alinear el menú al inicio o al final del botón (respetando LTR/RTL) y añadirle una +/// alineación diferente a partir de un punto de ruptura ([`BreakPoint`]). +#[derive(AutoDefault)] +pub enum MenuAlign { + /// Alineación al inicio (comportamiento por defecto). + #[default] + Start, + /// Alineación al inicio a partir del punto de ruptura indicado. + StartAt(BreakPoint), + /// Alineación al inicio por defecto, y al final a partir de un punto de ruptura válido. + StartAndEnd(BreakPoint), + /// Alineación al final. + End, + /// Alineación al final a partir del punto de ruptura indicado. + EndAt(BreakPoint), + /// Alineación al final por defecto, y al inicio a partir de un punto de ruptura válido. + EndAndStart(BreakPoint), +} + +// **< MenuPosition >******************************************************************************* + +/// Posición relativa del menú desplegable [`Dropdown`]. +/// +/// Permite indicar un desplazamiento (*offset*) manual o referenciar al elemento padre para el +/// cálculo de la posición. +#[derive(AutoDefault)] +pub enum MenuPosition { + /// Posicionamiento automático por defecto. + #[default] + Default, + /// Desplazamiento manual en píxeles `(x, y)` aplicado al menú. Se admiten valores negativos. + Offset(i8, i8), + /// Posiciona el menú tomando como referencia el botón padre. Especialmente útil cuando + /// [`button_split()`](crate::theme::Dropdown::button_split) es `true`. + Parent, +} + +// **< Dropdown >********************************************************************************** + +/// Componente para crear un **menú desplegable**. +/// +/// Renderiza un botón (único o desdoblado, ver [`with_button_split()`](Self::with_button_split)) +/// para mostrar un menú desplegable de elementos [`dropdown::Item`], que se muestra/oculta según la +/// interacción del usuario. Admite variaciones de tamaño/color del botón, también dirección de +/// apertura, alineación o política de cierre. +/// +/// Sin título para el botón (ver [`with_button_title()`](Self::with_button_title)) se muestra +/// únicamente la lista de elementos sin ningún botón para interactuar. +/// +/// # Ejemplo +/// +/// ```rust +/// # use pagetop::prelude::*; +/// # use pagetop_bootsier::prelude::*; +/// let dd = Dropdown::new() +/// .with_button_title(L10n::n("Menu")) +/// .with_button_color(ButtonColor::Background(Color::Secondary)) +/// .with_auto_close(dropdown::AutoClose::ClickableInside) +/// .with_direction(dropdown::Direction::Dropend) +/// .add_item(dropdown::Item::link(L10n::n("Home"), |_| "/")) +/// .add_item(dropdown::Item::link_blank(L10n::n("External"), |_| "https://www.google.es")) +/// .add_item(dropdown::Item::divider()) +/// .add_item(dropdown::Item::header(L10n::n("User session"))) +/// .add_item(dropdown::Item::button(L10n::n("Sign out"))); +/// ``` #[rustfmt::skip] #[derive(AutoDefault)] pub struct Dropdown { - id : AttrId, - classes: AttrClasses, - items : Children, + id : AttrId, + classes : AttrClasses, + button_title : L10n, + button_size : ButtonSize, + button_color : ButtonColor, + button_split : bool, + button_grouped: bool, + auto_close : dropdown::AutoClose, + direction : dropdown::Direction, + menu_align : dropdown::MenuAlign, + menu_position : dropdown::MenuPosition, + items : Children, } impl Component for Dropdown { @@ -19,42 +140,134 @@ impl Component for Dropdown { self.id.get() } + #[rustfmt::skip] fn setup_before_prepare(&mut self, _cx: &mut Context) { - self.alter_classes(ClassesOp::Prepend, "dropdown"); + let g = self.button_grouped(); + self.alter_classes(ClassesOp::Prepend, [ + if g { "btn-group" } else { "" }, + match self.direction() { + Direction::Default if g => "", + Direction::Default => "dropdown", + Direction::Centered => "dropdown-center", + Direction::Dropup => "dropup", + Direction::DropupCentered => "dropup-center", + Direction::Dropend => "dropend", + Direction::Dropstart => "dropstart", + } + ].join(" ")); } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + // Si no hay elementos en el menú, no se prepara. let items = self.items().render(cx); if items.is_empty() { return PrepareMarkup::None; } + // Título opcional para el menú desplegable. + let button_title = self.button_title().using(cx); + PrepareMarkup::With(html! { div id=[self.id()] class=[self.classes().get()] { - button - type="button" - class="btn btn-secondary dropdown-toggle" - data-bs-toggle="dropdown" - aria-expanded="false" - { - ("Dropdown button") - } - ul class="dropdown-menu" { - li { - a class="dropdown-item" href="#" { - ("Action") + @if !button_title.is_empty() { + @let mut btn_classes = AttrClasses::new([ + "btn", + &self.button_size().to_string(), + &self.button_color().to_string(), + ].join(" ")); + @let (offset, reference) = match self.menu_position() { + MenuPosition::Default => (None, None), + MenuPosition::Offset(x, y) => (Some(format!("{x},{y}")), None), + MenuPosition::Parent => (None, Some("parent")), + }; + @let auto_close = match self.auto_close { + AutoClose::Default => None, + AutoClose::ClickableInside => Some("inside"), + AutoClose::ClickableOutside => Some("outside"), + AutoClose::ManualClose => Some("false"), + }; + @let menu_classes = AttrClasses::new("dropdown-menu") + .with_value(ClassesOp::Add, match self.menu_align() { + MenuAlign::Start => String::new(), + MenuAlign::StartAt(bp) => bp.try_class("dropdown-menu") + .map_or(String::new(), |class| join!(class, "-start")), + MenuAlign::StartAndEnd(bp) => bp.try_class("dropdown-menu") + .map_or( + "dropdown-menu-start".into(), + |class| join!("dropdown-menu-start ", class, "-end") + ), + MenuAlign::End => "dropdown-menu-end".into(), + MenuAlign::EndAt(bp) => bp.try_class("dropdown-menu") + .map_or(String::new(), |class| join!(class, "-end")), + MenuAlign::EndAndStart(bp) => bp.try_class("dropdown-menu") + .map_or( + "dropdown-menu-end".into(), + |class| join!("dropdown-menu-end ", class, "-start") + ), + }); + + // Renderizado en modo split (dos botones) o simple (un botón). + @if self.button_split() { + // Botón principal (acción/etiqueta). + @let btn = html! { + button + type="button" + class=[btn_classes.get()] + { + (button_title) + } + }; + // Botón *toggle* que abre/cierra el menú asociado. + @let btn_toggle = html! { + button + type="button" + class=[btn_classes.alter_value( + ClassesOp::Add, "dropdown-toggle dropdown-toggle-split" + ).get()] + data-bs-toggle="dropdown" + data-bs-offset=[offset] + data-bs-reference=[reference] + data-bs-auto-close=[auto_close] + aria-expanded="false" + { + span class="visually-hidden" { + (L10n::t("dropdown_toggle", &LOCALES_BOOTSIER).using(cx)) + } + } + }; + // Orden según dirección (en `dropstart` el *toggle* se sitúa antes). + @match self.direction() { + Direction::Dropstart => { + (btn_toggle) + ul class=[menu_classes.get()] { (items) } + (btn) + } + _ => { + (btn) + (btn_toggle) + ul class=[menu_classes.get()] { (items) } + } } - } - li { - a class="dropdown-item" href="#" { - ("Another action") - } - } - li { - a class="dropdown-item" href="#" { - ("Something else here") + } @else { + // Botón único con funcionalidad de *toggle*. + button + type="button" + class=[btn_classes.alter_value( + ClassesOp::Add, "dropdown-toggle" + ).get()] + data-bs-toggle="dropdown" + data-bs-offset=[offset] + data-bs-reference=[reference] + data-bs-auto-close=[auto_close] + aria-expanded="false" + { + (button_title) } + ul class=[menu_classes.get()] { (items) } } + } @else { + // Sin botón: sólo el listado como menú contextual. + ul class="dropdown-menu" { (items) } } } }) @@ -64,23 +277,91 @@ impl Component for Dropdown { impl Dropdown { // **< Dropdown BUILDER >*********************************************************************** + /// Establece el identificador único (`id`) del menú desplegable. #[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 menú desplegable. #[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 botón. + #[builder_fn] + pub fn with_button_title(mut self, title: L10n) -> Self { + self.button_title = title; + self + } + + /// Ajusta el tamaño del botón. + #[builder_fn] + pub fn with_button_size(mut self, size: ButtonSize) -> Self { + self.button_size = size; + self + } + + /// Define el color/estilo del botón. + #[builder_fn] + pub fn with_button_color(mut self, color: ButtonColor) -> Self { + self.button_color = color; + self + } + + /// Activa/desactiva el modo *split* (botón de acción + *toggle*). + #[builder_fn] + pub fn with_button_split(mut self, split: bool) -> Self { + self.button_split = split; + self + } + + /// Indica si el botón del menú está integrado en un grupo de botones. + #[builder_fn] + pub fn with_button_grouped(mut self, grouped: bool) -> Self { + self.button_grouped = grouped; + self + } + + /// Establece la política de cierre automático del menú desplegable. + #[builder_fn] + pub fn with_auto_close(mut self, auto_close: dropdown::AutoClose) -> Self { + self.auto_close = auto_close; + self + } + + /// Establece la dirección de despliegue del menú. + #[builder_fn] + pub fn with_direction(mut self, direction: dropdown::Direction) -> Self { + self.direction = direction; + self + } + + /// Configura la alineación horizontal (con posible comportamiento *responsive* adicional). + #[builder_fn] + pub fn with_menu_align(mut self, align: dropdown::MenuAlign) -> Self { + self.menu_align = align; + self + } + + /// Configura la posición del menú. + #[builder_fn] + pub fn with_menu_position(mut self, position: dropdown::MenuPosition) -> Self { + self.menu_position = position; + self + } + + /// Añade un nuevo elemento hijo al menú. + #[inline] pub fn add_item(mut self, item: dropdown::Item) -> Self { self.items.add(Child::with(item)); self } + /// Modifica la lista de elementos (`children`) aplicando una operación [`TypedOp`]. #[builder_fn] pub fn with_items(mut self, op: TypedOp<dropdown::Item>) -> Self { self.items.alter_typed(op); @@ -89,10 +370,57 @@ impl Dropdown { // **< Dropdown GETTERS >*********************************************************************** + /// Devuelve las clases CSS asociadas al menú desplegable. pub fn classes(&self) -> &AttrClasses { &self.classes } + /// Devuelve el título del botón. + pub fn button_title(&self) -> &L10n { + &self.button_title + } + + /// Devuelve el tamaño configurado del botón. + pub fn button_size(&self) -> &ButtonSize { + &self.button_size + } + + /// Devuelve el color/estilo configurado del botón. + pub fn button_color(&self) -> &ButtonColor { + &self.button_color + } + + /// Devuelve si se debe desdoblar (*split*) el botón (botón de acción + *toggle*). + pub fn button_split(&self) -> bool { + self.button_split + } + + /// Devuelve si el botón del menú está integrado en un grupo de botones. + pub fn button_grouped(&self) -> bool { + self.button_grouped + } + + /// Devuelve la política de cierre automático del menú desplegado. + pub fn auto_close(&self) -> &dropdown::AutoClose { + &self.auto_close + } + + /// Devuelve la dirección de despliegue configurada. + pub fn direction(&self) -> &dropdown::Direction { + &self.direction + } + + /// Devuelve la configuración de alineación horizontal del menú desplegable. + pub fn menu_align(&self) -> &dropdown::MenuAlign { + &self.menu_align + } + + /// Devuelve la posición configurada para el menú desplegable. + pub fn menu_position(&self) -> &dropdown::MenuPosition { + &self.menu_position + } + + /// Devuelve la lista de elementos (`children`) del menú. pub fn items(&self) -> &Children { &self.items } diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/item.rs b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs index 1edd64b1..548024c5 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/item.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs @@ -1,22 +1,53 @@ use pagetop::prelude::*; -// **< ItemType >*********************************************************************************** +// **< ItemKind >*********************************************************************************** +/// Tipos de [`dropdown::Item`](crate::theme::dropdown::Item) disponibles en un menú desplegable +/// [`Dropdown`](crate::theme::Dropdown). +/// +/// Define internamente la naturaleza del elemento y su comportamiento al mostrarse o interactuar +/// con él. #[derive(AutoDefault)] -pub enum ItemType { +pub enum ItemKind { + /// Elemento vacío, no produce salida. #[default] Void, + /// Etiqueta sin comportamiento interactivo. Label(L10n), - Link(L10n, FnPathByContext), - LinkBlank(L10n, FnPathByContext), + /// Elemento de navegación. Opcionalmente puede abrirse en una nueva ventana y estar + /// inicialmente deshabilitado. + Link { + label: L10n, + path: FnPathByContext, + blank: bool, + disabled: bool, + }, + /// Acción ejecutable en la propia página, sin navegación asociada. Inicialmente puede estar + /// deshabilitado. + Button { label: L10n, disabled: bool }, + /// Título o encabezado que separa grupos de opciones. + Header(L10n), + /// Separador visual entre bloques de elementos. + Divider, } // **< Item >*************************************************************************************** +/// Representa un **elemento individual** de un menú desplegable +/// [`Dropdown`](crate::theme::Dropdown). +/// +/// Cada instancia de [`dropdown::Item`](crate::theme::dropdown::Item) se traduce en un componente +/// visible que puede comportarse como texto, enlace, botón, encabezado o separador, según su +/// [`ItemKind`]. +/// +/// Permite definir identificador, clases de estilo adicionales o tipo de interacción asociada, +/// manteniendo una interfaz común para renderizar todos los ítems del menú. #[rustfmt::skip] #[derive(AutoDefault)] pub struct Item { - item_type: ItemType, + id : AttrId, + classes : AttrClasses, + item_kind: ItemKind, } impl Component for Item { @@ -24,86 +55,227 @@ impl Component for Item { Item::default() } + fn id(&self) -> Option<String> { + self.id.get() + } + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let description: Option<String> = None; + match self.item_kind() { + ItemKind::Void => PrepareMarkup::None, - // Obtiene la URL actual desde `cx.request`. - let current_path = cx.request().map(|request| request.path()); - - match self.item_type() { - ItemType::Void => PrepareMarkup::None, - ItemType::Label(label) => PrepareMarkup::With(html! { - li class="dropdown-item" { - span title=[description] { - //(left_icon) + ItemKind::Label(label) => PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { + span class="dropdown-item-text" { (label.using(cx)) - //(right_icon) } } }), - ItemType::Link(label, path) => { - let item_path = path(cx); - let (class, aria) = if current_path == Some(item_path) { - ("dropdown-item active", Some("page")) - } else { - ("dropdown-item", None) - }; + + ItemKind::Link { + label, + path, + blank, + disabled, + } => { + let path = path(cx); + let current_path = cx.request().map(|request| request.path()); + let is_current = !*disabled && current_path.map(|p| p == path).unwrap_or(false); + + let mut classes = "dropdown-item".to_string(); + if is_current { + classes.push_str(" active"); + } + if *disabled { + classes.push_str(" disabled"); + } + + let href = (!disabled).then_some(path); + let target = (!disabled && *blank).then_some("_blank"); + let rel = (!disabled && *blank).then_some("noopener noreferrer"); + + let aria_current = (href.is_some() && is_current).then_some("page"); + let aria_disabled = disabled.then_some("true"); + let tabindex = disabled.then_some("-1"); + PrepareMarkup::With(html! { - li class=(class) aria-current=[aria] { - a class="nav-link" href=(item_path) title=[description] { - //(left_icon) + li id=[self.id()] class=[self.classes().get()] { + a + class=(classes) + href=[href] + target=[target] + rel=[rel] + aria-current=[aria_current] + aria-disabled=[aria_disabled] + tabindex=[tabindex] + { (label.using(cx)) - //(right_icon) } } }) } - ItemType::LinkBlank(label, path) => { - let item_path = path(cx); - let (class, aria) = if current_path == Some(item_path) { - ("dropdown-item active", Some("page")) - } else { - ("dropdown-item", None) - }; + + ItemKind::Button { label, disabled } => { + let mut classes = "dropdown-item".to_owned(); + if *disabled { + classes.push_str(" disabled"); + } + + let aria_disabled = disabled.then_some("true"); + let disabled_attr = disabled.then_some("disabled"); + PrepareMarkup::With(html! { - li class=(class) aria-current=[aria] { - a class="nav-link" href=(item_path) title=[description] target="_blank" { - //(left_icon) + li id=[self.id()] class=[self.classes().get()] { + button + class=(classes) + type="button" + aria-disabled=[aria_disabled] + disabled=[disabled_attr] + { (label.using(cx)) - //(right_icon) } } }) } + + ItemKind::Header(label) => PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { + h6 class="dropdown-header" { + (label.using(cx)) + } + } + }), + + ItemKind::Divider => PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { hr class="dropdown-divider" {} } + }), } } } impl Item { + /// Crea un elemento de tipo texto, mostrado sin interacción. pub fn label(label: L10n) -> Self { Item { - item_type: ItemType::Label(label), + item_kind: ItemKind::Label(label), ..Default::default() } } + /// Crea un enlace para la navegación. pub fn link(label: L10n, path: FnPathByContext) -> Self { Item { - item_type: ItemType::Link(label, path), + item_kind: ItemKind::Link { + label, + path, + blank: false, + disabled: false, + }, ..Default::default() } } + /// Crea un enlace deshabilitado que no permite la interacción. + pub fn link_disabled(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: false, + disabled: true, + }, + ..Default::default() + } + } + + /// Crea un enlace que se abre en una nueva ventana o pestaña. pub fn link_blank(label: L10n, path: FnPathByContext) -> Self { Item { - item_type: ItemType::LinkBlank(label, path), + item_kind: ItemKind::Link { + label, + path, + blank: true, + disabled: false, + }, ..Default::default() } } - // Item GETTERS. + /// Crea un enlace deshabilitado que se abriría en una nueva ventana. + pub fn link_blank_disabled(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: true, + disabled: true, + }, + ..Default::default() + } + } - pub fn item_type(&self) -> &ItemType { - &self.item_type + /// Crea un botón de acción local, sin navegación asociada. + pub fn button(label: L10n) -> Self { + Item { + item_kind: ItemKind::Button { + label, + disabled: false, + }, + ..Default::default() + } + } + + /// Crea un botón deshabilitado. + pub fn button_disabled(label: L10n) -> Self { + Item { + item_kind: ItemKind::Button { + label, + disabled: true, + }, + ..Default::default() + } + } + + /// Crea un encabezado para un grupo de elementos dentro del menú. + pub fn header(label: L10n) -> Self { + Item { + item_kind: ItemKind::Header(label), + ..Default::default() + } + } + + /// Crea un separador visual entre bloques de elementos. + pub fn divider() -> Self { + Item { + item_kind: ItemKind::Divider, + ..Default::default() + } + } + + // **< Item BUILDER >*************************************************************************** + + /// Establece el identificador único (`id`) del elemento. + #[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 elemento. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + // **< Item GETTERS >*************************************************************************** + + /// Devuelve las clases CSS asociadas al elemento. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el tipo de elemento representado por este ítem. + pub fn item_kind(&self) -> &ItemKind { + &self.item_kind } } From c3a0255d441e02ba67a24952adb11499625bfa3e Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 25 Oct 2025 10:52:33 +0200 Subject: [PATCH 223/244] =?UTF-8?q?=F0=9F=9A=A7=20Cambia=20el=20uso=20de?= =?UTF-8?q?=20`BreakPoint`=20para=20`Container`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extensions/pagetop-bootsier/src/theme.rs | 2 +- .../src/theme/aux/breakpoint.rs | 43 +++---- .../pagetop-bootsier/src/theme/container.rs | 108 +++++++++++------- 3 files changed, 87 insertions(+), 66 deletions(-) diff --git a/extensions/pagetop-bootsier/src/theme.rs b/extensions/pagetop-bootsier/src/theme.rs index 51073d43..ec95165c 100644 --- a/extensions/pagetop-bootsier/src/theme.rs +++ b/extensions/pagetop-bootsier/src/theme.rs @@ -4,7 +4,7 @@ pub mod aux; // Container. mod container; -pub use container::{Container, ContainerType}; +pub use container::{Container, ContainerType, ContainerWidth}; // Dropdown. pub mod dropdown; diff --git a/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs b/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs index 963bb3b5..601aa547 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs @@ -7,10 +7,6 @@ use std::fmt; /// - `"sm"`, `"md"`, `"lg"`, `"xl"` o `"xxl"` para los puntos de ruptura `SM`, `MD`, `LG`, `XL` o /// `XXL`, respectivamente. /// - `""` (cadena vacía) para `None`. -/// - `"fluid"` para las variantes `Fluid` y `FluidMax(_)`, útil para modelar `container-fluid` en -/// [`Container`](crate::theme::Container). Se debe tener en cuenta que `"fluid"` **no** es un -/// sufijo de *breakpoint*. Para construir clases válidas con prefijo (p. ej., `"col-md"`), se -/// recomienda usar `to_class()` (Self::to_class) o `try_class()` (Self::try_class). /// /// # Ejemplos /// @@ -18,13 +14,14 @@ use std::fmt; /// # use pagetop_bootsier::prelude::*; /// assert_eq!(BreakPoint::MD.to_string(), "md"); /// assert_eq!(BreakPoint::None.to_string(), ""); -/// assert_eq!(BreakPoint::Fluid.to_string(), "fluid"); /// /// // Forma correcta para clases con prefijo: -/// //assert_eq!(BreakPoint::MD.to_class("col"), "col-md"); -/// //assert_eq!(BreakPoint::Fluid.to_class("offcanvas"), "offcanvas"); +/// assert_eq!(BreakPoint::MD.to_class("col"), "col-md"); +/// assert_eq!(BreakPoint::None.to_class("offcanvas"), "offcanvas"); +/// +/// assert_eq!(BreakPoint::XXL.try_class("col"), Some("col-xxl".to_string())); +/// assert_eq!(BreakPoint::None.try_class("offcanvas"), None); /// ``` -#[rustfmt::skip] #[derive(AutoDefault)] pub enum BreakPoint { /// **Menos de 576px**. Dispositivos muy pequeños: teléfonos en modo vertical. @@ -40,11 +37,6 @@ pub enum BreakPoint { XL, /// **1400px o más** - Dispositivos extragrandes: puestos de escritorio más grandes. XXL, - /// Para [`Container`](crate::theme::Container), ocupa el 100% del ancho del dispositivo. - Fluid, - /// Para [`Container`](crate::theme::Container), ocupa el 100% del ancho del dispositivo hasta - /// un ancho máximo indicado. - FluidMax(UnitValue) } impl BreakPoint { @@ -53,7 +45,7 @@ impl BreakPoint { /// Devuelve `true` si el valor es `SM`, `MD`, `LG`, `XL` o `XXL`; y `false` en otro caso. #[inline] pub const fn is_breakpoint(&self) -> bool { - matches!(self, Self::SM | Self::MD | Self::LG | Self::XL | Self::XXL) + !matches!(self, Self::None) } /// Genera un nombre de clase CSS basado en el punto de ruptura. @@ -65,11 +57,12 @@ impl BreakPoint { /// # Ejemplo /// /// ```rust + /// # use pagetop_bootsier::prelude::*; /// let breakpoint = BreakPoint::MD; /// let class = breakpoint.to_class("col"); /// assert_eq!(class, "col-md".to_string()); /// - /// let breakpoint = BreakPoint::Fluid; + /// let breakpoint = BreakPoint::None; /// let class = breakpoint.to_class("offcanvas"); /// assert_eq!(class, "offcanvas".to_string()); /// ``` @@ -91,12 +84,13 @@ impl BreakPoint { /// # Ejemplo /// /// ```rust + /// # use pagetop_bootsier::prelude::*; /// let breakpoint = BreakPoint::MD; /// let class = breakpoint.try_class("col"); /// assert_eq!(class, Some("col-md".to_string())); /// - /// let breakpoint = BreakPoint::Fluid; - /// let class = breakpoint.try_class("navbar-expanded"); + /// let breakpoint = BreakPoint::None; + /// let class = breakpoint.try_class("navbar-expand"); /// assert_eq!(class, None); /// ``` #[inline] @@ -113,15 +107,12 @@ impl BreakPoint { impl fmt::Display for BreakPoint { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::None => Ok(()), - Self::SM => f.write_str("sm"), - Self::MD => f.write_str("md"), - Self::LG => f.write_str("lg"), - Self::XL => f.write_str("xl"), - Self::XXL => f.write_str("xxl"), - // Devuelven "fluid" (para modelar `container-fluid`). - Self::Fluid => f.write_str("fluid"), - Self::FluidMax(_) => f.write_str("fluid"), + Self::None => Ok(()), + Self::SM => f.write_str("sm"), + Self::MD => f.write_str("md"), + Self::LG => f.write_str("lg"), + Self::XL => f.write_str("xl"), + Self::XXL => f.write_str("xxl"), } } } diff --git a/extensions/pagetop-bootsier/src/theme/container.rs b/extensions/pagetop-bootsier/src/theme/container.rs index 65ce9230..22f7fc6c 100644 --- a/extensions/pagetop-bootsier/src/theme/container.rs +++ b/extensions/pagetop-bootsier/src/theme/container.rs @@ -2,11 +2,12 @@ use pagetop::prelude::*; use crate::prelude::*; +// **< ContainerType >****************************************************************************** + /// Tipo de contenedor ([`Container`]). /// /// Permite aplicar la etiqueta HTML apropiada (`<main>`, `<header>`, etc.) manteniendo una API /// común a todos los contenedores. -#[rustfmt::skip] #[derive(AutoDefault)] pub enum ContainerType { /// Contenedor genérico (`<div>`). @@ -24,22 +25,42 @@ pub enum ContainerType { Article, } -/// Componente genérico para crear un contenedor de componentes. +// **< ContainerWidth >***************************************************************************** + +/// Define el comportamiento para ajustar el ancho de un contenedor ([`Container`]). +#[derive(AutoDefault)] +pub enum ContainerWidth { + /// Comportamiento por defecto, aplica los anchos máximos predefinidos para cada punto de + /// ruptura. Por debajo del menor punto de ruptura ocupa el 100% del ancho disponible. + #[default] + Default, + /// Aplica los anchos máximos predefinidos a partir del punto de ruptura indicado. Por debajo de + /// ese punto de ruptura ocupa el 100% del ancho disponible. + From(BreakPoint), + /// Ocupa el 100% del ancho disponible siempre. + Fluid, + /// Ocupa el 100% del ancho disponible hasta un ancho máximo explícito. + FluidMax(UnitValue), +} + +// **< Container >********************************************************************************** + +/// Componente para crear un **contenedor de componentes**. /// /// Envuelve el contenido con la etiqueta HTML indicada por [`ContainerType`]. Sólo se renderiza si /// existen componentes hijos (*children*). #[rustfmt::skip] #[derive(AutoDefault)] pub struct Container { - id : AttrId, - classes : AttrClasses, - container_type: ContainerType, - breakpoint : BreakPoint, - children : Children, - bg_color : BgColor, - text_color : TextColor, - border : Border, - rounded : Rounded, + id : AttrId, + classes : AttrClasses, + container_type : ContainerType, + container_width: ContainerWidth, + bg_color : BgColor, + text_color : TextColor, + border : Border, + rounded : Rounded, + children : Children, } impl Component for Container { @@ -55,7 +76,16 @@ impl Component for Container { self.alter_classes( ClassesOp::Prepend, [ - join_pair!("container", "-", self.breakpoint().to_string()), + join_pair!( + "container", + "-", + match self.width() { + ContainerWidth::Default => String::new(), + ContainerWidth::From(bp) => bp.to_string(), + ContainerWidth::Fluid => "fluid".to_string(), + ContainerWidth::FluidMax(_) => "fluid".to_string(), + } + ), self.bg_color().to_string(), self.text_color().to_string(), self.border().to_string(), @@ -70,8 +100,8 @@ impl Component for Container { if output.is_empty() { return PrepareMarkup::None; } - let style = match self.breakpoint() { - BreakPoint::FluidMax(w) if w.is_measurable() => { + let style = match self.width() { + ContainerWidth::FluidMax(w) if w.is_measurable() => { Some(join!("max-width: ", w.to_string(), ";")) } _ => None, @@ -168,24 +198,10 @@ impl Container { self } - /// Establece el *punto de ruptura* del contenedor. + /// Establece el comportamiento del ancho para el contenedor. #[builder_fn] - pub fn with_breakpoint(mut self, bp: BreakPoint) -> Self { - self.breakpoint = bp; - self - } - - /// Añade un nuevo componente hijo al contenedor. - pub fn add_child(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); + pub fn with_width(mut self, width: ContainerWidth) -> Self { + self.container_width = width; self } @@ -225,6 +241,20 @@ impl Container { self } + /// Añade un nuevo componente hijo al contenedor. + #[inline] + pub fn add_child(mut self, component: impl Component) -> Self { + self.children.add(Child::with(component)); + self + } + + /// Modifica la lista de componentes (`children`) aplicando una operación [`ChildOp`]. + #[builder_fn] + pub fn with_child(mut self, op: ChildOp) -> Self { + self.children.alter_child(op); + self + } + // **< Container GETTERS >********************************************************************** /// Devuelve las clases CSS asociadas al contenedor. @@ -237,14 +267,9 @@ impl Container { &self.container_type } - /// Devuelve el *punto de ruptura* actualmente configurado. - pub fn breakpoint(&self) -> &BreakPoint { - &self.breakpoint - } - - /// Devuelve la lista de hijos (`children`) del contenedor. - pub fn children(&self) -> &Children { - &self.children + /// Devuelve el comportamiento para el ancho del contenedor. + pub fn width(&self) -> &ContainerWidth { + &self.container_width } /// Devuelve el color de fondo del contenedor. @@ -266,4 +291,9 @@ impl Container { pub fn rounded(&self) -> &Rounded { &self.rounded } + + /// Devuelve la lista de componentes (`children`) del contenedor. + pub fn children(&self) -> &Children { + &self.children + } } From c58b011943d9146dfb69068ff4c88afeb22328f1 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 25 Oct 2025 10:55:34 +0200 Subject: [PATCH 224/244] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactoriza=20`Dro?= =?UTF-8?q?pdown`=20para=20separar=20propiedades?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pagetop-bootsier/src/theme/dropdown.rs | 4 +- .../src/theme/dropdown/component.rs | 127 +++--------------- .../src/theme/dropdown/props.rs | 86 ++++++++++++ 3 files changed, 110 insertions(+), 107 deletions(-) create mode 100644 extensions/pagetop-bootsier/src/theme/dropdown/props.rs diff --git a/extensions/pagetop-bootsier/src/theme/dropdown.rs b/extensions/pagetop-bootsier/src/theme/dropdown.rs index 9e81c7a3..02df7fd0 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown.rs @@ -10,9 +10,11 @@ //! Su propósito es ofrecer una base uniforme sobre la que construir menús consistentes, adaptados //! al contexto de cada aplicación. +mod props; +pub use props::{AutoClose, Direction, MenuAlign, MenuPosition}; + mod component; pub use component::Dropdown; -pub use component::{AutoClose, Direction, MenuAlign, MenuPosition}; mod item; pub use item::{Item, ItemKind}; diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs index 9aef2562..e9d36d7f 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs @@ -3,91 +3,6 @@ use pagetop::prelude::*; use crate::prelude::*; use crate::LOCALES_BOOTSIER; -// **< AutoClose >********************************************************************************** - -/// Estrategia para el cierre automático de un menú [`Dropdown`]. -/// -/// Define cuándo se cierra el menú desplegado según la interacción del usuario. -#[derive(AutoDefault)] -pub enum AutoClose { - /// Comportamiento por defecto, se cierra con clics dentro y fuera del menú, o pulsando `Esc`. - #[default] - Default, - /// Sólo se cierra con clics dentro del menú. - ClickableInside, - /// Sólo se cierra con clics fuera del menú. - ClickableOutside, - /// Cierre manual, no se cierra con clics; sólo al pulsar nuevamente el botón del menú - /// (*toggle*), o pulsando `Esc`. - ManualClose, -} - -// **< Direction >********************************************************************************** - -/// Dirección de despliegue de un menú [`Dropdown`]. -/// -/// Controla desde qué posición se muestra el menú respecto al botón. -#[derive(AutoDefault)] -pub enum Direction { - /// Comportamiento por defecto (despliega el menú hacia abajo desde la posición inicial, - /// respetando LTR/RTL). - #[default] - Default, - /// Centra horizontalmente el menú respecto al botón. - Centered, - /// Despliega el menú hacia arriba. - Dropup, - /// Despliega el menú hacia arriba y centrado. - DropupCentered, - /// Despliega el menú desde el lateral final, respetando LTR/RTL. - Dropend, - /// Despliega el menú desde el lateral inicial, respetando LTR/RTL. - Dropstart, -} - -// **< MenuAlign >********************************************************************************** - -/// Alineación horizontal del menú desplegable [`Dropdown`]. -/// -/// Permite alinear el menú al inicio o al final del botón (respetando LTR/RTL) y añadirle una -/// alineación diferente a partir de un punto de ruptura ([`BreakPoint`]). -#[derive(AutoDefault)] -pub enum MenuAlign { - /// Alineación al inicio (comportamiento por defecto). - #[default] - Start, - /// Alineación al inicio a partir del punto de ruptura indicado. - StartAt(BreakPoint), - /// Alineación al inicio por defecto, y al final a partir de un punto de ruptura válido. - StartAndEnd(BreakPoint), - /// Alineación al final. - End, - /// Alineación al final a partir del punto de ruptura indicado. - EndAt(BreakPoint), - /// Alineación al final por defecto, y al inicio a partir de un punto de ruptura válido. - EndAndStart(BreakPoint), -} - -// **< MenuPosition >******************************************************************************* - -/// Posición relativa del menú desplegable [`Dropdown`]. -/// -/// Permite indicar un desplazamiento (*offset*) manual o referenciar al elemento padre para el -/// cálculo de la posición. -#[derive(AutoDefault)] -pub enum MenuPosition { - /// Posicionamiento automático por defecto. - #[default] - Default, - /// Desplazamiento manual en píxeles `(x, y)` aplicado al menú. Se admiten valores negativos. - Offset(i8, i8), - /// Posiciona el menú tomando como referencia el botón padre. Especialmente útil cuando - /// [`button_split()`](crate::theme::Dropdown::button_split) es `true`. - Parent, -} - -// **< Dropdown >********************************************************************************** - /// Componente para crear un **menú desplegable**. /// /// Renderiza un botón (único o desdoblado, ver [`with_button_split()`](Self::with_button_split)) @@ -146,13 +61,13 @@ impl Component for Dropdown { self.alter_classes(ClassesOp::Prepend, [ if g { "btn-group" } else { "" }, match self.direction() { - Direction::Default if g => "", - Direction::Default => "dropdown", - Direction::Centered => "dropdown-center", - Direction::Dropup => "dropup", - Direction::DropupCentered => "dropup-center", - Direction::Dropend => "dropend", - Direction::Dropstart => "dropstart", + dropdown::Direction::Default if g => "", + dropdown::Direction::Default => "dropdown", + dropdown::Direction::Centered => "dropdown-center", + dropdown::Direction::Dropup => "dropup", + dropdown::Direction::DropupCentered => "dropup-center", + dropdown::Direction::Dropend => "dropend", + dropdown::Direction::Dropstart => "dropstart", } ].join(" ")); } @@ -176,30 +91,30 @@ impl Component for Dropdown { &self.button_color().to_string(), ].join(" ")); @let (offset, reference) = match self.menu_position() { - MenuPosition::Default => (None, None), - MenuPosition::Offset(x, y) => (Some(format!("{x},{y}")), None), - MenuPosition::Parent => (None, Some("parent")), + dropdown::MenuPosition::Default => (None, None), + dropdown::MenuPosition::Offset(x, y) => (Some(format!("{x},{y}")), None), + dropdown::MenuPosition::Parent => (None, Some("parent")), }; @let auto_close = match self.auto_close { - AutoClose::Default => None, - AutoClose::ClickableInside => Some("inside"), - AutoClose::ClickableOutside => Some("outside"), - AutoClose::ManualClose => Some("false"), + dropdown::AutoClose::Default => None, + dropdown::AutoClose::ClickableInside => Some("inside"), + dropdown::AutoClose::ClickableOutside => Some("outside"), + dropdown::AutoClose::ManualClose => Some("false"), }; @let menu_classes = AttrClasses::new("dropdown-menu") .with_value(ClassesOp::Add, match self.menu_align() { - MenuAlign::Start => String::new(), - MenuAlign::StartAt(bp) => bp.try_class("dropdown-menu") + dropdown::MenuAlign::Start => String::new(), + dropdown::MenuAlign::StartAt(bp) => bp.try_class("dropdown-menu") .map_or(String::new(), |class| join!(class, "-start")), - MenuAlign::StartAndEnd(bp) => bp.try_class("dropdown-menu") + dropdown::MenuAlign::StartAndEnd(bp) => bp.try_class("dropdown-menu") .map_or( "dropdown-menu-start".into(), |class| join!("dropdown-menu-start ", class, "-end") ), - MenuAlign::End => "dropdown-menu-end".into(), - MenuAlign::EndAt(bp) => bp.try_class("dropdown-menu") + dropdown::MenuAlign::End => "dropdown-menu-end".into(), + dropdown::MenuAlign::EndAt(bp) => bp.try_class("dropdown-menu") .map_or(String::new(), |class| join!(class, "-end")), - MenuAlign::EndAndStart(bp) => bp.try_class("dropdown-menu") + dropdown::MenuAlign::EndAndStart(bp) => bp.try_class("dropdown-menu") .map_or( "dropdown-menu-end".into(), |class| join!("dropdown-menu-end ", class, "-start") @@ -237,7 +152,7 @@ impl Component for Dropdown { }; // Orden según dirección (en `dropstart` el *toggle* se sitúa antes). @match self.direction() { - Direction::Dropstart => { + dropdown::Direction::Dropstart => { (btn_toggle) ul class=[menu_classes.get()] { (items) } (btn) diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/props.rs b/extensions/pagetop-bootsier/src/theme/dropdown/props.rs new file mode 100644 index 00000000..da305ea7 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/dropdown/props.rs @@ -0,0 +1,86 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +// **< AutoClose >********************************************************************************** + +/// Estrategia para el cierre automático de un menú [`Dropdown`]. +/// +/// Define cuándo se cierra el menú desplegado según la interacción del usuario. +#[derive(AutoDefault)] +pub enum AutoClose { + /// Comportamiento por defecto, se cierra con clics dentro y fuera del menú, o pulsando `Esc`. + #[default] + Default, + /// Sólo se cierra con clics dentro del menú. + ClickableInside, + /// Sólo se cierra con clics fuera del menú. + ClickableOutside, + /// Cierre manual, no se cierra con clics; sólo al pulsar nuevamente el botón del menú + /// (*toggle*), o pulsando `Esc`. + ManualClose, +} + +// **< Direction >********************************************************************************** + +/// Dirección de despliegue de un menú [`Dropdown`]. +/// +/// Controla desde qué posición se muestra el menú respecto al botón. +#[derive(AutoDefault)] +pub enum Direction { + /// Comportamiento por defecto (despliega el menú hacia abajo desde la posición inicial, + /// respetando LTR/RTL). + #[default] + Default, + /// Centra horizontalmente el menú respecto al botón. + Centered, + /// Despliega el menú hacia arriba. + Dropup, + /// Despliega el menú hacia arriba y centrado. + DropupCentered, + /// Despliega el menú desde el lateral final, respetando LTR/RTL. + Dropend, + /// Despliega el menú desde el lateral inicial, respetando LTR/RTL. + Dropstart, +} + +// **< MenuAlign >********************************************************************************** + +/// Alineación horizontal del menú desplegable [`Dropdown`]. +/// +/// Permite alinear el menú al inicio o al final del botón (respetando LTR/RTL) y añadirle una +/// alineación diferente a partir de un punto de ruptura ([`BreakPoint`]). +#[derive(AutoDefault)] +pub enum MenuAlign { + /// Alineación al inicio (comportamiento por defecto). + #[default] + Start, + /// Alineación al inicio a partir del punto de ruptura indicado. + StartAt(BreakPoint), + /// Alineación al inicio por defecto, y al final a partir de un punto de ruptura válido. + StartAndEnd(BreakPoint), + /// Alineación al final. + End, + /// Alineación al final a partir del punto de ruptura indicado. + EndAt(BreakPoint), + /// Alineación al final por defecto, y al inicio a partir de un punto de ruptura válido. + EndAndStart(BreakPoint), +} + +// **< MenuPosition >******************************************************************************* + +/// Posición relativa del menú desplegable [`Dropdown`]. +/// +/// Permite indicar un desplazamiento (*offset*) manual o referenciar al elemento padre para el +/// cálculo de la posición. +#[derive(AutoDefault)] +pub enum MenuPosition { + /// Posicionamiento automático por defecto. + #[default] + Default, + /// Desplazamiento manual en píxeles `(x, y)` aplicado al menú. Se admiten valores negativos. + Offset(i8, i8), + /// Posiciona el menú tomando como referencia el botón padre. Especialmente útil cuando + /// [`button_split()`](crate::theme::Dropdown::button_split) es `true`. + Parent, +} From 1bf7ada6076e8220ab4318c8f177b5b5b296a631 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 25 Oct 2025 19:02:47 +0200 Subject: [PATCH 225/244] =?UTF-8?q?=E2=9C=A8=20(bootsier):=20A=C3=B1ade=20?= =?UTF-8?q?paneles=20deslizables=20`Offcanvas`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/locale/en-US/components.ftl | 2 +- .../src/locale/es-ES/components.ftl | 2 +- extensions/pagetop-bootsier/src/theme.rs | 7 +- .../pagetop-bootsier/src/theme/offcanvas.rs | 305 +----------------- .../src/theme/offcanvas/component.rs | 261 +++++++++++++++ .../src/theme/offcanvas/props.rs | 60 ++++ 6 files changed, 331 insertions(+), 306 deletions(-) create mode 100644 extensions/pagetop-bootsier/src/theme/offcanvas/component.rs create mode 100644 extensions/pagetop-bootsier/src/theme/offcanvas/props.rs diff --git a/extensions/pagetop-bootsier/src/locale/en-US/components.ftl b/extensions/pagetop-bootsier/src/locale/en-US/components.ftl index 0bb7fba6..e3b0d6e6 100644 --- a/extensions/pagetop-bootsier/src/locale/en-US/components.ftl +++ b/extensions/pagetop-bootsier/src/locale/en-US/components.ftl @@ -2,7 +2,7 @@ dropdown_toggle = Toggle Dropdown # Offcanvas -close = Close +offcanvas_close = Close # Navbar toggle = Toggle navigation diff --git a/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl b/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl index 045191e3..ab7ff687 100644 --- a/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl +++ b/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl @@ -2,7 +2,7 @@ dropdown_toggle = Mostrar/ocultar menú # Offcanvas -close = Cerrar +offcanvas_close = Cerrar # Navbar toggle = Mostrar/ocultar navegación diff --git a/extensions/pagetop-bootsier/src/theme.rs b/extensions/pagetop-bootsier/src/theme.rs index ec95165c..b5be6b71 100644 --- a/extensions/pagetop-bootsier/src/theme.rs +++ b/extensions/pagetop-bootsier/src/theme.rs @@ -21,7 +21,6 @@ pub mod navbar; pub use navbar::{Navbar, NavbarToggler}; // Offcanvas. -mod offcanvas; -pub use offcanvas::{ - Offcanvas, OffcanvasBackdrop, OffcanvasBodyScroll, OffcanvasPlacement, OffcanvasVisibility, -}; +pub mod offcanvas; +#[doc(inline)] +pub use offcanvas::Offcanvas; diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas.rs b/extensions/pagetop-bootsier/src/theme/offcanvas.rs index b790522b..560bd30a 100644 --- a/extensions/pagetop-bootsier/src/theme/offcanvas.rs +++ b/extensions/pagetop-bootsier/src/theme/offcanvas.rs @@ -1,302 +1,7 @@ -use pagetop::prelude::*; +//! Definiciones para crear paneles laterales deslizantes [`Offcanvas`]. -use crate::prelude::*; -use crate::LOCALES_BOOTSIER; +mod props; +pub use props::{Backdrop, BodyScroll, Placement, Visibility}; -use std::fmt; - -// **< OffcanvasPlacement >************************************************************************* - -/// Posición de aparición del panel **deslizante** ([`Offcanvas`]). -/// -/// Define desde qué borde de la ventana entra y se ancla el panel. -#[derive(AutoDefault)] -pub enum OffcanvasPlacement { - /// Opción por defecto, desde el borde inicial según dirección de lectura (respetando LTR/RTL). - #[default] - Start, - /// Desde el borde final según dirección de lectura (respetando LTR/RTL). - End, - /// Desde la parte superior. - Top, - /// Desde la parte inferior. - Bottom, -} - -#[rustfmt::skip] -impl fmt::Display for OffcanvasPlacement { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - OffcanvasPlacement::Start => f.write_str("offcanvas-start"), - OffcanvasPlacement::End => f.write_str("offcanvas-end"), - OffcanvasPlacement::Top => f.write_str("offcanvas-top"), - OffcanvasPlacement::Bottom => f.write_str("offcanvas-bottom"), - } - } -} - -// **< OffcanvasVisibility >************************************************************************ - -/// Estado inicial del panel ([`Offcanvas`]). -#[derive(AutoDefault)] -pub enum OffcanvasVisibility { - /// El panel **permanece oculto** desde el principio. - #[default] - Default, - /// El panel **se muestra abierto** al cargar. - Show, -} - -impl fmt::Display for OffcanvasVisibility { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - OffcanvasVisibility::Default => Ok(()), - OffcanvasVisibility::Show => f.write_str("show"), - } - } -} - -// **< OffcanvasBodyScroll >************************************************************************ - -/// Controla si la página principal puede **desplazarse** al abrir el panel ([`Offcanvas`]). -#[derive(AutoDefault)] -pub enum OffcanvasBodyScroll { - /// Opción por defecto, la página principal se **bloquea** centrando la interacción en el panel. - #[default] - Disabled, - /// **Permite** el desplazamiento de la página principal. - Enabled, -} - -// **< OffcanvasBackdrop >************************************************************************** - -/// Comportamiento de la **capa de fondo** (*backdrop*) del panel ([`Offcanvas`]) al desplegarse. -#[derive(AutoDefault)] -pub enum OffcanvasBackdrop { - /// **Sin capa** de fondo; la página principal permanece visible e interactiva. - Disabled, - /// Opción por defecto, se **oscurece** el fondo; un clic fuera del panel suele cerrarlo. - #[default] - Enabled, - /// Se muestra capa de fondo pero **no** se cierra al pulsar fuera (útil cuando se requiere - /// completar una acción antes de salir). - Static, -} - -// **< Offcanvas >********************************************************************************** - -/// Panel lateral **deslizante** para contenido complementario. -/// -/// Útil para navegación, filtros, formularios o menús contextuales. Incluye las siguientes -/// características principales: -/// -/// - **Entrada configurable desde un borde** de la ventana. -/// - **Encabezado con título** y **botón de cierre** integrado. -/// - **Accesibilidad**: asocia título y controles a un identificador único y expone atributos -/// adecuados para lectores de pantalla y navegación por teclado. -/// - **Opcionalmente** bloquea el desplazamiento del documento y/o muestra una capa de fondo para -/// centrar la atención del usuario. -/// - **Responsive**: puede cambiar su comportamiento según el punto de ruptura indicado. -/// - **No se renderiza** si no tiene contenido. -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Offcanvas { - id : AttrId, - classes : AttrClasses, - title : L10n, - breakpoint: BreakPoint, - placement : OffcanvasPlacement, - visibility: OffcanvasVisibility, - scrolling : OffcanvasBodyScroll, - backdrop : OffcanvasBackdrop, - children : Children, -} - -impl Component for Offcanvas { - fn new() -> Self { - Offcanvas::default() - } - - fn id(&self) -> Option<String> { - self.id.get() - } - - fn setup_before_prepare(&mut self, _cx: &mut Context) { - self.alter_classes( - ClassesOp::Prepend, - [ - self.breakpoint().to_class("offcanvas"), - self.placement().to_string(), - self.visibility().to_string(), - ] - .join(" "), - ); - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let body = self.children().render(cx); - if body.is_empty() { - return PrepareMarkup::None; - } - - let id = cx.required_id::<Self>(self.id()); - let id_label = join!(id, "-label"); - let id_target = join!("#", id); - - let body_scroll = match self.body_scroll() { - OffcanvasBodyScroll::Disabled => None, - OffcanvasBodyScroll::Enabled => Some("true"), - }; - - let backdrop = match self.backdrop() { - OffcanvasBackdrop::Disabled => Some("false"), - OffcanvasBackdrop::Enabled => None, - OffcanvasBackdrop::Static => Some("static"), - }; - - let title = self.title().using(cx); - - PrepareMarkup::With(html! { - div - id=(id) - class=[self.classes().get()] - tabindex="-1" - data-bs-scroll=[body_scroll] - data-bs-backdrop=[backdrop] - aria-labelledby=(id_label) - { - div class="offcanvas-header" { - @if !title.is_empty() { - h5 class="offcanvas-title" id=(id_label) { (title) } - } - button - type="button" - class="btn-close" - data-bs-dismiss="offcanvas" - data-bs-target=(id_target) - aria-label=[L10n::t("close", &LOCALES_BOOTSIER).lookup(cx)] - {} - } - div class="offcanvas-body" { - (body) - } - } - }) - } -} - -impl Offcanvas { - // **< Offcanvas BUILDER >********************************************************************** - - /// Establece el identificador único (`id`) del panel. - #[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 panel. - #[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 encabezado. - #[builder_fn] - pub fn with_title(mut self, title: L10n) -> Self { - self.title = title; - self - } - - /// Configura el **punto de ruptura** para activar el comportamiento responsive del panel. - #[builder_fn] - pub fn with_breakpoint(mut self, bp: BreakPoint) -> Self { - self.breakpoint = bp; - self - } - - /// Indica la **posición** desde la que entra el panel. - #[builder_fn] - pub fn with_placement(mut self, placement: OffcanvasPlacement) -> Self { - self.placement = placement; - self - } - - /// Fija el **estado inicial** del panel (oculto o visible al cargar). - #[builder_fn] - pub fn with_visibility(mut self, visibility: OffcanvasVisibility) -> Self { - self.visibility = visibility; - self - } - - /// Permite o bloquea el **desplazamiento** de la página principal mientras el panel está - /// abierto. - #[builder_fn] - pub fn with_body_scroll(mut self, scrolling: OffcanvasBodyScroll) -> Self { - self.scrolling = scrolling; - self - } - - /// Ajusta la **capa de fondo** del panel para definir su comportamiento al interactuar fuera. - #[builder_fn] - pub fn with_backdrop(mut self, backdrop: OffcanvasBackdrop) -> Self { - self.backdrop = backdrop; - self - } - - /// Añade un nuevo componente hijo al panel. - pub fn add_child(mut self, child: impl Component) -> Self { - self.children.add(Child::with(child)); - self - } - - /// Modifica la lista de hijos (`children`) aplicando una operación [`ChildOp`]. - #[builder_fn] - pub fn with_children(mut self, op: ChildOp) -> Self { - self.children.alter_child(op); - self - } - - // **< Offcanvas GETTERS >********************************************************************** - - /// Devuelve las clases CSS asociadas al panel. - pub fn classes(&self) -> &AttrClasses { - &self.classes - } - - /// Devuelve el título del panel como [`L10n`]. - pub fn title(&self) -> &L10n { - &self.title - } - - /// Devuelve el punto de ruptura configurado. - pub fn breakpoint(&self) -> &BreakPoint { - &self.breakpoint - } - - /// Devuelve la posición del panel. - pub fn placement(&self) -> &OffcanvasPlacement { - &self.placement - } - - /// Devuelve el estado inicial del panel. - pub fn visibility(&self) -> &OffcanvasVisibility { - &self.visibility - } - - /// Indica si la página principal puede desplazarse mientras el panel está abierto. - pub fn body_scroll(&self) -> &OffcanvasBodyScroll { - &self.scrolling - } - - /// Devuelve la configuración de la capa de fondo. - pub fn backdrop(&self) -> &OffcanvasBackdrop { - &self.backdrop - } - - /// Devuelve la lista de hijos (`children`) del panel. - pub fn children(&self) -> &Children { - &self.children - } -} +mod component; +pub use component::Offcanvas; diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs b/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs new file mode 100644 index 00000000..7cd7dffe --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs @@ -0,0 +1,261 @@ +use pagetop::prelude::*; + +use crate::prelude::*; +use crate::LOCALES_BOOTSIER; + +/// Componente para crear un **panel lateral deslizante** con contenidos adicionales. +/// +/// Útil para navegación, filtros, formularios o menús contextuales. Incluye las siguientes +/// características principales: +/// +/// - Puede mostrar una capa de fondo para centrar la atención del usuario en el panel +/// ([`with_backdrop()`](Self::with_backdrop)); o puede bloquear el desplazamiento del documento +/// principal ([`with_body_scroll()`](Self::with_body_scroll)). +/// - Se puede configurar el borde de la ventana desde el que se desliza el panel +/// ([`with_placement()`](Self::with_placement)). +/// - Encabezado con título ([`with_title()`](Self::with_title)) y **botón de cierre** integrado. +/// - Puede cambiar su comportamiento a partir de un punto de ruptura +/// ([`with_breakpoint()`](Self::with_breakpoint)). +/// - Asocia título y controles de accesibilidad a un identificador único y expone atributos +/// adecuados para lectores de pantalla y navegación por teclado. +/// - **No se renderiza** si no tiene contenido. +/// +/// # Ejemplo +/// +/// ```rust +/// # use pagetop::prelude::*; +/// # use pagetop_bootsier::prelude::*; +/// let panel = Offcanvas::new() +/// .with_id("offcanvas_example") +/// .with_title(L10n::n("Offcanvas title")) +/// .with_placement(offcanvas::Placement::End) +/// .with_backdrop(offcanvas::Backdrop::Enabled) +/// .with_body_scroll(offcanvas::BodyScroll::Enabled) +/// .with_visibility(offcanvas::Visibility::Default) +/// .add_child(Dropdown::new() +/// .with_button_title(L10n::n("Menu")) +/// .add_item(dropdown::Item::label(L10n::n("Label"))) +/// .add_item(dropdown::Item::link_blank(L10n::n("Google"), |_| "https://www.google.es")) +/// .add_item(dropdown::Item::link(L10n::n("Sign out"), |_| "/signout")) +/// ); +/// ``` +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Offcanvas { + id : AttrId, + classes : AttrClasses, + title : L10n, + breakpoint: BreakPoint, + backdrop : offcanvas::Backdrop, + scrolling : offcanvas::BodyScroll, + placement : offcanvas::Placement, + visibility: offcanvas::Visibility, + children : Children, +} + +impl Component for Offcanvas { + fn new() -> Self { + Offcanvas::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + #[rustfmt::skip] + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes( + ClassesOp::Prepend, + [ + self.breakpoint().to_class("offcanvas"), + match self.placement() { + offcanvas::Placement::Start => "offcanvas-start", + offcanvas::Placement::End => "offcanvas-end", + offcanvas::Placement::Top => "offcanvas-top", + offcanvas::Placement::Bottom => "offcanvas-bottom", + }.to_string(), + match self.visibility() { + offcanvas::Visibility::Default => "", + offcanvas::Visibility::Show => "show", + }.to_string(), + ] + .join(" "), + ); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let body = self.children().render(cx); + if body.is_empty() { + return PrepareMarkup::None; + } + + let id = cx.required_id::<Self>(self.id()); + let id_label = join!(id, "-label"); + let id_target = join!("#", id); + + let body_scroll = match self.body_scroll() { + offcanvas::BodyScroll::Disabled => None, + offcanvas::BodyScroll::Enabled => Some("true"), + }; + + let backdrop = match self.backdrop() { + offcanvas::Backdrop::Disabled => Some("false"), + offcanvas::Backdrop::Enabled => None, + offcanvas::Backdrop::Static => Some("static"), + }; + + let title = self.title().using(cx); + + PrepareMarkup::With(html! { + div + id=(id) + class=[self.classes().get()] + tabindex="-1" + data-bs-scroll=[body_scroll] + data-bs-backdrop=[backdrop] + aria-labelledby=(id_label) + { + div class="offcanvas-header" { + @if !title.is_empty() { + h5 class="offcanvas-title" id=(id_label) { (title) } + } + button + type="button" + class="btn-close" + data-bs-dismiss="offcanvas" + data-bs-target=(id_target) + aria-label=[L10n::t("offcanvas_close", &LOCALES_BOOTSIER).lookup(cx)] + {} + } + div class="offcanvas-body" { + (body) + } + } + }) + } +} + +impl Offcanvas { + // **< Offcanvas BUILDER >********************************************************************** + + /// Establece el identificador único (`id`) del panel. + #[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 panel. + #[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 encabezado. + #[builder_fn] + pub fn with_title(mut self, title: L10n) -> Self { + self.title = title; + self + } + + /// Establece el punto de ruptura a partir del cual cambia el comportamiento del panel. + /// + /// - **Por debajo** de ese tamaño de pantalla, el componente actúa como panel deslizante + /// ([`Offcanvas`]). + /// - **Por encima**, el contenido del panel se muestra tal cual, integrado en la página. + /// + /// Por ejemplo, con `BreakPoint::LG`, será *offcanvas* en móviles y tabletas, y visible + /// directamente en pantallas grandes. Por defecto usa `BreakPoint::None` para que sea + /// *offcanvas* siempre. + #[builder_fn] + pub fn with_breakpoint(mut self, bp: BreakPoint) -> Self { + self.breakpoint = bp; + self + } + + /// Ajusta la capa de fondo del panel para definir su comportamiento al hacer clic fuera del + /// panel. + #[builder_fn] + pub fn with_backdrop(mut self, backdrop: offcanvas::Backdrop) -> Self { + self.backdrop = backdrop; + self + } + + /// Permite o bloquea el desplazamiento de la página principal mientras el panel está abierto. + #[builder_fn] + pub fn with_body_scroll(mut self, scrolling: offcanvas::BodyScroll) -> Self { + self.scrolling = scrolling; + self + } + + /// Indica desde qué borde de la ventana entra y se ancla el panel. + #[builder_fn] + pub fn with_placement(mut self, placement: offcanvas::Placement) -> Self { + self.placement = placement; + self + } + + /// Fija el estado inicial del panel (oculto o visible al cargar). + #[builder_fn] + pub fn with_visibility(mut self, visibility: offcanvas::Visibility) -> Self { + self.visibility = visibility; + self + } + + /// Añade un nuevo componente hijo al panel. + #[inline] + pub fn add_child(mut self, child: impl Component) -> Self { + self.children.add(Child::with(child)); + self + } + + /// Modifica la lista de componentes (`children`) aplicando una operación [`ChildOp`]. + #[builder_fn] + pub fn with_children(mut self, op: ChildOp) -> Self { + self.children.alter_child(op); + self + } + + // **< Offcanvas GETTERS >********************************************************************** + + /// Devuelve las clases CSS asociadas al panel. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el título del panel. + pub fn title(&self) -> &L10n { + &self.title + } + + /// Devuelve el punto de ruptura configurado para cambiar el comportamiento del panel. + pub fn breakpoint(&self) -> &BreakPoint { + &self.breakpoint + } + + /// Devuelve el comportamiento configurado para la capa de fondo. + pub fn backdrop(&self) -> &offcanvas::Backdrop { + &self.backdrop + } + + /// Indica si la página principal puede desplazarse mientras el panel está abierto. + pub fn body_scroll(&self) -> &offcanvas::BodyScroll { + &self.scrolling + } + + /// Devuelve la posición de inicio del panel. + pub fn placement(&self) -> &offcanvas::Placement { + &self.placement + } + + /// Devuelve el estado inicial del panel. + pub fn visibility(&self) -> &offcanvas::Visibility { + &self.visibility + } + + /// Devuelve la lista de componentes (`children`) del panel. + pub fn children(&self) -> &Children { + &self.children + } +} diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas/props.rs b/extensions/pagetop-bootsier/src/theme/offcanvas/props.rs new file mode 100644 index 00000000..cbacbd74 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/offcanvas/props.rs @@ -0,0 +1,60 @@ +use pagetop::prelude::*; + +// **< Backdrop >*********************************************************************************** + +/// Comportamiento de la capa de fondo (*backdrop*) de un panel +/// [`Offcanvas`](crate::theme::Offcanvas) al deslizarse. +#[derive(AutoDefault)] +pub enum Backdrop { + /// Sin capa de fondo, la página principal permanece visible e interactiva. + Disabled, + /// Opción por defecto, se oscurece el fondo; un clic fuera del panel suele cerrarlo. + #[default] + Enabled, + /// Muestra la capa de fondo pero no se cierra al hacer clic fuera del panel. Útil si se + /// requiere completar una acción antes de salir. + Static, +} + +// **< BodyScroll >********************************************************************************* + +/// Controla si la página principal puede desplazarse al abrir un panel +/// [`Offcanvas`](crate::theme::Offcanvas). +#[derive(AutoDefault)] +pub enum BodyScroll { + /// Opción por defecto, la página principal se bloquea centrando la interacción en el panel. + #[default] + Disabled, + /// Permite el desplazamiento de la página principal. + Enabled, +} + +// **< Placement >********************************************************************************** + +/// Posición de aparición de un panel [`Offcanvas`](crate::theme::Offcanvas) al deslizarse. +/// +/// Define desde qué borde de la ventana entra y se ancla el panel. +#[derive(AutoDefault)] +pub enum Placement { + /// Opción por defecto, desde el borde inicial según dirección de lectura (respetando LTR/RTL). + #[default] + Start, + /// Desde el borde final según dirección de lectura (respetando LTR/RTL). + End, + /// Desde la parte superior. + Top, + /// Desde la parte inferior. + Bottom, +} + +// **< Visibility >********************************************************************************* + +/// Estado inicial de un panel [`Offcanvas`](crate::theme::Offcanvas). +#[derive(AutoDefault)] +pub enum Visibility { + /// El panel permanece oculto desde el principio. + #[default] + Default, + /// El panel se muestra abierto al cargar. + Show, +} From 5ac26c0b0609cb7e953e74161b9331ebda650275 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 25 Oct 2025 19:04:35 +0200 Subject: [PATCH 226/244] =?UTF-8?q?=F0=9F=A9=B9=20Correcciones=20menores?= =?UTF-8?q?=20en=20comentarios=20y=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-macros/src/lib.rs | 7 +++---- src/base/component/block.rs | 2 +- src/base/component/intro.rs | 6 +++--- src/core/extension/definition.rs | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 2781aef8..732bbad7 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -277,8 +277,7 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { .collect(); // Documentación del método alter_...(). - let alter_doc = - format!("Equivalente a [`Self::{with_name_str}()`], pero fuera del patrón *builder*."); + let doc = format!("Equivale a [`Self::{with_name_str}()`], pero fuera del patrón *builder*."); // Genera el código final. let expanded = match body_opt { @@ -288,7 +287,7 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { fn #with_name #generics (self, #(#args),*) -> Self #where_clause; #(#non_doc_or_inline_attrs)* - #[doc = #alter_doc] + #[doc = #doc] fn #alter_ident #generics (&mut self, #(#args),*) -> &mut Self #where_clause; } } @@ -322,7 +321,7 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { #with_fn #(#non_doc_or_inline_attrs)* - #[doc = #alter_doc] + #[doc = #doc] #vis_pub fn #alter_ident #generics (&mut self, #(#args),*) -> &mut Self #where_clause { #body } diff --git a/src/base/component/block.rs b/src/base/component/block.rs index 76d094ff..b2a754e5 100644 --- a/src/base/component/block.rs +++ b/src/base/component/block.rs @@ -91,7 +91,7 @@ impl Block { &self.classes } - /// Devuelve el título del bloque como [`L10n`]. + /// Devuelve el título del bloque. pub fn title(&self) -> &L10n { &self.title } diff --git a/src/base/component/intro.rs b/src/base/component/intro.rs index a20d6232..49488ee4 100644 --- a/src/base/component/intro.rs +++ b/src/base/component/intro.rs @@ -237,7 +237,7 @@ impl Intro { /// /// ```rust /// # use pagetop::prelude::*; - /// let intro = Intro::default().with_title(L10n::n("Título de entrada")); + /// let intro = Intro::default().with_title(L10n::n("Intro title")); /// ``` #[builder_fn] pub fn with_title(mut self, title: L10n) -> Self { @@ -251,7 +251,7 @@ impl Intro { /// /// ```rust /// # use pagetop::prelude::*; - /// let intro = Intro::default().with_slogan(L10n::n("Un eslogan para la entrada")); + /// let intro = Intro::default().with_slogan(L10n::n("A short slogan")); /// ``` #[builder_fn] pub fn with_slogan(mut self, slogan: L10n) -> Self { @@ -270,7 +270,7 @@ impl Intro { /// ```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"))); + /// let intro = Intro::default().with_button(Some((L10n::n("Learn more"), |_| "/start"))); /// // Descarta el botón de la intro. /// let intro_no_button = Intro::default().with_button(None); /// ``` diff --git a/src/core/extension/definition.rs b/src/core/extension/definition.rs index 5699130d..520153d0 100644 --- a/src/core/extension/definition.rs +++ b/src/core/extension/definition.rs @@ -21,7 +21,7 @@ pub type ExtensionRef = &'static dyn Extension; /// /// impl Extension for Blog { /// fn name(&self) -> L10n { L10n::n("Blog") } -/// fn description(&self) -> L10n { L10n::n("Sistema de blogs") } +/// fn description(&self) -> L10n { L10n::n("Blog system") } /// } /// ``` pub trait Extension: AnyInfo + Send + Sync { From 534b1f9615d0dab00d84c5ba6c65bec67d280a8c Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 26 Oct 2025 06:38:10 +0100 Subject: [PATCH 227/244] =?UTF-8?q?=F0=9F=8D=B1=20Reemplaza=20im=C3=A1gene?= =?UTF-8?q?s=20del=20logo=20de=20PageTop=20con=20SVG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component/intro.rs | 28 +-------- src/html.rs | 3 + src/html/logo.rs | 93 ++++++++++++++++++++++++++++ src/prelude.rs | 4 +- static/css/intro.css | 8 ++- static/img/monster-pagetop_250.avif | Bin 10834 -> 0 bytes static/img/monster-pagetop_250.png | Bin 32018 -> 0 bytes static/img/monster-pagetop_250.webp | Bin 12090 -> 0 bytes static/img/monster-pagetop_500.avif | Bin 20876 -> 0 bytes static/img/monster-pagetop_500.png | Bin 80504 -> 0 bytes static/img/monster-pagetop_500.webp | Bin 22974 -> 0 bytes 11 files changed, 106 insertions(+), 30 deletions(-) create mode 100644 src/html/logo.rs delete mode 100644 static/img/monster-pagetop_250.avif delete mode 100644 static/img/monster-pagetop_250.png delete mode 100644 static/img/monster-pagetop_250.webp delete mode 100644 static/img/monster-pagetop_500.avif delete mode 100644 static/img/monster-pagetop_500.png delete mode 100644 static/img/monster-pagetop_500.webp diff --git a/src/base/component/intro.rs b/src/base/component/intro.rs index 49488ee4..052f9c60 100644 --- a/src/base/component/intro.rs +++ b/src/base/component/intro.rs @@ -140,20 +140,7 @@ impl Component for 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"; - } + (PageTopSvg::Color.render(cx)) } } } @@ -202,18 +189,7 @@ impl Component for Intro { 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" {} - } + (PageTopSvg::LineLight.render(cx)) } div class="intro-footer__links" { a href="https://crates.io/crates/pagetop" target="_blank" rel="noopener noreferrer" { ("Crates.io") } diff --git a/src/html.rs b/src/html.rs index f85c24ed..5f5b833a 100644 --- a/src/html.rs +++ b/src/html.rs @@ -11,6 +11,9 @@ pub use assets::javascript::JavaScript; pub use assets::stylesheet::{StyleSheet, TargetMedia}; pub use assets::{Asset, Assets}; +mod logo; +pub use logo::PageTopSvg; + // **< HTML DOCUMENT CONTEXT >********************************************************************** /// **Obsoleto desde la versión 0.5.0**: usar [`core::component::Context`] en su lugar. diff --git a/src/html/logo.rs b/src/html/logo.rs new file mode 100644 index 00000000..f5057d94 --- /dev/null +++ b/src/html/logo.rs @@ -0,0 +1,93 @@ +use crate::core::component::Context; +use crate::html::{html, Markup}; +use crate::locale::L10n; +use crate::AutoDefault; + +/// Representación SVG del **logotipo de PageTop** para incrustar en HTML. +/// +/// # Ejemplo +/// +/// ```rust +/// # use pagetop::prelude::*; +/// fn render_logo(cx: &mut Context) -> PrepareMarkup { +/// PrepareMarkup::With(html! { +/// div class="logo_color" { +/// (PageTopSvg::Color.render(cx)) +/// } +/// div class="line_dark" { +/// (PageTopSvg::LineDark.render(cx)) +/// } +/// div class="line_light" { +/// (PageTopSvg::LineLight.render(cx)) +/// } +/// div class="line_red" { +/// (PageTopSvg::LineRGB(255, 0, 0).render(cx)) +/// } +/// }) +/// }; +/// ``` + +#[derive(AutoDefault)] +pub enum PageTopSvg { + /// Versión por defecto con el logotipo a color. + #[default] + Color, + /// Versión monocroma (línea) oscura, ideal sobre fondos claros. + LineDark, + /// Versión monocroma (línea) clara, ideal sobre fondos oscuros. + LineLight, + /// Versión monocroma configurable por RGB. + LineRGB(u8, u8, u8), +} + +impl PageTopSvg { + /// Renderiza el SVG del logotipo según la variante elegida. + pub fn render(&self, cx: &Context) -> Markup { + let path_fills = match self { + Self::Color => self.logo_color(), + Self::LineDark => self.logo_line(10, 11, 9), + Self::LineLight => self.logo_line(255, 255, 255), + Self::LineRGB(r, g, b) => self.logo_line(*r, *g, *b), + }; + html! { + 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_fills) + } + } + } + + // **< PageTopSvg HELPERS >********************************************************************* + + fn logo_color(&self) -> Markup { + html! { + path fill="rgb(255,184,75)" d="M 633,61 L 633,61 C 579,61 527,75 480,102 433,129 395,167 368,214 341,261 327,313 327,367 L 327,1244 327,1245 C 327,1299 341,1351 368,1398 395,1445 433,1483 480,1510 527,1537 579,1551 633,1551 L 982,1550 982,1551 C 1036,1551 1088,1537 1135,1510 1182,1483 1220,1445 1247,1398 1274,1351 1288,1299 1288,1245 L 1288,367 1288,367 1288,367 C 1288,313 1274,261 1247,214 1220,167 1182,129 1135,102 1088,75 1036,61 982,61 L 633,61 Z" {} + path fill="rgb(158,96,0)" d="M 1389,573 L 1328,573 1328,460 1449,460 1449,573 1389,573 Z M 1491,627 L 1430,627 1430,404 1551,404 1551,627 1491,627 Z M 222,573 L 161,573 161,460 282,460 282,573 222,573 Z M 120,627 L 59,627 59,404 180,404 180,627 120,627 Z" {} + path fill="rgb(150,0,184)" d="M 678,1040 L 678,1040 C 645,1040 612,1049 583,1065 554,1082 530,1106 513,1135 497,1164 488,1197 488,1230 L 488,1230 488,1230 C 488,1263 497,1296 513,1325 530,1354 554,1378 583,1395 612,1411 645,1420 678,1420 L 940,1420 940,1420 C 973,1420 1006,1411 1035,1395 1064,1378 1088,1354 1105,1325 1121,1296 1130,1263 1130,1230 L 1130,1230 1130,1230 1130,1230 C 1130,1197 1121,1164 1105,1135 1088,1106 1064,1082 1035,1065 1006,1049 973,1040 940,1040 L 678,1040 Z M 488,1040 L 488,1040 488,1040 488,1040 488,1040 488,1040 488,1238 488,1238 488,1238 488,1238 488,1238 1130,1238 1130,1238 1130,1238 1130,1238 1130,1238 1130,1238 1130,1040 1130,1040 1130,1040 1130,1040 1130,1040 488,1040 Z" {} + path fill="rgb(255,255,255)" d="M 518,1128 L 488,1128 488,1066 547,1066 547,1128 518,1128 Z M 966,1128 L 908,1128 908,1066 1024,1066 1024,1128 966,1128 Z" {} + path fill="rgb(221,255,149)" d="M 898,71 C 940,48 987,36 1035,36 1086,36 1137,50 1181,77 1226,104 1263,142 1289,189 1314,236 1328,288 1328,342 1328,396 1314,448 1289,495 1281,509 1272,522 1262,535 L 898,71 Z M 1337,429 C 1307,460 1272,480 1233,488 1192,496 1148,490 1107,470 1066,451 1029,418 999,375 969,332 948,281 938,227 927,173 928,117 940,66 943,51 948,36 953,22 L 1337,429 Z" {} + path fill="rgb(146,128,99)" d="M 703,99 C 717,121 722,149 719,178 715,208 702,238 682,267 661,295 634,320 602,340 571,360 536,373 501,379 467,385 434,383 405,373 377,363 355,346 341,323 327,301 322,273 325,244 329,214 342,184 362,155 383,127 410,102 442,82 473,62 508,49 543,43 577,37 610,39 639,49 667,59 689,76 703,99 L 703,99 Z" {} + path fill="rgb(146,128,99)" d="M 672,550 C 683,568 685,590 678,615 671,640 655,668 632,694 609,720 580,745 547,765 514,785 479,801 446,810 412,819 381,821 355,816 329,811 310,799 299,782 288,765 286,742 293,717 301,692 316,665 339,638 362,612 391,588 424,567 457,547 492,531 526,523 559,514 591,511 616,516 642,521 661,533 672,550 L 672,550 Z" {} + path fill="rgb(146,128,99)" d="M 455,160 L 456,160 C 430,160 404,167 381,180 359,193 340,212 327,234 314,257 307,283 307,309 L 307,580 307,580 C 307,606 314,632 327,655 340,677 359,696 381,709 404,722 430,729 456,729 L 529,729 529,729 C 555,729 581,722 604,709 626,696 645,677 658,655 671,632 678,606 678,580 L 677,308 678,309 678,309 C 678,283 671,257 658,234 645,212 626,193 604,180 581,167 555,160 529,160 L 455,160 Z" {} + path fill="rgb(240,0,0)" d="M 698,1332 L 699,1332 C 696,1332 694,1333 691,1334 689,1335 687,1337 686,1339 685,1342 684,1344 684,1347 L 684,1405 684,1405 C 684,1408 685,1410 686,1413 687,1415 689,1417 691,1418 694,1419 696,1420 699,1420 L 914,1419 914,1420 C 917,1420 919,1419 922,1418 924,1417 926,1415 927,1413 928,1410 929,1408 929,1405 L 929,1346 929,1347 929,1347 C 929,1344 928,1342 927,1339 926,1337 924,1335 922,1334 919,1333 917,1332 914,1332 L 698,1332 Z M 643,780 C 643,797 638,814 630,830 621,845 608,858 593,867 577,875 560,880 543,880 525,880 508,875 492,867 477,858 464,845 455,830 447,814 442,797 442,780 442,762 447,745 455,729 464,714 477,701 492,692 508,684 525,679 542,679 560,679 577,684 593,692 608,701 621,714 630,729 638,745 643,762 643,779 L 643,780 Z M 1171,780 C 1171,797 1166,814 1158,830 1149,845 1136,858 1121,867 1105,875 1088,880 1071,880 1053,880 1036,875 1020,867 1005,858 992,845 983,830 975,814 970,797 970,780 970,762 975,745 983,729 992,714 1005,701 1020,692 1036,684 1053,679 1071,679 1088,679 1105,684 1121,692 1136,701 1149,714 1158,729 1166,745 1171,762 1171,779 L 1171,780 Z" {} + path fill="rgb(10,11,9)" 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(10,11,9)" 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(10,11,9)" 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" {} + } + } + + fn logo_line(&self, r: u8, g: u8, b: u8) -> Markup { + let logo_rgb = format!("rgb({r},{g},{b})"); + html! { + path fill=(logo_rgb) 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=(logo_rgb) 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=(logo_rgb) 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" {} + } + } +} diff --git a/src/prelude.rs b/src/prelude.rs index cd3191f6..377dcdfd 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -33,8 +33,8 @@ pub use crate::trace; // alias obsoletos se volverá a declarar como `pub use crate::html::*;`. pub use crate::html::{ display, html_private, Asset, Assets, AttrClasses, AttrId, AttrL10n, AttrName, AttrValue, - ClassesOp, Escaper, Favicon, JavaScript, Markup, PreEscaped, PrepareMarkup, StyleSheet, - TargetMedia, UnitValue, DOCTYPE, + ClassesOp, Escaper, Favicon, JavaScript, Markup, PageTopSvg, PreEscaped, PrepareMarkup, + StyleSheet, TargetMedia, UnitValue, DOCTYPE, }; pub use crate::locale::*; diff --git a/static/css/intro.css b/static/css/intro.css index 17ab5bef..dbc72252 100644 --- a/static/css/intro.css +++ b/static/css/intro.css @@ -103,9 +103,10 @@ width: 100%; } .intro-header__monster { - margin-right: 12rem; - margin-top: 1rem; + margin: 2rem; flex-shrink: 1; + width: 280px; + height: 280px; } @media (min-width: 64rem) { .intro-header { @@ -118,6 +119,9 @@ .intro-header__image { justify-content: flex-end; } + .intro-header__monster { + margin-right: 12rem; + } } /* diff --git a/static/img/monster-pagetop_250.avif b/static/img/monster-pagetop_250.avif deleted file mode 100644 index df864b85c67c980d485216b1ef18737713114554..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10834 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 diff --git a/static/img/monster-pagetop_250.png b/static/img/monster-pagetop_250.png deleted file mode 100644 index baa7d1f895f60e0966aa09e926922e653ef469f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32018 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 diff --git a/static/img/monster-pagetop_250.webp b/static/img/monster-pagetop_250.webp deleted file mode 100644 index dcc5ef26308dd2f26d1e9c2c1c688f750d544984..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12090 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 YceFZN(cAxq=dFKgq5Ge|ng6l>1Gp;yN&o-= diff --git a/static/img/monster-pagetop_500.avif b/static/img/monster-pagetop_500.avif deleted file mode 100644 index d07f359de0e7a7c5d1d9378c55a8819a257838ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20876 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 LA51~|H)nvri_}K9 diff --git a/static/img/monster-pagetop_500.png b/static/img/monster-pagetop_500.png deleted file mode 100644 index d0b9e0b1399bf5939bd0e0f784f3105d4c52d0b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80504 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 diff --git a/static/img/monster-pagetop_500.webp b/static/img/monster-pagetop_500.webp deleted file mode 100644 index 18896fe50ed014ffe5571b8d0a115b755d63823e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22974 zcmaHR19WCfl<ptfwr$(CZFJ0z(XrJ@I<`8tZQJSCPRG{&a_`J~GwZFHSL>Wp-}(05 zb*gsh)T&aIk(6xK0RXflM3ps_xwT;d008sXeFyT-B_k%LoCo^#3INTsGqZOA{}S0d zxPDia5+&Bw(ItjD1wa9a0O$Y`0J@2pi<5$yr20SF|8sa;27vq{Sz!1lt^Zl)e`OKO zzqyzJ03gI)8p38y-(A13@fYUwaCQ0zr+r~`Gb<DGFI@SB>A!zv@C*O>hd2EXeDM#q z{1^XQDD>~@s$ySdL;vE5E&m%f{cqUJ>bw1y4*Qo5xw*Z=SNfpZ|AEc_!M^`sdpozU zy!{*gDIxqf2Mx8anEdO;2S@>A015zQ05QN6;0CY;*a2Jt3}3Os7vlm@{gR9RFZQ_q z+ADuqnSNPW1I)fG!~u=~dw|Km_JDut;7jK#{FiTCEZA88r9j|C0RV_CAn=X?0D$@h z0DQy)fp7Uh;70)f0JZ@D^g8^Py<;8#!2R&W$Nv{co(ljVg#ZA}ga5^urUC#h;Q#>k zs*}lglYhSh_Vom{umAvVO8@|bueO9X3jo0C{fFPaWdFzkg)0Dn`j@ZdrvQNT3;=-A z@+)oq|E1i}Uk3lzZ~tGN|MZ`Tyt4EV&R1=t58LDMB)&5F1Pfq&qOgFxmsl=_on|Fm zCH^QVxh^<$Gkz+nr_6KEG>eK9oMuVOT)}GsT>5OOvBypljYQUw4Fz06^w=Q12@NS! zrAy-#isr|U_vJITvU9w*cHl9tKzMj~wE8)Fc$Ds39xJb?FKn70^<@9G__eLCATA$3 zwcd;&(`<i!&6AJDONA0+&E2-MBLi6+kWK@FzBbv3Wv4A~*_Kd08^Yp^)S4bcBUT&{ z8Kx*M54e5VKK9QA{`fqu!!=X3@~n7NsdI*jlp$ngAz|b!|50&0OI#Q>fJ2(dy8Yt! zK3*kN!%tmWYEQf<mKc^174)VRXJ^3j+2O(ZixmEyzI6l(P4jAE%rTE}D<QSP<KcOx z9qNwhM`{9|(l!H1*$Or0Hcyj@czv9n$q%O<FC8!U1n=wufvdBuZV~Uv?Ao!6_Gjm8 z;nGyukoIsmdrdU0ev?zRdi}+7H^b~Co1sqW1+RlR)ia7zJG`9AU6I!qj5fE$=;{fb zl;VB<KipPta0%Y4{dZL#v1!{@8AVq$sAX7;YfpdZaTU>$9#eHiyIfTphA>CX?rA3E z%CwB?i(2A3#1(qvx<1#{c&{<;;^`1!dtc?YabCuLzQ6nD^p=r`hIt6y#dc4A;57;J zATUPk_k6~r{CZ!!>aNJb6r1@>X8NVBlJetbJjPWY;-QL3%ySg!V{hA1vAm<m(LYsf z24)IAPc6QGjT_;q_I;SEm*ywYX$Kg=w2Y$#u@|mvwV&M)J_FW<bN}=Btl;c%rC?6r zKu}vgzZlw&(zv0y?(pdO^DL)wl&Z}Yl>vr#$W4#=eqkU225$};3ss2eqE|@`QHd36 zXT*5SAFjMB9gU71DY#TC!KSS7jj_nf6=;TR?0%B|6-_m-U#>e10h(3y-@`|{5NWTb z-gfY@kiJ=cOfz=}tm9*qW{uX!9o18`N;&UJ(@ml{O~NFMujb}womS@U+t3mI4QT_3 z6Ot{BndM^2`dfKhXR+u;jp+iqVJ(!*=AXp9@0DF4IhOO7h9rLJF-EdG8d|U{4yU}5 z<HUHq08F+Xp$U%G_+jFqhIsu8h;Ehogp~DCo*(ysd9Cx=YSP#7)JoVW+GrC6;~9p6 z)Ck87^g3j&4noFbz%>PAKQ0|NBBjG|u_xza<|#p0frJ-UtN38Gy3Vd8O`QeoVs>s1 zEjR0TT5H(uu3><44s=3}Z)CUfn&Zn9(awgYe=5JVX0ak+RR@yq=YZ#wTAaQK%T1HW z=O5Fa?3tH>wq*e7kMJbMX(P`8)U1Al%5WIVoM366>$u~vP84ZP!VDGN^MP<9n?;rN zM4G{-_{ww{c)|Hg<`mzSp0<x{xF=dOm{`QlgLRADXCCsh^qGH|m;2#qo3thII7@J& zPqSxQY07C&xibII(vrxi%o(^6s_+)ft0a2V$MB(t=y|f8p<dukprBik7$Qlz#}Wc5 z>6@W3+jjoeSgP6Q;ZGp1u%axfpW&8ppvu<UD+C9MI!$dMV_6Mr{>^!cBky53%mlqL zl68EfoiqTBN&*758UY;TQgdKFm~PLISt0rF7`CXNEe)BW9!dfIPwzPlZ|EV6y3P`P zI7{jYF<VeM5%iFh2>9<Exa}!&FdPwgAd9bp-+W8V1o~$DcPoDSoiigcDeljx9x*%d zm=Hga?y#**@0_Uo48I~1NN0(IB`fQLJPaz2DNG*dTR0##q26f7m|_q(HpbmcOdAtq zbA=QroUe%1p8Dx{s)x%#jR^tyT14dJ%9aJs5&GasH2p`HGJJW6UU9C!_^(PF(p7EF z&SYR@MEP8Bl`&iGWL_CzuH(Ca@y2g11KgMjUlpO*G|JhVRx^Q~<ySd&ix{=t`p;=V z`ZXK9Bf}a@m>K?pn6x`&p3O)<Ah=_hmA|&2Wp#U16h?`hCy-nTvMN&mXFx(Iu|AJ< zqYuw&23&?*MX-9`1{h4pcq9O?yv%<3o&%mcEmyw;j%AB8&{0SG3hCQax1oI!gdW;| z$dHgfSB{*2x<Nc=$x9!>3{CG@t){EG{5XV=13e|a#!F((leNICJ&k6)?O!_mr{hZD zK+BD1RHioMP~|jLxelvFJxCkz)rDH!up%DP3BiPC97_1`scBvj$u=TrsPu(Gy%~Dm zK}cVsiZQH~kovVjTz8YMpDiUQYreneuL3Oro%N3CRz!%*tD5z$1I4Z%3*l4X*huKS z;<mnwx<S<YlL_lGBLl%oVirTG<{@<2B<gRCZrTv+vrT3Ma!&$?AWAf4sCHcP6o1yD z2lMcZ(zIyYPm2)g=pXY3`y3c<`duDe!P4jZ^S2eYQ790NqEe(Js6HyX?~CPYwt=|0 z(LvIww(z-z8c7nPieb_->+`pI=d$~#8z+bfNj~#Vx?13vJBmyZMFNSEm6feV0dJg+ z;uYrfN=Is8<2{~Dyx?a~)CPo=8ue?~c4ET{IRzVIXp)HVDfvJbq}ubG)(yqrJN!Q- zX99oe#71}K(5RGDE)Q<RRN-k88!rt7G@767)&V$%rG_>$188c6OYFhSfy;Y3Ld|`A zM%-mruRiCf>I3c~MdKcuK=pm=_>edjumXIW-ygRm`QunK>*@sqCZe0Sic#S*3DdhZ zpLW(rrFw~Ce>M92>GK`hY5z2I=5IlA|H_j?s}F21vyI8c70=4M%pf{f@t*zIfm0YM z5FXl#-V7x~(h5#fZON~(;UA;R?g7)cw)oI#bX03$h*b#|KkME;5g60b^N)-JYYm}) zCE5(9EE7q@`#4eQ{`1V&H^b-@8Fmxj@Z9k%6S)F=xx)~s$cFW6qLa__d}++9)rOhE z(ok*U95R!ySHWQ;07KmSh#1dromRg5VL!DTs{2vVTYjFrH4B6Y88cKi(gfD#`|X0% zGILqgXK#F+;T|94UZP?t)z>^l9=FgfElm%HW*%bn#bIy7RE+&vDX`;rO5cXp!&zhP z{C*0TNv;@OG254P*|zaM8ArHq==w3oEt?$YJe8m+6%t*6>%vZYiiV9UCt9O&AVvv* z4Eko)DI54QWSy$>$<5vSFtjUE60Jp@m{y($^oBMW7@Yu%=CqE=^E3Q}PmucACo0^8 zfAX|D;9nK*NiBs+?92bG1vf^2C_UapdniLVvqF^^KIVGv?Ur6I&%seM_EI)6rQW8R zcNc>oJ>$_)Lb(E!jBEX9am4z%`SXM)*CjM$9Z#_6N;%(UZ3odwbH8X^54C+|EoAiX z--@apJ@sMud}2c))QTu*Fi;u%(m#!YJ~tl12B1}7L>l0mwU4Vt#tJvW=W$AwCwY1p zKAvFbi3+Si<fC8_3};<iIB}}Uh>)|0HmQ-F9J|@kbk=OPIVL{(?&RT}Br1ZJgGj38 z8cV3CR083t?P^;grC?hh8(7`fp-irjbEK7(z45o~Kf^VfNfJMHJ^2X-kzFFk!^7@2 z90))BnCT1Sz?xfs#r*1ohKfO%c3WS4z$aRhz^?kB^w`G5<brN#eeA#S>cJKxrXlsb zEQ?ug*)oXe<`BjN+u7LmQ~TCf-L%fNjs0Pw3#q^kyW;YG9Xsc^Rn_z@4hgc6&c?Kx zgo_=qGi=vNW`(&EG58iYg*7(F_Ro4sQD;y#TdYBQm;wEd5jyRKxwJbBc$_fLod>y} zf%^%b5O6gMrEjtHU0vqS5zAz`$&N+e-acD;ICgEN1}<gxf5)xs=etX(^|aG+#^N!# z%^QY&RBUHluW#3E&nm1AFthfOFI~SXofZ3N$7vhP7_p@lLB^Q~Z!7RD&OH3|CT|16 zxxM)*(Y3bcK8Phg3}E{Xlp(Q$b_V_Bi$24UXN@h}f2i<^)lB|-3AL0!twanJlW3lR zhJ_kMg+3Ew1bz1+T|#TQ`)2g6ObF-bZ)%L4!;NpH!Dyn%x>YiA@F`!eF7Xul#=W<c zw`t$veBXOE=jvHig7L)EIv}?l^3C{zrIx@d4$P$->XNK=s;b!rxpmQAQIa^hH}hqq z_PPq+@ETnA?F>R>q@TuO5mX|_C6gl1Cg4rb?bn&(J?%~Gog&Y!Q(Fs!I%AGFPd;kX zEKvEJQi-(=m$=6$xlQ7u-na-B3AjQ-HJ!%-R}m)=q9&#SfnGnpi}}0fUhM3I>(RMu zFC-OCG#=OW6xv(s+mr@~x7~LP<pv6`puIDq*hjJQRj<#nN_`5;TmwD;83%SZ$m`X5 zIR{u5=`z3?vPvj3yW*ho*Ii<Kx$c?-U7MI1`7!?eAWsm6R)8PwB7g*ao<(=;Fa7BG zJ=aAq&RHDBHk`pq|GCG?4;q&^X^i!UN`9mhp-gV6Z(Yu3ZC<}?ET(ToDniu;{+?Ir zr+<X5rv?no5h;QkDl?E{O0{e^=_<O3StHS}i=%o$i+*PconA6s^(9UZ6AX+|z{&A; z`2NWX3qZiYr;$bqiDg|p&69A4=}%B@76yUfiX0D;`qno=%qdy{zUFeFt*itg9r&wA zFXI~kF4ts1IX}sIBqx+5;xEX$w3N@8Hla<~EwVgl%2i^lHCo$G2ug{`V(O+ygevQ_ z0;?@?#j|MaLC{6Xp+vn|u6{^X^L8cXTF#doN$^=d*EepdU~{O)wLg8Q34_QpnInEm z`?Frcw#L!r=5qUio5oIXZErr&N_s7xk6A5<#`r-<Hjbt30fK15Ab3)DAhAxOL);sS z2O-XY>>x?wbt@rOb8mt*XK{r}vHN~I?lAjcW^pd?;UzrTmOg+3zT~Xq=sxoK+$r~z zUxc&bZi)~y{^HM**3Oy{nPIQxfiPCzv3MS>18-`}Oav4?N$-Ij-4PAE)n5;q&G0Xt zg5jOuFD8N=3Su*NZ3@w~nM%DWBIz?EOo94Gg`Im@$G_^nop=ehSi{V3`r>Y~&adB{ zy22dr=i;rhhRw`a{v~vsm_>re%8urIz;<Qy<_y3K^S$h2?o}GyKT!V}9P{e{D!7lT zbuSb6w#tQvs=zs`vh2L*O^vXM(t>1z2_g6Bpxzb_%VjAxuTa3h0bgZOD#PsBhX9}2 zSf-qH(tE?bd=TUub0*Fs6_=-ojG&=(4I(Ft7p;bG&0k1)0>4oP*KoEx&qY{@SzBI9 zE#Te<I9%?hCai4Z91}KeUtGYBTaOmgP^)lDXrP%ew;*>=$}qM@qs!EVEAWh7hread z<B+i@*MaUs?^?rkV7pKnVxA?0(rm$_CufVwhRV=rLB>F(4AK>E3`Q7-Ed<~ulM-9? ztn-Qz<4nWWC4kt7w!=3TS|<CXjqakFsDfjHe+0=a%;F;*Ut?!L`m&dR7BN%BSZVmA zOqTFw7XenwILYEe`V+-Ah{+M`7k-ZnpHU<eOGuv~8{ziWkINQ9M+TCcDktjbsIPSj z$d|%M5Qd(~*{UX^(YEHtqsd26uF&NwSLg5>r+8oJ++5~q!Qks@cJZ80LUNz;YIfUm zvOMm|X@6YE?P~@@xdl_}iz_&hd2HA~+dKw-_J?-fUneC0aTs+)eTZ+(TLrsM<CcmO zrc_Y-=48U5n9SjlqaTRgCQq_B6sTNmrOvH2Eey>XL5c*+$a>!m9Ra@U>ori=PDb;Z z23=-P+WN=XDjD5NKJ-A5$C2^oWB`ZhbhlJL)ceo5oVT|z#LLj#^081Z(D(C=$+^tn z!TQ%+N`_`v{oLQs@uiv#<DBj5=$AHPYq`^X7ZL=$@w*Kz25Amugw1|cy;u=jlon=b z4&Jh%7_X=!;8X65KX4OTH})|@bxy5&SRxy4?XSYj1MyLRW0wk@=;XmDLUlP*cCdw= zeL=Fw=qjEovV+EtI`U)^GbgG_8pnvCoXpPMw)b3swpKgF!}(c=J#>egTL*?fWyQYa zU}JUf6l53&k{ykhH)Dvq9FO}<=w<6~b1%kHI~t41vJmHPui%T7MZ;#&vkXu!eC%aD zS3RDCV-Z0+I+%UcmYfW3L~Fge@=B^9?&FQ!^hq%97&INZ#F6|>Kn`66OHpTvDtp!s zfxmDGlO^NcU(4EX={2&@z5q8!%O`tenYNPJ;n^|Xd1LPWm25-gQ!hP}nQOdFlKI07 zABxHX{+bK(h(Z0NFz$4G`1A^Gc&hBmkye*%;`!HB_O4v`vEJG+TwFHFjydOl{+QcS zcZbYFaGA-5<jNPyy1}zi;9(U%jsIYPqD%<=W>Lb5gFNF$KPZDJ3kMsEQAJJ+4^FgF zBzGm0-Di=9iUVe%ka`jX`-kwDD~#V{s|GPZHywM9WgNvDU-#e!x~AkcnqW(vZj8kz zK~P*5nBCv1iYNrP;)U#+T`w~uP?}xHPORpQWfC{Ih8&HEqv-Gs7=(!o>J34s`KnVR z@Di{M*E#<9o4jBMio=+t>Cye#dxOjKk+*-l9W1k^X6=03TYZflf)+d=EH93;11$?2 zVZU@HN^5MRiM>WPhTelx(UE|;CL0Sl=<_B6rEF&t&zKk%ZJm>|pjeRD3`p4`;3*4) zS)-?plTy2a2wZ}93JP0>;sqauIY(CZ*P^R(6fnmwRqV|G6{N-_NBV)SbthNasY!xx zo#zAR-TJ4HRtgKcajOi<Sl`RPG~`gmCCZLCF&tbIV{9NVrRW~`wS>CnA!Ue!vSt9s z*KcH8^Q<+hhnm_Sg@I4uQ9NXE#dLROg-GQ@C>EU0b)nUs%?x5MNmQ7x;98<`O|zJ# z%ELTSUyGuNhO1yk4qVb5ubm()wISi=u$oLz3YIMZmqzyGwE$zm5TQF^6~czi7#Qlz z1i8mCPUn{hMr1dw4Ft2gSc?Bf+wdp|Js_muH22fk7z*pczLz{8zm)Xnn6hFuFAOZa zYh>Io(Y;fjfi3p5;<RbO8M<KM@JNB=v_4$X@YtBKQoobPZV3*01t;vdj3YKI3TQkm z$hS)bkqHrNt?64UY|u()ey}plh%9?`^aZO~)rAU^co?gz&ij;YT;gEJB-z5j-|)qK z&4zE{xu9YuM&N6lQrP+$urx6jBFuO<@yeii3x(K-ouGJ|t|jacROqvmK0Epe1fvpi z&|h<$b3G)d)eak^Xy*Ze-6APA{F3~)B=?J@=>F>>CeZ3bK!PO3fG4ByccfoiE7m2H z7drRYJWBN=-~{aDi6ZDsi|XRZ%*0D&!5|@+Frqc(VNv<eomH1?%B>`g;ORbn)O6)0 zA@}JL5Uy}>R2~Dn!I+Wopj_lp@%D&^1(Q-PZSi<15GR;6$VViA5p))10+er~hV7~* zl5I>&G9&%6BYAasXd(Bu+Os?b=mo_jsUSyS48O!wF{hneSs50@pgpQA^7>Io$KzqM zWEUU7143B>{7Bd}DNUgBdlBfrA4hzj7bWi#T%^ATk3MHvxKU)N07Z^))@1>Mk-}Fz zB$TM?wPp%r>z3(b7VWFhK`tOGH$}BwezD?|uW%&@I#minPJ$9NGnUPf&RQ9o(~+lF zdL?1TTZw>2cN-#iNMV`dNQ&u)1<O)?dZX{e(lU>+B>{h(_Fzx!7=xZ)IM;c%jI|~H z{^*8=Qd+fYw~EsiPM>XjtZ1htY7)9tWr91s1r3q{pCNK}Y+UY*2C`nC1=B|WbM~D^ z_=&f-aTcBd-zWQ9b;RIp07#{&J9`-ByuVr%toe$Wb9;(gqkq2GwL`a|`8+=yYuWIj zba}rQtbBh4GWg9PeSbgqWN=a(3zJCPMJO9Wq~>=X#J=|dR?097O7aHgoOAccq{&tH zgrh_c<k=5PF6KI+nXn=Y)-8b`?;VPbZ>)5dzBpD6X=hLz=#3*ogVmXHg|et`ncC6M zdw|68^e2I-YWqOwi&is4yf^L!4P2<Tn#KVqu{DtyJNVm;c<Hx&KV5LIfm%~e*c=?j zal_|ep`b1=8;te46~VcXJjd0O`27tbtag{k*Cq>aV7x#OyxoBpF##MbUoZ+1{PuZb zU{vcTXm8N8f#x8DbNCN&NSj|PIr>QuW0&q}NW}OagA`ySK^!G2eL>Y?EZ8@q_-^t^ zf#yh+9L4~-C@Ef(K_usMvmpA}0bL*ETJwQ?>6lj2XU1@R@_cP0Wz6br3yIFT_I6!D z3xeh4yteosUT}j%nF@@*!toF4i**s`^;xTF_7W7r(8tA#NUDEhvudXt_*;tj&es49 zO8Ci<MJfr9VT?_VtKfwO={T|x7csnfvI984@X;n#F0E@s@Ee9Y*T0*q7B?l9Mxq_f z*u*^-zbw#`68&Bjp)j>a4v*%X9VSl|Vkg-ui!`F*g#0}^yO6=%5g~0=2wSnoyq8B} zB;d|5JRv&F7Z08SOB~rD4Qp?{5<HVZDp(%<VhdrNl`6v8(@MW|C_xFMs5su@I#23g z^ZKd!qp)hP9nJ_3S?e$NL-Uh|iz?rso?BOHlBb6RoR1AkI6|X+8OauI+14x-;6^8Q zsCk{y+pOS+lw&lcv!2~W&qLdeJ<QB!f^~1i)!BT?;i8vX)2f`E?qDE?%s@+ur<?>3 zJ0${zYM4Qd%Fx|gXj%@<j)7%wjM8>I2+9rgMl(X$!{6a5g>o>vPLSDb`LI(>mq_$* zLXK@7^a1<E#$f*H<1bZ@OYVwTd&iIOf8)U!_O?Ve1@T&JlpZI%m9&7Ywlm{Gerp`a z&Mv^~!I+kwkNsPJ{BBpKn##4^TXaS#H=V6bx$w`ri=W$_$qCq(KcD$H!9&BEY_KrU zuyWH5NYM88O$*kVVBrv0jSud6W`KggxAz${5Wv?yBr&PL*FNMmARC1C9^@WG5Cb|` zgaiWAg9jX-LT|qvSVGHfYbd?r4fww7xis)Ob8FcLDRkqp3d96f`;P*d?wqy#e4f}| zf4(W*5c%W|UaB?nFLeIAz53g;Bh>Bx>vIlx^{KVx_+WJ9uhWzK-uBt@8T?7qN_11R z2VC)Q_xA(xe5?Rh-kBy1<9a$@AwIJ|kUq4Y{kND>ke-AtfZIMJp97yIpFdlL?th*N zT?p}YGyg~f4*AzTf_?t}xcdxmSb4d6%RTo0<NyAu_>l{2`E-2pIk9{JKKMWP<PZ@P zy?0gn2l(GT03Nu`RvwHliE91pjb#03UauZ%hW#)7pFi&2)y|2U{e=9Me7ZG{GlYu# z%|4$#klsC>nAZFw{Wm@(yrX-WZh*Tzt3q1-gFr7}-RISskefo#J>ui9UEq<w9B{)w z?PK^6{BvNw23hHdsNa9$v&w%22nC$kL>g}n=$Y#Y1C9aZKKwt4Ui^VTYyVW>0MP!U z@U!LB=u-&zsp0zpwA~PT@xPwA2Ojj416P0;z_-usb^lL)H^W%}BBF<$4ZpV(x5_jE z^WJkxC>>_rvA|_{#Cl`5Uts?aiNNV5(++Bi&?q868i-ansZ{5Qw9Y!3LSZA99tqub zHu(s~5E+o_SBwq+5ax9$vki1Ie3d6kxp(K_HR3;+QC9<1%kEd)ri>dwacW|b;jovp z%U5QXI@YF=YPPO!`uBqZ>)J@a!x>=RRq&?3_>S1!dTA|m328=OIr%vRoGMvw1k8Mz z41mM`Xr~^&4O=#l<@y%$)Dr!84JD(ugY=tzD-s%&v!sgzoO8plb-iM>sp*Sq@9xx& zDA8M8#S0+K7_<IKgR#I$o8PXuFc`bXy)2QVRIASw(;o%58oSSj^M3A1{5U`o8yu^y zGVNo-n{K1}fS*XefY{eM4liCv%E6C9zOy95rc|w>3l#@p><5wWz_^Zb@&oppxstKI z6-~T^A|8f*6k)7l9@Mmwu)i|b%}_korgphB`2@TPvrd}T2NXKZ=^aGq<wOTr$KCIW z$jmKO|1}NqU=2{Z7I-K2>B_C4zC$BYJ=rCO;>7ccgDW2ZSN*+GL++E!faO5X+qL4) zy!C9o&gMU8p<@w{Vi^bbasaXKk9}uMO)l#n?wcq`vf>vPk7%^~joQ?kE~mjU6NYc& zc=wS{mKL~$j2kUjoNJi|@v^G^$1vEv64h`@h=09cj1HXqE@|1zNK-M&UDa~^;<!G= zKF@mwYAFMo-=MFB<DfD@Zo3r46=p*pM^)c0h|@dQbR{Xfrgy3^tQd5I@x#NT=467A zGOC!i3bUh#IYd60a-q^dbJcq+iitzK)Oow|9TWQ_<}WnSG7e?>BZpK7jsIo-pJA|b z=*{!!Uedz(<s4ydg28CcI=+diS|$89(;J4_k8@9^KhTbxw7e_+p*04T>b5godwRgd zBCY-_*8Cwt3_MfVclgjLc|l#j$Zs-aGz@pj4dd-Q${E;{D^FAIHvZx#P1x@Ne){~h zgs-cuaY9EWk%fY#w`H8Bj#NYufp`hJoqTHxUrinlRKu?tSE4$Bk*rXfT9$TG!XFW{ zOtfSRBxTePyzewU7jTQ>m)6{kk9h_hO-hL~vi_&T<kue1DV$LoApOaRO?5E!3rt39 z&e4hzEx+*;!dSxdS!N1l2Xpcldl4VenW)55P!VxTu0@SL)P`@S1l7qoF_*1PMiA`q z5HJ+Hc=C?sW?h`wlalrFhX<CExBQZB>fdx7=GZ<?c3aMG<oP$F1m>yWWHI(%J<dP7 zS)s&v3Kx5?5rbmGVF_O|C~NgM9^>FOD{+bLSAUj!PLHhB!m|avvQOkvQr51h9dMm4 zjBT$7J^3}7^-d|s@#oB@I5N|<>7Op&6Peb<o6%|?FR8`Lo~Tdt@WHq`$~_ta^N`|d zMw4}1<?9*8@|A0YPxn<$16eh8>}dO0+*pEhT>^$r{hB{7xHr(#YfSz*8Y{Yklf}HR zB%#*tQ8)Gp0@b?e>99H(_rGlNOyA9DjZ?l^b}0+weC->%z{-Pnyx*4pU^~bVKDL1z znD3!Uh;#Lx(psz3SfjVRigBlsn7&m!YK#43HhmWNLqjt>y?n^43XHo)u(=myC5NH; z4_|6GPomKvAYP6cm6Sy-WmIlx_epx;S|oQZCe8*!q4i3N3c{+t4BC9;I(mTRs`Bpt zf`#@oZFhSc-TSBd3Cs(HbDw__`cdSc$KOpFJL}mCGygWqsD-^AqSh%oVEfDZZUY4_ zktObKw^8E04ttd(5sgW&U4dt6Ow^r6N#ekZ$tCO~ACqOcJglCxwsUk7HFo$w`aFhM z$GO(~t&SP>>aM}!uQHV7Avb;V!Q@I&nn!_KNUfFVWeP%dfFx1FAoUO~dy7RaZni+{ ze9ojMi^t2M0cx2yF9X`DK8_$pQCwjp(wN8y_k^i2#lKDBe;Td-a|llz1pq#QE?);h zz5<-%`{>*EkxzAPZK!jaaRm;$#lU#jO1eJFzF+*FTyT|Ep&j_`f#seNy_|9>w>9%> zTvRq@ecq)6t(MxM)Lze`xGOV@$4k9c^&2@JM%PIyJ`{r53FFc%M5aYx)N#=>*7N{I z;2k-F{}C3y+92tm$0GZCM7rkk`G9ki!<-8eSTPw2U6!>3A2H4Su_D`VRy3|>1(XjQ z<?+y3=Po|>a|g@6F|cy_&{ACJO%zFIK}|zWfUtXost|aZ_bem^eqaDBzFQc}%jS2w zsC1WgF3czaeItVN?H*s=q~XD1<?r2)BHos(JRc&UoiTxj0w(}7bJ9dooT#mza~+fn z8gSGpBdM0^wWZwfq{iC>yPRldsK0s3NT8jy@t4OZ#d9iaF|t*){>VV>PsnF)4%_h= zU6a-)<(1q03U5l#ex(<1TmwCI8h9DYz4BN1jtduDb;{JSa;H6;izP?H=X%?N_dP>7 z=xJz8coK_Wc0uUKm&c)bL6@S$uSe!JSPsccm+M8_PYP!xo{u+N)%l%?rVc?XuuvkY zSZYdjEmq9L%fJNIZ$LXc1bi#|QO6sr|NVf&xB+~HERH_>sosvH1xEDo>4%h`0uWGs z#7)~i(_Ce8!eus}7LJVj;RW#q4auqCnPkE=h;hV$s-OCy&@@62<_A*R%*-Oz&flq~ z_G*==k0-_CvPHpV8JVC8743R)A?OaZX#J~L!Yfl2hK%e6%>h;{va7>`&X2-R@K)@n z@OFv&GliGug!Nf?LZ;iBE7UV$$0ZUl{xm`Rxh)>5%0qG)tkXCY%0`hX6G5ICkz(*q zF@`#5R`yOXyt9+eeuhkcEY3$`>XHj5>}sY0Z8|^MYu(Wi|FOFwE$v+|)kUHHr&Obb zA1D1QMyaz#AnOUj%=;La(M#xbC%VHWG0kk1NBfBP6D;I-_!;aUUFi~!KlwMjuNKJ1 z+{I1%b!7ECTpr6FN#{4v)XKE;d#$u9MuQr{SqNI8M@{xE8KVzs(`$|MR&Q}?G7Of> zEfhaL)iKbB=Q_k*<{@WfvU)+KmfQs1m@!gSs_&fh!>L-WVR@Js#PSLRJGe7=+ohQ9 z*e_3OoP-sqftzgziJpjc`GnQTyOG)IA4+th$BD<G;lUnW-#Cov5oC3$q4$frb-Ts{ zHk)tL8u)PsoNFH@(#1N1yi`**X%Wu~n&`M3u!AoqzS+K7>_OzO!`&iMPlZq5)gMd& z`LNp}RQf7c@&tdPkf2oyHXoWfj?&O1w)!@v7w_|kVV|l~WEv56Ot>xK!)$tDtkIGj z(#?&dJmyOhxAJ*T)yWkSGjRZFB90dr=C#QSNa7^7H4?>=p=+_WBjJsN5~=mh8@y|3 zX6oP3nQ7#rh#f1CP*T@2^A4dO<Rr!Pal?7iDdS4V@FX#mO9vKdG;iD5#w8UN-5KyQ zd!vK;dYNqEVLpW5CWp0Rb5Y@Cv@cEFv%2r!qX2o5_`g-SX{i%!YtKhFb4|&Jo3m5V zyZzo2UM9HSX3^rWfCRXBM|mJPz%(s2-3zrEo27|M%w@94RmGFp=+vrw>D<{zRxXGn zRzBf+$>d9oGB;W@rUvEjXpHNx2bfLV<su>32-#O%me2L6H@-grqtql!#zA|!!T6u{ zmg<(~yPoyaA)`MZWJELk0XfoYo@|sh-kKS~<Fq?uq7U?d<}$7Es&|XL3X7mgz2r+n zqVOK$fTs~FP&zXL=_Xi5H($E`1<~Tz(`ydJyP_5fY++Cg<i7Z2*sfpT8fmLomkofO zS^D!Q(UC^>Xne4a9foe42^t6%0*K@pnEAhWjj`zwZSVqnWa^Ogbrke&M6;K=+F!GH z^T&=&MQ7-5pN92L0dh<GWUE+%P;PLXb^}W6z@puyXgflp1T*kN7AXPwFkYLuj)HCQ zb98S2j8e6M*9CUHw@xsf2`7z+9B0aCyerEj_c%_H340lIz@dbh9p-6%At#`HZy_Rr z%8Woh{J#G2W2hLc!%mDzZ==x3sYSZKN3Y0sq^MBr0!r7XSPOUv%Bd?Fj_36|h&xwT zx**C*^~M03W4B2CNJn__#6PjV%{TXzYMUTq$?-6#z$B4C`F9V;j}C0TW)sypnQw^@ zBkPBDILk-;yHHiPk4u`KM}C>HBTJ&u6dOIq%55g!<-(xUSRn!{0_9HI$d|o+DD?N6 z-@dUF1{qy8CeJK+V3BX0Ilnv(D`mg29JVBO(+)C196WHdWpZU@vDp2B7>W80R5yti zC!&5Mhqh~LyHCD3h%Xs7;chCjp~{Plm9OlWn8?tIiQcvmkWz-b-;OUBqA>Ta*Qfqq zSJVzbBr<gcxqa3Qx(k7?q^=-&7n`G@m^)#gEQGl@sF5iWS_!05E5V2B4|@_U#|@bQ ztM@8Wc(zR}?m5U4|M@!$bAC>>lt7|wn(XSgD1g!->w8yYjHMkmDOTCh=SZ}kRxv;? zbV8h~zI&7T=|Q44)^YKKo|JW|%+qEkcrcp_q1DHcCJBBj97IHEV4Q6^?|FlME*2zu za-k|Jyo&RN1I(cY;~m4YpI)a6l@VE&K8Wy&VPNQ0vU++gd3cc_rIA+K-|79s!}q+i z9MNrkZuY0ylUoMDou9}NV%!<<2o+u*32Pzf6y&XgE9DbcvPi4RBJA~i(<_jFBT8*L z?;LDhk~iI_ZaMMcNv3y>&q+(^JJ_f#p6<y)xr>l}BeH~PWcOZWUX%2*dT1bfexR$5 zN#Qmm@MxYa2${KPM%$C>;&a}fhM|~SmR9mOsG}JPL?4+-^qUxXMwwAvRPc>oc5#&H zh*<di5ZfJCkwWrwEGB;u10LuWC-au9YOC9p_2r?KkxH-hyKknPYmOIY#Z!$!zQUY1 zrfpSyN+hXXVB`04IgAQP$B-83XieEtj!1$*PV$yq_*o>1JMPFs<8~qW3_|*tB2rYi z>L=^S)=y4MpNrvmmS7j|!mI+HFg>wmphc_k!9u$XH183^xs<&<X2V~;W3r@CJnf0# zcadlEg|0K543<N15cp>S;E^{wzUo{q^VUQQ2+?0mu1q$g^~F+)POIW&T62RL4x6?) zuzlfco`vk{yZ*lU?K3|7K(G`2<-a4Iq;GGVCe-P7HvMzLVDCcx>`c7I-8i|qJYH2q z<(s;Oak;k_?WfHzm3-jvsCVw-mzgs*92uIizRk){H0)5i33cdwQRje`9)XF_g!i5M zBJW?Ke}qvVNYtpegYiuPi9v3QSf=4YM;RXxKg3;TvUDL{VG8_f=S`RwTT4&FuReS% z>0s{M+0~hR<$d!6Lb!m!4~=g!j*@Wk9o9h3Ov|*SOB#y^L~XIY)|Lq{(yEpjq*HN) zCu_0a<a(t$n%tVcx*rPDIfsR#0olaG4jxcF*(1hTEiHvk{=_xEfHO+8yDTQFtFhyi zXrHJ4aaRD2fMvC|J->o#?|JPSWgvU#(A*WJ2#Q5m$M1!LJ|H9bFrTE}l%<bX^L@Yw z9wv+$Ny6~uN-~*R-`{B92i@Dljc846uv{EJW{~Xq`9)LlOx37lO-lL%M2kiJBBLr& zhAgKVOZtF;#@?%vutHADJy;pL_ml&)L8P$hgPOWgGW!WIMyj<_{4EbOw=^TWBO^lH ziAiOte`G9gc_%ch65pUo)$pz~q;K{Nf!GI_PW0*Z0QR`hq)b9wL!5Wf|9}Dm|FK&x zd$jFSQBY<H`+!3FZ1~|WgrkO(SkHv^65^AGo-2B6OoIPb8MW?gHo;WP=AaGJE?s5o zFNrGv(l()6c|U_h$Ha<)&NJ9<!1!x21B|9bxfYhrZ`UWF&S}4FCD5de;~v+lu_@yk zqA5T5u#Dy-Mk&p`7_vOs5oB~UviomNYFq`rFuR+ijx5)hqV^A@7+GqKb?|;NFK>dU zb;PT6OP>*`uvSu)S_xcueiI4J=dI;{;<Upy6jX7EZ?;svQ&^9wSj0O;FnBA*+pf=p z2jt=+TqBXcB;=L8AylECKNBXqNCrql^y=+t2G5=wA3g{(=e0nA+|s~e5T~OXIqc!U zxigAb);o?<;L6P0+2%fiFps}On!R%|h5JaPi<F8f?P7JCHx}{05})Y-&Rojlbvf3_ z?=DrDw|RSiNc8!@4DoGnvV(#~vrag}M@_$Nb?X&l5It`Q_GAa9qa4bm5tiI=Zcltx zGHDF>`DEzXV_}@@<g%Sw*P4^1Ia#_+#QB=(p9b}}amHb-P&_<hHX@XeG@x+K5aIN^ z;qWx5$hvq-IO~?hgkoSmCY2riOfzj5zT1hHh%?kY318;16W(T}y5<#CJf^SAUh8qQ zJO>gAwy}<0EQXZ}3ls8~<N6hp<`&I5xxZb6uu`uqTPHXcUt7G{`&BD~)(43=sJ#Kn z9e()3G*j%RC*$(HucL;?%(w48KR90AmaHKyhVH%Oe7{-$ure5NnghTDVx$S&GZvc| z7Z)WJy-x(s(Fl&D#F2iV-tV!}SirdbO_|bz5GN1IyS^7rhncZ{>qSPWdokq5oGEtH z6WT5IBrfx#G;6LmXRGR!4wpGXgKEI^P{9Xwrf$yYY(Ce=!mQR7iB)IaZ>q>fzCU<C z=;NnfbdO6~71Vc@N#WY6hCY4;DRrwV&53tJ$aW$1WQ9L{bv!fdDk^?G&DybI0eiNF znSw|S*g2MOFnd-Y(03f+7$BtPA&Ug;`d35I>Q@;vy=&K0{5n-(7@8VFd%VUR25pVD zCFa$C-$r=)CS;3!xr<>#4Q$8xRv=|~Y^L{hW{DRn&{&=p2<^G0TMj@aVIQA9zHNEo zTFXiwR?JN_7?*ZYYO{2-=<mhzNuX=upF7dRlx=og9DD%78ngA%H2ujb1F(fdw&+J= zpr+t{2fx_Z8+UNb(jXfN7_WM`E|jGRD~_yt4d^v~x-zQy??YOt@%bTJlKDdQO!@pd zseFcg^+&{DMyC4V-@EY6=LY325rUYct3jE>RYiXpfm;=@to8GKx7am^z!)7I@#%r1 zrMTV2%FdhD8?$9JPse^TpLyN`6j$_SYKwS1xiRffN?vomj8q!i#<re-;I~Zqjx<?( zAw+_etza`XTN3C`QD!^bs4-$ifzbkZ#G+IyW&9`(=%PqLkcL&aD;9;XGp^`sy1c<h z$#LJ=URuy){f~Z<@bqNmS6HPqo=>%CW|(e+$Fr?#o!U0|n+6@yz_m%oX_vlXd&N;O zVN`EX`xdr*Y!cX9-4Z;+4M3*QZQ_KHYarT(NdHAOy95J^R`#b^6A)`QPuus7^UVik zNK}EQk*7Pn4xsYF1-TH_d6qLS);@MyERk;Iel8jh&e+mT3R(9@a6YPbl~UYD5R}9l zmIr4s>LX9XY9`P`MN<q(0GPy!dau|%_Q#~l!l*BBLCqa_D7f4%YH$w)eMpTn>AB1M z_^zZ{3sMlswNT;<GU+hultY6gC|HR5GgYe2g+lm{n@+<aLCbR&9sCKgrc>{FSFn>J zJ759z^Ac@C+0`RKRq73OVG+kDk)52m5_I}A(*f^25u6}bvF;Y)riAzHCh-F6jLh~= zGo7Wa#S#m22S`1_^HTwuI#?d}XT2J7#d~@TV@v@WA@@C=2$|mc-DLfUum14!_X*nJ zOn0o)b!Iam{i(yao<?Oq!C;v@2tS_<xB`?UAP-BgBb~i|H?OXcFc*mDUe9>dP5KM@ z1gSs+qYvq70cp8xzmZ<lR2YPkIzCwo-H8<qxMeY`t*NMqF(TSxORV7r_#J0qf~cI+ zEBwOJ`aReUcmx;b!`<ba=CzLMX?4bxuKY8hQ6fPLoby}JH#5BA@OcQHj<;)HKUW+% zX|t9n5!l=CkKOGbJ%Z~M%>1*lf6>w0zh$*An+*g8J**Y#DF+_41-KOHa6xn6vU%@M zFPE)g8#pU_@PXnB*z-*tGBErei1a66TyfYn<t>l;4L2sxY_u2BEkYKnyGnM)tm<mh za&f<N+RXP(lrhJu2@dV$iWf+`5niFjmJF94gmMAVMThH3#mu&h@k+UfY$40>@_@V0 zirMdS-1v0z<2hU?Fpp{=4X#q*Y(dwZ%7++A^tWq@xgzn2B=IS_r8j{e6!{OxGv`be zof6P;tD-acr|g%2W%3~no|;dL{&L$>-hxo7MvlBAG@!m(BWj}6)4ox52_?AylH~Gt zyINWS-64GGTrSj(3u@4>BO}539)G6_nibCa52tTK27U(pad2?`8$C}k!JH##7&MDj zh&`c}aOXsG8JUr>oczS)R7g<-D+~o8CXc1vcyu7Ri#>FyF(nrQFBW&9ntpdlh|{<j z*HA<i#M#I;Pcx!+8XTikO}4x@;8=j^PQ>DFc6-iw%l3Sxe>$pm_gq%<3G>4&{I%$b z3pmXmU~KeW^bkA@iamG9ba(k)OLHnVqf&buJxI$XGTz?8dGZW*&Tb9V(a0hQl&Pz{ zkbZK3UD%-cU5F21F|v4U3N*~JCrO?vQV%7@FT)>PtEi~IJsvZK0b{w6G2y>}5*^Yw zD-*<3gF{6O>mR!Gu^EePTl?lGonF9E_nftArN^QXNWs^{Nj;ZEEEK7-WQ8~^p7^#C z<=YXV5N)Cuwi~KPVY1apHNB9j_$u2LQbva#zA3|nkTSX5{*E2XVoA1yMdrpqD4SC< zENay`sPxBLfQI@Y$<G2LrhmLwDtYRb3k%S0#esw&C6VF5m6#uFwaXEw)DpPQ9LFT@ zO*)k9l#XG1BC1JC3>Gh|E#aDJqtK=@JW>rOG*oG%sHKUjlj$+Z*w)%a%*=0QJ#2kZ zmOwkmO4+xF2nFS@_$eh6UXv-DT8SE{^1*0ziB#N*`T&FL-DK}Gvo|f{;5ehy?E?hc ze$>hfa}XLMXBnWZS4i+pMsJ#`;f_gw8Rck&4S8p()_wb+KD2>{5drfVHm-~KYyhoI zi)*<WF_oXGb~kn@`H9ki`TR=2pCr64<c)m?MZMZj#oHPX4k!k#CxRzEoJ2gB2xJ?D zEv7C(-^p0?A>&E6!yY7NKH{1WcKFRZg+~B<k_v2h&Q0DOwnSVA6v_C-Lr$EA#%VA5 z=R28~nn-nV*esaymBw=3hIke^D+yHXQSs++#}Mn%TYvPdMh4fmAemY^78ee@O41f3 zuaJIQ3w5rfOtJLk$JERWDmyeKfovQbrZUYvO@MPmRv1ZBTVp37$BkvV8a<7`?qm1k zS_W#iPod(3Q|;l#5ec-Vg>a)~jw$7uJ&FD6%5{)7k}R3)J%cP<P;s}c6^1f_HqF>! z%V4PSZ%}wam>*HIklX-i=X8vbkB2%x80=<v)5*z9guqqsC|<MdpRP2VMiW0T$*Jll zGq7KeHKEj(4ak%=&4!M%_PQ1nLG`TL<;HFm2X;1`2gD3zPv=$ayT5TflE%m+5VBV_ zEsd^(TsBx8(S+<4h`fNL(yfSVrPyt&-O46-sZt24xWdsu^p5<Nbb1$jFyR3-NxbOu zs<)to7uvL3-RN|(VeUzgA)`eM9V;|$Etu{uIZrnEC2`4$@Ugp7t)N`4_Opx3hrhQn zR)C6Yguk&v=bP9%qkAtL*X$a=iFd%_`zCk>OK;O{qSlb+K-#E^T01m7-^krp!oAAk z1y;rs5>18-1D`<=Vxc_H;aqTi=uxXMpmjF46&l<--GU)y7E=Fgyqm?(=fU^-&cPqQ zt<8~XiXAkBbg{gWDf5&c&1u|XJT`r6t;Y>&a=o%G;tx~qayc!GZPm*u5s0}joksz? za9y{{BzQ%<=jZ!n8bVG>7E2oj0%h<DHF(c{7jYKj9YA?AoE*X3IUP)IME&EtfGgqL z9VNqh&|F{g&y`9UQ&^1dj(j#EoItTXT`-k{*%R>zQ&bi&tCKU9meRFJ0HGBhrN+4$ z$93Xtiga#CYGIgl7;xe_Hl(IL#>y`n2C;BPfgO}c?+r9dK@CW+3xz)GB;he4sx4DD zN~G!Dhw##M_Ll9|NqPRFLNjn&{b95e#FTAt(~qI}v9ru;yK-lK$lSCwaE1YgEycE0 z#E3vhNn35Tp9aHb`tW_?JCkeJ0{m!hpfLV8TntZMH~uGJ6UyebHbuZrI(Vz>kgMFR zkYaXqu+Dr2$RY;}(%_m|Ai1ce?q=P_j&IWDUtbfLC05cx2$_UfJJDcQvGs3m(42kH zAk6Zs`Tex6<gQD|vXoZM*O}1qqc(r2{*rK=8KQo~-ZK(LGd&+2O-Yp*p2jNGUsq&~ z`!8pGO&WY&qJ_hsy93HjRzqyC`fZ<*72()gt+JicRvpYAp3(iqQ#RZisj8okGAhdc zt&_#S^d_RaX#&j#&C`;~mHSElc2}?GBCFT+fomavPb&|yLklr8;r;Nt`GKexVM_hR zr;W3Gz@eXNMLN(QmH$WPeapoD9tJZ#*sz7!vc6E=x*KHy8}~QUbc1vFvP91%1l5u) z?|8$#<LG*I+*}o9PdLQ6@C7z(7A?O<ect!p7F^CGJFGFW9pjK64L^;{+e0KVU~wgf z#2ZW-y*pMlx(wJRri0-p9UOMmumhXHy2N?4W17eOq&?8J|3>6Ia-WvVn81&&NI8$G z6jk`0jUv|i{eeW(uxeYHrYMv}WWp@xMIWnT5D3a>dma(E6u7s`&cw;RKF>t0t_Q7x zuEF%k9HJ#8Y2<=>RJw5Pa27g1BR#wGeZfgK0xwfys`KI1%w%^9sM|XE^op0R;vu=j zYrT{&Lp#dDr!aDMZh_7RgK0A;U0ez!^d+P<0!v-yrrQ;!(h+X??vrUeWGfU3f<;y( z&Tu#C#{pTFH$ExR^YUG`ga_~ov;v78Bp{4A<j*-?L)b3`B&g}Ds>VX<yQ?m2TPy^m zRA2KaMEJ1%Fp9n|*_mugwXjJoCFf(Wj6W-<?bj|%kKKlTH0Q4#eA+3)r-W*{`11mD zq`f*=kyQ-G9m*#R@O-)~_2&g1;G;y*GG1n#z0-F|@<(9llgKqc<%O?>((M$5yF$WY zuvt~N<Hb`v$2VnWf;W7gM!8=n@lBJby%$v3XAR3z$GktJP$hACEHxrNef3#09lMkd z4c;yq2e{UfyrKR?t$Xx`s<ex%-L(T#kHpKY%l&Dsj2CsR^&s>r@fS?;z}rCiO8v=f zRwS^#9k-uLB8lrsCC&8Z6nreU4)qG}`RH&h>uafGPieWf9bH3SbU-`){A-qExpTCG zcS}`|z|VFwF<o$RrDdT~CORq~d>gCtc)<Owct@+_yCZ*7wIg6fI_dO=T3H~l#@ZAR zF2mHwJod2rZf2lXSv38b;bvpe^%O=sQg?|yLf;!HLaOmJV67zat@o5=;`sruOY=$i zSqosGakz%P<*kSPC!;|@L`QT*Sz&gh>aXT+opY1lNU0hra1=j35`se!2~HDG6TgKt zkpIR;XKbI*&ci%#KeOp>E<5pKwbaofS?i!xRCouO`^=;FPUXd`U$yBhQiw-FvzEs^ zG=S*+3z)1JUFbdKtSw*TP-`Q(h@(q3<(f1mc^2WnVA!fF!?N)I_NcSpR&b~$ByA<b z{M&U&$dzxizD2+3*%H9$(~id(0hU=7j)<d0hKMEnWBo<e(*5*J<RGF^ac?bzKz{6S z^uBP3)%+${W%wtnbGqTr_UWv@W}J6@wo4&sulz3`6EM)CE|)T|XEa7l=4qOT*f@|; z1gyMO$aP)n2Elo_!r*kygtAu)Vh>WUcef3&oy2hC^u8Hge`l`ZosMLQ>r?Q2q>NZt z`f}$dd$+qD>gp)bB!8O><4O!}^Oomofhp3K)TB^YyKT(!`N(*m9!zQgKjWSeXnLpa z(wAd<+iYvZ64F}91P7Y&O$BQ*=rZn}@;z%`P^_qUqzW)`nA-7^AJnnx48yY`jp2l9 z+(eI0@m+037-}|AozVEj6EjzMI0o(U>EGHVWvXe6Gzr28pKF^$o)5&5*Sm%L^0L^c zQ84tpyTcw{$gYq~6zv^L&>cMu8b%<jQyqHiLRa3dGlOJ({R0^g#7O}XqW4)M@P>1D zF+&RfC-D~!=+++Z_&6XNVWV-qEf-LmI5T%b1TyWI;fgR(H@8!QsN)eWJ~F15LBrdH zgts|1HWRimaS{LfGzH-#oe68dVIh$gzKkT9tMM(}hkD242k@1IX!`ae6SzZ9b(kry zJG4~(Ax?FGc(6+h2?4<w&LbIqp10_;S%XVz(V_xFseIWqH}@1~D0jOk`sO-t?tI{Z z*;iX#t}G|4*xXH`V#d)biu&eO_wkCZJsiMs5zYw8;|d0pU$;aluKr&<PS~<7%2;l? zy2rRB>sKwW4Ad4{$7#i}ja$2)0i~UnG-4U%JzeFz+KX@j@Pe3%u@1g#o(g7(?vhCV z?^Zd3jXp2l*b5#A!~=h{sm0icauP90Tl@y11$;v&x^T{4_OP<J_cbQ(sONJ2MgjFb zI)CYiTxt841xY`909gyT6}`HY2phr;MpS=oMOIDv9-3h?^g!_x*8+rV$BI_Su!^u? z((%|fc>4d(#h1}Cu2Wg`vA?OL=YSJCrU+#<=e~(^5Isebbov51^(;TyLQf82{;`Y; zQSXNv(SZM8<~S4=g{T5Pv9b=Uk&tba-*bs>Xd0B4JPB%BO}I#ug~;7<gS>jE*y3{w zs4TJxl6D)vxb=*NtuD}n>Lm;8fk?Em<r<oqNrvOTe>`MJ)AA1D1MtYo0Eup>;v_!w zDnwHc6EI?Kq-rAd08=ic?kDLeQSkIdd4A}FVXC%|OMbdLp9*!>XnnYl?H^yY6pe4c z7vnfa2HUn2O)FuHwvUo5-<!g_C-U-L`(46f`~5L@psp5ZbYy)5AWiz8o&GpYgOVHJ zJAf%o^;sh`extKA>)1pOGf|MHPCsNqYWZ`Vu~HYo9i|6Wdb2O_4vhn(k%kCpFWnW) zma0_(ZlaXAZy;PBBGCOz=1Wf8NkZp(im)O8$k_jr1iqPP&)aBUARdx0D7O*_7J`k` zC;X@y7B35-a#9T-H+!>cW=GR6Zn9A#GTt$kf+^=m;#AS-9?2(5O_avM?8GOOW@(Jf zK$gDb&r_r9&{-V#8CCwzzpA}$>1Zy#p-2ax(Y!&Aq;Qk?sVg<(MbDv%RI&84UL4|J zYHH;;=-@?&Lc;J%!x^_x45bVX5IV!Wl{Dro9LMP`VqK*aVyRR6^PLHRlHc~X5q}(F zD>)ispT*`1b56G0kAOU^88XQl$t#TcU?nytuv8QG*F5%wKpDEPb5djbPvIA@ko6z^ z84#AoSUk)C1TSs#*Rx)0!TP?{1!ZFtR+2D&M<16;Nq<?}G$Rv?1!HE=hv(RZKP`W; zVd4eO61I7?D9Nt;H-xe;w}%ym`$OlB7@p&)4pVme(G9i&(Dkt;vR`vqE(s3S$#*R) za}F$BAe)+{Y^NTnxyaSMrN;KbkGf`;GRpsX*OmQe$gyzAO~4J>lPoJJzIz%lwD@+B z)wV4lE+;|SSK9TMO9Pa>RH{l<<Di;`Xc%S8yfE+z0x?us)|%(mEwloOvu{qB<~Y&* z$nujm!Kqfow{kk7@<qUBVh2-?A2}zcEAL*Y3UmZoMk-tH^CXi}vcHy;YaHq&?<jZk zduf<}UxE0_hlh1$-p@x<>ZoeTJRasn(Cd03CVAQ=7On-YB~%HBGZXyjJ69|nPrDfm zy#-cg*#81d-x!|a$$2s+-2eVuF%U}e$iu5>*6!Iv3-{f?00j5F*2ZVhD%kuRwMso^ zb*gc;!}$qUd>$T{uX+jncf+M{Awk{$5aXE~NPLJ?T=*WVeOjRo-ml&@{*p&=BX0-Q ze>FKB>9h+e@EtX&@`RlnpMDw;sx{XkuRRZmQf+C`F>lio=Q+u_0gZ`=r)^MxF?Z0B zNA-x>q%fU&saqBn#8|J4VtTa&E_(B48K$B)S&%_*<$8lJ#0DT(y8@QS6&+9wyJk$A z7jSsuvc=RnqILe)@CM%NU95=#9RU^kx*Os^000A$%|7^(d1?TYXYwf<)#-m*sh)C{ zWmP)pwl9#L3s+#yvRpL2{yY_$|A2@^u)RGrHE_W4b<pF6Jw-K1z@*-<)l9%Q&;~c4 zDnJIa;0veL1?(xW2baXLkug1EU}@=Iz_b=vdPVVglsF#{H9cwDZ9vnu+JUESwF5__ zi>BI_^cLf-?YcS`U`sqYoydD>y_FE|f4rny9*@ZjqXFs_H&{2=OM3&oTE@%p|0?|V zUN$d2SU59($evPgN7eo0Kp$ctiH__Yvpl1SvBm+tO--<p(EfG&ck1arP!C$>64Kc8 zAHw)Z`4%dXAc}_pb8?9Y18TJkPW}jLy;J5%vH?F(Q?GDZ(vjLlY}rgkC#$w7zoS0a zZc1Jo9$G<AcdGRR%#uHAx4+WV;1m55Kr%AG7Gr>A>_;U)remsh|1FPc3ylmc3iY*T zI|FlTjz}hb*>l@yB?_5>%QN;q3vEkRi$Nc{G$ZazeLyAa*eDz4@iq2q7V&o`$GTNi z-DQA!c~2YUfi{(q0wJuSwejgl>PC2{?RTr{SogS*aW64ag(X_Fq(D>^&4WeW<HvZ2 z9di{|*A?v6&3GE-kVZ=C%r!golci^#dnT?5?uvuU`9EwCrigN1W^ZK32NM#~v0R>K zb}(s2;b(Hp6tt4pf}rtW8nkdt)YlbI`R_MWuqbH|7zSHc&1NfkYufMz*V(cv9$Wpk zrDu`pcE9DE^ic#1_&x({&6(X<9~=*SW{aVgEMJBvZSM{zZEm_dWPy`g-uFYef>2G$ zd{tB^ugtqb2DW;kp^p-s>24GvOP2Hu3XdT@5Wo1i&Nu5gL%)_|Cfh`Qis?r&#!>w= zGqU07G}dj0#dWYrT;@@`cExF92p%uZb&?;*I2+A<U_9CYZ91K=D-eRub1HwkaOyi8 zF(`K8&FaZU<P}GHkWw}^cn9BC`<(`4K1pW<yeW%90^j29RSRw+l+P|JF~H(K#Ie7L zKuF=_S?cO|pXKf}K_FJoG8d21*L^!fUkNF+^t-qaC40C-e=s@FS2JTCC`wDx3}H>J zcy8$4I<Nv2%A3uow*WE`3s6v5sX^?%2XK@&ff$ll5u_%-Ir;o|RTg`ZCQ(a>fr-@K zpfmo`t=z#Kj0xZ?oD${H&83M_m)2`Lui*dv@D_6lg%ZdBJg=M!DMxBUJ}v@5wC$(J z8$RR$;L`Jwy<mE6#lAnao(u?!L9TnPUfEPy<Jp83;)0(TuuO%ht%d(e$P_Q`eouaj zKE3t~O^&FfYrXQkouEp59T{D@a-<_-)fZssOo4Z+ZMo-@unSfq?1r?Jl1C%D-M^>t zhT_sHVs-n}crZYtKk#Coi;*S(8UQpR9y0E5ds9sf=Wg}Wt8<q^4o?!u&T{I%Cb!uh z{C<LvVgyoyQ`1}vD|JAy*98dqP|8!WP2|Gy)c65-wRBrI4Te-TWM;r(!IXBKvY(Ly zNgyX44vRd13+CwV66a6Q(Q19#1hE;^ZxMi4GGxXqcL{}jw9=0&rYm<0UYkJmHea^N zAqk{z9cf*gVlPEc`;s~s^y26D_~~k}o8ici-%Y$UdfuGWjP+&;Z$$~P{nt@t3vw&V z+(Af0XrqrU&PfC3ij7o1Z69CU`P9fO^BN^_zKzP#B;aZoM{d|&i+HG*n3kBbftRe= zvT9S##N2SvHjJl=V`}1ps!#90Wkr@tpSgS1Xb|$afoS=P)ho!lG1qH;Xpxr>@Ie<K zdHNBBKo=2vMX~CZYPoW6Pqa_vfihw*dFS^K;P|rn+-f$pCU1SC>~8LvnCtf|pa5X4 zmWTno{hop2)PWgU*kCqkAd_uOi}GHOirwEsa57;z_;G`v-NQ<Xj0<%>ZT$+y1OcB8 z>}x6(6rV$~{EG)i?8eilH#^hfVb&=Rwrzj2PpYUNhNF=%uy;v_iF5rlzl}m$=w!x) z=;NMdi4~mj;s~C;)BH#6R$^<p&!!fKzGMK2e-$zw!|sIXPglr&A8srsT(RJVMBD$k zMLY6^cpUq`>U{W9Z)of!vj$cAt}K32L!@;LvJ$}&ADqqqOc?))4EvmeIYp_rHChO3 zt<%$QnrqqB=U>GI2>6}20)Zq~N)y?yRUmDV^CY$0zo1Sg|Er^@&l3m2@7C!t(J!Y4 zJg^D&Al-Wz-bDoK{8j$wg_m!L{)-R8mAQ&0N`v(Kg6;ch80ai{2Doi`k)n`vut3mQ zke0nAbK1(|r$$1_y_xn!)mUPA0@1;pz)UII%Ht?X$z29erAdUTx9u^z#UH;jc&eM| z3aMtlgvN}nW)lC7K_G{5_F6xEo{C24xwefIIP6|MX=kEZ1fmDS#B)~DBe``+Z|GL$ zsmnfGQX7M|lip^}!13?QJ#8@&H|D?SWtC}X&jufvxZ;&RN{+-yx3CpzW=*L4`e++} z0%hlCdhfeMgDVr1l+)}#Kj$o8zLHI8c1E_4MK3g8s2`ECl{(@2WAP&F7=S<cJJW)P zf5E<I92nU;@>Ruwf*U&k4vqGdQqGLevdXSW<mwBi1m^;Jb0?zgx3J`EJAjrjex{4o z@#Wux<nm^TYmz?dtdccG#8=Fm?Euo(h2VtV-(tGgtQ!Jj1Xp=l>-Z2$!lF@|X9jOR zdB)WvWM?u~uJ7Y8dEg^=ii3TTaM~Y~jUBURR(v9VL#^z|9M6I_zN$kb_^e-lw%4JL z@I=a%PV27q2ep+)x84S6crZDKxp{vuw)|IiNS)U^{0mAS2;1zw7>chn9LBA?H&lQH zSpWZ5l%icLU#jT>U5?Fz#o){mCbltwB{C48vEkV749D{Blp!Mt=WB8r#_{}LE;1Or z!Is(Bg_Afv4QGfCUj-nDV9Jk1KG;OY`oK|eG;#)A6Po71tR<Ltz{wM^w=8F(gJ0ia zXj|z5PAdbdmw0!8Pf*g*)dD_x*9R$`3T33(w?htP1VGuL^CD7cPMe4po6>xz-3a4T z6lQGvKk7>=*59peX|i?u(y`%2*u=|#A8%%1^JVQMRea=65i`#8#XHwbMSDH0HBmeO zKP;T5U)ny_Y=63t8{M(;`@+j#{Wp^KLIEd8#>z`q*s9YV{7T$H2yMb>5PGe3zm<gn zhf%X)HH8UVephvvB#kmTuFb4&DExW!aLuzO@;1z?t-Sl@rwFiz!V2{2w>0_a^S*mz zZybH93<Fv?%LT^j!4%-bA{kQ4KtAQ(VBumz&p+K!KI2DUJ8G-jh9Y4nh@F>&>sEPj zdu5Wm;Lgt54DS}SYDe35#;*}=f!CIyq3oeBC1`Xn{lq)*TW^{?#-&nQ5R-bComIs{ zuF!Koch(=cy6P_?T^Nh##AH@#RqiR>EHFJ~sjfKn9O+0s2<WJzBqMvfsByUOkCB8( zj}iEg-t!hdc#aX-RO%7a$d%273&jQ1NRpGOrpcjp?>N(J+gj$o*vb!9Bv8F_)tLU7 zb0eXhchO7WV{P?33MD!$3zm-`#I%bro3S&2)XOpV21SM*-NVMccJ#Cw*+?gjjtWS8 z8-9z8EyEd@ds!yjxe9WyVa-E%8tl1G&Uev}=N9hoP3Ioiin_zmN-XW;mw6`8W`mbr z=d|hcX)1V?9zxk_ouZI}I@%!F%RVs@*o`n4f00>g3R~?a%FssiYK)7UMa>w4#2cB3 z5C6RE#0M0wyT8EsjixB0g;0tatUs3QY;-L@zROwl-xFoz%Bi*wRTYWvBne(vb|l~z znYxCrm$A^!C@gOOzu;5y6DSjtlp0sv$t*KzbG;pMzExfE(<j%2H}Z@L1Ex!TrO;;b z0VQIBXD`fjuRNM%i&(B_Ax&YG@ltywbCrQ2@P_NdRT4vb;0Ps>Ep>|T=RQ+ckJbOb zJ4a&?%S|CC%p2;i*al(QnQZyKliAC5XJt?;u>UFxgM17c19;r_>Z=9gKS8YncLQME zRXBFK$p%q5UvI~LJu1k`FKca0t>FiV|21EVkL0aGtsvIO$@H(1TDdhbj4P~>@eqA5 zsl4yQan()mNVpIh?;M>o0#Of@5Z44Z8H!pNERzS07j4K7!%+9G41_{+y926tqL$h5 zTA6GZbcK1%o9);GvPrrOXlEb52NtIO%!-vT?6Hbv=VB+HM@qluTAFzm1?dZAjqsH` zj(ItvDa@Y6pLRgCqZSLU+z_=qlFbi{G<kM(c+=doWRGqE!U77=Cf)LL<S&IeLCnPr zbJQ^Rk~5ogY6`IHv$V(nv5zaDdPxvDyHM!o&dX#qwd*nNA+(Q&Kqw%p`*b|o+T#x9 zwfmUnXwQl3oPEN(Bu4`|lN7ogDAM18{<a;@=51uwD=mD%^vQ(+pa4}ABe5PseM-mw zh$)<u%?h-7eI~%#D5+ro?H8Z_{>e3i)G9lOaZmsQO2GW=ddIG+-5hXs^$rrJ(3d@U z70yjO6AiZjK)0~_w^_rKIx;%#F`XFIh6p2QzOD||K89$y7at~b0o!=viC9cym#5No z(~kFK?0^rJOy*T}Om=D8V!a2_-p`)WSk&G6HPdArasLYI!45|FT1GFI>#h(W_&&p> zI6({oWS}Mt9Ay>ERqQI?A68*P=f{5~K`#Uh-8|O29>(?n>c;tNx&FS+egCxb^W`U4 zd7Cs{FVDde60Z&k<c5HYBV_}|hwWxY2E0WO2ltA8da?{soch`eQ|8g`5LU=<Pikl4 zb1FYaup++iOi&vj18AXE#a;+Z3JpNWVp5Z__ep%;lUeDR;c-Ig%~@!?(`+NU>2)mp z!YyFR(L6{p1Sw}Ec80*7!@ivvN%>N&IitOH3HRX&4;E}`R}IAr`Mnrrdu@_jk2NQV z?%-ras(XW0hy8C$XRbY9sfGNQ>O4(quxaSFix*>1fkJ*JsDMl(7F|IRRpDfGy}QlB z`bb~XGFnSqc6gZVSvj%{o5*r|=8olJ?wB<f1PdYP{w@n0XV49#FSFow!PqZSr~8^= z0^E=~AnJ9Hz*9zQottTeM+3;tU~?X%-G$&ChCq-=M4ClW4l^qd2aip1)q-1C8Dv;& zl_~Hv@&;#~ajCxDCCa<ptrJH`H0NIm1t5G8+>lXU9x(s(*lmZUVuD?@*>qYYJv<>_ zf|!YiOc>JFnLmGpJ7sMQJ%Qr@ndL$7vld)K{r1=bfz#|m3h|(m&q<I2;G3p=!zEM7 z!E<fU0+Fm|1U752?LsUCHO&l87}40Xx-3tCYlT&<+u=jEOe0qq@9q(r0jY(egj}P& zA1Y-mJcg|zLt6g#;D>MxSjDOSZHQuK1Z2VKh8nbH2(fTrF@pd9uBd<i|FUKP0DTAL zk83#eyrbjbDM?#qY0C~T?vSq~IH7B5Mz=lpO<2K7GxFD`nohg{jbm#Af*3w3vH{L* z+sI0Eg=9ooK*_NZu>YpodU7=87AP5wx?_G*d6wRG)&gAQZYYK~Q`IMuus7O{#t!W3 zv7RAYNbe&0Kc)hcyPDU+#Q+@E4cMREbF%W9f%&_=!ghzQM*WqLuZ<<f{m)#Q!E{8) zCz=JK`&@kR1_%JT0P3>q<E9XAN751k;w|>rgQ%XfIWwc?_{Jwpl5bZ4fjSfRu3J`b z?kQpQ9HL4OF-G|qQ27nFm%5VCKJVSfRzUZ(+3?YyRyIt=_5;2t+qi%A%WC>eE0~32 zxi_r@84!_2tV{i^yv{jo=(HJ{ztF!Eqy|j=Gb89bkis=_>J8MxMez-#<L$)MD=jFn za9aHd?Q$}yvU($#e`dcK60{F`0B=0<&9MlWYyZq(Fr*EKTt+WH7J<6n0C-#!#Q$0~ zs3chxn@!$_+$Fj2$u?NsDMi5Q$OEfiMQ@J87e&2YC!IDUC$s(<)|%<YCJ!+=p4Dx5 zC9Xgx<dcS;$7SnqeNJ?GG8zIr;gJEftmNB&1DS_w3`gj0tgC#QAh>Ml6pAg%?H>cZ zvP9xrQWDybmei0?&5A!fA8b)@Egm1|8=+Z_v5`taQXzU2%$=*oB!(U;@YPAt>MkGt zM>%CCl+qNo@%`F?JA@L&6%m!TZG57+<cwDn=O_z2^ZC{+9cB1Xi>h`~!`sO*y2uAw zq-9yc!wSKY!+4&qPY3@ode-Kj%Sa83008kNLJzx;&ToSHwW8Z92>;Ao0000000000 F006P8s)7Ij From c3fd566025cfa53d14d58582e15ae91d763b74d9 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 26 Oct 2025 09:18:33 +0100 Subject: [PATCH 228/244] =?UTF-8?q?=E2=9C=A8=20(bootsier):=20A=C3=B1ade=20?= =?UTF-8?q?componente=20`Image`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extensions/pagetop-bootsier/src/theme.rs | 5 +- .../pagetop-bootsier/src/theme/container.rs | 6 +- .../pagetop-bootsier/src/theme/image.rs | 189 +---------------- .../src/theme/image/component.rs | 194 ++++++++++++++++++ .../pagetop-bootsier/src/theme/image/props.rs | 53 +++++ 5 files changed, 258 insertions(+), 189 deletions(-) create mode 100644 extensions/pagetop-bootsier/src/theme/image/component.rs create mode 100644 extensions/pagetop-bootsier/src/theme/image/props.rs diff --git a/extensions/pagetop-bootsier/src/theme.rs b/extensions/pagetop-bootsier/src/theme.rs index b5be6b71..ece34f06 100644 --- a/extensions/pagetop-bootsier/src/theme.rs +++ b/extensions/pagetop-bootsier/src/theme.rs @@ -12,8 +12,9 @@ pub mod dropdown; pub use dropdown::Dropdown; // Image. -mod image; -pub use image::{Image, ImageSize}; +pub mod image; +#[doc(inline)] +pub use image::Image; // Navbar. pub mod navbar; diff --git a/extensions/pagetop-bootsier/src/theme/container.rs b/extensions/pagetop-bootsier/src/theme/container.rs index 22f7fc6c..17512505 100644 --- a/extensions/pagetop-bootsier/src/theme/container.rs +++ b/extensions/pagetop-bootsier/src/theme/container.rs @@ -234,7 +234,7 @@ impl Container { self } - /// Establece esquinas redondeadas para el contenedor. + /// Establece esquinas redondeadas para el contenedor ([`Rounded`]). #[builder_fn] pub fn with_rounded(mut self, rounded: Rounded) -> Self { self.rounded = rounded; @@ -282,12 +282,12 @@ impl Container { &self.text_color } - /// Devuelve el borde del contenedor. + /// Devuelve el borde configurado del contenedor. pub fn border(&self) -> &Border { &self.border } - /// Devuelve las esquinas redondeadas del contenedor. + /// Devuelve las esquinas redondeadas configuradas para el contenedor. pub fn rounded(&self) -> &Rounded { &self.rounded } diff --git a/extensions/pagetop-bootsier/src/theme/image.rs b/extensions/pagetop-bootsier/src/theme/image.rs index 6c602780..837d25a1 100644 --- a/extensions/pagetop-bootsier/src/theme/image.rs +++ b/extensions/pagetop-bootsier/src/theme/image.rs @@ -1,186 +1,7 @@ -use pagetop::prelude::*; +//! Definiciones para renderizar imágenes ([`Image`]). -use crate::prelude::*; +mod props; +pub use props::{Size, Source}; -#[derive(AutoDefault)] -pub enum ImageSource { - #[default] - //Logo(PageTopLogo), - Responsive(String), - Thumbnail(String), - Static(String), -} - -#[derive(AutoDefault)] -pub enum ImageSize { - #[default] - Auto, - Dimensions(UnitValue, UnitValue), - Width(UnitValue), - Height(UnitValue), - Both(UnitValue), -} - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Image { - id : AttrId, - classes: AttrClasses, - source : ImageSource, - alt : AttrL10n, - size : ImageSize, - border : Border, - rounded: Rounded, -} - -impl Component for Image { - fn new() -> Self { - Image::default() - } - - fn id(&self) -> Option<String> { - self.id.get() - } - - fn setup_before_prepare(&mut self, _cx: &mut Context) { - self.alter_classes( - ClassesOp::Prepend, - [ - String::from(match self.source() { - //ImageSource::Logo(_) => "img-fluid", - ImageSource::Responsive(_) => "img-fluid", - ImageSource::Thumbnail(_) => "img-thumbnail", - _ => "", - }), - self.border().to_string(), - self.rounded().to_string(), - ] - .join(" "), - ); - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let dimensions = match self.size() { - ImageSize::Auto => None, - ImageSize::Dimensions(w, h) => { - let w = w.to_string(); - let h = h.to_string(); - Some(join!("width: ", w, "; height: ", h, ";")) - } - ImageSize::Width(w) => { - let w = w.to_string(); - Some(join!("width: ", w, ";")) - } - ImageSize::Height(h) => { - let h = h.to_string(); - Some(join!("height: ", h, ";")) - } - ImageSize::Both(v) => { - let v = v.to_string(); - Some(join!("width: ", v, "; height: ", v, ";")) - } - }; - let source = match self.source() { - /* - ImageSource::Logo(logo) => { - return PrepareMarkup::With(html! { - span - id=[self.id()] - class=[self.classes().get()] - style=[dimensions] - { - (logo.render(cx)) - } - }) - } - */ - ImageSource::Responsive(source) => Some(source), - ImageSource::Thumbnail(source) => Some(source), - ImageSource::Static(source) => Some(source), - }; - PrepareMarkup::With(html! { - img - src=[source] - alt=[self.alternative().lookup(cx)] - id=[self.id()] - class=[self.classes().get()] - style=[dimensions] {} - }) - } -} - -impl Image { - pub fn with(source: ImageSource) -> Self { - Image::default().with_source(source) - } - - // **< Image BUILDER >************************************************************************** - - #[builder_fn] - pub fn with_id(mut self, id: impl AsRef<str>) -> Self { - self.id.alter_value(id); - self - } - - #[builder_fn] - pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { - self.classes.alter_value(op, classes); - self - } - - #[builder_fn] - pub fn with_source(mut self, source: ImageSource) -> Self { - self.source = source; - self - } - - #[builder_fn] - pub fn with_alternative(mut self, alt: L10n) -> Self { - self.alt.alter_value(alt); - self - } - - #[builder_fn] - pub fn with_size(mut self, size: ImageSize) -> Self { - self.size = size; - self - } - - #[builder_fn] - pub fn with_border(mut self, border: Border) -> Self { - self.border = border; - self - } - - #[builder_fn] - pub fn with_rounded(mut self, rounded: Rounded) -> Self { - self.rounded = rounded; - self - } - - // **< Image GETTERS >************************************************************************** - - pub fn classes(&self) -> &AttrClasses { - &self.classes - } - - pub fn source(&self) -> &ImageSource { - &self.source - } - - pub fn alternative(&self) -> &AttrL10n { - &self.alt - } - - pub fn size(&self) -> &ImageSize { - &self.size - } - - pub fn border(&self) -> &Border { - &self.border - } - - pub fn rounded(&self) -> &Rounded { - &self.rounded - } -} +mod component; +pub use component::Image; diff --git a/extensions/pagetop-bootsier/src/theme/image/component.rs b/extensions/pagetop-bootsier/src/theme/image/component.rs new file mode 100644 index 00000000..0345adb2 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/image/component.rs @@ -0,0 +1,194 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +/// Componente para renderizar una **imagen**. +/// +/// - Ajusta su disposición según el origen definido en [`image::Source`]. +/// - Permite configurar **dimensiones** ([`with_size()`](Self::with_size)), **borde** +/// ([`with_border()`](Self::with_border)) y **redondeo de esquinas** +/// ([`with_rounded()`](Self::with_rounded)). +/// - Resuelve el texto alternativo `alt` con **localización** mediante [`L10n`]. +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Image { + id : AttrId, + classes: AttrClasses, + size : image::Size, + source : image::Source, + alt : AttrL10n, + border : Border, + rounded: Rounded, +} + +impl Component for Image { + fn new() -> Self { + Image::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes( + ClassesOp::Prepend, + [ + String::from(match self.source() { + image::Source::Logo(_) => "img-fluid", + image::Source::Responsive(_) => "img-fluid", + image::Source::Thumbnail(_) => "img-thumbnail", + image::Source::Plain(_) => "", + }), + self.border().to_string(), + self.rounded().to_string(), + ] + .join(" "), + ); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let dimensions = match self.size() { + image::Size::Auto => None, + image::Size::Dimensions(w, h) => { + let w = w.to_string(); + let h = h.to_string(); + Some(join!("width: ", w, "; height: ", h, ";")) + } + image::Size::Width(w) => { + let w = w.to_string(); + Some(join!("width: ", w, ";")) + } + image::Size::Height(h) => { + let h = h.to_string(); + Some(join!("height: ", h, ";")) + } + image::Size::Both(v) => { + let v = v.to_string(); + Some(join!("width: ", v, "; height: ", v, ";")) + } + }; + let alt_text = self.alternative().lookup(cx).unwrap_or_default(); + let is_decorative = alt_text.is_empty(); + let source = match self.source() { + image::Source::Logo(logo) => { + return PrepareMarkup::With(html! { + span + id=[self.id()] + class=[self.classes().get()] + style=[dimensions] + role=[(!is_decorative).then_some("img")] + aria-label=[(!is_decorative).then_some(alt_text)] + aria-hidden=[is_decorative.then_some("true")] + { + (logo.render(cx)) + } + }) + } + image::Source::Responsive(source) => Some(source), + image::Source::Thumbnail(source) => Some(source), + image::Source::Plain(source) => Some(source), + }; + PrepareMarkup::With(html! { + img + src=[source] + alt=(alt_text) + id=[self.id()] + class=[self.classes().get()] + style=[dimensions] {} + }) + } +} + +impl Image { + /// Crea rápidamente una imagen especificando su origen. + pub fn with(source: image::Source) -> Self { + Image::default().with_source(source) + } + + // **< Image BUILDER >************************************************************************** + + /// Establece el identificador único (`id`) de la imagen. + #[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 a la imagen. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + /// Define las dimensiones de la imagen (auto, ancho/alto, ambos). + #[builder_fn] + pub fn with_size(mut self, size: image::Size) -> Self { + self.size = size; + self + } + + /// Establece el origen de la imagen, influyendo en su disposición en el contenido. + #[builder_fn] + pub fn with_source(mut self, source: image::Source) -> Self { + self.source = source; + self + } + + /// Define el texto alternativo localizado ([`L10n`]) para la imagen. + /// + /// Se recomienda siempre aportar un texto alternativo salvo que la imagen sea puramente + /// decorativa. + #[builder_fn] + pub fn with_alternative(mut self, alt: L10n) -> Self { + self.alt.alter_value(alt); + self + } + + /// Establece el borde de la imagen ([`Border`]). + #[builder_fn] + pub fn with_border(mut self, border: Border) -> Self { + self.border = border; + self + } + + /// Establece esquinas redondeadas para la imagen ([`Rounded`]). + #[builder_fn] + pub fn with_rounded(mut self, rounded: Rounded) -> Self { + self.rounded = rounded; + self + } + + // **< Image GETTERS >************************************************************************** + + /// Devuelve las clases CSS asociadas a la imagen. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve las dimensiones de la imagen. + pub fn size(&self) -> &image::Size { + &self.size + } + + /// Devuelve el origen de la imagen. + pub fn source(&self) -> &image::Source { + &self.source + } + + /// Devuelve el texto alternativo localizado. + pub fn alternative(&self) -> &AttrL10n { + &self.alt + } + + /// Devuelve el borde configurado de la imagen. + pub fn border(&self) -> &Border { + &self.border + } + + /// Devuelve las esquinas redondeadas configuradas para la imagen. + pub fn rounded(&self) -> &Rounded { + &self.rounded + } +} diff --git a/extensions/pagetop-bootsier/src/theme/image/props.rs b/extensions/pagetop-bootsier/src/theme/image/props.rs new file mode 100644 index 00000000..f871de70 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/image/props.rs @@ -0,0 +1,53 @@ +use pagetop::prelude::*; + +// **< Size >*************************************************************************************** + +/// Define las **dimensiones** de una imagen ([`Image`](crate::theme::Image)). +#[derive(AutoDefault)] +pub enum Size { + /// Ajuste automático por defecto. + /// + /// La imagen usa su tamaño natural o se ajusta al contenedor donde se publica. + #[default] + Auto, + /// Establece explícitamente el **ancho y alto** de la imagen. + /// + /// Útil cuando se desea fijar ambas dimensiones de forma exacta. Ten en cuenta que la imagen + /// puede distorsionarse si no se mantiene la proporción original. + Dimensions(UnitValue, UnitValue), + /// Establece sólo el **ancho** de la imagen. + /// + /// La altura se ajusta proporcionalmente de manera automática. + Width(UnitValue), + /// Establece sólo la **altura** de la imagen. + /// + /// El ancho se ajusta proporcionalmente de manera automática. + Height(UnitValue), + /// Establece **el mismo valor** para el ancho y el alto de la imagen. + /// + /// Práctico para forzar rápidamente un área cuadrada. Ten en cuenta que la imagen puede + /// distorsionarse si la original no es cuadrada. + Both(UnitValue), +} + +// **< Source >************************************************************************************* + +/// Especifica la **fuente** para publicar una imagen ([`Image`](crate::theme::Image)). +#[derive(AutoDefault)] +pub enum Source { + /// Imagen con el logotipo de PageTop. + #[default] + Logo(PageTopSvg), + /// Imagen que se adapta automáticamente a su contenedor. + /// + /// El `String` asociado es la URL (o ruta) de la imagen. + Responsive(String), + /// Imagen que aplica el estilo **miniatura** de Bootstrap. + /// + /// El `String` asociado es la URL (o ruta) de la imagen. + Thumbnail(String), + /// Imagen sin clases específicas de Bootstrap, útil para controlar con CSS propio. + /// + /// El `String` asociado es la URL (o ruta) de la imagen. + Plain(String), +} From 80b18cc38063f5de790e1d2d7a888785d3fb25a2 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Wed, 29 Oct 2025 13:47:59 +0100 Subject: [PATCH 229/244] =?UTF-8?q?=E2=9C=A8=20(bootsier):=20A=C3=B1ade=20?= =?UTF-8?q?componente=20`Nav`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Adapta `Dropdown` para poder integrarlo en los menús `Nav`. - Actualiza `Children` para soportar operaciones múltiples. --- extensions/pagetop-bootsier/src/theme.rs | 5 + .../pagetop-bootsier/src/theme/dropdown.rs | 5 +- .../src/theme/dropdown/component.rs | 32 ++- .../src/theme/dropdown/item.rs | 8 +- extensions/pagetop-bootsier/src/theme/nav.rs | 17 ++ .../src/theme/nav/component.rs | 168 ++++++++++++ .../pagetop-bootsier/src/theme/nav/item.rs | 257 ++++++++++++++++++ .../pagetop-bootsier/src/theme/nav/props.rs | 39 +++ .../pagetop-bootsier/src/theme/navbar.rs | 6 - .../pagetop-bootsier/src/theme/navbar/item.rs | 113 -------- .../pagetop-bootsier/src/theme/navbar/nav.rs | 75 ----- src/core/component/children.rs | 103 ++++++- 12 files changed, 602 insertions(+), 226 deletions(-) create mode 100644 extensions/pagetop-bootsier/src/theme/nav.rs create mode 100644 extensions/pagetop-bootsier/src/theme/nav/component.rs create mode 100644 extensions/pagetop-bootsier/src/theme/nav/item.rs create mode 100644 extensions/pagetop-bootsier/src/theme/nav/props.rs delete mode 100644 extensions/pagetop-bootsier/src/theme/navbar/item.rs delete mode 100644 extensions/pagetop-bootsier/src/theme/navbar/nav.rs diff --git a/extensions/pagetop-bootsier/src/theme.rs b/extensions/pagetop-bootsier/src/theme.rs index ece34f06..d34c0a9f 100644 --- a/extensions/pagetop-bootsier/src/theme.rs +++ b/extensions/pagetop-bootsier/src/theme.rs @@ -16,6 +16,11 @@ pub mod image; #[doc(inline)] pub use image::Image; +// Nav. +pub mod nav; +#[doc(inline)] +pub use nav::Nav; + // Navbar. pub mod navbar; #[doc(inline)] diff --git a/extensions/pagetop-bootsier/src/theme/dropdown.rs b/extensions/pagetop-bootsier/src/theme/dropdown.rs index 02df7fd0..eb00e4c8 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown.rs @@ -1,14 +1,11 @@ //! Definiciones para crear menús desplegables [`Dropdown`]. //! //! Cada [`dropdown::Item`](crate::theme::dropdown::Item) representa un elemento individual del -//! desplegable [`Dropdown`], con distintos comportamientos según su finalidad: enlaces de +//! desplegable [`Dropdown`], con distintos comportamientos según su finalidad, como enlaces de //! navegación, botones de acción, encabezados o divisores visuales. //! //! Los ítems pueden estar activos, deshabilitados o abrirse en nueva ventana según su contexto y //! configuración, y permiten incluir etiquetas localizables usando [`L10n`](pagetop::locale::L10n). -//! -//! Su propósito es ofrecer una base uniforme sobre la que construir menús consistentes, adaptados -//! al contexto de cada aplicación. mod props; pub use props::{AutoClose, Direction, MenuAlign, MenuPosition}; diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs index e9d36d7f..984a3e06 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs @@ -10,8 +10,12 @@ use crate::LOCALES_BOOTSIER; /// interacción del usuario. Admite variaciones de tamaño/color del botón, también dirección de /// apertura, alineación o política de cierre. /// -/// Sin título para el botón (ver [`with_button_title()`](Self::with_button_title)) se muestra -/// únicamente la lista de elementos sin ningún botón para interactuar. +/// Si no tiene título (ver [`with_title()`](Self::with_title)) se muestra únicamente la lista de +/// elementos sin ningún botón para interactuar. +/// +/// Si este componente se usa en un menú [`Nav`] (ver [`nav::Item::dropdown()`]) sólo se tendrán en +/// cuenta **el título** (si no existe le asigna uno por defecto) y **la lista de elementos**; el +/// resto de propiedades no afectarán a su representación en [`Nav`]. /// /// # Ejemplo /// @@ -19,7 +23,7 @@ use crate::LOCALES_BOOTSIER; /// # use pagetop::prelude::*; /// # use pagetop_bootsier::prelude::*; /// let dd = Dropdown::new() -/// .with_button_title(L10n::n("Menu")) +/// .with_title(L10n::n("Menu")) /// .with_button_color(ButtonColor::Background(Color::Secondary)) /// .with_auto_close(dropdown::AutoClose::ClickableInside) /// .with_direction(dropdown::Direction::Dropend) @@ -34,7 +38,7 @@ use crate::LOCALES_BOOTSIER; pub struct Dropdown { id : AttrId, classes : AttrClasses, - button_title : L10n, + title : L10n, button_size : ButtonSize, button_color : ButtonColor, button_split : bool, @@ -80,11 +84,11 @@ impl Component for Dropdown { } // Título opcional para el menú desplegable. - let button_title = self.button_title().using(cx); + let title = self.title().using(cx); PrepareMarkup::With(html! { div id=[self.id()] class=[self.classes().get()] { - @if !button_title.is_empty() { + @if !title.is_empty() { @let mut btn_classes = AttrClasses::new([ "btn", &self.button_size().to_string(), @@ -129,7 +133,7 @@ impl Component for Dropdown { type="button" class=[btn_classes.get()] { - (button_title) + (title) } }; // Botón *toggle* que abre/cierra el menú asociado. @@ -176,7 +180,7 @@ impl Component for Dropdown { data-bs-auto-close=[auto_close] aria-expanded="false" { - (button_title) + (title) } ul class=[menu_classes.get()] { (items) } } @@ -206,10 +210,10 @@ impl Dropdown { self } - /// Establece el título del botón. + /// Establece el título del menú desplegable. #[builder_fn] - pub fn with_button_title(mut self, title: L10n) -> Self { - self.button_title = title; + pub fn with_title(mut self, title: L10n) -> Self { + self.title = title; self } @@ -290,9 +294,9 @@ impl Dropdown { &self.classes } - /// Devuelve el título del botón. - pub fn button_title(&self) -> &L10n { - &self.button_title + /// Devuelve el título del menú desplegable. + pub fn title(&self) -> &L10n { + &self.title } /// Devuelve el tamaño configurado del botón. diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/item.rs b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs index 548024c5..1aed83b4 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/item.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs @@ -41,7 +41,7 @@ pub enum ItemKind { /// [`ItemKind`]. /// /// Permite definir identificador, clases de estilo adicionales o tipo de interacción asociada, -/// manteniendo una interfaz común para renderizar todos los ítems del menú. +/// manteniendo una interfaz común para renderizar todos los elementos del menú. #[rustfmt::skip] #[derive(AutoDefault)] pub struct Item { @@ -79,7 +79,7 @@ impl Component for Item { } => { let path = path(cx); let current_path = cx.request().map(|request| request.path()); - let is_current = !*disabled && current_path.map(|p| p == path).unwrap_or(false); + let is_current = !*disabled && current_path.map_or(false, |p| p == path); let mut classes = "dropdown-item".to_string(); if is_current { @@ -200,7 +200,7 @@ impl Item { } } - /// Crea un enlace deshabilitado que se abriría en una nueva ventana. + /// Crea un enlace inicialmente deshabilitado que se abriría en una nueva ventana. pub fn link_blank_disabled(label: L10n, path: FnPathByContext) -> Self { Item { item_kind: ItemKind::Link { @@ -274,7 +274,7 @@ impl Item { &self.classes } - /// Devuelve el tipo de elemento representado por este ítem. + /// Devuelve el tipo de elemento representado por este elemento. pub fn item_kind(&self) -> &ItemKind { &self.item_kind } diff --git a/extensions/pagetop-bootsier/src/theme/nav.rs b/extensions/pagetop-bootsier/src/theme/nav.rs new file mode 100644 index 00000000..b540c323 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/nav.rs @@ -0,0 +1,17 @@ +//! Definiciones para crear menús [`Nav`] o alguna de sus variantes de presentación. +//! +//! Cada [`nav::Item`](crate::theme::nav::Item) representa un elemento individual del menú [`Nav`], +//! con distintos comportamientos según su finalidad, como enlaces de navegación o menús +//! desplegables [`Dropdown`](crate::theme::Dropdown). +//! +//! Los ítems pueden estar activos, deshabilitados o abrirse en nueva ventana según su contexto y +//! configuración, y permiten incluir etiquetas localizables usando [`L10n`](pagetop::locale::L10n). + +mod props; +pub use props::{Kind, Layout}; + +mod component; +pub use component::Nav; + +mod item; +pub use item::{Item, ItemKind}; diff --git a/extensions/pagetop-bootsier/src/theme/nav/component.rs b/extensions/pagetop-bootsier/src/theme/nav/component.rs new file mode 100644 index 00000000..34c33b94 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/nav/component.rs @@ -0,0 +1,168 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +/// Componente para crear un **menú** o alguna de sus variantes ([`nav::Kind`]). +/// +/// Presenta un menú con una lista de elementos usando una vista básica, o alguna de sus variantes +/// como *pestañas* (`Tabs`), *botones* (`Pills`) o *subrayado* (`Underline`). También permite +/// controlar su distribución y orientación ([`nav::Layout`](crate::theme::nav::Layout)). +/// +/// # Ejemplo +/// +/// ```rust +/// # use pagetop::prelude::*; +/// # use pagetop_bootsier::prelude::*; +/// let nav = Nav::tabs() +/// .with_layout(nav::Layout::End) +/// .add_item(nav::Item::link(L10n::n("Home"), |_| "/")) +/// .add_item(nav::Item::link_blank(L10n::n("External"), |_| "https://www.google.es")) +/// .add_item(nav::Item::dropdown( +/// Dropdown::new() +/// .with_title(L10n::n("Options")) +/// .with_items(TypedOp::AddMany(vec![ +/// Typed::with(dropdown::Item::link(L10n::n("Action"), |_| "/action")), +/// Typed::with(dropdown::Item::link(L10n::n("Another action"), |_| "/another")), +/// ])), +/// )) +/// .add_item(nav::Item::link_disabled(L10n::n("Disabled"), |_| "#")); +/// ``` +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Nav { + id : AttrId, + classes : AttrClasses, + items : Children, + nav_kind : nav::Kind, + nav_layout: nav::Layout, +} + +impl Component for Nav { + fn new() -> Self { + Nav::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes( + ClassesOp::Prepend, + [ + "nav", + match self.nav_kind() { + nav::Kind::Default => "", + nav::Kind::Tabs => "nav-tabs", + nav::Kind::Pills => "nav-pills", + nav::Kind::Underline => "nav-underline", + }, + match self.nav_layout() { + nav::Layout::Default => "", + nav::Layout::Start => "justify-content-start", + nav::Layout::Center => "justify-content-center", + nav::Layout::End => "justify-content-end", + nav::Layout::Vertical => "flex-column", + nav::Layout::Fill => "nav-fill", + nav::Layout::Justified => "nav-justified", + }, + ] + .join(" "), + ); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let items = self.items().render(cx); + if items.is_empty() { + return PrepareMarkup::None; + } + + PrepareMarkup::With(html! { + ul id=[self.id()] class=[self.classes().get()] { + (items) + } + }) + } +} + +impl Nav { + /// Crea un `Nav` usando pestañas para los elementos (*Tabs*). + pub fn tabs() -> Self { + Nav::default().with_kind(nav::Kind::Tabs) + } + + /// Crea un `Nav` usando botones para los elementos (*Pills*). + pub fn pills() -> Self { + Nav::default().with_kind(nav::Kind::Pills) + } + + /// Crea un `Nav` usando elementos subrayados (*Underline*). + pub fn underline() -> Self { + Nav::default().with_kind(nav::Kind::Underline) + } + + // **< Nav BUILDER >**************************************************************************** + + /// Establece el identificador único (`id`) del menú. + #[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 menú. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + /// Cambia el estilo del menú (*Tabs*, *Pills*, *Underline* o *Default*). + #[builder_fn] + pub fn with_kind(mut self, kind: nav::Kind) -> Self { + self.nav_kind = kind; + self + } + + /// Selecciona la distribución y orientación del menú. + #[builder_fn] + pub fn with_layout(mut self, layout: nav::Layout) -> Self { + self.nav_layout = layout; + self + } + + /// Añade un nuevo elemento hijo al menú. + pub fn add_item(mut self, item: nav::Item) -> Self { + self.items.add(Child::with(item)); + self + } + + /// Modifica la lista de elementos (`children`) aplicando una operación [`TypedOp`]. + #[builder_fn] + pub fn with_items(mut self, op: TypedOp<nav::Item>) -> Self { + self.items.alter_typed(op); + self + } + + // **< Nav GETTERS >**************************************************************************** + + /// Devuelve las clases CSS asociadas al menú. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el estilo visual seleccionado. + pub fn nav_kind(&self) -> &nav::Kind { + &self.nav_kind + } + + /// Devuelve la distribución y orientación seleccionada. + pub fn nav_layout(&self) -> &nav::Layout { + &self.nav_layout + } + + /// Devuelve la lista de elementos (`children`) del menú. + pub fn items(&self) -> &Children { + &self.items + } +} diff --git a/extensions/pagetop-bootsier/src/theme/nav/item.rs b/extensions/pagetop-bootsier/src/theme/nav/item.rs new file mode 100644 index 00000000..63248f8d --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/nav/item.rs @@ -0,0 +1,257 @@ +use pagetop::prelude::*; + +use crate::prelude::*; +use crate::LOCALES_BOOTSIER; + +// **< ItemKind >*********************************************************************************** + +/// Tipos de [`nav::Item`](crate::theme::nav::Item) disponibles en un menú +/// [`Nav`](crate::theme::Nav). +/// +/// Define internamente la naturaleza del elemento y su comportamiento al mostrarse o interactuar +/// con él. +#[derive(AutoDefault)] +pub enum ItemKind { + /// Elemento vacío, no produce salida. + #[default] + Void, + /// Etiqueta sin comportamiento interactivo. + Label(L10n), + /// Elemento de navegación. Opcionalmente puede abrirse en una nueva ventana y estar + /// inicialmente deshabilitado. + Link { + label: L10n, + path: FnPathByContext, + blank: bool, + disabled: bool, + }, + /// Elemento que despliega un menú [`Dropdown`]. + Dropdown(Typed<Dropdown>), +} + +// **< Item >*************************************************************************************** + +/// Representa un **elemento individual** de un menú [`Nav`](crate::theme::Nav). +/// +/// Cada instancia de [`nav::Item`](crate::theme::nav::Item) se traduce en un componente visible que +/// puede comportarse como texto, enlace, botón o menú desplegable según su [`ItemKind`]. +/// +/// Permite definir identificador, clases de estilo adicionales o tipo de interacción asociada, +/// manteniendo una interfaz común para renderizar todos los elementos del menú. +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Item { + id : AttrId, + classes : AttrClasses, + item_kind: ItemKind, +} + +impl Component for Item { + fn new() -> Self { + Item::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes( + ClassesOp::Prepend, + if matches!(self.item_kind(), ItemKind::Dropdown(_)) { + "nav-item dropdown" + } else { + "nav-item" + }, + ); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + match self.item_kind() { + ItemKind::Void => PrepareMarkup::None, + + ItemKind::Label(label) => PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { + span { + (label.using(cx)) + } + } + }), + + ItemKind::Link { + label, + path, + blank, + disabled, + } => { + let path = path(cx); + let current_path = cx.request().map(|request| request.path()); + let is_current = !*disabled && current_path.map_or(false, |p| p == path); + + let mut classes = "nav-link".to_string(); + if is_current { + classes.push_str(" active"); + } + if *disabled { + classes.push_str(" disabled"); + } + + let href = (!disabled).then_some(path); + let target = (!disabled && *blank).then_some("_blank"); + let rel = (!disabled && *blank).then_some("noopener noreferrer"); + + let aria_current = (href.is_some() && is_current).then_some("page"); + let aria_disabled = disabled.then_some("true"); + + PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { + a + class=(classes) + href=[href] + target=[target] + rel=[rel] + aria-current=[aria_current] + aria-disabled=[aria_disabled] + { + (label.using(cx)) + } + } + }) + } + + ItemKind::Dropdown(menu) => { + if let Some(dd) = menu.borrow() { + let items = dd.items().render(cx); + if items.is_empty() { + return PrepareMarkup::None; + } + let title = dd.title().lookup(cx).unwrap_or_else(|| { + L10n::t("dropdown", &LOCALES_BOOTSIER) + .lookup(cx) + .unwrap_or_else(|| "Dropdown".to_string()) + }); + PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { + a + class="nav-link dropdown-toggle" + data-bs-toggle="dropdown" + href="#" + role="button" + aria-expanded="false" + { + (title) + } + ul class="dropdown-menu" { + (items) + } + } + }) + } else { + PrepareMarkup::None + } + } + } + } +} + +impl Item { + /// Crea un elemento de tipo texto, mostrado sin interacción. + pub fn label(label: L10n) -> Self { + Item { + item_kind: ItemKind::Label(label), + ..Default::default() + } + } + + /// Crea un enlace para la navegación. + pub fn link(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: false, + disabled: false, + }, + ..Default::default() + } + } + + /// Crea un enlace deshabilitado que no permite la interacción. + pub fn link_disabled(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: false, + disabled: true, + }, + ..Default::default() + } + } + + /// Crea un enlace que se abre en una nueva ventana o pestaña. + pub fn link_blank(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: true, + disabled: false, + }, + ..Default::default() + } + } + + /// Crea un enlace inicialmente deshabilitado que se abriría en una nueva ventana. + pub fn link_blank_disabled(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: true, + disabled: true, + }, + ..Default::default() + } + } + + /// Crea un elemento de navegación que contiene un menú desplegable [`Dropdown`]. + /// + /// Sólo se tienen en cuenta **el título** (si no existe le asigna uno por defecto) y **la lista + /// de elementos** del [`Dropdown`]; el resto de propiedades del componente no afectarán a su + /// representación en [`Nav`]. + pub fn dropdown(menu: Dropdown) -> Self { + Item { + item_kind: ItemKind::Dropdown(Typed::with(menu)), + ..Default::default() + } + } + + // **< Item BUILDER >*************************************************************************** + + /// Establece el identificador único (`id`) del elemento. + #[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 elemento. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + // **< Item GETTERS >*************************************************************************** + + /// Devuelve las clases CSS asociadas al elemento. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el tipo de elemento representado por este elemento. + pub fn item_kind(&self) -> &ItemKind { + &self.item_kind + } +} diff --git a/extensions/pagetop-bootsier/src/theme/nav/props.rs b/extensions/pagetop-bootsier/src/theme/nav/props.rs new file mode 100644 index 00000000..bd8ac1e1 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/nav/props.rs @@ -0,0 +1,39 @@ +use pagetop::prelude::*; + +// **< Kind >*************************************************************************************** + +/// Define la variante de presentación de un menú [`Nav`](crate::theme::Nav). +#[derive(AutoDefault)] +pub enum Kind { + /// Estilo por defecto, lista de enlaces flexible y minimalista. + #[default] + Default, + /// Pestañas con borde para cambiar entre secciones. + Tabs, + /// Botones con fondo que resaltan el elemento activo. + Pills, + /// Variante con subrayado del elemento activo, estética ligera. + Underline, +} + +// **< Layout >************************************************************************************* + +/// Distribución y orientación de un menú [`Nav`](crate::theme::Nav). +#[derive(AutoDefault)] +pub enum Layout { + /// Comportamiento por defecto, ancho definido por el contenido y sin alineación forzada. + #[default] + Default, + /// Alinea los elementos al inicio de la fila. + Start, + /// Centra horizontalmente los elementos. + Center, + /// Alinea los elementos al final de la fila. + End, + /// Apila los elementos en columna. + Vertical, + /// Los elementos se expanden para rellenar la fila. + Fill, + /// Todos los elementos ocupan el mismo ancho rellenando la fila. + Justified, +} diff --git a/extensions/pagetop-bootsier/src/theme/navbar.rs b/extensions/pagetop-bootsier/src/theme/navbar.rs index 3745b116..72a3af3d 100644 --- a/extensions/pagetop-bootsier/src/theme/navbar.rs +++ b/extensions/pagetop-bootsier/src/theme/navbar.rs @@ -9,9 +9,3 @@ pub use content::{Content, ContentType}; mod brand; pub use brand::Brand; - -mod nav; -pub use nav::Nav; - -mod item; -pub use item::{Item, ItemType}; diff --git a/extensions/pagetop-bootsier/src/theme/navbar/item.rs b/extensions/pagetop-bootsier/src/theme/navbar/item.rs deleted file mode 100644 index 08a2aeee..00000000 --- a/extensions/pagetop-bootsier/src/theme/navbar/item.rs +++ /dev/null @@ -1,113 +0,0 @@ -use pagetop::prelude::*; - -use crate::theme::Dropdown; - -type Label = L10n; - -#[derive(AutoDefault)] -pub enum ItemType { - #[default] - Void, - Label(Label), - Link(Label, FnPathByContext), - LinkBlank(Label, FnPathByContext), - Dropdown(Typed<Dropdown>), -} - -// Item. - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Item { - item_type: ItemType, -} - -impl Component for Item { - fn new() -> Self { - Item::default() - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let description: Option<String> = None; - - // Obtiene la URL actual desde `cx.request`. - let current_path = cx.request().map(|request| request.path()); - - match self.item_type() { - ItemType::Void => PrepareMarkup::None, - ItemType::Label(label) => PrepareMarkup::With(html! { - li class="nav-item" { - span title=[description] { - //(left_icon) - (label.using(cx)) - //(right_icon) - } - } - }), - ItemType::Link(label, path) => { - let item_path = path(cx); - let (class, aria) = if current_path == Some(item_path) { - ("nav-item active", Some("page")) - } else { - ("nav-item", None) - }; - PrepareMarkup::With(html! { - li class=(class) aria-current=[aria] { - a class="nav-link" href=(item_path) title=[description] { - //(left_icon) - (label.using(cx)) - //(right_icon) - } - } - }) - } - ItemType::LinkBlank(label, path) => { - let item_path = path(cx); - let (class, aria) = if current_path == Some(item_path) { - ("nav-item active", Some("page")) - } else { - ("nav-item", None) - }; - PrepareMarkup::With(html! { - li class=(class) aria-current=[aria] { - a class="nav-link" href=(item_path) title=[description] target="_blank" { - //(left_icon) - (label.using(cx)) - //(right_icon) - } - } - }) - } - ItemType::Dropdown(menu) => PrepareMarkup::With(html! { (menu.render(cx)) }), - } - } -} - -impl Item { - pub fn label(label: L10n) -> Self { - Item { - item_type: ItemType::Label(label), - ..Default::default() - } - } - - pub fn link(label: L10n, path: FnPathByContext) -> Self { - Item { - item_type: ItemType::Link(label, path), - ..Default::default() - } - } - - pub fn link_blank(label: L10n, path: FnPathByContext) -> Self { - Item { - item_type: ItemType::LinkBlank(label, path), - ..Default::default() - } - } - - // Item GETTERS. - - pub fn item_type(&self) -> &ItemType { - &self.item_type - } -} diff --git a/extensions/pagetop-bootsier/src/theme/navbar/nav.rs b/extensions/pagetop-bootsier/src/theme/navbar/nav.rs deleted file mode 100644 index bc03a291..00000000 --- a/extensions/pagetop-bootsier/src/theme/navbar/nav.rs +++ /dev/null @@ -1,75 +0,0 @@ -use pagetop::prelude::*; - -use crate::theme::navbar; - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Nav { - id : AttrId, - classes: AttrClasses, - items : Children, -} - -impl Component for Nav { - fn new() -> Self { - Nav::default() - } - - fn id(&self) -> Option<String> { - self.id.get() - } - - fn setup_before_prepare(&mut self, _cx: &mut Context) { - self.alter_classes(ClassesOp::Prepend, "navbar-nav"); - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let items = self.items().render(cx); - if items.is_empty() { - return PrepareMarkup::None; - } - - PrepareMarkup::With(html! { - ul id=[self.id()] class=[self.classes().get()] { - (items) - } - }) - } -} - -impl Nav { - // Nav BUILDER. - - #[builder_fn] - pub fn with_id(mut self, id: impl AsRef<str>) -> Self { - self.id.alter_value(id); - self - } - - #[builder_fn] - pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { - self.classes.alter_value(op, classes); - self - } - - pub fn with_item(mut self, item: navbar::Item) -> Self { - self.items.add(Child::with(item)); - self - } - - #[builder_fn] - pub fn with_items(mut self, op: TypedOp<navbar::Item>) -> Self { - self.items.alter_typed(op); - self - } - - // Nav GETTERS. - - pub fn classes(&self) -> &AttrClasses { - &self.classes - } - - pub fn items(&self) -> &Children { - &self.items - } -} diff --git a/src/core/component/children.rs b/src/core/component/children.rs index c0c8841e..3b8f2abf 100644 --- a/src/core/component/children.rs +++ b/src/core/component/children.rs @@ -4,6 +4,9 @@ use crate::{builder_fn, AutoDefault, UniqueId}; use parking_lot::RwLock; +pub use parking_lot::RwLockReadGuard as ComponentReadGuard; +pub use parking_lot::RwLockWriteGuard as ComponentWriteGuard; + use std::sync::Arc; use std::vec::IntoIter; @@ -93,6 +96,57 @@ impl<C: Component> Typed<C> { self.0.as_ref().and_then(|c| c.read().id()) } + /// Devuelve una **referencia inmutable** al componente interno. + /// + /// - Devuelve `Some(ComponentReadGuard<C>)` si existe el componente, o `None` si está vacío. + /// - Permite realizar **múltiples lecturas concurrentes**. + /// - Mientras el *guard* esté activo, no se pueden realizar escrituras concurrentes (ver + /// [`borrow_mut`](Self::borrow_mut)). + /// - Se recomienda mantener el *guard* **el menor tiempo posible** para evitar bloqueos + /// innecesarios. + /// + /// # Ejemplo + /// + /// Lectura del nombre del componente: + /// + /// ```rust + /// # use pagetop::prelude::*; + /// let typed = Typed::with(Html::with(|_| html! { "Prueba" })); + /// { + /// if let Some(component) = typed.borrow() { + /// assert_eq!(component.name(), "Html"); + /// } + /// }; // El *guard* se libera aquí, antes del *drop* de `typed`. + /// ``` + pub fn borrow(&self) -> Option<ComponentReadGuard<'_, C>> { + self.0.as_ref().map(|a| a.read()) + } + + /// Obtiene una **referencia mutable exclusiva** al componente interno. + /// + /// - Devuelve `Some(ComponentWriteGuard<C>)` si existe el componente, o `None` si está vacío. + /// - **Exclusivo**: mientras el *guard* esté activo, no habrá otros lectores ni escritores. + /// - Usar sólo para operaciones que **modifican** el estado interno. + /// - Igual que con [`borrow`](Self::borrow), se recomienda mantener el *guard* en un **ámbito + /// reducido**. + /// + /// # Ejemplo + /// + /// Acceso mutable (ámbito corto): + /// + /// ```rust + /// # use pagetop::prelude::*; + /// let typed = Typed::with(Block::new().with_title(L10n::n("Título"))); + /// { + /// if let Some(mut component) = typed.borrow_mut() { + /// component.alter_title(L10n::n("Nuevo título")); + /// } + /// }; // El *guard* se libera aquí, antes del *drop* de `typed`. + /// ``` + pub fn borrow_mut(&self) -> Option<ComponentWriteGuard<'_, C>> { + self.0.as_ref().map(|a| a.write()) + } + // **< Typed RENDER >*************************************************************************** /// Renderiza el componente con el contexto proporcionado. @@ -102,9 +156,9 @@ impl<C: Component> Typed<C> { // **< Typed HELPERS >************************************************************************** - // Convierte el componente tipado en un [`Child`]. + // Método interno para convertir un componente tipado en un [`Child`]. #[inline] - fn into_child(self) -> Child { + fn into(self) -> Child { if let Some(c) = &self.0 { Child(Some(c.clone())) } else { @@ -115,12 +169,14 @@ impl<C: Component> Typed<C> { // ************************************************************************************************* -/// Operaciones con un componente hijo [`Child`] en una lista [`Children`]. +/// Operaciones para componentes hijo [`Child`] en una lista [`Children`]. pub enum ChildOp { Add(Child), + AddMany(Vec<Child>), InsertAfterId(&'static str, Child), InsertBeforeId(&'static str, Child), Prepend(Child), + PrependMany(Vec<Child>), RemoveById(&'static str), ReplaceById(&'static str, Child), Reset, @@ -129,9 +185,11 @@ pub enum ChildOp { /// Operaciones con un componente hijo tipado [`Typed<C>`] en una lista [`Children`]. pub enum TypedOp<C: Component> { Add(Typed<C>), + AddMany(Vec<Typed<C>>), InsertAfterId(&'static str, Typed<C>), InsertBeforeId(&'static str, Typed<C>), Prepend(Typed<C>), + PrependMany(Vec<Typed<C>>), RemoveById(&'static str), ReplaceById(&'static str, Typed<C>), Reset, @@ -172,9 +230,11 @@ impl Children { pub fn with_child(mut self, op: ChildOp) -> Self { match op { ChildOp::Add(any) => self.add(any), + ChildOp::AddMany(many) => self.add_many(many), ChildOp::InsertAfterId(id, any) => self.insert_after_id(id, any), ChildOp::InsertBeforeId(id, any) => self.insert_before_id(id, any), ChildOp::Prepend(any) => self.prepend(any), + ChildOp::PrependMany(many) => self.prepend_many(many), ChildOp::RemoveById(id) => self.remove_by_id(id), ChildOp::ReplaceById(id, any) => self.replace_by_id(id, any), ChildOp::Reset => self.reset(), @@ -183,14 +243,16 @@ impl Children { /// Ejecuta una operación con [`TypedOp`] en la lista. #[builder_fn] - pub fn with_typed<C: Component + Default>(mut self, op: TypedOp<C>) -> Self { + pub fn with_typed<C: Component>(mut self, op: TypedOp<C>) -> Self { match op { - TypedOp::Add(typed) => self.add(typed.into_child()), - TypedOp::InsertAfterId(id, typed) => self.insert_after_id(id, typed.into_child()), - TypedOp::InsertBeforeId(id, typed) => self.insert_before_id(id, typed.into_child()), - TypedOp::Prepend(typed) => self.prepend(typed.into_child()), + TypedOp::Add(typed) => self.add(typed.into()), + TypedOp::AddMany(many) => self.add_many(many.into_iter().map(Typed::<C>::into)), + TypedOp::InsertAfterId(id, typed) => self.insert_after_id(id, typed.into()), + TypedOp::InsertBeforeId(id, typed) => self.insert_before_id(id, typed.into()), + TypedOp::Prepend(typed) => self.prepend(typed.into()), + TypedOp::PrependMany(many) => self.prepend_many(many.into_iter().map(Typed::<C>::into)), TypedOp::RemoveById(id) => self.remove_by_id(id), - TypedOp::ReplaceById(id, typed) => self.replace_by_id(id, typed.into_child()), + TypedOp::ReplaceById(id, typed) => self.replace_by_id(id, typed.into()), TypedOp::Reset => self.reset(), } } @@ -230,7 +292,7 @@ impl Children { /// Devuelve un iterador sobre los componentes hijo con el identificador de tipo ([`UniqueId`]) /// indicado. pub fn iter_by_type_id(&self, type_id: UniqueId) -> impl Iterator<Item = &Child> { - self.0.iter().filter(move |&c| c.type_id() == Some(type_id)) + self.0.iter().filter(move |c| c.type_id() == Some(type_id)) } // **< Children RENDER >************************************************************************ @@ -246,6 +308,16 @@ impl Children { // **< Children HELPERS >*********************************************************************** + // Añade más de un componente hijo al final de la lista (en el orden recibido). + #[inline] + fn add_many<I>(&mut self, iter: I) -> &mut Self + where + I: IntoIterator<Item = Child>, + { + self.0.extend(iter); + self + } + // Inserta un hijo después del componente con el `id` dado, o al final si no se encuentra. #[inline] fn insert_after_id(&mut self, id: impl AsRef<str>, child: Child) -> &mut Self { @@ -275,6 +347,17 @@ impl Children { self } + // Inserta más de un componente hijo al principio de la lista (manteniendo el orden recibido). + #[inline] + fn prepend_many<I>(&mut self, iter: I) -> &mut Self + where + I: IntoIterator<Item = Child>, + { + let buf: Vec<Child> = iter.into_iter().collect(); + self.0.splice(0..0, buf); + self + } + // Elimina el primer hijo con el `id` dado. #[inline] fn remove_by_id(&mut self, id: impl AsRef<str>) -> &mut Self { From 5a00968223c26b1b8de4c2418a44c925b327a972 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 2 Nov 2025 12:40:26 +0100 Subject: [PATCH 230/244] =?UTF-8?q?=E2=9C=A8=20(bootsier):=20A=C3=B1ade=20?= =?UTF-8?q?componente=20`Navbar`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extensions/pagetop-bootsier/build.rs | 3 +- extensions/pagetop-bootsier/src/lib.rs | 2 +- extensions/pagetop-bootsier/src/theme.rs | 2 +- .../pagetop-bootsier/src/theme/navbar.rs | 139 +++++- .../src/theme/navbar/brand.rs | 105 +++-- .../src/theme/navbar/button_toggler.rs | 73 --- .../src/theme/navbar/component.rs | 421 ++++++++++-------- .../src/theme/navbar/content.rs | 69 --- .../pagetop-bootsier/src/theme/navbar/item.rs | 108 +++++ .../src/theme/navbar/props.rs | 64 +++ .../static/js/bootstrap.bundle.min.js | 7 + .../static/js/bootstrap.bundle.min.js.map | 1 + .../static/js/bootstrap.min.js | 7 - .../static/js/bootstrap.min.js.map | 1 - 14 files changed, 615 insertions(+), 387 deletions(-) delete mode 100644 extensions/pagetop-bootsier/src/theme/navbar/button_toggler.rs delete mode 100644 extensions/pagetop-bootsier/src/theme/navbar/content.rs create mode 100644 extensions/pagetop-bootsier/src/theme/navbar/item.rs create mode 100644 extensions/pagetop-bootsier/src/theme/navbar/props.rs create mode 100644 extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js create mode 100644 extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js.map delete mode 100644 extensions/pagetop-bootsier/static/js/bootstrap.min.js delete mode 100644 extensions/pagetop-bootsier/static/js/bootstrap.min.js.map diff --git a/extensions/pagetop-bootsier/build.rs b/extensions/pagetop-bootsier/build.rs index a96301c5..df7a2750 100644 --- a/extensions/pagetop-bootsier/build.rs +++ b/extensions/pagetop-bootsier/build.rs @@ -13,7 +13,8 @@ fn main() -> std::io::Result<()> { } fn bootstrap_js_files(path: &Path) -> bool { + let bootstrap_js = "bootstrap.bundle.min.js"; // No filtra durante el desarrollo, solo en la compilación "release". env::var("PROFILE").unwrap_or_else(|_| "release".to_string()) != "release" - || path.file_name().is_some_and(|n| n == "bootstrap.min.js") + || path.file_name().is_some_and(|f| f == bootstrap_js) } diff --git a/extensions/pagetop-bootsier/src/lib.rs b/extensions/pagetop-bootsier/src/lib.rs index a0e6c703..6df5341c 100644 --- a/extensions/pagetop-bootsier/src/lib.rs +++ b/extensions/pagetop-bootsier/src/lib.rs @@ -127,7 +127,7 @@ impl Theme for Bootsier { .with_weight(-90), )) .alter_assets(ContextOp::AddJavaScript( - JavaScript::defer("/bootsier/js/bootstrap.min.js") + JavaScript::defer("/bootsier/js/bootstrap.bundle.min.js") .with_version(BOOTSTRAP_VERSION) .with_weight(-90), )); diff --git a/extensions/pagetop-bootsier/src/theme.rs b/extensions/pagetop-bootsier/src/theme.rs index d34c0a9f..4c547f6a 100644 --- a/extensions/pagetop-bootsier/src/theme.rs +++ b/extensions/pagetop-bootsier/src/theme.rs @@ -24,7 +24,7 @@ pub use nav::Nav; // Navbar. pub mod navbar; #[doc(inline)] -pub use navbar::{Navbar, NavbarToggler}; +pub use navbar::Navbar; // Offcanvas. pub mod offcanvas; diff --git a/extensions/pagetop-bootsier/src/theme/navbar.rs b/extensions/pagetop-bootsier/src/theme/navbar.rs index 72a3af3d..7b958d7f 100644 --- a/extensions/pagetop-bootsier/src/theme/navbar.rs +++ b/extensions/pagetop-bootsier/src/theme/navbar.rs @@ -1,11 +1,136 @@ -mod component; -pub use component::{Navbar, NavbarToggler, NavbarType}; +//! Definiciones para crear barras de navegación [`Navbar`]. +//! +//! Cada [`navbar::Item`](crate::theme::navbar::Item) representa un elemento individual de la barra +//! de navegación [`Navbar`], con distintos comportamientos según su finalidad, como menús +//! [`Nav`](crate::theme::Nav) o textos localizados usando [`L10n`](pagetop::locale::L10n). +//! +//! También puede mostrar una marca de identidad ([`navbar::Brand`](crate::theme::navbar::Brand)) +//! que identifique la compañía, producto o nombre del proyecto asociado a la solución web. +//! +//! # Ejemplos +//! +//! Barra **simple**, sólo con un menú horizontal: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let navbar = Navbar::simple() +//! .add_item(navbar::Item::nav( +//! Nav::new() +//! .add_item(nav::Item::link(L10n::n("Home"), |_| "/")) +//! .add_item(nav::Item::link(L10n::n("About"), |_| "/about")) +//! .add_item(nav::Item::link(L10n::n("Contact"), |_| "/contact")) +//! )); +//! ``` +//! +//! Barra **colapsable**, con botón de despliegue y contenido en el desplegable cuando colapsa: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let navbar = Navbar::simple_toggle() +//! .with_expand(BreakPoint::MD) +//! .add_item(navbar::Item::nav( +//! Nav::new() +//! .add_item(nav::Item::link(L10n::n("Home"), |_| "/")) +//! .add_item(nav::Item::link_blank(L10n::n("Docs"), |_| "https://docs.example.com")) +//! .add_item(nav::Item::link(L10n::n("Support"), |_| "/support")) +//! )); +//! ``` +//! +//! Barra con **marca de identidad a la izquierda** y menú a la derecha, típica de una cabecera: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let brand = navbar::Brand::new() +//! .with_title(L10n::n("PageTop")) +//! .with_path(Some(|_| "/")); +//! +//! let navbar = Navbar::brand_left(brand) +//! .add_item(navbar::Item::nav( +//! Nav::new() +//! .add_item(nav::Item::link(L10n::n("Home"), |_| "/")) +//! .add_item(nav::Item::dropdown( +//! Dropdown::new() +//! .with_title(L10n::n("Tools")) +//! .add_item(dropdown::Item::link(L10n::n("Generator"), |_| "/tools/gen")) +//! .add_item(dropdown::Item::link(L10n::n("Reports"), |_| "/tools/reports")) +//! )) +//! .add_item(nav::Item::link_disabled(L10n::n("Disabled"), |_| "#")) +//! )); +//! ``` +//! +//! Barra con **botón de despliegue a la izquierda** y **marca de identidad a la derecha**: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let brand = navbar::Brand::new() +//! .with_title(L10n::n("Intranet")) +//! .with_path(Some(|_| "/")); +//! +//! let navbar = Navbar::brand_right(brand) +//! .with_expand(BreakPoint::LG) +//! .add_item(navbar::Item::nav( +//! Nav::pills() +//! .add_item(nav::Item::link(L10n::n("Dashboard"), |_| "/dashboard")) +//! .add_item(nav::Item::link(L10n::n("Users"), |_| "/users")) +//! )); +//! ``` +//! +//! Barra con el **contenido en un *offcanvas***, ideal para dispositivos móviles o menús largos: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let oc = Offcanvas::new() +//! .with_id("main_offcanvas") +//! .with_title(L10n::n("Main menu")) +//! .with_placement(offcanvas::Placement::Start) +//! .with_backdrop(offcanvas::Backdrop::Enabled); +//! +//! let navbar = Navbar::offcanvas(oc) +//! .add_item(navbar::Item::nav( +//! Nav::new() +//! .add_item(nav::Item::link(L10n::n("Home"), |_| "/")) +//! .add_item(nav::Item::link(L10n::n("Profile"), |_| "/profile")) +//! .add_item(nav::Item::dropdown( +//! Dropdown::new() +//! .with_title(L10n::n("More")) +//! .add_item(dropdown::Item::link(L10n::n("Settings"), |_| "/settings")) +//! .add_item(dropdown::Item::link(L10n::n("Help"), |_| "/help")) +//! )) +//! )); +//! ``` +//! +//! Barra **fija arriba**: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let brand = navbar::Brand::new() +//! .with_title(L10n::n("Main App")) +//! .with_path(Some(|_| "/")); +//! +//! let navbar = Navbar::brand_left(brand) +//! .with_position(navbar::Position::FixedTop) +//! .add_item(navbar::Item::nav( +//! Nav::new() +//! .add_item(nav::Item::link(L10n::n("Dashboard"), |_| "/")) +//! .add_item(nav::Item::link(L10n::n("Donors"), |_| "/donors")) +//! .add_item(nav::Item::link(L10n::n("Stock"), |_| "/stock")) +//! )); +//! ``` -mod button_toggler; -pub use button_toggler::ButtonToggler; - -mod content; -pub use content::{Content, ContentType}; +mod props; +pub use props::{Layout, Position}; mod brand; pub use brand::Brand; + +mod component; +pub use component::Navbar; + +mod item; +pub use item::Item; diff --git a/extensions/pagetop-bootsier/src/theme/navbar/brand.rs b/extensions/pagetop-bootsier/src/theme/navbar/brand.rs index cfeb45aa..e969b0e4 100644 --- a/extensions/pagetop-bootsier/src/theme/navbar/brand.rs +++ b/extensions/pagetop-bootsier/src/theme/navbar/brand.rs @@ -2,16 +2,25 @@ use pagetop::prelude::*; use crate::prelude::*; +/// Marca de identidad para mostrar en una barra de navegación [`Navbar`]. +/// +/// Representa la identidad del sitio con una imagen, título y eslogan: +/// +/// - Si hay URL ([`with_path()`](Self::with_path)), el bloque completo actúa como enlace. Por +/// defecto enlaza a la raíz del sitio (`/`). +/// - Si no hay imagen ([`with_image()`](Self::with_image)) ni título +/// ([`with_title()`](Self::with_title)), la marca de identidad no se renderiza. +/// - El eslogan ([`with_slogan()`](Self::with_slogan)) es opcional; por defecto no tiene contenido. #[rustfmt::skip] #[derive(AutoDefault)] pub struct Brand { - id : AttrId, - #[default(_code = "global::SETTINGS.app.name.to_owned()")] - app_name : String, - slogan : AttrL10n, - logo : Typed<Image>, - #[default(_code = "|_| \"/\"")] - home : FnPathByContext, + id : AttrId, + image : Typed<Image>, + #[default(_code = "L10n::n(&global::SETTINGS.app.name)")] + title : L10n, + slogan: L10n, + #[default(_code = "Some(|_| \"/\")")] + path : Option<FnPathByContext>, } impl Component for Brand { @@ -24,81 +33,79 @@ impl Component for Brand { } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let logo = self.logo().render(cx); - let home = self.home()(cx); - let title = &L10n::l("site_home").lookup(cx); + let image = self.image().render(cx); + let title = self.title().using(cx); + if title.is_empty() && image.is_empty() { + return PrepareMarkup::None; + } + let slogan = self.slogan().using(cx); PrepareMarkup::With(html! { - div id=[self.id()] class="branding__container" { - div class="branding__content" { - @if !logo.is_empty() { - a class="branding__logo" href=(home) title=[title] rel="home" { - (logo) - } - } - div class="branding__text" { - a class="branding__name" href=(home) title=[title] rel="home" { - (self.app_name()) - } - @if let Some(slogan) = self.slogan().lookup(cx) { - div class="branding__slogan" { - (slogan) - } - } - } - } + @if let Some(path) = self.path() { + a class="navbar-brand" href=(path(cx)) { (image) (title) (slogan) } + } @else { + span class="navbar-brand" { (image) (title) (slogan) } } }) } } impl Brand { - // Brand BUILDER. + // **< Brand BUILDER >************************************************************************** + /// Establece el identificador único (`id`) de la marca. #[builder_fn] pub fn with_id(mut self, id: impl AsRef<str>) -> Self { self.id.alter_value(id); self } + /// Asigna o quita la imagen de marca. Si se pasa `None`, no se mostrará. #[builder_fn] - pub fn with_app_name(mut self, app_name: impl Into<String>) -> Self { - self.app_name = app_name.into(); + pub fn with_image(mut self, image: Option<Image>) -> Self { + self.image.alter_component(image); self } + /// Establece el título de la identidad de marca. + #[builder_fn] + pub fn with_title(mut self, title: L10n) -> Self { + self.title = title; + self + } + + /// Define el eslogan de la marca. #[builder_fn] pub fn with_slogan(mut self, slogan: L10n) -> Self { - self.slogan.alter_value(slogan); + self.slogan = slogan; self } + /// Define la URL de destino. Si es `None`, la marca no será un enlace. #[builder_fn] - pub fn with_logo(mut self, logo: Option<Image>) -> Self { - self.logo.alter_component(logo); + pub fn with_path(mut self, path: Option<FnPathByContext>) -> Self { + self.path = path; self } - #[builder_fn] - pub fn with_home(mut self, home: FnPathByContext) -> Self { - self.home = home; - self + // **< Brand GETTERS >************************************************************************** + + /// Devuelve la imagen de marca (si la hay). + pub fn image(&self) -> &Typed<Image> { + &self.image } - // Brand GETTERS. - - pub fn app_name(&self) -> &String { - &self.app_name + /// Devuelve el título de la identidad de marca. + pub fn title(&self) -> &L10n { + &self.title } - pub fn slogan(&self) -> &AttrL10n { + /// Devuelve el eslogan de la marca. + pub fn slogan(&self) -> &L10n { &self.slogan } - pub fn logo(&self) -> &Typed<Image> { - &self.logo - } - - pub fn home(&self) -> &FnPathByContext { - &self.home + /// Devuelve la función que resuelve la URL asociada a la marca (si existe). + pub fn path(&self) -> &Option<FnPathByContext> { + &self.path } } diff --git a/extensions/pagetop-bootsier/src/theme/navbar/button_toggler.rs b/extensions/pagetop-bootsier/src/theme/navbar/button_toggler.rs deleted file mode 100644 index 036182a7..00000000 --- a/extensions/pagetop-bootsier/src/theme/navbar/button_toggler.rs +++ /dev/null @@ -1,73 +0,0 @@ -use pagetop::prelude::*; - -use crate::LOCALES_BOOTSIER; - -use std::fmt; - -#[derive(AutoDefault, PartialEq)] -pub(crate) enum Toggle { - #[default] - Collapse, - Offcanvas, -} - -#[rustfmt::skip] -impl fmt::Display for Toggle { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Toggle::Collapse => write!(f, "collapse"), - Toggle::Offcanvas => write!(f, "offcanvas"), - } - } -} - -#[derive(AutoDefault)] -pub struct ButtonToggler; - -impl Component for ButtonToggler { - fn new() -> Self { - ButtonToggler::default() - } - - fn prepare_component(&self, _cx: &mut Context) -> PrepareMarkup { - PrepareMarkup::With(html! { - button - type="button" - class="navbar-toggler" - { - span class="navbar-toggler-icon" {} - } - }) - } -} - -impl ButtonToggler { - // ButtonToggler PRIVATE RENDER. - - pub(crate) fn render( - &self, - cx: &mut Context, - id_content: String, - data_bs_toggle: Toggle, - ) -> Markup { - let id_content_target = join!("#", id_content); - let aria_expanded = if data_bs_toggle == Toggle::Collapse { - Some("false") - } else { - None - }; - html! { - button - type="button" - class="navbar-toggler" - data-bs-toggle=(data_bs_toggle) - data-bs-target=(id_content_target) - aria-controls=(id_content) - aria-expanded=[aria_expanded] - aria-label=[L10n::t("toggle", &LOCALES_BOOTSIER).lookup(cx)] - { - span class="navbar-toggler-icon" {} - } - } - } -} diff --git a/extensions/pagetop-bootsier/src/theme/navbar/component.rs b/extensions/pagetop-bootsier/src/theme/navbar/component.rs index 4a203c3f..fc46175a 100644 --- a/extensions/pagetop-bootsier/src/theme/navbar/component.rs +++ b/extensions/pagetop-bootsier/src/theme/navbar/component.rs @@ -6,32 +6,23 @@ use crate::LOCALES_BOOTSIER; const TOGGLE_COLLAPSE: &str = "collapse"; const TOGGLE_OFFCANVAS: &str = "offcanvas"; -#[derive(AutoDefault)] -pub enum NavbarToggler { - #[default] - Enabled, - Disabled, -} - -#[derive(AutoDefault)] -pub enum NavbarType { - #[default] - None, - Nav(Typed<navbar::Nav>), - Offcanvas(Typed<Offcanvas>), - Text(L10n), -} - +/// Componente para crear una **barra de navegación**. +/// +/// Permite mostrar enlaces, menús y una marca de identidad en distintas disposiciones (simples, con +/// botón de despliegue o dentro de un [`offcanvas`]), controladas por [`navbar::Layout`]. También +/// puede fijarse en la parte superior o inferior del documento mediante [`navbar::Position`]. +/// +/// Ver ejemplos en el módulo [`navbar`]. +/// Si no contiene elementos, el componente **no se renderiza**. #[rustfmt::skip] #[derive(AutoDefault)] pub struct Navbar { - id : AttrId, - classes : AttrClasses, - expand : BreakPoint, - toggler : NavbarToggler, - navbar_type: NavbarType, - contents : Children, - brand : Typed<navbar::Brand>, + id : AttrId, + classes : AttrClasses, + expand : BreakPoint, + layout : navbar::Layout, + position: navbar::Position, + items : Children, } impl Component for Navbar { @@ -49,162 +40,22 @@ impl Component for Navbar { [ "navbar".to_string(), self.expand().try_class("navbar-expand").unwrap_or_default(), + match self.position() { + navbar::Position::Static => "", + navbar::Position::FixedTop => "fixed-top", + navbar::Position::FixedBottom => "fixed-bottom", + navbar::Position::StickyTop => "sticky-top", + navbar::Position::StickyBottom => "sticky-bottom", + } + .to_string(), ] .join(" "), ); } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let id = cx.required_id::<Self>(self.id()); - - let navbar_type = match self.navbar_type() { - NavbarType::None => return PrepareMarkup::None, - NavbarType::Nav(nav) => { - let id_content = join!(id, "-content"); - match self.toggler() { - NavbarToggler::Enabled => self.toggler_wrapper( - TOGGLE_COLLAPSE, - L10n::t("toggle", &LOCALES_BOOTSIER).lookup(cx), - id_content, - self.brand().render(cx), - nav.render(cx), - ), - NavbarToggler::Disabled => nav.render(cx), - } - } - NavbarType::Offcanvas(oc) => { - let id_content = oc.id().unwrap_or_default(); - self.toggler_wrapper( - TOGGLE_OFFCANVAS, - L10n::t("toggle", &LOCALES_BOOTSIER).lookup(cx), - id_content, - self.brand().render(cx), - oc.render(cx), - ) - } - NavbarType::Text(text) => html! { - span class="navbar-text" { - (text.using(cx)) - } - }, - }; - - self.nav_wrapper(id, self.brand().render(cx), navbar_type) - } -} - -impl Navbar { - pub fn with_nav(nav: navbar::Nav) -> Self { - Navbar::default().with_navbar_type(NavbarType::Nav(Typed::with(nav))) - } - - pub fn with_offcanvas(offcanvas: Offcanvas) -> Self { - Navbar::default().with_navbar_type(NavbarType::Offcanvas(Typed::with(offcanvas))) - } - - // Navbar BUILDER. - - #[builder_fn] - pub fn with_id(mut self, id: impl AsRef<str>) -> Self { - self.id.alter_value(id); - self - } - - #[builder_fn] - pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { - self.classes.alter_value(op, classes); - self - } - - #[builder_fn] - pub fn with_expand(mut self, bp: BreakPoint) -> Self { - self.expand = bp; - self - } - - #[builder_fn] - pub fn with_toggler(mut self, toggler: NavbarToggler) -> Self { - self.toggler = toggler; - self - } - - #[builder_fn] - pub fn with_navbar_type(mut self, navbar_type: NavbarType) -> Self { - self.navbar_type = navbar_type; - self - } - - pub fn with_content(mut self, content: navbar::Content) -> Self { - self.contents.add(Child::with(content)); - self - } - - #[builder_fn] - pub fn with_contents(mut self, op: TypedOp<navbar::Content>) -> Self { - self.contents.alter_typed(op); - self - } - - #[builder_fn] - pub fn with_brand(mut self, brand: Option<navbar::Brand>) -> Self { - self.brand.alter_component(brand); - self - } - - // Navbar GETTERS. - - pub fn classes(&self) -> &AttrClasses { - &self.classes - } - - pub fn expand(&self) -> &BreakPoint { - &self.expand - } - - pub fn toggler(&self) -> &NavbarToggler { - &self.toggler - } - - pub fn navbar_type(&self) -> &NavbarType { - &self.navbar_type - } - - pub fn contents(&self) -> &Children { - &self.contents - } - - pub fn brand(&self) -> &Typed<navbar::Brand> { - &self.brand - } - - // Navbar HELPERS. - - fn nav_wrapper(&self, id: String, brand: Markup, content: Markup) -> PrepareMarkup { - if content.is_empty() { - PrepareMarkup::None - } else { - PrepareMarkup::With(html! { - (brand) - nav id=(id) class=[self.classes().get()] { - div class="container-fluid" { - (content) - } - } - }) - } - } - - fn toggler_wrapper( - &self, - data_bs_toggle: &str, - aria_label: Option<String>, - id_content: String, - brand: Markup, - content: Markup, - ) -> Markup { - if content.is_empty() { - html! {} - } else { + // Botón de despliegue (colapso u offcanvas) para la barra. + fn button(cx: &mut Context, data_bs_toggle: &str, id_content: &str) -> Markup { let id_content_target = join!("#", id_content); let aria_expanded = if data_bs_toggle == TOGGLE_COLLAPSE { Some("false") @@ -212,7 +63,6 @@ impl Navbar { None }; html! { - (brand) button type="button" class="navbar-toggler" @@ -220,14 +70,229 @@ impl Navbar { data-bs-target=(id_content_target) aria-controls=(id_content) aria-expanded=[aria_expanded] - aria-label=[aria_label] + aria-label=[L10n::t("toggle", &LOCALES_BOOTSIER).lookup(cx)] { span class="navbar-toggler-icon" {} } - div id=(id_content) class="collapse navbar-collapse" { - (content) - } } } + + // Si no hay contenidos, no tiene sentido mostrar una barra vacía. + let items = self.items().render(cx); + if items.is_empty() { + return PrepareMarkup::None; + } + + // Asegura que la barra tiene un id estable para poder asociarlo al colapso/offcanvas. + let id = cx.required_id::<Self>(self.id()); + + PrepareMarkup::With(html! { + nav id=(id) class=[self.classes().get()] { + div class="container-fluid" { + @match self.layout() { + // Barra más sencilla: sólo contenido. + navbar::Layout::Simple => { + (items) + }, + + // Barra sencilla que se puede contraer/expandir. + navbar::Layout::SimpleToggle => { + @let id_content = join!(id, "-content"); + + (button(cx, TOGGLE_COLLAPSE, &id_content)) + div id=(id_content) class="collapse navbar-collapse" { + (items) + } + }, + + // Barra con marca a la izquierda, siempre visible. + navbar::Layout::SimpleBrandLeft(brand) => { + (brand.render(cx)) + (items) + }, + + // Barra con marca a la izquierda y botón a la derecha. + navbar::Layout::BrandLeft(brand) => { + @let id_content = join!(id, "-content"); + + (brand.render(cx)) + (button(cx, TOGGLE_COLLAPSE, &id_content)) + div id=(id_content) class="collapse navbar-collapse" { + (items) + } + }, + + // Barra con botón a la izquierda y marca a la derecha. + navbar::Layout::BrandRight(brand) => { + @let id_content = join!(id, "-content"); + + (button(cx, TOGGLE_COLLAPSE, &id_content)) + (brand.render(cx)) + div id=(id_content) class="collapse navbar-collapse" { + (items) + } + }, + + // Barra cuyo contenido se muestra en un offcanvas, sin marca. + navbar::Layout::Offcanvas(offcanvas) => { + @let id_content = offcanvas.id().unwrap_or_default(); + + (button(cx, TOGGLE_OFFCANVAS, &id_content)) + @if let Some(oc) = offcanvas.borrow() { + (oc.render_offcanvas(cx, Some(self.items()))) + } + }, + + // Barra con marca a la izquierda y contenido en offcanvas. + navbar::Layout::OffcanvasBrandLeft(brand, offcanvas) => { + @let id_content = offcanvas.id().unwrap_or_default(); + + (brand.render(cx)) + (button(cx, TOGGLE_OFFCANVAS, &id_content)) + @if let Some(oc) = offcanvas.borrow() { + (oc.render_offcanvas(cx, Some(self.items()))) + } + }, + + // Barra con contenido en offcanvas y marca a la derecha. + navbar::Layout::OffcanvasBrandRight(brand, offcanvas) => { + @let id_content = offcanvas.id().unwrap_or_default(); + + (button(cx, TOGGLE_OFFCANVAS, &id_content)) + (brand.render(cx)) + @if let Some(oc) = offcanvas.borrow() { + (oc.render_offcanvas(cx, Some(self.items()))) + } + }, + } + } + } + }) + } +} + +impl Navbar { + /// Crea una barra de navegación **simple**, sin marca y sin botón. + pub fn simple() -> Self { + Navbar::default().with_layout(navbar::Layout::Simple) + } + + /// Crea una barra de navegación **simple pero colapsable**, con botón a la izquierda. + pub fn simple_toggle() -> Self { + Navbar::default().with_layout(navbar::Layout::SimpleToggle) + } + + /// Crea una barra de navegación **con marca a la izquierda**, siempre visible. + pub fn simple_brand_left(brand: navbar::Brand) -> Self { + Navbar::default().with_layout(navbar::Layout::SimpleBrandLeft(Typed::with(brand))) + } + + /// Crea una barra de navegación con **marca a la izquierda** y **botón a la derecha**. + pub fn brand_left(brand: navbar::Brand) -> Self { + Navbar::default().with_layout(navbar::Layout::BrandLeft(Typed::with(brand))) + } + + /// Crea una barra de navegación con **botón a la izquierda** y **marca a la derecha**. + pub fn brand_right(brand: navbar::Brand) -> Self { + Navbar::default().with_layout(navbar::Layout::BrandRight(Typed::with(brand))) + } + + /// Crea una barra de navegación cuyo contenido se muestra en un **offcanvas**. + pub fn offcanvas(oc: Offcanvas) -> Self { + Navbar::default().with_layout(navbar::Layout::Offcanvas(Typed::with(oc))) + } + + /// Crea una barra de navegación con **marca a la izquierda** y contenido en **offcanvas**. + pub fn offcanvas_brand_left(brand: navbar::Brand, oc: Offcanvas) -> Self { + Navbar::default().with_layout(navbar::Layout::OffcanvasBrandLeft( + Typed::with(brand), + Typed::with(oc), + )) + } + + /// Crea una barra de navegación con **marca a la derecha** y contenido en **offcanvas**. + pub fn offcanvas_brand_right(brand: navbar::Brand, oc: Offcanvas) -> Self { + Navbar::default().with_layout(navbar::Layout::OffcanvasBrandRight( + Typed::with(brand), + Typed::with(oc), + )) + } + + // **< Navbar BUILDER >************************************************************************* + + /// Establece el identificador único (`id`) de la barra de navegación. + #[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 a la barra de navegación. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + /// Define a partir de qué punto de ruptura la barra de navegación deja de colapsar. + #[builder_fn] + pub fn with_expand(mut self, bp: BreakPoint) -> Self { + self.expand = bp; + self + } + + /// Define el tipo de disposición que tendrá la barra de navegación. + #[builder_fn] + pub fn with_layout(mut self, layout: navbar::Layout) -> Self { + self.layout = layout; + self + } + + /// Define dónde se mostrará la barra de navegación dentro del documento. + #[builder_fn] + pub fn with_position(mut self, position: navbar::Position) -> Self { + self.position = position; + self + } + + /// Añade un nuevo contenido hijo. + #[inline] + pub fn add_item(mut self, item: navbar::Item) -> Self { + self.items.add(Child::with(item)); + self + } + + /// Modifica la lista de contenidos (`children`) aplicando una operación [`TypedOp`]. + #[builder_fn] + pub fn with_items(mut self, op: TypedOp<navbar::Item>) -> Self { + self.items.alter_typed(op); + self + } + + // **< Navbar GETTERS >************************************************************************* + + /// Devuelve las clases CSS asociadas a la barra de navegación. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el punto de ruptura configurado. + pub fn expand(&self) -> &BreakPoint { + &self.expand + } + + /// Devuelve la disposición configurada para la barra de navegación. + pub fn layout(&self) -> &navbar::Layout { + &self.layout + } + + /// Devuelve la posición configurada para la barra de navegación. + pub fn position(&self) -> &navbar::Position { + &self.position + } + + /// Devuelve la lista de contenidos (`children`). + pub fn items(&self) -> &Children { + &self.items } } diff --git a/extensions/pagetop-bootsier/src/theme/navbar/content.rs b/extensions/pagetop-bootsier/src/theme/navbar/content.rs deleted file mode 100644 index 2efb4a05..00000000 --- a/extensions/pagetop-bootsier/src/theme/navbar/content.rs +++ /dev/null @@ -1,69 +0,0 @@ -use pagetop::prelude::*; - -use crate::theme::navbar; - -#[derive(AutoDefault)] -pub enum ContentType { - #[default] - None, - Brand(Typed<navbar::Brand>), - Nav(Typed<navbar::Nav>), - Text(L10n), -} - -// Item. - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Content { - content: ContentType, -} - -impl Component for Content { - fn new() -> Self { - Content::default() - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - match self.content() { - ContentType::None => PrepareMarkup::None, - ContentType::Brand(brand) => PrepareMarkup::With(html! { - (brand.render(cx)) - }), - ContentType::Nav(nav) => PrepareMarkup::With(html! { - (nav.render(cx)) - }), - ContentType::Text(text) => PrepareMarkup::With(html! { - span class="navbar-text" { - (text.using(cx)) - } - }), - } - } -} - -impl Content { - pub fn brand(content: navbar::Brand) -> Self { - Content { - content: ContentType::Brand(Typed::with(content)), - } - } - - pub fn nav(content: navbar::Nav) -> Self { - Content { - content: ContentType::Nav(Typed::with(content)), - } - } - - pub fn text(content: L10n) -> Self { - Content { - content: ContentType::Text(content), - } - } - - // Content GETTERS. - - pub fn content(&self) -> &ContentType { - &self.content - } -} diff --git a/extensions/pagetop-bootsier/src/theme/navbar/item.rs b/extensions/pagetop-bootsier/src/theme/navbar/item.rs new file mode 100644 index 00000000..f0646406 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar/item.rs @@ -0,0 +1,108 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +/// Elementos que puede contener una barra de navegación [`Navbar`](crate::theme::Navbar). +/// +/// Cada variante determina qué se renderiza y cómo. Estos elementos se colocan **dentro del +/// contenido** de la barra (la parte colapsable, el *offcanvas* o el bloque simple), por lo que son +/// independientes de la marca o del botón que ya pueda definir el propio [`navbar::Layout`]. +#[derive(AutoDefault)] +pub enum Item { + /// Sin contenido, no produce salida. + #[default] + Void, + /// Marca de identidad mostrada dentro del contenido de la barra de navegación. + /// + /// Útil cuando el [`navbar::Layout`] no incluye marca, y se quiere incluir dentro del área + /// colapsable/*offcanvas*. Si el *layout* ya muestra una marca, esta variante no la sustituye, + /// sólo añade otra dentro del bloque de contenidos. + Brand(Typed<navbar::Brand>), + /// Representa un menú de navegación [`Nav`](crate::theme::Nav). + Nav(Typed<Nav>), + /// Representa un texto libre localizado. + Text(L10n), +} + +impl Component for Item { + fn new() -> Self { + Item::default() + } + + fn id(&self) -> Option<String> { + match self { + Self::Void => None, + Self::Brand(brand) => brand.id(), + Self::Nav(nav) => nav.id(), + Self::Text(_) => None, + } + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + match self { + Self::Void => PrepareMarkup::None, + Self::Brand(brand) => PrepareMarkup::With(html! { (brand.render(cx)) }), + Self::Nav(nav) => { + if let Some(nav) = nav.borrow() { + let items = nav.items().render(cx); + if items.is_empty() { + return PrepareMarkup::None; + } + let classes = AttrClasses::new( + [ + "navbar-nav", + match nav.nav_kind() { + nav::Kind::Default => "", + nav::Kind::Tabs => "nav-tabs", + nav::Kind::Pills => "nav-pills", + nav::Kind::Underline => "nav-underline", + }, + match nav.nav_layout() { + nav::Layout::Default => "", + nav::Layout::Start => "justify-content-start", + nav::Layout::Center => "justify-content-center", + nav::Layout::End => "justify-content-end", + nav::Layout::Vertical => "flex-column", + nav::Layout::Fill => "nav-fill", + nav::Layout::Justified => "nav-justified", + }, + ] + .join(" "), + ); + PrepareMarkup::With(html! { + ul id=[nav.id()] class=[classes.get()] { + (items) + } + }) + } else { + PrepareMarkup::None + } + } + Self::Text(text) => PrepareMarkup::With(html! { + span class="navbar-text" { + (text.using(cx)) + } + }), + } + } +} + +impl Item { + /// Crea un elemento de tipo [`navbar::Brand`] para añadir en el contenido de [`Navbar`]. + /// + /// Pensado para barras colapsables u offcanvas donde se quiere que la marca aparezca en la zona + /// desplegable. + pub fn brand(brand: navbar::Brand) -> Self { + Self::Brand(Typed::with(brand)) + } + + /// Crea un elemento de tipo [`Nav`] para añadir al contenido de [`Navbar`]. + pub fn nav(item: Nav) -> Self { + Self::Nav(Typed::with(item)) + } + + /// Crea un elemento de texto localizado, mostrado sin interacción. + pub fn text(item: L10n) -> Self { + Self::Text(item) + } +} diff --git a/extensions/pagetop-bootsier/src/theme/navbar/props.rs b/extensions/pagetop-bootsier/src/theme/navbar/props.rs new file mode 100644 index 00000000..86326574 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar/props.rs @@ -0,0 +1,64 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +// **< Layout >************************************************************************************* + +/// Representa los diferentes tipos de presentación de una barra de navegación [`Navbar`]. +#[derive(AutoDefault)] +pub enum Layout { + /// Barra simple, sin marca de identidad y sin botón de despliegue. + /// + /// La barra de navegación no se colapsa. + #[default] + Simple, + + /// Barra simple, con botón de despliegue a la izquierda y sin marca de identidad. + SimpleToggle, + + /// Barra simple, con marca de identidad a la izquierda y sin botón de despliegue. + /// + /// La barra de navegación no se colapsa. + SimpleBrandLeft(Typed<navbar::Brand>), + + /// Barra con marca de identidad a la izquierda y botón de despliegue a la derecha. + BrandLeft(Typed<navbar::Brand>), + + /// Barra con botón de despliegue a la izquierda y marca de identidad a la derecha. + BrandRight(Typed<navbar::Brand>), + + /// Contenido en [`Offcanvas`], con botón de despliegue a la izquierda y sin marca de identidad. + Offcanvas(Typed<Offcanvas>), + + /// Contenido en [`Offcanvas`], con marca de identidad a la izquierda y botón de despliegue a la + /// derecha. + OffcanvasBrandLeft(Typed<navbar::Brand>, Typed<Offcanvas>), + + /// Contenido en [`Offcanvas`], con botón de despliegue a la izquierda y marca de identidad a la + /// derecha. + OffcanvasBrandRight(Typed<navbar::Brand>, Typed<Offcanvas>), +} + +// **< Position >*********************************************************************************** + +/// Posición global de una barra de navegación [`Navbar`] en el documento. +#[derive(AutoDefault)] +pub enum Position { + /// Barra normal, fluye con el documento. + #[default] + Static, + /// Barra fijada en la parte superior, siempre visible. + /// + /// Puede ser necesario reservar espacio en la parte superior del contenido que fluye debajo + /// para evitar que quede oculto por la barra. + FixedTop, + /// Barra fijada en la parte inferior, siempre visible. + /// + /// Puede ser necesario reservar espacio en la parte inferior del contenido que fluye debajo + /// para evitar que quede oculto por la barra. + FixedBottom, + /// La barra de navegación se fija en la parte superior al hacer *scroll*. + StickyTop, + /// La barra de navegación se fija en la parte inferior al hacer *scroll*. + StickyBottom, +} diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js b/extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js new file mode 100644 index 00000000..0b873693 --- /dev/null +++ b/extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.3.8 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,(t,e)=>`#${CSS.escape(e)}`)),t),s=t=>null==t?`${t}`:Object.prototype.toString.call(t).match(/\s([a-z]+)/i)[1].toLowerCase(),o=t=>{t.dispatchEvent(new Event(i))},r=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),a=t=>r(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,l=t=>{if(!r(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",()=>{for(const t of p)t()}),p.push(e)):e()},_=(t,e=[],i=t)=>"function"==typeof t?t.call(...e):i,b=(t,e,n=!0)=>{if(!n)return void _(t);const s=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),_(t))};e.addEventListener(i,a),setTimeout(()=>{r||o(e)},s)},v=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,A=/::\d+$/,E={};let T=1;const C={mouseenter:"mouseover",mouseleave:"mouseout"},O=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function x(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function k(t){const e=x(t);return t.uidEvent=e,E[e]=E[e]||{},E[e]}function L(t,e,i=null){return Object.values(t).find(t=>t.callable===e&&t.delegationSelector===i)}function S(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=N(t);return O.has(o)||(o=t),[n,s,o]}function D(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=S(e,i,n);if(e in C){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=k(t),c=l[a]||(l[a]={}),h=L(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=x(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return j(s,{delegateTarget:r}),n.oneOff&&P.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return j(n,{delegateTarget:t}),i.oneOff&&P.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function $(t,e,i,n,s){const o=L(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function I(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&$(t,e,i,r.callable,r.delegationSelector)}function N(t){return t=t.replace(w,""),C[t]||t}const P={on(t,e,i,n){D(t,e,i,n,!1)},one(t,e,i,n){D(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=k(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))I(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(A,"");a&&!e.includes(s)||$(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;$(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f();let s=null,o=!0,r=!0,a=!1;e!==N(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=j(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function j(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function M(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function F(t){return t.replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`)}const H={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter(t=>t.startsWith("bs")&&!t.startsWith("bsConfig"));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1),e[i]=M(t.dataset[n])}return e},getDataAttribute:(t,e)=>M(t.getAttribute(`data-bs-${F(e)}`))};class W{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=r(e)?H.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...r(e)?H.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[i,n]of Object.entries(e)){const e=t[i],o=r(e)?"element":s(e);if(!new RegExp(n).test(o))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${i}" provided type "${o}" but expected type "${n}".`)}}}class B extends W{constructor(t,i){super(),(t=a(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),P.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){b(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(a(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.8"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const z=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map(t=>n(t)).join(","):null},R={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter(t=>t.matches(e)),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map(t=>`${t}:not([tabindex^="-"])`).join(",");return this.find(e,t).filter(t=>!c(t)&&l(t))},getSelectorFromElement(t){const e=z(t);return e&&R.findOne(e)?e:null},getElementFromSelector(t){const e=z(t);return e?R.findOne(e):null},getMultipleElementsFromSelector(t){const e=z(t);return e?R.find(e):[]}},q=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;P.on(document,i,`[data-bs-dismiss="${n}"]`,function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const s=R.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()})},V=".bs.alert",K=`close${V}`,Q=`closed${V}`;class X extends B{static get NAME(){return"alert"}close(){if(P.trigger(this._element,K).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback(()=>this._destroyElement(),this._element,t)}_destroyElement(){this._element.remove(),P.trigger(this._element,Q),this.dispose()}static jQueryInterface(t){return this.each(function(){const e=X.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}})}}q(X,"close"),g(X);const Y='[data-bs-toggle="button"]';class U extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each(function(){const e=U.getOrCreateInstance(this);"toggle"===t&&e[t]()})}}P.on(document,"click.bs.button.data-api",Y,t=>{t.preventDefault();const e=t.target.closest(Y);U.getOrCreateInstance(e).toggle()}),g(U);const G=".bs.swipe",J=`touchstart${G}`,Z=`touchmove${G}`,tt=`touchend${G}`,et=`pointerdown${G}`,it=`pointerup${G}`,nt={endCallback:null,leftCallback:null,rightCallback:null},st={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class ot extends W{constructor(t,e){super(),this._element=t,t&&ot.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return nt}static get DefaultType(){return st}static get NAME(){return"swipe"}dispose(){P.off(this._element,G)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),_(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&_(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(P.on(this._element,et,t=>this._start(t)),P.on(this._element,it,t=>this._end(t)),this._element.classList.add("pointer-event")):(P.on(this._element,J,t=>this._start(t)),P.on(this._element,Z,t=>this._move(t)),P.on(this._element,tt,t=>this._end(t)))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const rt=".bs.carousel",at=".data-api",lt="ArrowLeft",ct="ArrowRight",ht="next",dt="prev",ut="left",ft="right",pt=`slide${rt}`,mt=`slid${rt}`,gt=`keydown${rt}`,_t=`mouseenter${rt}`,bt=`mouseleave${rt}`,vt=`dragstart${rt}`,yt=`load${rt}${at}`,wt=`click${rt}${at}`,At="carousel",Et="active",Tt=".active",Ct=".carousel-item",Ot=Tt+Ct,xt={[lt]:ft,[ct]:ut},kt={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Lt={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class St extends B{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=R.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===At&&this.cycle()}static get Default(){return kt}static get DefaultType(){return Lt}static get NAME(){return"carousel"}next(){this._slide(ht)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(dt)}pause(){this._isSliding&&o(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval(()=>this.nextWhenVisible(),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?P.one(this._element,mt,()=>this.cycle()):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void P.one(this._element,mt,()=>this.to(t));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?ht:dt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&P.on(this._element,gt,t=>this._keydown(t)),"hover"===this._config.pause&&(P.on(this._element,_t,()=>this.pause()),P.on(this._element,bt,()=>this._maybeEnableCycle())),this._config.touch&&ot.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of R.find(".carousel-item img",this._element))P.on(t,vt,t=>t.preventDefault());const t={leftCallback:()=>this._slide(this._directionToOrder(ut)),rightCallback:()=>this._slide(this._directionToOrder(ft)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout(()=>this._maybeEnableCycle(),500+this._config.interval))}};this._swipeHelper=new ot(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=xt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=R.findOne(Tt,this._indicatorsElement);e.classList.remove(Et),e.removeAttribute("aria-current");const i=R.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(Et),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===ht,s=e||v(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>P.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(pt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),u(s),i.classList.add(l),s.classList.add(l),this._queueCallback(()=>{s.classList.remove(l,c),s.classList.add(Et),i.classList.remove(Et,c,l),this._isSliding=!1,r(mt)},i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return R.findOne(Ot,this._element)}_getItems(){return R.find(Ct,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return m()?t===ut?dt:ht:t===ut?ht:dt}_orderToDirection(t){return m()?t===dt?ut:ft:t===dt?ft:ut}static jQueryInterface(t){return this.each(function(){const e=St.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)})}}P.on(document,wt,"[data-bs-slide], [data-bs-slide-to]",function(t){const e=R.getElementFromSelector(this);if(!e||!e.classList.contains(At))return;t.preventDefault();const i=St.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===H.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())}),P.on(window,yt,()=>{const t=R.find('[data-bs-ride="carousel"]');for(const e of t)St.getOrCreateInstance(e)}),g(St);const Dt=".bs.collapse",$t=`show${Dt}`,It=`shown${Dt}`,Nt=`hide${Dt}`,Pt=`hidden${Dt}`,jt=`click${Dt}.data-api`,Mt="show",Ft="collapse",Ht="collapsing",Wt=`:scope .${Ft} .${Ft}`,Bt='[data-bs-toggle="collapse"]',zt={parent:null,toggle:!0},Rt={parent:"(null|element)",toggle:"boolean"};class qt extends B{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=R.find(Bt);for(const t of i){const e=R.getSelectorFromElement(t),i=R.find(e).filter(t=>t===this._element);null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return zt}static get DefaultType(){return Rt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter(t=>t!==this._element).map(t=>qt.getOrCreateInstance(t,{toggle:!1}))),t.length&&t[0]._isTransitioning)return;if(P.trigger(this._element,$t).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Ft),this._element.classList.add(Ht),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback(()=>{this._isTransitioning=!1,this._element.classList.remove(Ht),this._element.classList.add(Ft,Mt),this._element.style[e]="",P.trigger(this._element,It)},this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(P.trigger(this._element,Nt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(Ht),this._element.classList.remove(Ft,Mt);for(const t of this._triggerArray){const e=R.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback(()=>{this._isTransitioning=!1,this._element.classList.remove(Ht),this._element.classList.add(Ft),P.trigger(this._element,Pt)},this._element,!0)}_isShown(t=this._element){return t.classList.contains(Mt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=a(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Bt);for(const e of t){const t=R.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=R.find(Wt,this._config.parent);return R.find(t,this._config.parent).filter(t=>!e.includes(t))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each(function(){const i=qt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}})}}P.on(document,jt,Bt,function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of R.getMultipleElementsFromSelector(this))qt.getOrCreateInstance(t,{toggle:!1}).toggle()}),g(qt);var Vt="top",Kt="bottom",Qt="right",Xt="left",Yt="auto",Ut=[Vt,Kt,Qt,Xt],Gt="start",Jt="end",Zt="clippingParents",te="viewport",ee="popper",ie="reference",ne=Ut.reduce(function(t,e){return t.concat([e+"-"+Gt,e+"-"+Jt])},[]),se=[].concat(Ut,[Yt]).reduce(function(t,e){return t.concat([e,e+"-"+Gt,e+"-"+Jt])},[]),oe="beforeRead",re="read",ae="afterRead",le="beforeMain",ce="main",he="afterMain",de="beforeWrite",ue="write",fe="afterWrite",pe=[oe,re,ae,le,ce,he,de,ue,fe];function me(t){return t?(t.nodeName||"").toLowerCase():null}function ge(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function _e(t){return t instanceof ge(t).Element||t instanceof Element}function be(t){return t instanceof ge(t).HTMLElement||t instanceof HTMLElement}function ve(t){return"undefined"!=typeof ShadowRoot&&(t instanceof ge(t).ShadowRoot||t instanceof ShadowRoot)}const ye={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach(function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];be(s)&&me(s)&&(Object.assign(s.style,i),Object.keys(n).forEach(function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)}))})},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach(function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce(function(t,e){return t[e]="",t},{});be(n)&&me(n)&&(Object.assign(n.style,o),Object.keys(s).forEach(function(t){n.removeAttribute(t)}))})}},requires:["computeStyles"]};function we(t){return t.split("-")[0]}var Ae=Math.max,Ee=Math.min,Te=Math.round;function Ce(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map(function(t){return t.brand+"/"+t.version}).join(" "):navigator.userAgent}function Oe(){return!/^((?!chrome|android).)*safari/i.test(Ce())}function xe(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&be(t)&&(s=t.offsetWidth>0&&Te(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&Te(n.height)/t.offsetHeight||1);var r=(_e(t)?ge(t):window).visualViewport,a=!Oe()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function ke(t){var e=xe(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Le(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&ve(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Se(t){return ge(t).getComputedStyle(t)}function De(t){return["table","td","th"].indexOf(me(t))>=0}function $e(t){return((_e(t)?t.ownerDocument:t.document)||window.document).documentElement}function Ie(t){return"html"===me(t)?t:t.assignedSlot||t.parentNode||(ve(t)?t.host:null)||$e(t)}function Ne(t){return be(t)&&"fixed"!==Se(t).position?t.offsetParent:null}function Pe(t){for(var e=ge(t),i=Ne(t);i&&De(i)&&"static"===Se(i).position;)i=Ne(i);return i&&("html"===me(i)||"body"===me(i)&&"static"===Se(i).position)?e:i||function(t){var e=/firefox/i.test(Ce());if(/Trident/i.test(Ce())&&be(t)&&"fixed"===Se(t).position)return null;var i=Ie(t);for(ve(i)&&(i=i.host);be(i)&&["html","body"].indexOf(me(i))<0;){var n=Se(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function je(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function Me(t,e,i){return Ae(t,Ee(e,i))}function Fe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function He(t,e){return e.reduce(function(e,i){return e[i]=t,e},{})}const We={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=we(i.placement),l=je(a),c=[Xt,Qt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Fe("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:He(t,Ut))}(s.padding,i),d=ke(o),u="y"===l?Vt:Xt,f="y"===l?Kt:Qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=Pe(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Me(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Le(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Be(t){return t.split("-")[1]}var ze={top:"auto",right:"auto",bottom:"auto",left:"auto"};function Re(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Xt,y=Vt,w=window;if(c){var A=Pe(i),E="clientHeight",T="clientWidth";A===ge(i)&&"static"!==Se(A=$e(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===Vt||(s===Xt||s===Qt)&&o===Jt)&&(y=Kt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Xt&&(s!==Vt&&s!==Kt||o!==Jt)||(v=Qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&ze),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:Te(i*s)/s||0,y:Te(n*s)/s||0}}({x:f,y:m},ge(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const qe={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:we(e.placement),variation:Be(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,Re(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,Re(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var Ve={passive:!0};const Ke={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=ge(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach(function(t){t.addEventListener("scroll",i.update,Ve)}),a&&l.addEventListener("resize",i.update,Ve),function(){o&&c.forEach(function(t){t.removeEventListener("scroll",i.update,Ve)}),a&&l.removeEventListener("resize",i.update,Ve)}},data:{}};var Qe={left:"right",right:"left",bottom:"top",top:"bottom"};function Xe(t){return t.replace(/left|right|bottom|top/g,function(t){return Qe[t]})}var Ye={start:"end",end:"start"};function Ue(t){return t.replace(/start|end/g,function(t){return Ye[t]})}function Ge(t){var e=ge(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Je(t){return xe($e(t)).left+Ge(t).scrollLeft}function Ze(t){var e=Se(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function ti(t){return["html","body","#document"].indexOf(me(t))>=0?t.ownerDocument.body:be(t)&&Ze(t)?t:ti(Ie(t))}function ei(t,e){var i;void 0===e&&(e=[]);var n=ti(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=ge(n),r=s?[o].concat(o.visualViewport||[],Ze(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(ei(Ie(r)))}function ii(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ni(t,e,i){return e===te?ii(function(t,e){var i=ge(t),n=$e(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Oe();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Je(t),y:l}}(t,i)):_e(e)?function(t,e){var i=xe(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):ii(function(t){var e,i=$e(t),n=Ge(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=Ae(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=Ae(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Je(t),l=-n.scrollTop;return"rtl"===Se(s||i).direction&&(a+=Ae(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}($e(t)))}function si(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?we(s):null,r=s?Be(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case Vt:e={x:a,y:i.y-n.height};break;case Kt:e={x:a,y:i.y+i.height};break;case Qt:e={x:i.x+i.width,y:l};break;case Xt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?je(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Gt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Jt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function oi(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Zt:a,c=i.rootBoundary,h=void 0===c?te:c,d=i.elementContext,u=void 0===d?ee:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Fe("number"!=typeof g?g:He(g,Ut)),b=u===ee?ie:ee,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=ei(Ie(t)),i=["absolute","fixed"].indexOf(Se(t).position)>=0&&be(t)?Pe(t):t;return _e(i)?e.filter(function(t){return _e(t)&&Le(t,i)&&"body"!==me(t)}):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce(function(e,i){var s=ni(t,i,n);return e.top=Ae(s.top,e.top),e.right=Ee(s.right,e.right),e.bottom=Ee(s.bottom,e.bottom),e.left=Ae(s.left,e.left),e},ni(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(_e(y)?y:y.contextElement||$e(t.elements.popper),l,h,r),A=xe(t.elements.reference),E=si({reference:A,element:v,placement:s}),T=ii(Object.assign({},v,E)),C=u===ee?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===ee&&x){var k=x[s];Object.keys(O).forEach(function(t){var e=[Qt,Kt].indexOf(t)>=0?1:-1,i=[Vt,Kt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e})}return O}function ri(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?se:l,h=Be(n),d=h?a?ne:ne.filter(function(t){return Be(t)===h}):Ut,u=d.filter(function(t){return c.indexOf(t)>=0});0===u.length&&(u=d);var f=u.reduce(function(e,i){return e[i]=oi(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[we(i)],e},{});return Object.keys(f).sort(function(t,e){return f[t]-f[e]})}const ai={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=we(g),b=l||(_!==g&&p?function(t){if(we(t)===Yt)return[];var e=Xe(t);return[Ue(t),e,Ue(e)]}(g):[Xe(g)]),v=[g].concat(b).reduce(function(t,i){return t.concat(we(i)===Yt?ri(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)},[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C<v.length;C++){var O=v[C],x=we(O),k=Be(O)===Gt,L=[Vt,Kt].indexOf(x)>=0,S=L?"width":"height",D=oi(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?Qt:Xt:k?Kt:Vt;y[S]>w[S]&&($=Xe($));var I=Xe($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every(function(t){return t})){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find(function(e){var i=A.get(e);if(i)return i.slice(0,t).every(function(t){return t})});if(e)return T=e,"break"},j=p?3:1;j>0&&"break"!==P(j);j--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function li(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ci(t){return[Vt,Qt,Kt,Xt].some(function(e){return t[e]>=0})}const hi={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=oi(e,{elementContext:"reference"}),a=oi(e,{altBoundary:!0}),l=li(r,n),c=li(a,s,o),h=ci(l),d=ci(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},di={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=se.reduce(function(t,i){return t[i]=function(t,e,i){var n=we(t),s=[Xt,Vt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Xt,Qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t},{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ui={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=si({reference:e.rects.reference,element:e.rects.popper,placement:e.placement})},data:{}},fi={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=oi(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=we(e.placement),b=Be(e.placement),v=!b,y=je(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?Vt:Xt,D="y"===y?Kt:Qt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],j=f?-T[$]/2:0,M=b===Gt?E[$]:T[$],F=b===Gt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?ke(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Me(0,E[$],W[$]),V=v?E[$]/2-j-q-z-O.mainAxis:M-q-z-O.mainAxis,K=v?-E[$]/2+j+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&Pe(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Me(f?Ee(N,I+V-Y-X):N,I,f?Ae(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?Vt:Xt,tt="x"===y?Kt:Qt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[Vt,Xt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Me(t,e,i);return n>i?i:n}(at,et,lt):Me(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function pi(t,e,i){void 0===i&&(i=!1);var n,s,o=be(e),r=be(e)&&function(t){var e=t.getBoundingClientRect(),i=Te(e.width)/t.offsetWidth||1,n=Te(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=$e(e),l=xe(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==me(e)||Ze(a))&&(c=(n=e)!==ge(n)&&be(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Ge(n)),be(e)?((h=xe(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Je(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function mi(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach(function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}}),n.push(t)}return t.forEach(function(t){e.set(t.name,t)}),t.forEach(function(t){i.has(t.name)||s(t)}),n}var gi={placement:"bottom",modifiers:[],strategy:"absolute"};function _i(){for(var t=arguments.length,e=new Array(t),i=0;i<t;i++)e[i]=arguments[i];return!e.some(function(t){return!(t&&"function"==typeof t.getBoundingClientRect)})}function bi(t){void 0===t&&(t={});var e=t,i=e.defaultModifiers,n=void 0===i?[]:i,s=e.defaultOptions,o=void 0===s?gi:s;return function(t,e,i){void 0===i&&(i=o);var s,r,a={placement:"bottom",orderedModifiers:[],options:Object.assign({},gi,o),modifiersData:{},elements:{reference:t,popper:e},attributes:{},styles:{}},l=[],c=!1,h={state:a,setOptions:function(i){var s="function"==typeof i?i(a.options):i;d(),a.options=Object.assign({},o,a.options,s),a.scrollParents={reference:_e(t)?ei(t):t.contextElement?ei(t.contextElement):[],popper:ei(e)};var r,c,u=function(t){var e=mi(t);return pe.reduce(function(t,i){return t.concat(e.filter(function(t){return t.phase===i}))},[])}((r=[].concat(n,a.options.modifiers),c=r.reduce(function(t,e){var i=t[e.name];return t[e.name]=i?Object.assign({},i,e,{options:Object.assign({},i.options,e.options),data:Object.assign({},i.data,e.data)}):e,t},{}),Object.keys(c).map(function(t){return c[t]})));return a.orderedModifiers=u.filter(function(t){return t.enabled}),a.orderedModifiers.forEach(function(t){var e=t.name,i=t.options,n=void 0===i?{}:i,s=t.effect;if("function"==typeof s){var o=s({state:a,name:e,instance:h,options:n});l.push(o||function(){})}}),h.update()},forceUpdate:function(){if(!c){var t=a.elements,e=t.reference,i=t.popper;if(_i(e,i)){a.rects={reference:pi(e,Pe(i),"fixed"===a.options.strategy),popper:ke(i)},a.reset=!1,a.placement=a.options.placement,a.orderedModifiers.forEach(function(t){return a.modifiersData[t.name]=Object.assign({},t.data)});for(var n=0;n<a.orderedModifiers.length;n++)if(!0!==a.reset){var s=a.orderedModifiers[n],o=s.fn,r=s.options,l=void 0===r?{}:r,d=s.name;"function"==typeof o&&(a=o({state:a,options:l,name:d,instance:h})||a)}else a.reset=!1,n=-1}}},update:(s=function(){return new Promise(function(t){h.forceUpdate(),t(a)})},function(){return r||(r=new Promise(function(t){Promise.resolve().then(function(){r=void 0,t(s())})})),r}),destroy:function(){d(),c=!0}};if(!_i(t,e))return h;function d(){l.forEach(function(t){return t()}),l=[]}return h.setOptions(i).then(function(t){!c&&i.onFirstUpdate&&i.onFirstUpdate(t)}),h}}var vi=bi(),yi=bi({defaultModifiers:[Ke,ui,qe,ye]}),wi=bi({defaultModifiers:[Ke,ui,qe,ye,di,ai,fi,We,hi]});const Ai=Object.freeze(Object.defineProperty({__proto__:null,afterMain:he,afterRead:ae,afterWrite:fe,applyStyles:ye,arrow:We,auto:Yt,basePlacements:Ut,beforeMain:le,beforeRead:oe,beforeWrite:de,bottom:Kt,clippingParents:Zt,computeStyles:qe,createPopper:wi,createPopperBase:vi,createPopperLite:yi,detectOverflow:oi,end:Jt,eventListeners:Ke,flip:ai,hide:hi,left:Xt,main:ce,modifierPhases:pe,offset:di,placements:se,popper:ee,popperGenerator:bi,popperOffsets:ui,preventOverflow:fi,read:re,reference:ie,right:Qt,start:Gt,top:Vt,variationPlacements:ne,viewport:te,write:ue},Symbol.toStringTag,{value:"Module"})),Ei="dropdown",Ti=".bs.dropdown",Ci=".data-api",Oi="ArrowUp",xi="ArrowDown",ki=`hide${Ti}`,Li=`hidden${Ti}`,Si=`show${Ti}`,Di=`shown${Ti}`,$i=`click${Ti}${Ci}`,Ii=`keydown${Ti}${Ci}`,Ni=`keyup${Ti}${Ci}`,Pi="show",ji='[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)',Mi=`${ji}.${Pi}`,Fi=".dropdown-menu",Hi=m()?"top-end":"top-start",Wi=m()?"top-start":"top-end",Bi=m()?"bottom-end":"bottom-start",zi=m()?"bottom-start":"bottom-end",Ri=m()?"left-start":"right-start",qi=m()?"right-start":"left-start",Vi={autoClose:!0,boundary:"clippingParents",display:"dynamic",offset:[0,2],popperConfig:null,reference:"toggle"},Ki={autoClose:"(boolean|string)",boundary:"(string|element)",display:"string",offset:"(array|string|function)",popperConfig:"(null|object|function)",reference:"(string|element|object)"};class Qi extends B{constructor(t,e){super(t,e),this._popper=null,this._parent=this._element.parentNode,this._menu=R.next(this._element,Fi)[0]||R.prev(this._element,Fi)[0]||R.findOne(Fi,this._parent),this._inNavbar=this._detectNavbar()}static get Default(){return Vi}static get DefaultType(){return Ki}static get NAME(){return Ei}toggle(){return this._isShown()?this.hide():this.show()}show(){if(c(this._element)||this._isShown())return;const t={relatedTarget:this._element};if(!P.trigger(this._element,Si,t).defaultPrevented){if(this._createPopper(),"ontouchstart"in document.documentElement&&!this._parent.closest(".navbar-nav"))for(const t of[].concat(...document.body.children))P.on(t,"mouseover",d);this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Pi),this._element.classList.add(Pi),P.trigger(this._element,Di,t)}}hide(){if(c(this._element)||!this._isShown())return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){if(!P.trigger(this._element,ki,t).defaultPrevented){if("ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))P.off(t,"mouseover",d);this._popper&&this._popper.destroy(),this._menu.classList.remove(Pi),this._element.classList.remove(Pi),this._element.setAttribute("aria-expanded","false"),H.removeDataAttribute(this._menu,"popper"),P.trigger(this._element,Li,t)}}_getConfig(t){if("object"==typeof(t=super._getConfig(t)).reference&&!r(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ei.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(){if(void 0===Ai)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org/docs/v2/)");let t=this._element;"parent"===this._config.reference?t=this._parent:r(this._config.reference)?t=a(this._config.reference):"object"==typeof this._config.reference&&(t=this._config.reference);const e=this._getPopperConfig();this._popper=wi(t,this._menu,e)}_isShown(){return this._menu.classList.contains(Pi)}_getPlacement(){const t=this._parent;if(t.classList.contains("dropend"))return Ri;if(t.classList.contains("dropstart"))return qi;if(t.classList.contains("dropup-center"))return"top";if(t.classList.contains("dropdown-center"))return"bottom";const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?Wi:Hi:e?zi:Bi}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(H.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..._(this._config.popperConfig,[void 0,t])}}_selectMenuItem({key:t,target:e}){const i=R.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(t=>l(t));i.length&&v(i,e,t===xi,!i.includes(e)).focus()}static jQueryInterface(t){return this.each(function(){const e=Qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}})}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=R.find(Mi);for(const i of e){const e=Qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Oi,xi].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(ji)?this:R.prev(this,ji)[0]||R.next(this,ji)[0]||R.findOne(ji,t.delegateTarget.parentNode),o=Qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}P.on(document,Ii,ji,Qi.dataApiKeydownHandler),P.on(document,Ii,Fi,Qi.dataApiKeydownHandler),P.on(document,$i,Qi.clearMenus),P.on(document,Ni,Qi.clearMenus),P.on(document,$i,ji,function(t){t.preventDefault(),Qi.getOrCreateInstance(this).toggle()}),g(Qi);const Xi="backdrop",Yi="show",Ui=`mousedown.bs.${Xi}`,Gi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Ji={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Zi extends W{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Gi}static get DefaultType(){return Ji}static get NAME(){return Xi}show(t){if(!this._config.isVisible)return void _(t);this._append();const e=this._getElement();this._config.isAnimated&&u(e),e.classList.add(Yi),this._emulateAnimation(()=>{_(t)})}hide(t){this._config.isVisible?(this._getElement().classList.remove(Yi),this._emulateAnimation(()=>{this.dispose(),_(t)})):_(t)}dispose(){this._isAppended&&(P.off(this._element,Ui),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=a(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),P.on(t,Ui,()=>{_(this._config.clickCallback)}),this._isAppended=!0}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const tn=".bs.focustrap",en=`focusin${tn}`,nn=`keydown.tab${tn}`,sn="backward",on={autofocus:!0,trapElement:null},rn={autofocus:"boolean",trapElement:"element"};class an extends W{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return on}static get DefaultType(){return rn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),P.off(document,tn),P.on(document,en,t=>this._handleFocusin(t)),P.on(document,nn,t=>this._handleKeydown(t)),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,P.off(document,tn))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=R.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===sn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?sn:"forward")}}const ln=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",cn=".sticky-top",hn="padding-right",dn="margin-right";class un{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,hn,e=>e+t),this._setElementAttributes(ln,hn,e=>e+t),this._setElementAttributes(cn,dn,e=>e-t)}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,hn),this._resetElementAttributes(ln,hn),this._resetElementAttributes(cn,dn)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)})}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&H.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,t=>{const i=H.getDataAttribute(t,e);null!==i?(H.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)})}_applyManipulationCallback(t,e){if(r(t))e(t);else for(const i of R.find(t,this._element))e(i)}}const fn=".bs.modal",pn=`hide${fn}`,mn=`hidePrevented${fn}`,gn=`hidden${fn}`,_n=`show${fn}`,bn=`shown${fn}`,vn=`resize${fn}`,yn=`click.dismiss${fn}`,wn=`mousedown.dismiss${fn}`,An=`keydown.dismiss${fn}`,En=`click${fn}.data-api`,Tn="modal-open",Cn="show",On="modal-static",xn={backdrop:!0,focus:!0,keyboard:!0},kn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class Ln extends B{constructor(t,e){super(t,e),this._dialog=R.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new un,this._addEventListeners()}static get Default(){return xn}static get DefaultType(){return kn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||P.trigger(this._element,_n,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Tn),this._adjustDialog(),this._backdrop.show(()=>this._showElement(t)))}hide(){this._isShown&&!this._isTransitioning&&(P.trigger(this._element,pn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(Cn),this._queueCallback(()=>this._hideModal(),this._element,this._isAnimated())))}dispose(){P.off(window,fn),P.off(this._dialog,fn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Zi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new an({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=R.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),u(this._element),this._element.classList.add(Cn),this._queueCallback(()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,P.trigger(this._element,bn,{relatedTarget:t})},this._dialog,this._isAnimated())}_addEventListeners(){P.on(this._element,An,t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())}),P.on(window,vn,()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()}),P.on(this._element,wn,t=>{P.one(this._element,yn,e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())})})}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide(()=>{document.body.classList.remove(Tn),this._resetAdjustments(),this._scrollBar.reset(),P.trigger(this._element,gn)})}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(P.trigger(this._element,mn).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(On)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(On),this._queueCallback(()=>{this._element.classList.remove(On),this._queueCallback(()=>{this._element.style.overflowY=e},this._dialog)},this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=m()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=m()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each(function(){const i=Ln.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}})}}P.on(document,En,'[data-bs-toggle="modal"]',function(t){const e=R.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),P.one(e,_n,t=>{t.defaultPrevented||P.one(e,gn,()=>{l(this)&&this.focus()})});const i=R.findOne(".modal.show");i&&Ln.getInstance(i).hide(),Ln.getOrCreateInstance(e).toggle(this)}),q(Ln),g(Ln);const Sn=".bs.offcanvas",Dn=".data-api",$n=`load${Sn}${Dn}`,In="show",Nn="showing",Pn="hiding",jn=".offcanvas.show",Mn=`show${Sn}`,Fn=`shown${Sn}`,Hn=`hide${Sn}`,Wn=`hidePrevented${Sn}`,Bn=`hidden${Sn}`,zn=`resize${Sn}`,Rn=`click${Sn}${Dn}`,qn=`keydown.dismiss${Sn}`,Vn={backdrop:!0,keyboard:!0,scroll:!1},Kn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class Qn extends B{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return Vn}static get DefaultType(){return Kn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||P.trigger(this._element,Mn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new un).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Nn),this._queueCallback(()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(In),this._element.classList.remove(Nn),P.trigger(this._element,Fn,{relatedTarget:t})},this._element,!0))}hide(){this._isShown&&(P.trigger(this._element,Hn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(Pn),this._backdrop.hide(),this._queueCallback(()=>{this._element.classList.remove(In,Pn),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new un).reset(),P.trigger(this._element,Bn)},this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Zi({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():P.trigger(this._element,Wn)}:null})}_initializeFocusTrap(){return new an({trapElement:this._element})}_addEventListeners(){P.on(this._element,qn,t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():P.trigger(this._element,Wn))})}static jQueryInterface(t){return this.each(function(){const e=Qn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}})}}P.on(document,Rn,'[data-bs-toggle="offcanvas"]',function(t){const e=R.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;P.one(e,Bn,()=>{l(this)&&this.focus()});const i=R.findOne(jn);i&&i!==e&&Qn.getInstance(i).hide(),Qn.getOrCreateInstance(e).toggle(this)}),P.on(window,$n,()=>{for(const t of R.find(jn))Qn.getOrCreateInstance(t).show()}),P.on(window,zn,()=>{for(const t of R.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&Qn.getOrCreateInstance(t).hide()}),q(Qn),g(Qn);const Xn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Yn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Un=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Gn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Yn.has(i)||Boolean(Un.test(t.nodeValue)):e.filter(t=>t instanceof RegExp).some(t=>t.test(i))},Jn={allowList:Xn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"<div></div>"},Zn={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},ts={entry:"(string|element|function|null)",selector:"(string|element)"};class es extends W{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Jn}static get DefaultType(){return Zn}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map(t=>this._resolvePossibleFunction(t)).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},ts)}_setContent(t,e,i){const n=R.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?r(e)?this._putElementInTemplate(a(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Gn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return _(t,[void 0,this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const is=new Set(["sanitize","allowList","sanitizeFn"]),ns="fade",ss="show",os=".tooltip-inner",rs=".modal",as="hide.bs.modal",ls="hover",cs="focus",hs="click",ds={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},us={allowList:Xn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',title:"",trigger:"hover focus"},fs={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class ps extends B{constructor(t,e){if(void 0===Ai)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org/docs/v2/)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return us}static get DefaultType(){return fs}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),P.off(this._element.closest(rs),as,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=P.trigger(this._element,this.constructor.eventName("show")),e=(h(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),P.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(ss),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))P.on(t,"mouseover",d);this._queueCallback(()=>{P.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1},this.tip,this._isAnimated())}hide(){if(this._isShown()&&!P.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(ss),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))P.off(t,"mouseover",d);this._activeTrigger[hs]=!1,this._activeTrigger[cs]=!1,this._activeTrigger[ls]=!1,this._isHovered=null,this._queueCallback(()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),P.trigger(this._element,this.constructor.eventName("hidden")))},this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ns,ss),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ns),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new es({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{[os]:this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ns)}_isShown(){return this.tip&&this.tip.classList.contains(ss)}_createPopper(t){const e=_(this._config.placement,[this,t,this._element]),i=ds[e.toUpperCase()];return wi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return _(t,[this._element,this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,..._(this._config.popperConfig,[void 0,e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)P.on(this._element,this.constructor.eventName("click"),this._config.selector,t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger[hs]=!(e._isShown()&&e._activeTrigger[hs]),e.toggle()});else if("manual"!==e){const t=e===ls?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ls?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");P.on(this._element,t,this._config.selector,t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?cs:ls]=!0,e._enter()}),P.on(this._element,i,this._config.selector,t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?cs:ls]=e._element.contains(t.relatedTarget),e._leave()})}this._hideModalHandler=()=>{this._element&&this.hide()},P.on(this._element.closest(rs),as,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout(()=>{this._isHovered&&this.show()},this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout(()=>{this._isHovered||this.hide()},this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=H.getDataAttributes(this._element);for(const t of Object.keys(e))is.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:a(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each(function(){const e=ps.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}})}}g(ps);const ms=".popover-header",gs=".popover-body",_s={...ps.Default,content:"",offset:[0,8],placement:"right",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>',trigger:"click"},bs={...ps.DefaultType,content:"(null|string|element|function)"};class vs extends ps{static get Default(){return _s}static get DefaultType(){return bs}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{[ms]:this._getTitle(),[gs]:this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each(function(){const e=vs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}})}}g(vs);const ys=".bs.scrollspy",ws=`activate${ys}`,As=`click${ys}`,Es=`load${ys}.data-api`,Ts="active",Cs="[href]",Os=".nav-link",xs=`${Os}, .nav-item > ${Os}, .list-group-item`,ks={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},Ls={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Ss extends B{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ks}static get DefaultType(){return Ls}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=a(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map(t=>Number.parseFloat(t))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(P.off(this._config.target,As),P.on(this._config.target,As,Cs,t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}}))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver(t=>this._observerCallback(t),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=R.find(Cs,this._config.target);for(const e of t){if(!e.hash||c(e))continue;const t=R.findOne(decodeURI(e.hash),this._element);l(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(Ts),this._activateParents(t),P.trigger(this._element,ws,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))R.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(Ts);else for(const e of R.parents(t,".nav, .list-group"))for(const t of R.prev(e,xs))t.classList.add(Ts)}_clearActiveClass(t){t.classList.remove(Ts);const e=R.find(`${Cs}.${Ts}`,t);for(const t of e)t.classList.remove(Ts)}static jQueryInterface(t){return this.each(function(){const e=Ss.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}})}}P.on(window,Es,()=>{for(const t of R.find('[data-bs-spy="scroll"]'))Ss.getOrCreateInstance(t)}),g(Ss);const Ds=".bs.tab",$s=`hide${Ds}`,Is=`hidden${Ds}`,Ns=`show${Ds}`,Ps=`shown${Ds}`,js=`click${Ds}`,Ms=`keydown${Ds}`,Fs=`load${Ds}`,Hs="ArrowLeft",Ws="ArrowRight",Bs="ArrowUp",zs="ArrowDown",Rs="Home",qs="End",Vs="active",Ks="fade",Qs="show",Xs=".dropdown-toggle",Ys=`:not(${Xs})`,Us='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Gs=`.nav-link${Ys}, .list-group-item${Ys}, [role="tab"]${Ys}, ${Us}`,Js=`.${Vs}[data-bs-toggle="tab"], .${Vs}[data-bs-toggle="pill"], .${Vs}[data-bs-toggle="list"]`;class Zs extends B{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),P.on(this._element,Ms,t=>this._keydown(t)))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?P.trigger(e,$s,{relatedTarget:t}):null;P.trigger(t,Ns,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Vs),this._activate(R.getElementFromSelector(t)),this._queueCallback(()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),P.trigger(t,Ps,{relatedTarget:e})):t.classList.add(Qs)},t,t.classList.contains(Ks)))}_deactivate(t,e){t&&(t.classList.remove(Vs),t.blur(),this._deactivate(R.getElementFromSelector(t)),this._queueCallback(()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),P.trigger(t,Is,{relatedTarget:e})):t.classList.remove(Qs)},t,t.classList.contains(Ks)))}_keydown(t){if(![Hs,Ws,Bs,zs,Rs,qs].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter(t=>!c(t));let i;if([Rs,qs].includes(t.key))i=e[t.key===Rs?0:e.length-1];else{const n=[Ws,zs].includes(t.key);i=v(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Zs.getOrCreateInstance(i).show())}_getChildren(){return R.find(Gs,this._parent)}_getActiveElem(){return this._getChildren().find(t=>this._elemIsActive(t))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=R.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=R.findOne(t,i);s&&s.classList.toggle(n,e)};n(Xs,Vs),n(".dropdown-menu",Qs),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Vs)}_getInnerElement(t){return t.matches(Gs)?t:R.findOne(Gs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each(function(){const e=Zs.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}})}}P.on(document,js,Us,function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||Zs.getOrCreateInstance(this).show()}),P.on(window,Fs,()=>{for(const t of R.find(Js))Zs.getOrCreateInstance(t)}),g(Zs);const to=".bs.toast",eo=`mouseover${to}`,io=`mouseout${to}`,no=`focusin${to}`,so=`focusout${to}`,oo=`hide${to}`,ro=`hidden${to}`,ao=`show${to}`,lo=`shown${to}`,co="hide",ho="show",uo="showing",fo={animation:"boolean",autohide:"boolean",delay:"number"},po={animation:!0,autohide:!0,delay:5e3};class mo extends B{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return po}static get DefaultType(){return fo}static get NAME(){return"toast"}show(){P.trigger(this._element,ao).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(co),u(this._element),this._element.classList.add(ho,uo),this._queueCallback(()=>{this._element.classList.remove(uo),P.trigger(this._element,lo),this._maybeScheduleHide()},this._element,this._config.animation))}hide(){this.isShown()&&(P.trigger(this._element,oo).defaultPrevented||(this._element.classList.add(uo),this._queueCallback(()=>{this._element.classList.add(co),this._element.classList.remove(uo,ho),P.trigger(this._element,ro)},this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(ho),super.dispose()}isShown(){return this._element.classList.contains(ho)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout(()=>{this.hide()},this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){P.on(this._element,eo,t=>this._onInteraction(t,!0)),P.on(this._element,io,t=>this._onInteraction(t,!1)),P.on(this._element,no,t=>this._onInteraction(t,!0)),P.on(this._element,so,t=>this._onInteraction(t,!1))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each(function(){const e=mo.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}})}}return q(mo),g(mo),{Alert:X,Button:U,Carousel:St,Collapse:qt,Dropdown:Qi,Modal:Ln,Offcanvas:Qn,Popover:vs,ScrollSpy:Ss,Tab:Zs,Toast:mo,Tooltip:ps}}); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js.map b/extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js.map new file mode 100644 index 00000000..3e678d4c --- /dev/null +++ b/extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js.map @@ -0,0 +1 @@ +{"version":3,"names":["elementMap","Map","Data","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete","TRANSITION_END","parseSelector","selector","window","CSS","escape","replace","match","id","toType","object","Object","prototype","toString","call","toLowerCase","triggerTransitionEnd","dispatchEvent","Event","isElement","jquery","nodeType","getElement","length","document","querySelector","isVisible","getClientRects","elementIsVisible","getComputedStyle","getPropertyValue","closedDetails","closest","summary","parentNode","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","getAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","noop","reflow","offsetHeight","getjQuery","jQuery","body","DOMContentLoadedCallbacks","isRTL","dir","defineJQueryPlugin","plugin","callback","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","readyState","addEventListener","push","execute","possibleCallback","args","defaultValue","executeAfterTransition","transitionElement","waitForTransition","emulatedDuration","transitionDuration","transitionDelay","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","split","getTransitionDurationFromElement","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","listLength","index","indexOf","Math","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","nativeEvents","Set","makeEventUid","uid","getElementEvents","findHandler","events","callable","delegationSelector","values","find","event","normalizeParameters","originalTypeEvent","delegationFunction","isDelegated","typeEvent","getTypeEvent","addHandler","oneOff","wrapFunction","relatedTarget","delegateTarget","this","handlers","previousFunction","domElements","querySelectorAll","domElement","hydrateObj","EventHandler","off","type","apply","bootstrapDelegationHandler","bootstrapHandler","removeHandler","Boolean","removeNamespacedHandlers","namespace","storeElementEvent","handlerKey","entries","includes","on","one","inNamespace","isNamespace","startsWith","elementEvent","slice","keyHandlers","trigger","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","evt","cancelable","preventDefault","obj","meta","value","_unused","defineProperty","configurable","normalizeData","JSON","parse","decodeURIComponent","normalizeDataKey","chr","Manipulator","setDataAttribute","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","dataset","filter","pureKey","charAt","getDataAttribute","Config","Default","DefaultType","Error","_getConfig","config","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","jsonConfig","constructor","configTypes","property","expectedTypes","valueType","RegExp","test","TypeError","toUpperCase","BaseComponent","super","_element","_config","DATA_KEY","dispose","EVENT_KEY","propertyName","getOwnPropertyNames","_queueCallback","isAnimated","getInstance","getOrCreateInstance","VERSION","eventName","getSelector","hrefAttribute","trim","map","sel","join","SelectorEngine","concat","Element","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","el","getSelectorFromElement","getElementFromSelector","getMultipleElementsFromSelector","enableDismissTrigger","component","method","clickEvent","tagName","EVENT_CLOSE","EVENT_CLOSED","Alert","close","_destroyElement","each","data","undefined","SELECTOR_DATA_TOGGLE","Button","toggle","button","EVENT_TOUCHSTART","EVENT_TOUCHMOVE","EVENT_TOUCHEND","EVENT_POINTERDOWN","EVENT_POINTERUP","endCallback","leftCallback","rightCallback","Swipe","isSupported","_deltaX","_supportPointerEvents","PointerEvent","_initEvents","_start","_eventIsPointerPenTouch","clientX","touches","_end","_handleSwipe","_move","absDeltaX","abs","direction","add","pointerType","navigator","maxTouchPoints","DATA_API_KEY","ARROW_LEFT_KEY","ARROW_RIGHT_KEY","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","EVENT_SLIDE","EVENT_SLID","EVENT_KEYDOWN","EVENT_MOUSEENTER","EVENT_MOUSELEAVE","EVENT_DRAG_START","EVENT_LOAD_DATA_API","EVENT_CLICK_DATA_API","CLASS_NAME_CAROUSEL","CLASS_NAME_ACTIVE","SELECTOR_ACTIVE","SELECTOR_ITEM","SELECTOR_ACTIVE_ITEM","KEY_TO_DIRECTION","ARROW_LEFT_KEY$1","ARROW_RIGHT_KEY$1","interval","keyboard","pause","ride","touch","wrap","Carousel","_interval","_activeElement","_isSliding","touchTimeout","_swipeHelper","_indicatorsElement","_addEventListeners","cycle","_slide","nextWhenVisible","hidden","_clearInterval","_updateInterval","setInterval","_maybeEnableCycle","to","items","_getItems","activeIndex","_getItemIndex","_getActive","order","defaultInterval","_keydown","_addTouchEventListeners","img","swipeConfig","_directionToOrder","endCallBack","clearTimeout","_setActiveIndicatorElement","activeIndicator","newActiveIndicator","elementInterval","parseInt","isNext","nextElement","nextElementIndex","triggerEvent","_orderToDirection","isCycling","directionalClassName","orderClassName","completeCallBack","_isAnimated","clearInterval","carousel","slideIndex","carousels","EVENT_SHOW","EVENT_SHOWN","EVENT_HIDE","EVENT_HIDDEN","CLASS_NAME_SHOW","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_DEEPER_CHILDREN","parent","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElement","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activeChildren","_getFirstLevelChildren","activeInstance","dimension","_getDimension","style","scrollSize","complete","getBoundingClientRect","selected","triggerArray","isOpen","top","bottom","right","left","auto","basePlacements","start","end","clippingParents","viewport","popper","reference","variationPlacements","reduce","acc","placement","placements","beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite","modifierPhases","getNodeName","nodeName","getWindow","node","ownerDocument","defaultView","isHTMLElement","HTMLElement","isShadowRoot","applyStyles$1","enabled","phase","_ref","state","elements","forEach","styles","assign","effect","_ref2","initialStyles","position","options","strategy","margin","arrow","hasOwnProperty","attribute","requires","getBasePlacement","round","getUAString","uaData","userAgentData","brands","isArray","item","brand","version","userAgent","isLayoutViewport","includeScale","isFixedStrategy","clientRect","scaleX","scaleY","offsetWidth","width","height","visualViewport","addVisualOffsets","x","offsetLeft","y","offsetTop","getLayoutRect","rootNode","isSameNode","host","isTableElement","getDocumentElement","getParentNode","assignedSlot","getTrueOffsetParent","offsetParent","getOffsetParent","isFirefox","currentNode","css","transform","perspective","contain","willChange","getContainingBlock","getMainAxisFromPlacement","within","mathMax","mathMin","mergePaddingObject","paddingObject","expandToHashMap","hashMap","arrow$1","_state$modifiersData$","arrowElement","popperOffsets","modifiersData","basePlacement","axis","len","padding","rects","toPaddingObject","arrowRect","minProp","maxProp","endDiff","startDiff","arrowOffsetParent","clientSize","clientHeight","clientWidth","centerToReference","center","offset","axisProp","centerOffset","_options$element","requiresIfExists","getVariation","unsetSides","mapToStyles","_Object$assign2","popperRect","variation","offsets","gpuAcceleration","adaptive","roundOffsets","isFixed","_offsets$x","_offsets$y","_ref3","hasX","hasY","sideX","sideY","win","heightProp","widthProp","_Object$assign","commonStyles","_ref4","dpr","devicePixelRatio","roundOffsetsByDPR","computeStyles$1","_ref5","_options$gpuAccelerat","_options$adaptive","_options$roundOffsets","passive","eventListeners","_options$scroll","scroll","_options$resize","resize","scrollParents","scrollParent","update","hash","getOppositePlacement","matched","getOppositeVariationPlacement","getWindowScroll","scrollLeft","pageXOffset","scrollTop","pageYOffset","getWindowScrollBarX","isScrollParent","_getComputedStyle","overflow","overflowX","overflowY","getScrollParent","listScrollParents","_element$ownerDocumen","isBody","updatedList","rectToClientRect","rect","getClientRectFromMixedType","clippingParent","html","layoutViewport","getViewportRect","clientTop","clientLeft","getInnerBoundingClientRect","winScroll","scrollWidth","scrollHeight","getDocumentRect","computeOffsets","commonX","commonY","mainAxis","detectOverflow","_options","_options$placement","_options$strategy","_options$boundary","boundary","_options$rootBoundary","rootBoundary","_options$elementConte","elementContext","_options$altBoundary","altBoundary","_options$padding","altContext","clippingClientRect","mainClippingParents","clipperElement","getClippingParents","firstClippingParent","clippingRect","accRect","getClippingRect","contextElement","referenceClientRect","popperClientRect","elementClientRect","overflowOffsets","offsetData","multiply","computeAutoPlacement","flipVariations","_options$allowedAutoP","allowedAutoPlacements","allPlacements","allowedPlacements","overflows","sort","a","b","flip$1","_skip","_options$mainAxis","checkMainAxis","_options$altAxis","altAxis","checkAltAxis","specifiedFallbackPlacements","fallbackPlacements","_options$flipVariatio","preferredPlacement","oppositePlacement","getExpandedFallbackPlacements","referenceRect","checksMap","makeFallbackChecks","firstFittingPlacement","i","_basePlacement","isStartVariation","isVertical","mainVariationSide","altVariationSide","checks","every","check","_loop","_i","fittingPlacement","reset","getSideOffsets","preventedOffsets","isAnySideFullyClipped","some","side","hide$1","preventOverflow","referenceOverflow","popperAltOverflow","referenceClippingOffsets","popperEscapeOffsets","isReferenceHidden","hasPopperEscaped","offset$1","_options$offset","invertDistance","skidding","distance","distanceAndSkiddingToXY","_data$state$placement","popperOffsets$1","preventOverflow$1","_options$tether","tether","_options$tetherOffset","tetherOffset","isBasePlacement","tetherOffsetValue","normalizedTetherOffsetValue","offsetModifierState","_offsetModifierState$","mainSide","altSide","additive","minLen","maxLen","arrowPaddingObject","arrowPaddingMin","arrowPaddingMax","arrowLen","minOffset","maxOffset","clientOffset","offsetModifierValue","tetherMax","preventedOffset","_offsetModifierState$2","_mainSide","_altSide","_offset","_len","_min","_max","isOriginSide","_offsetModifierValue","_tetherMin","_tetherMax","_preventedOffset","v","withinMaxClamp","getCompositeRect","elementOrVirtualElement","isOffsetParentAnElement","offsetParentIsScaled","isElementScaled","modifiers","visited","result","modifier","dep","depModifier","DEFAULT_OPTIONS","areValidElements","arguments","_key","popperGenerator","generatorOptions","_generatorOptions","_generatorOptions$def","defaultModifiers","_generatorOptions$def2","defaultOptions","pending","orderedModifiers","effectCleanupFns","isDestroyed","setOptions","setOptionsAction","cleanupModifierEffects","merged","orderModifiers","current","existing","m","_ref$options","cleanupFn","forceUpdate","_state$elements","_state$orderedModifie","_state$orderedModifie2","Promise","resolve","then","destroy","onFirstUpdate","createPopper","computeStyles","applyStyles","flip","ARROW_UP_KEY","ARROW_DOWN_KEY","EVENT_KEYDOWN_DATA_API","EVENT_KEYUP_DATA_API","SELECTOR_DATA_TOGGLE_SHOWN","SELECTOR_MENU","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","autoClose","display","popperConfig","Dropdown","_popper","_parent","_menu","_inNavbar","_detectNavbar","_createPopper","focus","_completeHide","Popper","referenceElement","_getPopperConfig","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","_selectMenuItem","clearMenus","openToggles","context","composedPath","isMenuTarget","dataApiKeydownHandler","isInput","isEscapeEvent","isUpOrDownEvent","getToggleButton","stopPropagation","EVENT_MOUSEDOWN","className","clickCallback","rootElement","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","EVENT_FOCUSIN","EVENT_KEYDOWN_TAB","TAB_NAV_BACKWARD","autofocus","trapElement","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","shiftKey","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","PROPERTY_PADDING","PROPERTY_MARGIN","ScrollBarHelper","getWidth","documentWidth","innerWidth","_disableOverFlow","_setElementAttributes","calculatedValue","_resetElementAttributes","isOverflowing","_saveInitialAttribute","styleProperty","scrollbarWidth","_applyManipulationCallback","setProperty","actualValue","removeProperty","callBack","EVENT_HIDE_PREVENTED","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_MOUSEDOWN_DISMISS","EVENT_KEYDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_scrollBar","_adjustDialog","_showElement","_hideModal","handleUpdate","modalBody","transitionComplete","_triggerBackdropTransition","event2","_resetAdjustments","isModalOverflowing","initialOverflowY","isBodyOverflowing","paddingLeft","paddingRight","showEvent","alreadyOpen","CLASS_NAME_SHOWING","CLASS_NAME_HIDING","OPEN_SELECTOR","Offcanvas","blur","completeCallback","DefaultAllowlist","area","br","col","code","dd","div","dl","dt","em","hr","h1","h2","h3","h4","h5","h6","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","uriAttributes","SAFE_URL_PATTERN","allowedAttribute","allowedAttributeList","attributeName","nodeValue","attributeRegex","regex","allowList","content","extraClass","sanitize","sanitizeFn","template","DefaultContentType","entry","TemplateFactory","getContent","_resolvePossibleFunction","hasContent","changeContent","_checkContent","toHtml","templateWrapper","innerHTML","_maybeSanitize","text","_setContent","arg","templateElement","_putElementInTemplate","textContent","unsafeHtml","sanitizeFunction","createdDocument","DOMParser","parseFromString","elementName","attributeList","allowedAttributes","sanitizeHtml","DISALLOWED_ATTRIBUTES","CLASS_NAME_FADE","SELECTOR_TOOLTIP_INNER","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","TRIGGER_CLICK","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","animation","container","customClass","delay","title","Tooltip","_isEnabled","_timeout","_isHovered","_activeTrigger","_templateFactory","_newContent","tip","_setListeners","_fixTitle","enable","disable","toggleEnabled","_leave","_enter","_hideModalHandler","_disposePopper","_isWithContent","isInTheDom","_getTipElement","_isWithActiveTrigger","_getTitle","_createTipElement","_getContentForTemplate","_getTemplateFactory","tipId","prefix","floor","random","getElementById","getUID","setContent","_initializeOnDelegatedTarget","_getDelegateConfig","attachment","triggers","eventIn","eventOut","_setTimeout","timeout","dataAttributes","dataAttribute","SELECTOR_TITLE","SELECTOR_CONTENT","Popover","_getContent","EVENT_ACTIVATE","EVENT_CLICK","SELECTOR_TARGET_LINKS","SELECTOR_NAV_LINKS","SELECTOR_LINK_ITEMS","rootMargin","smoothScroll","threshold","ScrollSpy","_targetLinks","_observableSections","_rootElement","_activeTarget","_observer","_previousScrollData","visibleEntryTop","parentScrollTop","refresh","_initializeTargetsAndObservables","_maybeEnableSmoothScroll","disconnect","_getNewObserver","section","observe","observableSection","scrollTo","behavior","IntersectionObserver","_observerCallback","targetElement","_process","userScrollsDown","isIntersecting","_clearActiveClass","entryIsLowerThanPrevious","targetLinks","anchor","decodeURI","_activateParents","listGroup","activeNodes","spy","HOME_KEY","END_KEY","SELECTOR_DROPDOWN_TOGGLE","NOT_SELECTOR_DROPDOWN_TOGGLE","SELECTOR_INNER_ELEM","SELECTOR_DATA_TOGGLE_ACTIVE","Tab","_setInitialAttributes","_getChildren","innerElem","_elemIsActive","active","_getActiveElem","hideEvent","_deactivate","_activate","relatedElem","_toggleDropDown","nextActiveElement","preventScroll","_setAttributeIfNotExists","_setInitialAttributesOnChild","_getInnerElement","isActive","outerElem","_getOuterElement","_setInitialAttributesOnTargetPanel","open","EVENT_MOUSEOVER","EVENT_MOUSEOUT","EVENT_FOCUSOUT","CLASS_NAME_HIDE","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","isShown","_onInteraction","isInteracting"],"sources":["../../js/src/dom/data.js","../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/manipulator.js","../../js/src/util/config.js","../../js/src/base-component.js","../../js/src/dom/selector-engine.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/util/swipe.js","../../js/src/carousel.js","../../js/src/collapse.js","../../node_modules/@popperjs/core/lib/enums.js","../../node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","../../node_modules/@popperjs/core/lib/dom-utils/getWindow.js","../../node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","../../node_modules/@popperjs/core/lib/modifiers/applyStyles.js","../../node_modules/@popperjs/core/lib/utils/getBasePlacement.js","../../node_modules/@popperjs/core/lib/utils/math.js","../../node_modules/@popperjs/core/lib/utils/userAgent.js","../../node_modules/@popperjs/core/lib/dom-utils/isLayoutViewport.js","../../node_modules/@popperjs/core/lib/dom-utils/getBoundingClientRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getLayoutRect.js","../../node_modules/@popperjs/core/lib/dom-utils/contains.js","../../node_modules/@popperjs/core/lib/dom-utils/getComputedStyle.js","../../node_modules/@popperjs/core/lib/dom-utils/isTableElement.js","../../node_modules/@popperjs/core/lib/dom-utils/getDocumentElement.js","../../node_modules/@popperjs/core/lib/dom-utils/getParentNode.js","../../node_modules/@popperjs/core/lib/dom-utils/getOffsetParent.js","../../node_modules/@popperjs/core/lib/utils/getMainAxisFromPlacement.js","../../node_modules/@popperjs/core/lib/utils/within.js","../../node_modules/@popperjs/core/lib/utils/mergePaddingObject.js","../../node_modules/@popperjs/core/lib/utils/getFreshSideObject.js","../../node_modules/@popperjs/core/lib/utils/expandToHashMap.js","../../node_modules/@popperjs/core/lib/modifiers/arrow.js","../../node_modules/@popperjs/core/lib/utils/getVariation.js","../../node_modules/@popperjs/core/lib/modifiers/computeStyles.js","../../node_modules/@popperjs/core/lib/modifiers/eventListeners.js","../../node_modules/@popperjs/core/lib/utils/getOppositePlacement.js","../../node_modules/@popperjs/core/lib/utils/getOppositeVariationPlacement.js","../../node_modules/@popperjs/core/lib/dom-utils/getWindowScroll.js","../../node_modules/@popperjs/core/lib/dom-utils/getWindowScrollBarX.js","../../node_modules/@popperjs/core/lib/dom-utils/isScrollParent.js","../../node_modules/@popperjs/core/lib/dom-utils/getScrollParent.js","../../node_modules/@popperjs/core/lib/dom-utils/listScrollParents.js","../../node_modules/@popperjs/core/lib/utils/rectToClientRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getClippingRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getViewportRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getDocumentRect.js","../../node_modules/@popperjs/core/lib/utils/computeOffsets.js","../../node_modules/@popperjs/core/lib/utils/detectOverflow.js","../../node_modules/@popperjs/core/lib/utils/computeAutoPlacement.js","../../node_modules/@popperjs/core/lib/modifiers/flip.js","../../node_modules/@popperjs/core/lib/modifiers/hide.js","../../node_modules/@popperjs/core/lib/modifiers/offset.js","../../node_modules/@popperjs/core/lib/modifiers/popperOffsets.js","../../node_modules/@popperjs/core/lib/modifiers/preventOverflow.js","../../node_modules/@popperjs/core/lib/utils/getAltAxis.js","../../node_modules/@popperjs/core/lib/dom-utils/getCompositeRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getNodeScroll.js","../../node_modules/@popperjs/core/lib/dom-utils/getHTMLElementScroll.js","../../node_modules/@popperjs/core/lib/utils/orderModifiers.js","../../node_modules/@popperjs/core/lib/createPopper.js","../../node_modules/@popperjs/core/lib/utils/debounce.js","../../node_modules/@popperjs/core/lib/utils/mergeByName.js","../../node_modules/@popperjs/core/lib/popper-lite.js","../../node_modules/@popperjs/core/lib/popper.js","../../js/src/dropdown.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/util/scrollbar.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/util/template-factory.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1_000_000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`)\n }\n\n return selector\n}\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`\n }\n\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = object => {\n if (!object || typeof object !== 'object') {\n return false\n }\n\n if (typeof object.jquery !== 'undefined') {\n object = object[0]\n }\n\n return typeof object.nodeType !== 'undefined'\n}\n\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (isElement(object)) {\n return object.jquery ? object[0] : object\n }\n\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object))\n }\n\n return null\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])')\n\n if (!closedDetails) {\n return elementIsVisible\n }\n\n if (closedDetails !== element) {\n const summary = element.closest('summary')\n if (summary && summary.parentNode !== closedDetails) {\n return false\n }\n\n if (summary === null) {\n return false\n }\n }\n\n return elementIsVisible\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.harrytheo.com/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight // eslint-disable-line no-unused-expressions\n}\n\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback()\n }\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback.call(...args) : defaultValue\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]\n }\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n defineJQueryPlugin,\n execute,\n executeAfterTransition,\n findShadowRoot,\n getElement,\n getjQuery,\n getNextActiveElement,\n getTransitionDurationFromElement,\n getUID,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n onDOMContentLoaded,\n parseSelector,\n reflow,\n triggerTransitionEnd,\n toType\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index.js'\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\n\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getElementEvents(element) {\n const uid = makeEventUid(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, { delegateTarget: element })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue\n }\n\n hydrateObj(event, { delegateTarget: target })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n}\n\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events)\n .find(event => event.callable === callable && event.delegationSelector === delegationSelector)\n}\n\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string'\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : (handler || delegationFunction)\n let typeEvent = getTypeEvent(originalTypeEvent)\n\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent\n }\n\n return [isDelegated, callable, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n callable = wrapFunction(callable)\n }\n\n const events = getElementEvents(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)\n\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff\n\n return\n }\n\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = isDelegated ?\n bootstrapDelegationHandler(element, handler, callable) :\n bootstrapHandler(element, callable)\n\n fn.delegationSelector = isDelegated ? handler : null\n fn.callable = callable\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, isDelegated)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false)\n },\n\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getElementEvents(element)\n const storeElementEvent = events[typeEvent] || {}\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return\n }\n\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)\n return\n }\n\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n }\n }\n\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n\n let jQueryEvent = null\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value\n } catch {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value\n }\n })\n }\n }\n\n return obj\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true\n }\n\n if (value === 'false') {\n return false\n }\n\n if (value === Number(value).toString()) {\n return Number(value)\n }\n\n if (value === '' || value === 'null') {\n return null\n }\n\n if (typeof value !== 'string') {\n return value\n }\n\n try {\n return JSON.parse(decodeURIComponent(value))\n } catch {\n return value\n }\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))\n\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1)\n attributes[pureKey] = normalizeData(element.dataset[key])\n }\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport { isElement, toType } from './index.js'\n\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {}\n }\n\n static get DefaultType() {\n return {}\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n return config\n }\n\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n }\n }\n\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property]\n const valueType = isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n }\n }\n}\n\nexport default Config\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data.js'\nimport EventHandler from './dom/event-handler.js'\nimport Config from './util/config.js'\nimport { executeAfterTransition, getElement } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.8'\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super()\n\n element = getElement(element)\n if (!element) {\n return\n }\n\n this._element = element\n this._config = this._getConfig(config)\n\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null\n }\n }\n\n // Private\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible, parseSelector } from '../util/index.js'\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`\n }\n\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null\n }\n\n return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null\n}\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n let ancestor = element.parentNode.closest(selector)\n\n while (ancestor) {\n parents.push(ancestor)\n ancestor = ancestor.parentNode.closest(selector)\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n },\n\n getSelectorFromElement(element) {\n const selector = getSelector(element)\n\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null\n }\n\n return null\n },\n\n getElementFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.findOne(selector) : null\n },\n\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.find(selector) : []\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isDisabled } from './index.js'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport { execute } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'swipe'\nconst EVENT_KEY = '.bs.swipe'\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n}\n\nconst DefaultType = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n}\n\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super()\n this._element = element\n\n if (!element || !Swipe.isSupported()) {\n return\n }\n\n this._config = this._getConfig(config)\n this._deltaX = 0\n this._supportPointerEvents = Boolean(window.PointerEvent)\n this._initEvents()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY)\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX\n\n return\n }\n\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX\n }\n }\n\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX\n }\n\n this._handleSwipe()\n execute(this._config.endCallback)\n }\n\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this._deltaX\n }\n\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX)\n\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltaX / this._deltaX\n\n this._deltaX = 0\n\n if (!direction) {\n return\n }\n\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)\n }\n\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))\n }\n }\n\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n }\n}\n\nexport default Swipe\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getNextActiveElement,\n isRTL,\n isVisible,\n reflow,\n triggerTransitionEnd\n} from './util/index.js'\nimport Swipe from './util/swipe.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)', // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._interval = null\n this._activeElement = null\n this._isSliding = false\n this.touchTimeout = null\n this._swipeHelper = null\n\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._addEventListeners()\n\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element)\n }\n\n this._clearInterval()\n }\n\n cycle() {\n this._clearInterval()\n this._updateInterval()\n\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval)\n }\n\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle())\n return\n }\n\n this.cycle()\n }\n\n to(index) {\n const items = this._getItems()\n if (index > items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n const activeIndex = this._getItemIndex(this._getActive())\n if (activeIndex === index) {\n return\n }\n\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV\n\n this._slide(order, items[index])\n }\n\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose()\n }\n\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval\n return config\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause())\n EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle())\n }\n\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault())\n }\n\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n }\n\n this._swipeHelper = new Swipe(this._element, swipeConfig)\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(this._directionToOrder(direction))\n }\n }\n\n _getItemIndex(element) {\n return this._getItems().indexOf(element)\n }\n\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return\n }\n\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement)\n\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE)\n newActiveIndicator.setAttribute('aria-current', 'true')\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || this._getActive()\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n this._config.interval = elementInterval || this._config.defaultInterval\n }\n\n _slide(order, element = null) {\n if (this._isSliding) {\n return\n }\n\n const activeElement = this._getActive()\n const isNext = order === ORDER_NEXT\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap)\n\n if (nextElement === activeElement) {\n return\n }\n\n const nextElementIndex = this._getItemIndex(nextElement)\n\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n })\n }\n\n const slideEvent = triggerEvent(EVENT_SLIDE)\n\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return\n }\n\n const isCycling = Boolean(this._interval)\n this.pause()\n\n this._isSliding = true\n\n this._setActiveIndicatorElement(nextElementIndex)\n this._activeElement = nextElement\n\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n triggerEvent(EVENT_SLID)\n }\n\n this._queueCallback(completeCallBack, activeElement, this._isAnimated())\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE)\n }\n\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n }\n\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element)\n }\n\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n }\n\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config)\n\n if (typeof config === 'number') {\n data.to(config)\n return\n }\n\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n event.preventDefault()\n\n const carousel = Carousel.getOrCreateInstance(target)\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n carousel.to(slideIndex)\n carousel._maybeEnableCycle()\n return\n }\n\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next()\n carousel._maybeEnableCycle()\n return\n }\n\n carousel.prev()\n carousel._maybeEnableCycle()\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getElement,\n reflow\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\nconst Default = {\n parent: null,\n toggle: true\n}\n\nconst DefaultType = {\n parent: '(null|element)',\n toggle: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isTransitioning = false\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElement => foundElement === this._element)\n\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let activeChildren = []\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)\n .filter(element => element !== this._element)\n .map(element => Collapse.getOrCreateInstance(element, { toggle: false }))\n }\n\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n for (const activeInstance of activeChildren) {\n activeInstance.hide()\n }\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger)\n\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n // Private\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)\n\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n }\n }\n\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element))\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen)\n element.setAttribute('aria-expanded', isOpen)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","export var top = 'top';\nexport var bottom = 'bottom';\nexport var right = 'right';\nexport var left = 'left';\nexport var auto = 'auto';\nexport var basePlacements = [top, bottom, right, left];\nexport var start = 'start';\nexport var end = 'end';\nexport var clippingParents = 'clippingParents';\nexport var viewport = 'viewport';\nexport var popper = 'popper';\nexport var reference = 'reference';\nexport var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {\n return acc.concat([placement + \"-\" + start, placement + \"-\" + end]);\n}, []);\nexport var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {\n return acc.concat([placement, placement + \"-\" + start, placement + \"-\" + end]);\n}, []); // modifiers that need to read the DOM\n\nexport var beforeRead = 'beforeRead';\nexport var read = 'read';\nexport var afterRead = 'afterRead'; // pure-logic modifiers\n\nexport var beforeMain = 'beforeMain';\nexport var main = 'main';\nexport var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)\n\nexport var beforeWrite = 'beforeWrite';\nexport var write = 'write';\nexport var afterWrite = 'afterWrite';\nexport var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];","export default function getNodeName(element) {\n return element ? (element.nodeName || '').toLowerCase() : null;\n}","export default function getWindow(node) {\n if (node == null) {\n return window;\n }\n\n if (node.toString() !== '[object Window]') {\n var ownerDocument = node.ownerDocument;\n return ownerDocument ? ownerDocument.defaultView || window : window;\n }\n\n return node;\n}","import getWindow from \"./getWindow.js\";\n\nfunction isElement(node) {\n var OwnElement = getWindow(node).Element;\n return node instanceof OwnElement || node instanceof Element;\n}\n\nfunction isHTMLElement(node) {\n var OwnElement = getWindow(node).HTMLElement;\n return node instanceof OwnElement || node instanceof HTMLElement;\n}\n\nfunction isShadowRoot(node) {\n // IE 11 has no ShadowRoot\n if (typeof ShadowRoot === 'undefined') {\n return false;\n }\n\n var OwnElement = getWindow(node).ShadowRoot;\n return node instanceof OwnElement || node instanceof ShadowRoot;\n}\n\nexport { isElement, isHTMLElement, isShadowRoot };","import getNodeName from \"../dom-utils/getNodeName.js\";\nimport { isHTMLElement } from \"../dom-utils/instanceOf.js\"; // This modifier takes the styles prepared by the `computeStyles` modifier\n// and applies them to the HTMLElements such as popper and arrow\n\nfunction applyStyles(_ref) {\n var state = _ref.state;\n Object.keys(state.elements).forEach(function (name) {\n var style = state.styles[name] || {};\n var attributes = state.attributes[name] || {};\n var element = state.elements[name]; // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n } // Flow doesn't support to extend this property, but it's the most\n // effective way to apply styles to an HTMLElement\n // $FlowFixMe[cannot-write]\n\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (name) {\n var value = attributes[name];\n\n if (value === false) {\n element.removeAttribute(name);\n } else {\n element.setAttribute(name, value === true ? '' : value);\n }\n });\n });\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state;\n var initialStyles = {\n popper: {\n position: state.options.strategy,\n left: '0',\n top: '0',\n margin: '0'\n },\n arrow: {\n position: 'absolute'\n },\n reference: {}\n };\n Object.assign(state.elements.popper.style, initialStyles.popper);\n state.styles = initialStyles;\n\n if (state.elements.arrow) {\n Object.assign(state.elements.arrow.style, initialStyles.arrow);\n }\n\n return function () {\n Object.keys(state.elements).forEach(function (name) {\n var element = state.elements[name];\n var attributes = state.attributes[name] || {};\n var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them\n\n var style = styleProperties.reduce(function (style, property) {\n style[property] = '';\n return style;\n }, {}); // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n }\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (attribute) {\n element.removeAttribute(attribute);\n });\n });\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'applyStyles',\n enabled: true,\n phase: 'write',\n fn: applyStyles,\n effect: effect,\n requires: ['computeStyles']\n};","import { auto } from \"../enums.js\";\nexport default function getBasePlacement(placement) {\n return placement.split('-')[0];\n}","export var max = Math.max;\nexport var min = Math.min;\nexport var round = Math.round;","export default function getUAString() {\n var uaData = navigator.userAgentData;\n\n if (uaData != null && uaData.brands && Array.isArray(uaData.brands)) {\n return uaData.brands.map(function (item) {\n return item.brand + \"/\" + item.version;\n }).join(' ');\n }\n\n return navigator.userAgent;\n}","import getUAString from \"../utils/userAgent.js\";\nexport default function isLayoutViewport() {\n return !/^((?!chrome|android).)*safari/i.test(getUAString());\n}","import { isElement, isHTMLElement } from \"./instanceOf.js\";\nimport { round } from \"../utils/math.js\";\nimport getWindow from \"./getWindow.js\";\nimport isLayoutViewport from \"./isLayoutViewport.js\";\nexport default function getBoundingClientRect(element, includeScale, isFixedStrategy) {\n if (includeScale === void 0) {\n includeScale = false;\n }\n\n if (isFixedStrategy === void 0) {\n isFixedStrategy = false;\n }\n\n var clientRect = element.getBoundingClientRect();\n var scaleX = 1;\n var scaleY = 1;\n\n if (includeScale && isHTMLElement(element)) {\n scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;\n scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;\n }\n\n var _ref = isElement(element) ? getWindow(element) : window,\n visualViewport = _ref.visualViewport;\n\n var addVisualOffsets = !isLayoutViewport() && isFixedStrategy;\n var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX;\n var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY;\n var width = clientRect.width / scaleX;\n var height = clientRect.height / scaleY;\n return {\n width: width,\n height: height,\n top: y,\n right: x + width,\n bottom: y + height,\n left: x,\n x: x,\n y: y\n };\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\"; // Returns the layout rect of an element relative to its offsetParent. Layout\n// means it doesn't take into account transforms.\n\nexport default function getLayoutRect(element) {\n var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.\n // Fixes https://github.com/popperjs/popper-core/issues/1223\n\n var width = element.offsetWidth;\n var height = element.offsetHeight;\n\n if (Math.abs(clientRect.width - width) <= 1) {\n width = clientRect.width;\n }\n\n if (Math.abs(clientRect.height - height) <= 1) {\n height = clientRect.height;\n }\n\n return {\n x: element.offsetLeft,\n y: element.offsetTop,\n width: width,\n height: height\n };\n}","import { isShadowRoot } from \"./instanceOf.js\";\nexport default function contains(parent, child) {\n var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method\n\n if (parent.contains(child)) {\n return true;\n } // then fallback to custom implementation with Shadow DOM support\n else if (rootNode && isShadowRoot(rootNode)) {\n var next = child;\n\n do {\n if (next && parent.isSameNode(next)) {\n return true;\n } // $FlowFixMe[prop-missing]: need a better way to handle this...\n\n\n next = next.parentNode || next.host;\n } while (next);\n } // Give up, the result is false\n\n\n return false;\n}","import getWindow from \"./getWindow.js\";\nexport default function getComputedStyle(element) {\n return getWindow(element).getComputedStyle(element);\n}","import getNodeName from \"./getNodeName.js\";\nexport default function isTableElement(element) {\n return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;\n}","import { isElement } from \"./instanceOf.js\";\nexport default function getDocumentElement(element) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]\n element.document) || window.document).documentElement;\n}","import getNodeName from \"./getNodeName.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport { isShadowRoot } from \"./instanceOf.js\";\nexport default function getParentNode(element) {\n if (getNodeName(element) === 'html') {\n return element;\n }\n\n return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle\n // $FlowFixMe[incompatible-return]\n // $FlowFixMe[prop-missing]\n element.assignedSlot || // step into the shadow DOM of the parent of a slotted node\n element.parentNode || ( // DOM Element detected\n isShadowRoot(element) ? element.host : null) || // ShadowRoot detected\n // $FlowFixMe[incompatible-call]: HTMLElement is a Node\n getDocumentElement(element) // fallback\n\n );\n}","import getWindow from \"./getWindow.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isHTMLElement, isShadowRoot } from \"./instanceOf.js\";\nimport isTableElement from \"./isTableElement.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport getUAString from \"../utils/userAgent.js\";\n\nfunction getTrueOffsetParent(element) {\n if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837\n getComputedStyle(element).position === 'fixed') {\n return null;\n }\n\n return element.offsetParent;\n} // `.offsetParent` reports `null` for fixed elements, while absolute elements\n// return the containing block\n\n\nfunction getContainingBlock(element) {\n var isFirefox = /firefox/i.test(getUAString());\n var isIE = /Trident/i.test(getUAString());\n\n if (isIE && isHTMLElement(element)) {\n // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport\n var elementCss = getComputedStyle(element);\n\n if (elementCss.position === 'fixed') {\n return null;\n }\n }\n\n var currentNode = getParentNode(element);\n\n if (isShadowRoot(currentNode)) {\n currentNode = currentNode.host;\n }\n\n while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {\n var css = getComputedStyle(currentNode); // This is non-exhaustive but covers the most common CSS properties that\n // create a containing block.\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n\n if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {\n return currentNode;\n } else {\n currentNode = currentNode.parentNode;\n }\n }\n\n return null;\n} // Gets the closest ancestor positioned element. Handles some edge cases,\n// such as table ancestors and cross browser bugs.\n\n\nexport default function getOffsetParent(element) {\n var window = getWindow(element);\n var offsetParent = getTrueOffsetParent(element);\n\n while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') {\n offsetParent = getTrueOffsetParent(offsetParent);\n }\n\n if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static')) {\n return window;\n }\n\n return offsetParent || getContainingBlock(element) || window;\n}","export default function getMainAxisFromPlacement(placement) {\n return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';\n}","import { max as mathMax, min as mathMin } from \"./math.js\";\nexport function within(min, value, max) {\n return mathMax(min, mathMin(value, max));\n}\nexport function withinMaxClamp(min, value, max) {\n var v = within(min, value, max);\n return v > max ? max : v;\n}","import getFreshSideObject from \"./getFreshSideObject.js\";\nexport default function mergePaddingObject(paddingObject) {\n return Object.assign({}, getFreshSideObject(), paddingObject);\n}","export default function getFreshSideObject() {\n return {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0\n };\n}","export default function expandToHashMap(value, keys) {\n return keys.reduce(function (hashMap, key) {\n hashMap[key] = value;\n return hashMap;\n }, {});\n}","import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport contains from \"../dom-utils/contains.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport { within } from \"../utils/within.js\";\nimport mergePaddingObject from \"../utils/mergePaddingObject.js\";\nimport expandToHashMap from \"../utils/expandToHashMap.js\";\nimport { left, right, basePlacements, top, bottom } from \"../enums.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar toPaddingObject = function toPaddingObject(padding, state) {\n padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {\n placement: state.placement\n })) : padding;\n return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n};\n\nfunction arrow(_ref) {\n var _state$modifiersData$;\n\n var state = _ref.state,\n name = _ref.name,\n options = _ref.options;\n var arrowElement = state.elements.arrow;\n var popperOffsets = state.modifiersData.popperOffsets;\n var basePlacement = getBasePlacement(state.placement);\n var axis = getMainAxisFromPlacement(basePlacement);\n var isVertical = [left, right].indexOf(basePlacement) >= 0;\n var len = isVertical ? 'height' : 'width';\n\n if (!arrowElement || !popperOffsets) {\n return;\n }\n\n var paddingObject = toPaddingObject(options.padding, state);\n var arrowRect = getLayoutRect(arrowElement);\n var minProp = axis === 'y' ? top : left;\n var maxProp = axis === 'y' ? bottom : right;\n var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];\n var startDiff = popperOffsets[axis] - state.rects.reference[axis];\n var arrowOffsetParent = getOffsetParent(arrowElement);\n var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;\n var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is\n // outside of the popper bounds\n\n var min = paddingObject[minProp];\n var max = clientSize - arrowRect[len] - paddingObject[maxProp];\n var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;\n var offset = within(min, center, max); // Prevents breaking syntax highlighting...\n\n var axisProp = axis;\n state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state,\n options = _ref2.options;\n var _options$element = options.element,\n arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;\n\n if (arrowElement == null) {\n return;\n } // CSS selector\n\n\n if (typeof arrowElement === 'string') {\n arrowElement = state.elements.popper.querySelector(arrowElement);\n\n if (!arrowElement) {\n return;\n }\n }\n\n if (!contains(state.elements.popper, arrowElement)) {\n return;\n }\n\n state.elements.arrow = arrowElement;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'arrow',\n enabled: true,\n phase: 'main',\n fn: arrow,\n effect: effect,\n requires: ['popperOffsets'],\n requiresIfExists: ['preventOverflow']\n};","export default function getVariation(placement) {\n return placement.split('-')[1];\n}","import { top, left, right, bottom, end } from \"../enums.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getWindow from \"../dom-utils/getWindow.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getComputedStyle from \"../dom-utils/getComputedStyle.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport { round } from \"../utils/math.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar unsetSides = {\n top: 'auto',\n right: 'auto',\n bottom: 'auto',\n left: 'auto'\n}; // Round the offsets to the nearest suitable subpixel based on the DPR.\n// Zooming can change the DPR, but it seems to report a value that will\n// cleanly divide the values into the appropriate subpixels.\n\nfunction roundOffsetsByDPR(_ref, win) {\n var x = _ref.x,\n y = _ref.y;\n var dpr = win.devicePixelRatio || 1;\n return {\n x: round(x * dpr) / dpr || 0,\n y: round(y * dpr) / dpr || 0\n };\n}\n\nexport function mapToStyles(_ref2) {\n var _Object$assign2;\n\n var popper = _ref2.popper,\n popperRect = _ref2.popperRect,\n placement = _ref2.placement,\n variation = _ref2.variation,\n offsets = _ref2.offsets,\n position = _ref2.position,\n gpuAcceleration = _ref2.gpuAcceleration,\n adaptive = _ref2.adaptive,\n roundOffsets = _ref2.roundOffsets,\n isFixed = _ref2.isFixed;\n var _offsets$x = offsets.x,\n x = _offsets$x === void 0 ? 0 : _offsets$x,\n _offsets$y = offsets.y,\n y = _offsets$y === void 0 ? 0 : _offsets$y;\n\n var _ref3 = typeof roundOffsets === 'function' ? roundOffsets({\n x: x,\n y: y\n }) : {\n x: x,\n y: y\n };\n\n x = _ref3.x;\n y = _ref3.y;\n var hasX = offsets.hasOwnProperty('x');\n var hasY = offsets.hasOwnProperty('y');\n var sideX = left;\n var sideY = top;\n var win = window;\n\n if (adaptive) {\n var offsetParent = getOffsetParent(popper);\n var heightProp = 'clientHeight';\n var widthProp = 'clientWidth';\n\n if (offsetParent === getWindow(popper)) {\n offsetParent = getDocumentElement(popper);\n\n if (getComputedStyle(offsetParent).position !== 'static' && position === 'absolute') {\n heightProp = 'scrollHeight';\n widthProp = 'scrollWidth';\n }\n } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it\n\n\n offsetParent = offsetParent;\n\n if (placement === top || (placement === left || placement === right) && variation === end) {\n sideY = bottom;\n var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]\n offsetParent[heightProp];\n y -= offsetY - popperRect.height;\n y *= gpuAcceleration ? 1 : -1;\n }\n\n if (placement === left || (placement === top || placement === bottom) && variation === end) {\n sideX = right;\n var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]\n offsetParent[widthProp];\n x -= offsetX - popperRect.width;\n x *= gpuAcceleration ? 1 : -1;\n }\n }\n\n var commonStyles = Object.assign({\n position: position\n }, adaptive && unsetSides);\n\n var _ref4 = roundOffsets === true ? roundOffsetsByDPR({\n x: x,\n y: y\n }, getWindow(popper)) : {\n x: x,\n y: y\n };\n\n x = _ref4.x;\n y = _ref4.y;\n\n if (gpuAcceleration) {\n var _Object$assign;\n\n return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? \"translate(\" + x + \"px, \" + y + \"px)\" : \"translate3d(\" + x + \"px, \" + y + \"px, 0)\", _Object$assign));\n }\n\n return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + \"px\" : '', _Object$assign2[sideX] = hasX ? x + \"px\" : '', _Object$assign2.transform = '', _Object$assign2));\n}\n\nfunction computeStyles(_ref5) {\n var state = _ref5.state,\n options = _ref5.options;\n var _options$gpuAccelerat = options.gpuAcceleration,\n gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,\n _options$adaptive = options.adaptive,\n adaptive = _options$adaptive === void 0 ? true : _options$adaptive,\n _options$roundOffsets = options.roundOffsets,\n roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;\n var commonStyles = {\n placement: getBasePlacement(state.placement),\n variation: getVariation(state.placement),\n popper: state.elements.popper,\n popperRect: state.rects.popper,\n gpuAcceleration: gpuAcceleration,\n isFixed: state.options.strategy === 'fixed'\n };\n\n if (state.modifiersData.popperOffsets != null) {\n state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.popperOffsets,\n position: state.options.strategy,\n adaptive: adaptive,\n roundOffsets: roundOffsets\n })));\n }\n\n if (state.modifiersData.arrow != null) {\n state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.arrow,\n position: 'absolute',\n adaptive: false,\n roundOffsets: roundOffsets\n })));\n }\n\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-placement': state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'computeStyles',\n enabled: true,\n phase: 'beforeWrite',\n fn: computeStyles,\n data: {}\n};","import getWindow from \"../dom-utils/getWindow.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar passive = {\n passive: true\n};\n\nfunction effect(_ref) {\n var state = _ref.state,\n instance = _ref.instance,\n options = _ref.options;\n var _options$scroll = options.scroll,\n scroll = _options$scroll === void 0 ? true : _options$scroll,\n _options$resize = options.resize,\n resize = _options$resize === void 0 ? true : _options$resize;\n var window = getWindow(state.elements.popper);\n var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);\n\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.addEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.addEventListener('resize', instance.update, passive);\n }\n\n return function () {\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.removeEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.removeEventListener('resize', instance.update, passive);\n }\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'eventListeners',\n enabled: true,\n phase: 'write',\n fn: function fn() {},\n effect: effect,\n data: {}\n};","var hash = {\n left: 'right',\n right: 'left',\n bottom: 'top',\n top: 'bottom'\n};\nexport default function getOppositePlacement(placement) {\n return placement.replace(/left|right|bottom|top/g, function (matched) {\n return hash[matched];\n });\n}","var hash = {\n start: 'end',\n end: 'start'\n};\nexport default function getOppositeVariationPlacement(placement) {\n return placement.replace(/start|end/g, function (matched) {\n return hash[matched];\n });\n}","import getWindow from \"./getWindow.js\";\nexport default function getWindowScroll(node) {\n var win = getWindow(node);\n var scrollLeft = win.pageXOffset;\n var scrollTop = win.pageYOffset;\n return {\n scrollLeft: scrollLeft,\n scrollTop: scrollTop\n };\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nexport default function getWindowScrollBarX(element) {\n // If <html> has a CSS width greater than the viewport, then this will be\n // incorrect for RTL.\n // Popper 1 is broken in this case and never had a bug report so let's assume\n // it's not an issue. I don't think anyone ever specifies width on <html>\n // anyway.\n // Browsers where the left scrollbar doesn't cause an issue report `0` for\n // this (e.g. Edge 2019, IE11, Safari)\n return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;\n}","import getComputedStyle from \"./getComputedStyle.js\";\nexport default function isScrollParent(element) {\n // Firefox wants us to check `-x` and `-y` variations as well\n var _getComputedStyle = getComputedStyle(element),\n overflow = _getComputedStyle.overflow,\n overflowX = _getComputedStyle.overflowX,\n overflowY = _getComputedStyle.overflowY;\n\n return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);\n}","import getParentNode from \"./getParentNode.js\";\nimport isScrollParent from \"./isScrollParent.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nexport default function getScrollParent(node) {\n if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return node.ownerDocument.body;\n }\n\n if (isHTMLElement(node) && isScrollParent(node)) {\n return node;\n }\n\n return getScrollParent(getParentNode(node));\n}","import getScrollParent from \"./getScrollParent.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport getWindow from \"./getWindow.js\";\nimport isScrollParent from \"./isScrollParent.js\";\n/*\ngiven a DOM element, return the list of all scroll parents, up the list of ancesors\nuntil we get to the top window object. This list is what we attach scroll listeners\nto, because if any of these parent elements scroll, we'll need to re-calculate the\nreference element's position.\n*/\n\nexport default function listScrollParents(element, list) {\n var _element$ownerDocumen;\n\n if (list === void 0) {\n list = [];\n }\n\n var scrollParent = getScrollParent(element);\n var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);\n var win = getWindow(scrollParent);\n var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;\n var updatedList = list.concat(target);\n return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here\n updatedList.concat(listScrollParents(getParentNode(target)));\n}","export default function rectToClientRect(rect) {\n return Object.assign({}, rect, {\n left: rect.x,\n top: rect.y,\n right: rect.x + rect.width,\n bottom: rect.y + rect.height\n });\n}","import { viewport } from \"../enums.js\";\nimport getViewportRect from \"./getViewportRect.js\";\nimport getDocumentRect from \"./getDocumentRect.js\";\nimport listScrollParents from \"./listScrollParents.js\";\nimport getOffsetParent from \"./getOffsetParent.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isElement, isHTMLElement } from \"./instanceOf.js\";\nimport getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport contains from \"./contains.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport rectToClientRect from \"../utils/rectToClientRect.js\";\nimport { max, min } from \"../utils/math.js\";\n\nfunction getInnerBoundingClientRect(element, strategy) {\n var rect = getBoundingClientRect(element, false, strategy === 'fixed');\n rect.top = rect.top + element.clientTop;\n rect.left = rect.left + element.clientLeft;\n rect.bottom = rect.top + element.clientHeight;\n rect.right = rect.left + element.clientWidth;\n rect.width = element.clientWidth;\n rect.height = element.clientHeight;\n rect.x = rect.left;\n rect.y = rect.top;\n return rect;\n}\n\nfunction getClientRectFromMixedType(element, clippingParent, strategy) {\n return clippingParent === viewport ? rectToClientRect(getViewportRect(element, strategy)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent, strategy) : rectToClientRect(getDocumentRect(getDocumentElement(element)));\n} // A \"clipping parent\" is an overflowable container with the characteristic of\n// clipping (or hiding) overflowing elements with a position different from\n// `initial`\n\n\nfunction getClippingParents(element) {\n var clippingParents = listScrollParents(getParentNode(element));\n var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0;\n var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;\n\n if (!isElement(clipperElement)) {\n return [];\n } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414\n\n\n return clippingParents.filter(function (clippingParent) {\n return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';\n });\n} // Gets the maximum area that the element is visible in due to any number of\n// clipping parents\n\n\nexport default function getClippingRect(element, boundary, rootBoundary, strategy) {\n var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);\n var clippingParents = [].concat(mainClippingParents, [rootBoundary]);\n var firstClippingParent = clippingParents[0];\n var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {\n var rect = getClientRectFromMixedType(element, clippingParent, strategy);\n accRect.top = max(rect.top, accRect.top);\n accRect.right = min(rect.right, accRect.right);\n accRect.bottom = min(rect.bottom, accRect.bottom);\n accRect.left = max(rect.left, accRect.left);\n return accRect;\n }, getClientRectFromMixedType(element, firstClippingParent, strategy));\n clippingRect.width = clippingRect.right - clippingRect.left;\n clippingRect.height = clippingRect.bottom - clippingRect.top;\n clippingRect.x = clippingRect.left;\n clippingRect.y = clippingRect.top;\n return clippingRect;\n}","import getWindow from \"./getWindow.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport isLayoutViewport from \"./isLayoutViewport.js\";\nexport default function getViewportRect(element, strategy) {\n var win = getWindow(element);\n var html = getDocumentElement(element);\n var visualViewport = win.visualViewport;\n var width = html.clientWidth;\n var height = html.clientHeight;\n var x = 0;\n var y = 0;\n\n if (visualViewport) {\n width = visualViewport.width;\n height = visualViewport.height;\n var layoutViewport = isLayoutViewport();\n\n if (layoutViewport || !layoutViewport && strategy === 'fixed') {\n x = visualViewport.offsetLeft;\n y = visualViewport.offsetTop;\n }\n }\n\n return {\n width: width,\n height: height,\n x: x + getWindowScrollBarX(element),\n y: y\n };\n}","import getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nimport { max } from \"../utils/math.js\"; // Gets the entire size of the scrollable document area, even extending outside\n// of the `<html>` and `<body>` rect bounds if horizontally scrollable\n\nexport default function getDocumentRect(element) {\n var _element$ownerDocumen;\n\n var html = getDocumentElement(element);\n var winScroll = getWindowScroll(element);\n var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;\n var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);\n var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);\n var x = -winScroll.scrollLeft + getWindowScrollBarX(element);\n var y = -winScroll.scrollTop;\n\n if (getComputedStyle(body || html).direction === 'rtl') {\n x += max(html.clientWidth, body ? body.clientWidth : 0) - width;\n }\n\n return {\n width: width,\n height: height,\n x: x,\n y: y\n };\n}","import getBasePlacement from \"./getBasePlacement.js\";\nimport getVariation from \"./getVariation.js\";\nimport getMainAxisFromPlacement from \"./getMainAxisFromPlacement.js\";\nimport { top, right, bottom, left, start, end } from \"../enums.js\";\nexport default function computeOffsets(_ref) {\n var reference = _ref.reference,\n element = _ref.element,\n placement = _ref.placement;\n var basePlacement = placement ? getBasePlacement(placement) : null;\n var variation = placement ? getVariation(placement) : null;\n var commonX = reference.x + reference.width / 2 - element.width / 2;\n var commonY = reference.y + reference.height / 2 - element.height / 2;\n var offsets;\n\n switch (basePlacement) {\n case top:\n offsets = {\n x: commonX,\n y: reference.y - element.height\n };\n break;\n\n case bottom:\n offsets = {\n x: commonX,\n y: reference.y + reference.height\n };\n break;\n\n case right:\n offsets = {\n x: reference.x + reference.width,\n y: commonY\n };\n break;\n\n case left:\n offsets = {\n x: reference.x - element.width,\n y: commonY\n };\n break;\n\n default:\n offsets = {\n x: reference.x,\n y: reference.y\n };\n }\n\n var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;\n\n if (mainAxis != null) {\n var len = mainAxis === 'y' ? 'height' : 'width';\n\n switch (variation) {\n case start:\n offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);\n break;\n\n case end:\n offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);\n break;\n\n default:\n }\n }\n\n return offsets;\n}","import getClippingRect from \"../dom-utils/getClippingRect.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getBoundingClientRect from \"../dom-utils/getBoundingClientRect.js\";\nimport computeOffsets from \"./computeOffsets.js\";\nimport rectToClientRect from \"./rectToClientRect.js\";\nimport { clippingParents, reference, popper, bottom, top, right, basePlacements, viewport } from \"../enums.js\";\nimport { isElement } from \"../dom-utils/instanceOf.js\";\nimport mergePaddingObject from \"./mergePaddingObject.js\";\nimport expandToHashMap from \"./expandToHashMap.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport default function detectOverflow(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n _options$placement = _options.placement,\n placement = _options$placement === void 0 ? state.placement : _options$placement,\n _options$strategy = _options.strategy,\n strategy = _options$strategy === void 0 ? state.strategy : _options$strategy,\n _options$boundary = _options.boundary,\n boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,\n _options$rootBoundary = _options.rootBoundary,\n rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,\n _options$elementConte = _options.elementContext,\n elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,\n _options$altBoundary = _options.altBoundary,\n altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,\n _options$padding = _options.padding,\n padding = _options$padding === void 0 ? 0 : _options$padding;\n var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n var altContext = elementContext === popper ? reference : popper;\n var popperRect = state.rects.popper;\n var element = state.elements[altBoundary ? altContext : elementContext];\n var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy);\n var referenceClientRect = getBoundingClientRect(state.elements.reference);\n var popperOffsets = computeOffsets({\n reference: referenceClientRect,\n element: popperRect,\n strategy: 'absolute',\n placement: placement\n });\n var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));\n var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect\n // 0 or negative = within the clipping rect\n\n var overflowOffsets = {\n top: clippingClientRect.top - elementClientRect.top + paddingObject.top,\n bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,\n left: clippingClientRect.left - elementClientRect.left + paddingObject.left,\n right: elementClientRect.right - clippingClientRect.right + paddingObject.right\n };\n var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element\n\n if (elementContext === popper && offsetData) {\n var offset = offsetData[placement];\n Object.keys(overflowOffsets).forEach(function (key) {\n var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;\n var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';\n overflowOffsets[key] += offset[axis] * multiply;\n });\n }\n\n return overflowOffsets;\n}","import getVariation from \"./getVariation.js\";\nimport { variationPlacements, basePlacements, placements as allPlacements } from \"../enums.js\";\nimport detectOverflow from \"./detectOverflow.js\";\nimport getBasePlacement from \"./getBasePlacement.js\";\nexport default function computeAutoPlacement(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n placement = _options.placement,\n boundary = _options.boundary,\n rootBoundary = _options.rootBoundary,\n padding = _options.padding,\n flipVariations = _options.flipVariations,\n _options$allowedAutoP = _options.allowedAutoPlacements,\n allowedAutoPlacements = _options$allowedAutoP === void 0 ? allPlacements : _options$allowedAutoP;\n var variation = getVariation(placement);\n var placements = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {\n return getVariation(placement) === variation;\n }) : basePlacements;\n var allowedPlacements = placements.filter(function (placement) {\n return allowedAutoPlacements.indexOf(placement) >= 0;\n });\n\n if (allowedPlacements.length === 0) {\n allowedPlacements = placements;\n } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...\n\n\n var overflows = allowedPlacements.reduce(function (acc, placement) {\n acc[placement] = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding\n })[getBasePlacement(placement)];\n return acc;\n }, {});\n return Object.keys(overflows).sort(function (a, b) {\n return overflows[a] - overflows[b];\n });\n}","import getOppositePlacement from \"../utils/getOppositePlacement.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getOppositeVariationPlacement from \"../utils/getOppositeVariationPlacement.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport computeAutoPlacement from \"../utils/computeAutoPlacement.js\";\nimport { bottom, top, start, right, left, auto } from \"../enums.js\";\nimport getVariation from \"../utils/getVariation.js\"; // eslint-disable-next-line import/no-unused-modules\n\nfunction getExpandedFallbackPlacements(placement) {\n if (getBasePlacement(placement) === auto) {\n return [];\n }\n\n var oppositePlacement = getOppositePlacement(placement);\n return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];\n}\n\nfunction flip(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n\n if (state.modifiersData[name]._skip) {\n return;\n }\n\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,\n specifiedFallbackPlacements = options.fallbackPlacements,\n padding = options.padding,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n _options$flipVariatio = options.flipVariations,\n flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,\n allowedAutoPlacements = options.allowedAutoPlacements;\n var preferredPlacement = state.options.placement;\n var basePlacement = getBasePlacement(preferredPlacement);\n var isBasePlacement = basePlacement === preferredPlacement;\n var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));\n var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {\n return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n flipVariations: flipVariations,\n allowedAutoPlacements: allowedAutoPlacements\n }) : placement);\n }, []);\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var checksMap = new Map();\n var makeFallbackChecks = true;\n var firstFittingPlacement = placements[0];\n\n for (var i = 0; i < placements.length; i++) {\n var placement = placements[i];\n\n var _basePlacement = getBasePlacement(placement);\n\n var isStartVariation = getVariation(placement) === start;\n var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;\n var len = isVertical ? 'width' : 'height';\n var overflow = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n altBoundary: altBoundary,\n padding: padding\n });\n var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;\n\n if (referenceRect[len] > popperRect[len]) {\n mainVariationSide = getOppositePlacement(mainVariationSide);\n }\n\n var altVariationSide = getOppositePlacement(mainVariationSide);\n var checks = [];\n\n if (checkMainAxis) {\n checks.push(overflow[_basePlacement] <= 0);\n }\n\n if (checkAltAxis) {\n checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);\n }\n\n if (checks.every(function (check) {\n return check;\n })) {\n firstFittingPlacement = placement;\n makeFallbackChecks = false;\n break;\n }\n\n checksMap.set(placement, checks);\n }\n\n if (makeFallbackChecks) {\n // `2` may be desired in some cases – research later\n var numberOfChecks = flipVariations ? 3 : 1;\n\n var _loop = function _loop(_i) {\n var fittingPlacement = placements.find(function (placement) {\n var checks = checksMap.get(placement);\n\n if (checks) {\n return checks.slice(0, _i).every(function (check) {\n return check;\n });\n }\n });\n\n if (fittingPlacement) {\n firstFittingPlacement = fittingPlacement;\n return \"break\";\n }\n };\n\n for (var _i = numberOfChecks; _i > 0; _i--) {\n var _ret = _loop(_i);\n\n if (_ret === \"break\") break;\n }\n }\n\n if (state.placement !== firstFittingPlacement) {\n state.modifiersData[name]._skip = true;\n state.placement = firstFittingPlacement;\n state.reset = true;\n }\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'flip',\n enabled: true,\n phase: 'main',\n fn: flip,\n requiresIfExists: ['offset'],\n data: {\n _skip: false\n }\n};","import { top, bottom, left, right } from \"../enums.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\n\nfunction getSideOffsets(overflow, rect, preventedOffsets) {\n if (preventedOffsets === void 0) {\n preventedOffsets = {\n x: 0,\n y: 0\n };\n }\n\n return {\n top: overflow.top - rect.height - preventedOffsets.y,\n right: overflow.right - rect.width + preventedOffsets.x,\n bottom: overflow.bottom - rect.height + preventedOffsets.y,\n left: overflow.left - rect.width - preventedOffsets.x\n };\n}\n\nfunction isAnySideFullyClipped(overflow) {\n return [top, right, bottom, left].some(function (side) {\n return overflow[side] >= 0;\n });\n}\n\nfunction hide(_ref) {\n var state = _ref.state,\n name = _ref.name;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var preventedOffsets = state.modifiersData.preventOverflow;\n var referenceOverflow = detectOverflow(state, {\n elementContext: 'reference'\n });\n var popperAltOverflow = detectOverflow(state, {\n altBoundary: true\n });\n var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);\n var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);\n var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);\n var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);\n state.modifiersData[name] = {\n referenceClippingOffsets: referenceClippingOffsets,\n popperEscapeOffsets: popperEscapeOffsets,\n isReferenceHidden: isReferenceHidden,\n hasPopperEscaped: hasPopperEscaped\n };\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-reference-hidden': isReferenceHidden,\n 'data-popper-escaped': hasPopperEscaped\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'hide',\n enabled: true,\n phase: 'main',\n requiresIfExists: ['preventOverflow'],\n fn: hide\n};","import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport { top, left, right, placements } from \"../enums.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport function distanceAndSkiddingToXY(placement, rects, offset) {\n var basePlacement = getBasePlacement(placement);\n var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;\n\n var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {\n placement: placement\n })) : offset,\n skidding = _ref[0],\n distance = _ref[1];\n\n skidding = skidding || 0;\n distance = (distance || 0) * invertDistance;\n return [left, right].indexOf(basePlacement) >= 0 ? {\n x: distance,\n y: skidding\n } : {\n x: skidding,\n y: distance\n };\n}\n\nfunction offset(_ref2) {\n var state = _ref2.state,\n options = _ref2.options,\n name = _ref2.name;\n var _options$offset = options.offset,\n offset = _options$offset === void 0 ? [0, 0] : _options$offset;\n var data = placements.reduce(function (acc, placement) {\n acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);\n return acc;\n }, {});\n var _data$state$placement = data[state.placement],\n x = _data$state$placement.x,\n y = _data$state$placement.y;\n\n if (state.modifiersData.popperOffsets != null) {\n state.modifiersData.popperOffsets.x += x;\n state.modifiersData.popperOffsets.y += y;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'offset',\n enabled: true,\n phase: 'main',\n requires: ['popperOffsets'],\n fn: offset\n};","import computeOffsets from \"../utils/computeOffsets.js\";\n\nfunction popperOffsets(_ref) {\n var state = _ref.state,\n name = _ref.name;\n // Offsets are the actual position the popper needs to have to be\n // properly positioned near its reference element\n // This is the most basic placement, and will be adjusted by\n // the modifiers in the next step\n state.modifiersData[name] = computeOffsets({\n reference: state.rects.reference,\n element: state.rects.popper,\n strategy: 'absolute',\n placement: state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'popperOffsets',\n enabled: true,\n phase: 'read',\n fn: popperOffsets,\n data: {}\n};","import { top, left, right, bottom, start } from \"../enums.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport getAltAxis from \"../utils/getAltAxis.js\";\nimport { within, withinMaxClamp } from \"../utils/within.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport getFreshSideObject from \"../utils/getFreshSideObject.js\";\nimport { min as mathMin, max as mathMax } from \"../utils/math.js\";\n\nfunction preventOverflow(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n padding = options.padding,\n _options$tether = options.tether,\n tether = _options$tether === void 0 ? true : _options$tether,\n _options$tetherOffset = options.tetherOffset,\n tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;\n var overflow = detectOverflow(state, {\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n altBoundary: altBoundary\n });\n var basePlacement = getBasePlacement(state.placement);\n var variation = getVariation(state.placement);\n var isBasePlacement = !variation;\n var mainAxis = getMainAxisFromPlacement(basePlacement);\n var altAxis = getAltAxis(mainAxis);\n var popperOffsets = state.modifiersData.popperOffsets;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {\n placement: state.placement\n })) : tetherOffset;\n var normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? {\n mainAxis: tetherOffsetValue,\n altAxis: tetherOffsetValue\n } : Object.assign({\n mainAxis: 0,\n altAxis: 0\n }, tetherOffsetValue);\n var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null;\n var data = {\n x: 0,\n y: 0\n };\n\n if (!popperOffsets) {\n return;\n }\n\n if (checkMainAxis) {\n var _offsetModifierState$;\n\n var mainSide = mainAxis === 'y' ? top : left;\n var altSide = mainAxis === 'y' ? bottom : right;\n var len = mainAxis === 'y' ? 'height' : 'width';\n var offset = popperOffsets[mainAxis];\n var min = offset + overflow[mainSide];\n var max = offset - overflow[altSide];\n var additive = tether ? -popperRect[len] / 2 : 0;\n var minLen = variation === start ? referenceRect[len] : popperRect[len];\n var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go\n // outside the reference bounds\n\n var arrowElement = state.elements.arrow;\n var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {\n width: 0,\n height: 0\n };\n var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();\n var arrowPaddingMin = arrowPaddingObject[mainSide];\n var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want\n // to include its full size in the calculation. If the reference is small\n // and near the edge of a boundary, the popper can overflow even if the\n // reference is not overflowing as well (e.g. virtual elements with no\n // width or height)\n\n var arrowLen = within(0, referenceRect[len], arrowRect[len]);\n var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis;\n var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis;\n var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);\n var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;\n var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0;\n var tetherMin = offset + minOffset - offsetModifierValue - clientOffset;\n var tetherMax = offset + maxOffset - offsetModifierValue;\n var preventedOffset = within(tether ? mathMin(min, tetherMin) : min, offset, tether ? mathMax(max, tetherMax) : max);\n popperOffsets[mainAxis] = preventedOffset;\n data[mainAxis] = preventedOffset - offset;\n }\n\n if (checkAltAxis) {\n var _offsetModifierState$2;\n\n var _mainSide = mainAxis === 'x' ? top : left;\n\n var _altSide = mainAxis === 'x' ? bottom : right;\n\n var _offset = popperOffsets[altAxis];\n\n var _len = altAxis === 'y' ? 'height' : 'width';\n\n var _min = _offset + overflow[_mainSide];\n\n var _max = _offset - overflow[_altSide];\n\n var isOriginSide = [top, left].indexOf(basePlacement) !== -1;\n\n var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0;\n\n var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis;\n\n var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max;\n\n var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);\n\n popperOffsets[altAxis] = _preventedOffset;\n data[altAxis] = _preventedOffset - _offset;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'preventOverflow',\n enabled: true,\n phase: 'main',\n fn: preventOverflow,\n requiresIfExists: ['offset']\n};","export default function getAltAxis(axis) {\n return axis === 'x' ? 'y' : 'x';\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getNodeScroll from \"./getNodeScroll.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport isScrollParent from \"./isScrollParent.js\";\nimport { round } from \"../utils/math.js\";\n\nfunction isElementScaled(element) {\n var rect = element.getBoundingClientRect();\n var scaleX = round(rect.width) / element.offsetWidth || 1;\n var scaleY = round(rect.height) / element.offsetHeight || 1;\n return scaleX !== 1 || scaleY !== 1;\n} // Returns the composite rect of an element relative to its offsetParent.\n// Composite means it takes into account transforms as well as layout.\n\n\nexport default function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {\n if (isFixed === void 0) {\n isFixed = false;\n }\n\n var isOffsetParentAnElement = isHTMLElement(offsetParent);\n var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);\n var documentElement = getDocumentElement(offsetParent);\n var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);\n var scroll = {\n scrollLeft: 0,\n scrollTop: 0\n };\n var offsets = {\n x: 0,\n y: 0\n };\n\n if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {\n if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078\n isScrollParent(documentElement)) {\n scroll = getNodeScroll(offsetParent);\n }\n\n if (isHTMLElement(offsetParent)) {\n offsets = getBoundingClientRect(offsetParent, true);\n offsets.x += offsetParent.clientLeft;\n offsets.y += offsetParent.clientTop;\n } else if (documentElement) {\n offsets.x = getWindowScrollBarX(documentElement);\n }\n }\n\n return {\n x: rect.left + scroll.scrollLeft - offsets.x,\n y: rect.top + scroll.scrollTop - offsets.y,\n width: rect.width,\n height: rect.height\n };\n}","import getWindowScroll from \"./getWindowScroll.js\";\nimport getWindow from \"./getWindow.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getHTMLElementScroll from \"./getHTMLElementScroll.js\";\nexport default function getNodeScroll(node) {\n if (node === getWindow(node) || !isHTMLElement(node)) {\n return getWindowScroll(node);\n } else {\n return getHTMLElementScroll(node);\n }\n}","export default function getHTMLElementScroll(element) {\n return {\n scrollLeft: element.scrollLeft,\n scrollTop: element.scrollTop\n };\n}","import { modifierPhases } from \"../enums.js\"; // source: https://stackoverflow.com/questions/49875255\n\nfunction order(modifiers) {\n var map = new Map();\n var visited = new Set();\n var result = [];\n modifiers.forEach(function (modifier) {\n map.set(modifier.name, modifier);\n }); // On visiting object, check for its dependencies and visit them recursively\n\n function sort(modifier) {\n visited.add(modifier.name);\n var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);\n requires.forEach(function (dep) {\n if (!visited.has(dep)) {\n var depModifier = map.get(dep);\n\n if (depModifier) {\n sort(depModifier);\n }\n }\n });\n result.push(modifier);\n }\n\n modifiers.forEach(function (modifier) {\n if (!visited.has(modifier.name)) {\n // check for visited object\n sort(modifier);\n }\n });\n return result;\n}\n\nexport default function orderModifiers(modifiers) {\n // order based on dependencies\n var orderedModifiers = order(modifiers); // order based on phase\n\n return modifierPhases.reduce(function (acc, phase) {\n return acc.concat(orderedModifiers.filter(function (modifier) {\n return modifier.phase === phase;\n }));\n }, []);\n}","import getCompositeRect from \"./dom-utils/getCompositeRect.js\";\nimport getLayoutRect from \"./dom-utils/getLayoutRect.js\";\nimport listScrollParents from \"./dom-utils/listScrollParents.js\";\nimport getOffsetParent from \"./dom-utils/getOffsetParent.js\";\nimport orderModifiers from \"./utils/orderModifiers.js\";\nimport debounce from \"./utils/debounce.js\";\nimport mergeByName from \"./utils/mergeByName.js\";\nimport detectOverflow from \"./utils/detectOverflow.js\";\nimport { isElement } from \"./dom-utils/instanceOf.js\";\nvar DEFAULT_OPTIONS = {\n placement: 'bottom',\n modifiers: [],\n strategy: 'absolute'\n};\n\nfunction areValidElements() {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n return !args.some(function (element) {\n return !(element && typeof element.getBoundingClientRect === 'function');\n });\n}\n\nexport function popperGenerator(generatorOptions) {\n if (generatorOptions === void 0) {\n generatorOptions = {};\n }\n\n var _generatorOptions = generatorOptions,\n _generatorOptions$def = _generatorOptions.defaultModifiers,\n defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,\n _generatorOptions$def2 = _generatorOptions.defaultOptions,\n defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;\n return function createPopper(reference, popper, options) {\n if (options === void 0) {\n options = defaultOptions;\n }\n\n var state = {\n placement: 'bottom',\n orderedModifiers: [],\n options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),\n modifiersData: {},\n elements: {\n reference: reference,\n popper: popper\n },\n attributes: {},\n styles: {}\n };\n var effectCleanupFns = [];\n var isDestroyed = false;\n var instance = {\n state: state,\n setOptions: function setOptions(setOptionsAction) {\n var options = typeof setOptionsAction === 'function' ? setOptionsAction(state.options) : setOptionsAction;\n cleanupModifierEffects();\n state.options = Object.assign({}, defaultOptions, state.options, options);\n state.scrollParents = {\n reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],\n popper: listScrollParents(popper)\n }; // Orders the modifiers based on their dependencies and `phase`\n // properties\n\n var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers\n\n state.orderedModifiers = orderedModifiers.filter(function (m) {\n return m.enabled;\n });\n runModifierEffects();\n return instance.update();\n },\n // Sync update – it will always be executed, even if not necessary. This\n // is useful for low frequency updates where sync behavior simplifies the\n // logic.\n // For high frequency updates (e.g. `resize` and `scroll` events), always\n // prefer the async Popper#update method\n forceUpdate: function forceUpdate() {\n if (isDestroyed) {\n return;\n }\n\n var _state$elements = state.elements,\n reference = _state$elements.reference,\n popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements\n // anymore\n\n if (!areValidElements(reference, popper)) {\n return;\n } // Store the reference and popper rects to be read by modifiers\n\n\n state.rects = {\n reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),\n popper: getLayoutRect(popper)\n }; // Modifiers have the ability to reset the current update cycle. The\n // most common use case for this is the `flip` modifier changing the\n // placement, which then needs to re-run all the modifiers, because the\n // logic was previously ran for the previous placement and is therefore\n // stale/incorrect\n\n state.reset = false;\n state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier\n // is filled with the initial data specified by the modifier. This means\n // it doesn't persist and is fresh on each update.\n // To ensure persistent data, use `${name}#persistent`\n\n state.orderedModifiers.forEach(function (modifier) {\n return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);\n });\n\n for (var index = 0; index < state.orderedModifiers.length; index++) {\n if (state.reset === true) {\n state.reset = false;\n index = -1;\n continue;\n }\n\n var _state$orderedModifie = state.orderedModifiers[index],\n fn = _state$orderedModifie.fn,\n _state$orderedModifie2 = _state$orderedModifie.options,\n _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,\n name = _state$orderedModifie.name;\n\n if (typeof fn === 'function') {\n state = fn({\n state: state,\n options: _options,\n name: name,\n instance: instance\n }) || state;\n }\n }\n },\n // Async and optimistically optimized update – it will not be executed if\n // not necessary (debounced to run at most once-per-tick)\n update: debounce(function () {\n return new Promise(function (resolve) {\n instance.forceUpdate();\n resolve(state);\n });\n }),\n destroy: function destroy() {\n cleanupModifierEffects();\n isDestroyed = true;\n }\n };\n\n if (!areValidElements(reference, popper)) {\n return instance;\n }\n\n instance.setOptions(options).then(function (state) {\n if (!isDestroyed && options.onFirstUpdate) {\n options.onFirstUpdate(state);\n }\n }); // Modifiers have the ability to execute arbitrary code before the first\n // update cycle runs. They will be executed in the same order as the update\n // cycle. This is useful when a modifier adds some persistent data that\n // other modifiers need to use, but the modifier is run after the dependent\n // one.\n\n function runModifierEffects() {\n state.orderedModifiers.forEach(function (_ref) {\n var name = _ref.name,\n _ref$options = _ref.options,\n options = _ref$options === void 0 ? {} : _ref$options,\n effect = _ref.effect;\n\n if (typeof effect === 'function') {\n var cleanupFn = effect({\n state: state,\n name: name,\n instance: instance,\n options: options\n });\n\n var noopFn = function noopFn() {};\n\n effectCleanupFns.push(cleanupFn || noopFn);\n }\n });\n }\n\n function cleanupModifierEffects() {\n effectCleanupFns.forEach(function (fn) {\n return fn();\n });\n effectCleanupFns = [];\n }\n\n return instance;\n };\n}\nexport var createPopper = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules\n\nexport { detectOverflow };","export default function debounce(fn) {\n var pending;\n return function () {\n if (!pending) {\n pending = new Promise(function (resolve) {\n Promise.resolve().then(function () {\n pending = undefined;\n resolve(fn());\n });\n });\n }\n\n return pending;\n };\n}","export default function mergeByName(modifiers) {\n var merged = modifiers.reduce(function (merged, current) {\n var existing = merged[current.name];\n merged[current.name] = existing ? Object.assign({}, existing, current, {\n options: Object.assign({}, existing.options, current.options),\n data: Object.assign({}, existing.data, current.data)\n }) : current;\n return merged;\n }, {}); // IE11 does not support Object.values\n\n return Object.keys(merged).map(function (key) {\n return merged[key];\n });\n}","import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow };","import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nimport offset from \"./modifiers/offset.js\";\nimport flip from \"./modifiers/flip.js\";\nimport preventOverflow from \"./modifiers/preventOverflow.js\";\nimport arrow from \"./modifiers/arrow.js\";\nimport hide from \"./modifiers/hide.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles, offset, flip, preventOverflow, arrow, hide];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow }; // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper as createPopperLite } from \"./popper-lite.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport * from \"./modifiers/index.js\";","/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n execute,\n getElement,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center'\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)'\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR = '.navbar'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\nconst PLACEMENT_TOPCENTER = 'top'\nconst PLACEMENT_BOTTOMCENTER = 'bottom'\n\nconst Default = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n}\n\nconst DefaultType = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n}\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._popper = null\n this._parent = this._element.parentNode // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.findOne(SELECTOR_MENU, this._parent)\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._createPopper()\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = super._getConfig(config)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org/docs/v2/)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = this._parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n }\n\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getPlacement() {\n const parentDropdown = this._parent\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig])\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {\n return\n }\n\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)\n\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle)\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n const relatedTarget = { relatedTarget: context._element }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName)\n const isEscapeEvent = event.key === ESCAPE_KEY\n const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)\n\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return\n }\n\n if (isInput && !isEscapeEvent) {\n return\n }\n\n event.preventDefault()\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?\n this :\n (SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode))\n\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (isUpOrDownEvent) {\n event.stopPropagation()\n instance.show()\n instance._selectMenuItem(event)\n return\n }\n\n if (instance._isShown()) { // else is escape and we check if it is shown\n event.stopPropagation()\n instance.hide()\n getToggleButton.focus()\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport {\n execute, executeAfterTransition, getElement, reflow\n} from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nconst Default = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n}\n\nconst DefaultType = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n}\n\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n const element = this._getElement()\n if (this._config.isAnimated) {\n reflow(element)\n }\n\n element.classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n const element = this._getElement()\n this._config.rootElement.append(element)\n\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nconst Default = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n}\n\nconst DefaultType = {\n autofocus: 'boolean',\n trapElement: 'element'\n}\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return\n }\n\n if (this._config.autofocus) {\n this._config.trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n _handleFocusin(event) {\n const { trapElement } = this._config\n\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\nconst PROPERTY_PADDING = 'padding-right'\nconst PROPERTY_MARGIN = 'margin-right'\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProperty)\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty)\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty)\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty)\n return\n }\n\n Manipulator.removeDataAttribute(element, styleProperty)\n element.style.setProperty(styleProperty, value)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n return\n }\n\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel)\n }\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin, isRTL, isVisible, reflow\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\nconst Default = {\n backdrop: true,\n focus: true,\n keyboard: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._isTransitioning = true\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._backdrop.show(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n this._isTransitioning = true\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated())\n }\n\n dispose() {\n EventHandler.off(window, EVENT_KEY)\n EventHandler.off(this._dialog, EVENT_KEY)\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated())\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n this._triggerBackdropTransition()\n })\n\n EventHandler.on(window, EVENT_RESIZE, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog()\n }\n })\n\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return\n }\n\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n return\n }\n\n if (this._config.backdrop) {\n this.hide()\n }\n })\n })\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const initialOverflowY = this._element.style.overflowY\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden'\n }\n\n this._element.classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY\n }, this._dialog)\n }, this._dialog)\n\n this._element.focus()\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin,\n isDisabled,\n isVisible\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\nconst CLASS_NAME_HIDING = 'hiding'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate()\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.add(CLASS_NAME_HIDING)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n return\n }\n\n this.hide()\n }\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop)\n\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n })\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show()\n }\n})\n\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide()\n }\n }\n})\n\nenableDismissTrigger(Offcanvas)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n dd: [],\n div: [],\n dl: [],\n dt: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n// js-docs-end allow-list\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n .some(regex => regex.test(attributeName))\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n }\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\nimport { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'\nimport { execute, getElement, isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'TemplateFactory'\n\nconst Default = {\n allowList: DefaultAllowlist,\n content: {}, // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '<div></div>'\n}\n\nconst DefaultType = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n}\n\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n}\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content)\n .map(config => this._resolvePossibleFunction(config))\n .filter(Boolean)\n }\n\n hasContent() {\n return this.getContent().length > 0\n }\n\n changeContent(content) {\n this._checkContent(content)\n this._config.content = { ...this._config.content, ...content }\n return this\n }\n\n toHtml() {\n const templateWrapper = document.createElement('div')\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template)\n\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector)\n }\n\n const template = templateWrapper.children[0]\n const extraClass = this._resolvePossibleFunction(this._config.extraClass)\n\n if (extraClass) {\n template.classList.add(...extraClass.split(' '))\n }\n\n return template\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config)\n this._checkContent(config.content)\n }\n\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({ selector, entry: content }, DefaultContentType)\n }\n }\n\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!templateElement) {\n return\n }\n\n content = this._resolvePossibleFunction(content)\n\n if (!content) {\n templateElement.remove()\n return\n }\n\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement)\n return\n }\n\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content)\n return\n }\n\n templateElement.textContent = content\n }\n\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [undefined, this])\n }\n\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = ''\n templateElement.append(element)\n return\n }\n\n templateElement.textContent = element.textContent\n }\n}\n\nexport default TemplateFactory\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport {\n defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop\n} from './util/index.js'\nimport { DefaultAllowlist } from './util/sanitizer.js'\nimport TemplateFactory from './util/template-factory.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\nconst EVENT_HIDE = 'hide'\nconst EVENT_HIDDEN = 'hidden'\nconst EVENT_SHOW = 'show'\nconst EVENT_SHOWN = 'shown'\nconst EVENT_INSERTED = 'inserted'\nconst EVENT_CLICK = 'click'\nconst EVENT_FOCUSIN = 'focusin'\nconst EVENT_FOCUSOUT = 'focusout'\nconst EVENT_MOUSEENTER = 'mouseenter'\nconst EVENT_MOUSELEAVE = 'mouseleave'\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '<div class=\"tooltip\" role=\"tooltip\">' +\n '<div class=\"tooltip-arrow\"></div>' +\n '<div class=\"tooltip-inner\"></div>' +\n '</div>',\n title: '',\n trigger: 'hover focus'\n}\n\nconst DefaultType = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n}\n\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org/docs/v2/)')\n }\n\n super(element, config)\n\n // Private\n this._isEnabled = true\n this._timeout = 0\n this._isHovered = null\n this._activeTrigger = {}\n this._popper = null\n this._templateFactory = null\n this._newContent = null\n\n // Protected\n this.tip = null\n\n this._setListeners()\n\n if (!this._config.selector) {\n this._fixTitle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle() {\n if (!this._isEnabled) {\n return\n }\n\n if (this._isShown()) {\n this._leave()\n return\n }\n\n this._enter()\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'))\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this._isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW))\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper()\n\n const tip = this._getTipElement()\n\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'))\n\n const { container } = this._config\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))\n }\n\n this._popper = this._createPopper(tip)\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN))\n\n if (this._isHovered === false) {\n this._leave()\n }\n\n this._isHovered = false\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n hide() {\n if (!this._isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE))\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const tip = this._getTipElement()\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n this._isHovered = null // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (!this._isHovered) {\n this._disposePopper()\n }\n\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN))\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n update() {\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle())\n }\n\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())\n }\n\n return this.tip\n }\n\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml()\n\n // TODO: remove this check in v6\n if (!tip) {\n return null\n }\n\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`)\n\n const tipId = getUID(this.constructor.NAME).toString()\n\n tip.setAttribute('id', tipId)\n\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n return tip\n }\n\n setContent(content) {\n this._newContent = content\n if (this._isShown()) {\n this._disposePopper()\n this.show()\n }\n }\n\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content)\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n })\n }\n\n return this._templateFactory\n }\n\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n }\n }\n\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title')\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _isAnimated() {\n return this._config.animation || (this.tip && this.tip.classList.contains(CLASS_NAME_FADE))\n }\n\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW)\n }\n\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element])\n const attachment = AttachmentMap[placement.toUpperCase()]\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element, this._element])\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement)\n }\n }\n ]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig])\n }\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[TRIGGER_CLICK] = !(context._isShown() && context._activeTrigger[TRIGGER_CLICK])\n context.toggle()\n })\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSEENTER) :\n this.constructor.eventName(EVENT_FOCUSIN)\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSELEAVE) :\n this.constructor.eventName(EVENT_FOCUSOUT)\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true\n context._enter()\n })\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] =\n context._element.contains(event.relatedTarget)\n\n context._leave()\n })\n }\n }\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n\n if (!title) {\n return\n }\n\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('data-bs-original-title', title) // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title')\n }\n\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true\n return\n }\n\n this._isHovered = true\n\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show()\n }\n }, this._config.delay.show)\n }\n\n _leave() {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n this._isHovered = false\n\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide()\n }\n }, this._config.delay.hide)\n }\n\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout)\n this._timeout = setTimeout(handler, timeout)\n }\n\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true)\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute]\n }\n }\n\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value\n }\n }\n\n config.selector = false\n config.trigger = 'manual'\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n\n if (this.tip) {\n this.tip.remove()\n this.tip = null\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Tooltip from './tooltip.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'popover'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Default = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>',\n trigger: 'click'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n}\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent()\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n }\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin, getElement, isDisabled, isVisible\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_CLICK = `click${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_TARGET_LINKS = '[href]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst Default = {\n offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n}\n\nconst DefaultType = {\n offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n}\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map()\n this._observableSections = new Map()\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element\n this._activeTarget = null\n this._observer = null\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n }\n this.refresh() // initialize\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables()\n this._maybeEnableSmoothScroll()\n\n if (this._observer) {\n this._observer.disconnect()\n } else {\n this._observer = this._getNewObserver()\n }\n\n for (const section of this._observableSections.values()) {\n this._observer.observe(section)\n }\n }\n\n dispose() {\n this._observer.disconnect()\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin\n\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))\n }\n\n return config\n }\n\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK)\n\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash)\n if (observableSection) {\n event.preventDefault()\n const root = this._rootElement || window\n const height = observableSection.offsetTop - this._element.offsetTop\n if (root.scrollTo) {\n root.scrollTo({ top: height, behavior: 'smooth' })\n return\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height\n }\n })\n }\n\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n }\n\n return new IntersectionObserver(entries => this._observerCallback(entries), options)\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop\n this._process(targetElement(entry))\n }\n\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop\n this._previousScrollData.parentScrollTop = parentScrollTop\n\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null\n this._clearActiveClass(targetElement(entry))\n\n continue\n }\n\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry)\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return\n }\n\n continue\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry)\n }\n }\n }\n\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map()\n this._observableSections = new Map()\n\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)\n\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue\n }\n\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor)\n this._observableSections.set(anchor.hash, observableSection)\n }\n }\n }\n\n _process(target) {\n if (this._activeTarget === target) {\n return\n }\n\n this._clearActiveClass(this._config.target)\n this._activeTarget = target\n target.classList.add(CLASS_NAME_ACTIVE)\n this._activateParents(target)\n\n EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })\n }\n\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n return\n }\n\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {\n item.classList.add(CLASS_NAME_ACTIVE)\n }\n }\n }\n\n _clearActiveClass(parent) {\n parent.classList.remove(CLASS_NAME_ACTIVE)\n\n const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent)\n for (const node of activeNodes) {\n node.classList.remove(CLASS_NAME_ACTIVE)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = ScrollSpy.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {\n ScrollSpy.getOrCreateInstance(spy)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(ScrollSpy)\n\nexport default ScrollSpy\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tab.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tab'\nconst DATA_KEY = 'bs.tab'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}`\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst HOME_KEY = 'Home'\nconst END_KEY = 'End'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_DROPDOWN = 'dropdown'\n\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\nconst SELECTOR_DROPDOWN_MENU = '.dropdown-menu'\nconst NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`\n\nconst SELECTOR_TAB_PANEL = '.list-group, .nav, [role=\"tablist\"]'\nconst SELECTOR_OUTER = '.nav-item, .list-group-item'\nconst SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role=\"tab\"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]' // TODO: could only be `tab` in v6\nconst SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`\n\nconst SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle=\"tab\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"pill\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"list\"]`\n\n/**\n * Class definition\n */\n\nclass Tab extends BaseComponent {\n constructor(element) {\n super(element)\n this._parent = this._element.closest(SELECTOR_TAB_PANEL)\n\n if (!this._parent) {\n return\n // TODO: should throw exception in v6\n // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)\n }\n\n // Set up initial aria attributes\n this._setInitialAttributes(this._parent, this._getChildren())\n\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n show() { // Shows this elem and deactivate the active sibling if exists\n const innerElem = this._element\n if (this._elemIsActive(innerElem)) {\n return\n }\n\n // Search for active tab on same parent to deactivate it\n const active = this._getActiveElem()\n\n const hideEvent = active ?\n EventHandler.trigger(active, EVENT_HIDE, { relatedTarget: innerElem }) :\n null\n\n const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, { relatedTarget: active })\n\n if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {\n return\n }\n\n this._deactivate(active, innerElem)\n this._activate(innerElem, active)\n }\n\n // Private\n _activate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.add(CLASS_NAME_ACTIVE)\n\n this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.add(CLASS_NAME_SHOW)\n return\n }\n\n element.removeAttribute('tabindex')\n element.setAttribute('aria-selected', true)\n this._toggleDropDown(element, true)\n EventHandler.trigger(element, EVENT_SHOWN, {\n relatedTarget: relatedElem\n })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _deactivate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.remove(CLASS_NAME_ACTIVE)\n element.blur()\n\n this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.remove(CLASS_NAME_SHOW)\n return\n }\n\n element.setAttribute('aria-selected', false)\n element.setAttribute('tabindex', '-1')\n this._toggleDropDown(element, false)\n EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _keydown(event) {\n if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key))) {\n return\n }\n\n event.stopPropagation()// stopPropagation/preventDefault both added to support up/down keys without scrolling the page\n event.preventDefault()\n\n const children = this._getChildren().filter(element => !isDisabled(element))\n let nextActiveElement\n\n if ([HOME_KEY, END_KEY].includes(event.key)) {\n nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]\n } else {\n const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)\n nextActiveElement = getNextActiveElement(children, event.target, isNext, true)\n }\n\n if (nextActiveElement) {\n nextActiveElement.focus({ preventScroll: true })\n Tab.getOrCreateInstance(nextActiveElement).show()\n }\n }\n\n _getChildren() { // collection of inner elements\n return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent)\n }\n\n _getActiveElem() {\n return this._getChildren().find(child => this._elemIsActive(child)) || null\n }\n\n _setInitialAttributes(parent, children) {\n this._setAttributeIfNotExists(parent, 'role', 'tablist')\n\n for (const child of children) {\n this._setInitialAttributesOnChild(child)\n }\n }\n\n _setInitialAttributesOnChild(child) {\n child = this._getInnerElement(child)\n const isActive = this._elemIsActive(child)\n const outerElem = this._getOuterElement(child)\n child.setAttribute('aria-selected', isActive)\n\n if (outerElem !== child) {\n this._setAttributeIfNotExists(outerElem, 'role', 'presentation')\n }\n\n if (!isActive) {\n child.setAttribute('tabindex', '-1')\n }\n\n this._setAttributeIfNotExists(child, 'role', 'tab')\n\n // set attributes to the related panel too\n this._setInitialAttributesOnTargetPanel(child)\n }\n\n _setInitialAttributesOnTargetPanel(child) {\n const target = SelectorEngine.getElementFromSelector(child)\n\n if (!target) {\n return\n }\n\n this._setAttributeIfNotExists(target, 'role', 'tabpanel')\n\n if (child.id) {\n this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)\n }\n }\n\n _toggleDropDown(element, open) {\n const outerElem = this._getOuterElement(element)\n if (!outerElem.classList.contains(CLASS_DROPDOWN)) {\n return\n }\n\n const toggle = (selector, className) => {\n const element = SelectorEngine.findOne(selector, outerElem)\n if (element) {\n element.classList.toggle(className, open)\n }\n }\n\n toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)\n toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)\n outerElem.setAttribute('aria-expanded', open)\n }\n\n _setAttributeIfNotExists(element, attribute, value) {\n if (!element.hasAttribute(attribute)) {\n element.setAttribute(attribute, value)\n }\n }\n\n _elemIsActive(elem) {\n return elem.classList.contains(CLASS_NAME_ACTIVE)\n }\n\n // Try to get the inner element (usually the .nav-link)\n _getInnerElement(elem) {\n return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem)\n }\n\n // Try to get the outer element (usually the .nav-item)\n _getOuterElement(elem) {\n return elem.closest(SELECTOR_OUTER) || elem\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tab.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n Tab.getOrCreateInstance(this).show()\n})\n\n/**\n * Initialize on focus\n */\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {\n Tab.getOrCreateInstance(element)\n }\n})\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tab)\n\nexport default Tab\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap toast.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin, reflow } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'toast'\nconst DATA_KEY = 'bs.toast'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\n\nconst DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n}\n\nconst Default = {\n animation: true,\n autohide: true,\n delay: 5000\n}\n\n/**\n * Class definition\n */\n\nclass Toast extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._timeout = null\n this._hasMouseInteraction = false\n this._hasKeyboardInteraction = false\n this._setListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show() {\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._clearTimeout()\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE)\n }\n\n const complete = () => {\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN)\n\n this._maybeScheduleHide()\n }\n\n this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\n reflow(this._element)\n this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)\n\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n hide() {\n if (!this.isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const complete = () => {\n this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\n this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.classList.add(CLASS_NAME_SHOWING)\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n dispose() {\n this._clearTimeout()\n\n if (this.isShown()) {\n this._element.classList.remove(CLASS_NAME_SHOW)\n }\n\n super.dispose()\n }\n\n isShown() {\n return this._element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n _maybeScheduleHide() {\n if (!this._config.autohide) {\n return\n }\n\n if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\n return\n }\n\n this._timeout = setTimeout(() => {\n this.hide()\n }, this._config.delay)\n }\n\n _onInteraction(event, isInteracting) {\n switch (event.type) {\n case 'mouseover':\n case 'mouseout': {\n this._hasMouseInteraction = isInteracting\n break\n }\n\n case 'focusin':\n case 'focusout': {\n this._hasKeyboardInteraction = isInteracting\n break\n }\n\n default: {\n break\n }\n }\n\n if (isInteracting) {\n this._clearTimeout()\n return\n }\n\n const nextElement = event.relatedTarget\n if (this._element === nextElement || this._element.contains(nextElement)) {\n return\n }\n\n this._maybeScheduleHide()\n }\n\n _setListeners() {\n EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\n EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\n }\n\n _clearTimeout() {\n clearTimeout(this._timeout)\n this._timeout = null\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Toast.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Toast)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Toast)\n\nexport default Toast\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap index.umd.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './src/alert.js'\nimport Button from './src/button.js'\nimport Carousel from './src/carousel.js'\nimport Collapse from './src/collapse.js'\nimport Dropdown from './src/dropdown.js'\nimport Modal from './src/modal.js'\nimport Offcanvas from './src/offcanvas.js'\nimport Popover from './src/popover.js'\nimport ScrollSpy from './src/scrollspy.js'\nimport Tab from './src/tab.js'\nimport Toast from './src/toast.js'\nimport Tooltip from './src/tooltip.js'\n\nexport default {\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Offcanvas,\n Popover,\n ScrollSpy,\n Tab,\n Toast,\n Tooltip\n}\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.min.js b/extensions/pagetop-bootsier/static/js/bootstrap.min.js deleted file mode 100644 index 7f2bc627..00000000 --- a/extensions/pagetop-bootsier/static/js/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v5.3.8 (https://getbootstrap.com/) - * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e(t.Popper)}(this,function(t){"use strict";function e(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t)for(const i in t)if("default"!==i){const s=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,s.get?s:{enumerable:!0,get:()=>t[i]})}return e.default=t,Object.freeze(e)}const i=e(t),s=new Map,n={set(t,e,i){s.has(t)||s.set(t,new Map);const n=s.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>s.has(t)&&s.get(t).get(e)||null,remove(t,e){if(!s.has(t))return;const i=s.get(t);i.delete(e),0===i.size&&s.delete(t)}},o="transitionend",r=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,(t,e)=>`#${CSS.escape(e)}`)),t),a=t=>null==t?`${t}`:Object.prototype.toString.call(t).match(/\s([a-z]+)/i)[1].toLowerCase(),l=t=>{t.dispatchEvent(new Event(o))},c=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),h=t=>c(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(r(t)):null,d=t=>{if(!c(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},u=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),_=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?_(t.parentNode):null},g=()=>{},f=t=>{t.offsetHeight},m=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,p=[],b=()=>"rtl"===document.documentElement.dir,v=t=>{var e;e=()=>{const e=m();if(e){const i=t.NAME,s=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=s,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",()=>{for(const t of p)t()}),p.push(e)):e()},y=(t,e=[],i=t)=>"function"==typeof t?t.call(...e):i,w=(t,e,i=!0)=>{if(!i)return void y(t);const s=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const s=Number.parseFloat(e),n=Number.parseFloat(i);return s||n?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let n=!1;const r=({target:i})=>{i===e&&(n=!0,e.removeEventListener(o,r),y(t))};e.addEventListener(o,r),setTimeout(()=>{n||l(e)},s)},A=(t,e,i,s)=>{const n=t.length;let o=t.indexOf(e);return-1===o?!i&&s?t[n-1]:t[0]:(o+=i?1:-1,s&&(o=(o+n)%n),t[Math.max(0,Math.min(o,n-1))])},E=/[^.]*(?=\..*)\.|.*/,C=/\..*/,T=/::\d+$/,k={};let $=1;const S={mouseenter:"mouseover",mouseleave:"mouseout"},L=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${$++}`||t.uidEvent||$++}function I(t){const e=O(t);return t.uidEvent=e,k[e]=k[e]||{},k[e]}function D(t,e,i=null){return Object.values(t).find(t=>t.callable===e&&t.delegationSelector===i)}function N(t,e,i){const s="string"==typeof e,n=s?i:e||i;let o=j(t);return L.has(o)||(o=t),[s,n,o]}function P(t,e,i,s,n){if("string"!=typeof e||!t)return;let[o,r,a]=N(e,i,s);if(e in S){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=I(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&n);const d=O(r,e.replace(E,"")),u=o?function(t,e,i){return function s(n){const o=t.querySelectorAll(e);for(let{target:r}=n;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return z(n,{delegateTarget:r}),s.oneOff&&F.off(t,n.type,e,i),i.apply(r,[n])}}(t,i,r):function(t,e){return function i(s){return z(s,{delegateTarget:t}),i.oneOff&&F.off(t,s.type,e),e.apply(t,[s])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=n,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function x(t,e,i,s,n){const o=D(e[i],s,n);o&&(t.removeEventListener(i,o,Boolean(n)),delete e[i][o.uidEvent])}function M(t,e,i,s){const n=e[i]||{};for(const[o,r]of Object.entries(n))o.includes(s)&&x(t,e,i,r.callable,r.delegationSelector)}function j(t){return t=t.replace(C,""),S[t]||t}const F={on(t,e,i,s){P(t,e,i,s,!1)},one(t,e,i,s){P(t,e,i,s,!0)},off(t,e,i,s){if("string"!=typeof e||!t)return;const[n,o,r]=N(e,i,s),a=r!==e,l=I(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))M(t,l,i,e.slice(1));for(const[i,s]of Object.entries(c)){const n=i.replace(T,"");a&&!e.includes(n)||x(t,l,r,s.callable,s.delegationSelector)}}else{if(!Object.keys(c).length)return;x(t,l,r,o,n?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const s=m();let n=null,o=!0,r=!0,a=!1;e!==j(e)&&s&&(n=s.Event(e,i),s(t).trigger(n),o=!n.isPropagationStopped(),r=!n.isImmediatePropagationStopped(),a=n.isDefaultPrevented());const l=z(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&n&&n.preventDefault(),l}};function z(t,e={}){for(const[i,s]of Object.entries(e))try{t[i]=s}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>s})}return t}function H(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function B(t){return t.replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`)}const q={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${B(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${B(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter(t=>t.startsWith("bs")&&!t.startsWith("bsConfig"));for(const s of i){let i=s.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1),e[i]=H(t.dataset[s])}return e},getDataAttribute:(t,e)=>H(t.getAttribute(`data-bs-${B(e)}`))};class W{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=c(e)?q.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...c(e)?q.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[i,s]of Object.entries(e)){const e=t[i],n=c(e)?"element":a(e);if(!new RegExp(s).test(n))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${i}" provided type "${n}" but expected type "${s}".`)}}}class R extends W{constructor(t,e){super(),(t=h(t))&&(this._element=t,this._config=this._getConfig(e),n.set(this._element,this.constructor.DATA_KEY,this))}dispose(){n.remove(this._element,this.constructor.DATA_KEY),F.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){w(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return n.get(h(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.8"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const K=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map(t=>r(t)).join(","):null},V={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter(t=>t.matches(e)),parents(t,e){const i=[];let s=t.parentNode.closest(e);for(;s;)i.push(s),s=s.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map(t=>`${t}:not([tabindex^="-"])`).join(",");return this.find(e,t).filter(t=>!u(t)&&d(t))},getSelectorFromElement(t){const e=K(t);return e&&V.findOne(e)?e:null},getElementFromSelector(t){const e=K(t);return e?V.findOne(e):null},getMultipleElementsFromSelector(t){const e=K(t);return e?V.find(e):[]}},Q=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;F.on(document,i,`[data-bs-dismiss="${s}"]`,function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),u(this))return;const n=V.getElementFromSelector(this)||this.closest(`.${s}`);t.getOrCreateInstance(n)[e]()})},X=".bs.alert",Y=`close${X}`,U=`closed${X}`;class G extends R{static get NAME(){return"alert"}close(){if(F.trigger(this._element,Y).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback(()=>this._destroyElement(),this._element,t)}_destroyElement(){this._element.remove(),F.trigger(this._element,U),this.dispose()}static jQueryInterface(t){return this.each(function(){const e=G.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}})}}Q(G,"close"),v(G);const J='[data-bs-toggle="button"]';class Z extends R{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each(function(){const e=Z.getOrCreateInstance(this);"toggle"===t&&e[t]()})}}F.on(document,"click.bs.button.data-api",J,t=>{t.preventDefault();const e=t.target.closest(J);Z.getOrCreateInstance(e).toggle()}),v(Z);const tt=".bs.swipe",et=`touchstart${tt}`,it=`touchmove${tt}`,st=`touchend${tt}`,nt=`pointerdown${tt}`,ot=`pointerup${tt}`,rt={endCallback:null,leftCallback:null,rightCallback:null},at={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class lt extends W{constructor(t,e){super(),this._element=t,t&&lt.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return rt}static get DefaultType(){return at}static get NAME(){return"swipe"}dispose(){F.off(this._element,tt)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),y(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&y(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(F.on(this._element,nt,t=>this._start(t)),F.on(this._element,ot,t=>this._end(t)),this._element.classList.add("pointer-event")):(F.on(this._element,et,t=>this._start(t)),F.on(this._element,it,t=>this._move(t)),F.on(this._element,st,t=>this._end(t)))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ct=".bs.carousel",ht=".data-api",dt="ArrowLeft",ut="ArrowRight",_t="next",gt="prev",ft="left",mt="right",pt=`slide${ct}`,bt=`slid${ct}`,vt=`keydown${ct}`,yt=`mouseenter${ct}`,wt=`mouseleave${ct}`,At=`dragstart${ct}`,Et=`load${ct}${ht}`,Ct=`click${ct}${ht}`,Tt="carousel",kt="active",$t=".active",St=".carousel-item",Lt=$t+St,Ot={[dt]:mt,[ut]:ft},It={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Dt={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class Nt extends R{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===Tt&&this.cycle()}static get Default(){return It}static get DefaultType(){return Dt}static get NAME(){return"carousel"}next(){this._slide(_t)}nextWhenVisible(){!document.hidden&&d(this._element)&&this.next()}prev(){this._slide(gt)}pause(){this._isSliding&&l(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval(()=>this.nextWhenVisible(),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?F.one(this._element,bt,()=>this.cycle()):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void F.one(this._element,bt,()=>this.to(t));const i=this._getItemIndex(this._getActive());if(i===t)return;const s=t>i?_t:gt;this._slide(s,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&F.on(this._element,vt,t=>this._keydown(t)),"hover"===this._config.pause&&(F.on(this._element,yt,()=>this.pause()),F.on(this._element,wt,()=>this._maybeEnableCycle())),this._config.touch&&lt.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of V.find(".carousel-item img",this._element))F.on(t,At,t=>t.preventDefault());const t={leftCallback:()=>this._slide(this._directionToOrder(ft)),rightCallback:()=>this._slide(this._directionToOrder(mt)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout(()=>this._maybeEnableCycle(),500+this._config.interval))}};this._swipeHelper=new lt(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Ot[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=V.findOne($t,this._indicatorsElement);e.classList.remove(kt),e.removeAttribute("aria-current");const i=V.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(kt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),s=t===_t,n=e||A(this._getItems(),i,s,this._config.wrap);if(n===i)return;const o=this._getItemIndex(n),r=e=>F.trigger(this._element,e,{relatedTarget:n,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(pt).defaultPrevented)return;if(!i||!n)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=n;const l=s?"carousel-item-start":"carousel-item-end",c=s?"carousel-item-next":"carousel-item-prev";n.classList.add(c),f(n),i.classList.add(l),n.classList.add(l),this._queueCallback(()=>{n.classList.remove(l,c),n.classList.add(kt),i.classList.remove(kt,c,l),this._isSliding=!1,r(bt)},i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return V.findOne(Lt,this._element)}_getItems(){return V.find(St,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return b()?t===ft?gt:_t:t===ft?_t:gt}_orderToDirection(t){return b()?t===gt?ft:mt:t===gt?mt:ft}static jQueryInterface(t){return this.each(function(){const e=Nt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)})}}F.on(document,Ct,"[data-bs-slide], [data-bs-slide-to]",function(t){const e=V.getElementFromSelector(this);if(!e||!e.classList.contains(Tt))return;t.preventDefault();const i=Nt.getOrCreateInstance(e),s=this.getAttribute("data-bs-slide-to");return s?(i.to(s),void i._maybeEnableCycle()):"next"===q.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())}),F.on(window,Et,()=>{const t=V.find('[data-bs-ride="carousel"]');for(const e of t)Nt.getOrCreateInstance(e)}),v(Nt);const Pt=".bs.collapse",xt=`show${Pt}`,Mt=`shown${Pt}`,jt=`hide${Pt}`,Ft=`hidden${Pt}`,zt=`click${Pt}.data-api`,Ht="show",Bt="collapse",qt="collapsing",Wt=`:scope .${Bt} .${Bt}`,Rt='[data-bs-toggle="collapse"]',Kt={parent:null,toggle:!0},Vt={parent:"(null|element)",toggle:"boolean"};class Qt extends R{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=V.find(Rt);for(const t of i){const e=V.getSelectorFromElement(t),i=V.find(e).filter(t=>t===this._element);null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Kt}static get DefaultType(){return Vt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter(t=>t!==this._element).map(t=>Qt.getOrCreateInstance(t,{toggle:!1}))),t.length&&t[0]._isTransitioning)return;if(F.trigger(this._element,xt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Bt),this._element.classList.add(qt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback(()=>{this._isTransitioning=!1,this._element.classList.remove(qt),this._element.classList.add(Bt,Ht),this._element.style[e]="",F.trigger(this._element,Mt)},this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(F.trigger(this._element,jt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,f(this._element),this._element.classList.add(qt),this._element.classList.remove(Bt,Ht);for(const t of this._triggerArray){const e=V.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback(()=>{this._isTransitioning=!1,this._element.classList.remove(qt),this._element.classList.add(Bt),F.trigger(this._element,Ft)},this._element,!0)}_isShown(t=this._element){return t.classList.contains(Ht)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=h(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Rt);for(const e of t){const t=V.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=V.find(Wt,this._config.parent);return V.find(t,this._config.parent).filter(t=>!e.includes(t))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each(function(){const i=Qt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}})}}F.on(document,zt,Rt,function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of V.getMultipleElementsFromSelector(this))Qt.getOrCreateInstance(t,{toggle:!1}).toggle()}),v(Qt);const Xt="dropdown",Yt=".bs.dropdown",Ut=".data-api",Gt="ArrowUp",Jt="ArrowDown",Zt=`hide${Yt}`,te=`hidden${Yt}`,ee=`show${Yt}`,ie=`shown${Yt}`,se=`click${Yt}${Ut}`,ne=`keydown${Yt}${Ut}`,oe=`keyup${Yt}${Ut}`,re="show",ae='[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)',le=`${ae}.${re}`,ce=".dropdown-menu",he=b()?"top-end":"top-start",de=b()?"top-start":"top-end",ue=b()?"bottom-end":"bottom-start",_e=b()?"bottom-start":"bottom-end",ge=b()?"left-start":"right-start",fe=b()?"right-start":"left-start",me={autoClose:!0,boundary:"clippingParents",display:"dynamic",offset:[0,2],popperConfig:null,reference:"toggle"},pe={autoClose:"(boolean|string)",boundary:"(string|element)",display:"string",offset:"(array|string|function)",popperConfig:"(null|object|function)",reference:"(string|element|object)"};class be extends R{constructor(t,e){super(t,e),this._popper=null,this._parent=this._element.parentNode,this._menu=V.next(this._element,ce)[0]||V.prev(this._element,ce)[0]||V.findOne(ce,this._parent),this._inNavbar=this._detectNavbar()}static get Default(){return me}static get DefaultType(){return pe}static get NAME(){return Xt}toggle(){return this._isShown()?this.hide():this.show()}show(){if(u(this._element)||this._isShown())return;const t={relatedTarget:this._element};if(!F.trigger(this._element,ee,t).defaultPrevented){if(this._createPopper(),"ontouchstart"in document.documentElement&&!this._parent.closest(".navbar-nav"))for(const t of[].concat(...document.body.children))F.on(t,"mouseover",g);this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(re),this._element.classList.add(re),F.trigger(this._element,ie,t)}}hide(){if(u(this._element)||!this._isShown())return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){if(!F.trigger(this._element,Zt,t).defaultPrevented){if("ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))F.off(t,"mouseover",g);this._popper&&this._popper.destroy(),this._menu.classList.remove(re),this._element.classList.remove(re),this._element.setAttribute("aria-expanded","false"),q.removeDataAttribute(this._menu,"popper"),F.trigger(this._element,te,t)}}_getConfig(t){if("object"==typeof(t=super._getConfig(t)).reference&&!c(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Xt.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(){if(void 0===i)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org/docs/v2/)");let t=this._element;"parent"===this._config.reference?t=this._parent:c(this._config.reference)?t=h(this._config.reference):"object"==typeof this._config.reference&&(t=this._config.reference);const e=this._getPopperConfig();this._popper=i.createPopper(t,this._menu,e)}_isShown(){return this._menu.classList.contains(re)}_getPlacement(){const t=this._parent;if(t.classList.contains("dropend"))return ge;if(t.classList.contains("dropstart"))return fe;if(t.classList.contains("dropup-center"))return"top";if(t.classList.contains("dropdown-center"))return"bottom";const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?de:he:e?_e:ue}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(q.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...y(this._config.popperConfig,[void 0,t])}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(t=>d(t));i.length&&A(i,e,t===Jt,!i.includes(e)).focus()}static jQueryInterface(t){return this.each(function(){const e=be.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}})}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=V.find(le);for(const i of e){const e=be.getInstance(i);if(!e||!1===e._config.autoClose)continue;const s=t.composedPath(),n=s.includes(e._menu);if(s.includes(e._element)||"inside"===e._config.autoClose&&!n||"outside"===e._config.autoClose&&n)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,s=[Gt,Jt].includes(t.key);if(!s&&!i)return;if(e&&!i)return;t.preventDefault();const n=this.matches(ae)?this:V.prev(this,ae)[0]||V.next(this,ae)[0]||V.findOne(ae,t.delegateTarget.parentNode),o=be.getOrCreateInstance(n);if(s)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),n.focus())}}F.on(document,ne,ae,be.dataApiKeydownHandler),F.on(document,ne,ce,be.dataApiKeydownHandler),F.on(document,se,be.clearMenus),F.on(document,oe,be.clearMenus),F.on(document,se,ae,function(t){t.preventDefault(),be.getOrCreateInstance(this).toggle()}),v(be);const ve="backdrop",ye="show",we=`mousedown.bs.${ve}`,Ae={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Ee={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ce extends W{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Ae}static get DefaultType(){return Ee}static get NAME(){return ve}show(t){if(!this._config.isVisible)return void y(t);this._append();const e=this._getElement();this._config.isAnimated&&f(e),e.classList.add(ye),this._emulateAnimation(()=>{y(t)})}hide(t){this._config.isVisible?(this._getElement().classList.remove(ye),this._emulateAnimation(()=>{this.dispose(),y(t)})):y(t)}dispose(){this._isAppended&&(F.off(this._element,we),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=h(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),F.on(t,we,()=>{y(this._config.clickCallback)}),this._isAppended=!0}_emulateAnimation(t){w(t,this._getElement(),this._config.isAnimated)}}const Te=".bs.focustrap",ke=`focusin${Te}`,$e=`keydown.tab${Te}`,Se="backward",Le={autofocus:!0,trapElement:null},Oe={autofocus:"boolean",trapElement:"element"};class Ie extends W{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return Le}static get DefaultType(){return Oe}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),F.off(document,Te),F.on(document,ke,t=>this._handleFocusin(t)),F.on(document,$e,t=>this._handleKeydown(t)),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,F.off(document,Te))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=V.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===Se?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Se:"forward")}}const De=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",Ne=".sticky-top",Pe="padding-right",xe="margin-right";class Me{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,Pe,e=>e+t),this._setElementAttributes(De,Pe,e=>e+t),this._setElementAttributes(Ne,xe,e=>e-t)}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,Pe),this._resetElementAttributes(De,Pe),this._resetElementAttributes(Ne,xe)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const s=this.getWidth();this._applyManipulationCallback(t,t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+s)return;this._saveInitialAttribute(t,e);const n=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(n))}px`)})}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&q.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,t=>{const i=q.getDataAttribute(t,e);null!==i?(q.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)})}_applyManipulationCallback(t,e){if(c(t))e(t);else for(const i of V.find(t,this._element))e(i)}}const je=".bs.modal",Fe=`hide${je}`,ze=`hidePrevented${je}`,He=`hidden${je}`,Be=`show${je}`,qe=`shown${je}`,We=`resize${je}`,Re=`click.dismiss${je}`,Ke=`mousedown.dismiss${je}`,Ve=`keydown.dismiss${je}`,Qe=`click${je}.data-api`,Xe="modal-open",Ye="show",Ue="modal-static",Ge={backdrop:!0,focus:!0,keyboard:!0},Je={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class Ze extends R{constructor(t,e){super(t,e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new Me,this._addEventListeners()}static get Default(){return Ge}static get DefaultType(){return Je}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||F.trigger(this._element,Be,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Xe),this._adjustDialog(),this._backdrop.show(()=>this._showElement(t)))}hide(){this._isShown&&!this._isTransitioning&&(F.trigger(this._element,Fe).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(Ye),this._queueCallback(()=>this._hideModal(),this._element,this._isAnimated())))}dispose(){F.off(window,je),F.off(this._dialog,je),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ce({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ie({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=V.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),f(this._element),this._element.classList.add(Ye),this._queueCallback(()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,F.trigger(this._element,qe,{relatedTarget:t})},this._dialog,this._isAnimated())}_addEventListeners(){F.on(this._element,Ve,t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())}),F.on(window,We,()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()}),F.on(this._element,Ke,t=>{F.one(this._element,Re,e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())})})}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide(()=>{document.body.classList.remove(Xe),this._resetAdjustments(),this._scrollBar.reset(),F.trigger(this._element,He)})}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(F.trigger(this._element,ze).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(Ue)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(Ue),this._queueCallback(()=>{this._element.classList.remove(Ue),this._queueCallback(()=>{this._element.style.overflowY=e},this._dialog)},this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=b()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=b()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each(function(){const i=Ze.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}})}}F.on(document,Qe,'[data-bs-toggle="modal"]',function(t){const e=V.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),F.one(e,Be,t=>{t.defaultPrevented||F.one(e,He,()=>{d(this)&&this.focus()})});const i=V.findOne(".modal.show");i&&Ze.getInstance(i).hide(),Ze.getOrCreateInstance(e).toggle(this)}),Q(Ze),v(Ze);const ti=".bs.offcanvas",ei=".data-api",ii=`load${ti}${ei}`,si="show",ni="showing",oi="hiding",ri=".offcanvas.show",ai=`show${ti}`,li=`shown${ti}`,ci=`hide${ti}`,hi=`hidePrevented${ti}`,di=`hidden${ti}`,ui=`resize${ti}`,_i=`click${ti}${ei}`,gi=`keydown.dismiss${ti}`,fi={backdrop:!0,keyboard:!0,scroll:!1},mi={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class pi extends R{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return fi}static get DefaultType(){return mi}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||F.trigger(this._element,ai,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new Me).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(ni),this._queueCallback(()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(si),this._element.classList.remove(ni),F.trigger(this._element,li,{relatedTarget:t})},this._element,!0))}hide(){this._isShown&&(F.trigger(this._element,ci).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(oi),this._backdrop.hide(),this._queueCallback(()=>{this._element.classList.remove(si,oi),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new Me).reset(),F.trigger(this._element,di)},this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ce({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():F.trigger(this._element,hi)}:null})}_initializeFocusTrap(){return new Ie({trapElement:this._element})}_addEventListeners(){F.on(this._element,gi,t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():F.trigger(this._element,hi))})}static jQueryInterface(t){return this.each(function(){const e=pi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}})}}F.on(document,_i,'[data-bs-toggle="offcanvas"]',function(t){const e=V.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),u(this))return;F.one(e,di,()=>{d(this)&&this.focus()});const i=V.findOne(ri);i&&i!==e&&pi.getInstance(i).hide(),pi.getOrCreateInstance(e).toggle(this)}),F.on(window,ii,()=>{for(const t of V.find(ri))pi.getOrCreateInstance(t).show()}),F.on(window,ui,()=>{for(const t of V.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&pi.getOrCreateInstance(t).hide()}),Q(pi),v(pi);const bi={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},vi=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),yi=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,wi=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!vi.has(i)||Boolean(yi.test(t.nodeValue)):e.filter(t=>t instanceof RegExp).some(t=>t.test(i))},Ai={allowList:bi,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"<div></div>"},Ei={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Ci={entry:"(string|element|function|null)",selector:"(string|element)"};class Ti extends W{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Ai}static get DefaultType(){return Ei}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map(t=>this._resolvePossibleFunction(t)).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Ci)}_setContent(t,e,i){const s=V.findOne(i,t);s&&((e=this._resolvePossibleFunction(e))?c(e)?this._putElementInTemplate(h(e),s):this._config.html?s.innerHTML=this._maybeSanitize(e):s.textContent=e:s.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const s=(new window.DOMParser).parseFromString(t,"text/html"),n=[].concat(...s.body.querySelectorAll("*"));for(const t of n){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const s=[].concat(...t.attributes),n=[].concat(e["*"]||[],e[i]||[]);for(const e of s)wi(e,n)||t.removeAttribute(e.nodeName)}return s.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return y(t,[void 0,this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const ki=new Set(["sanitize","allowList","sanitizeFn"]),$i="fade",Si="show",Li=".tooltip-inner",Oi=".modal",Ii="hide.bs.modal",Di="hover",Ni="focus",Pi="click",xi={AUTO:"auto",TOP:"top",RIGHT:b()?"left":"right",BOTTOM:"bottom",LEFT:b()?"right":"left"},Mi={allowList:bi,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',title:"",trigger:"hover focus"},ji={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class Fi extends R{constructor(t,e){if(void 0===i)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org/docs/v2/)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return Mi}static get DefaultType(){return ji}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),F.off(this._element.closest(Oi),Ii,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=F.trigger(this._element,this.constructor.eventName("show")),e=(_(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:s}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(s.append(i),F.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(Si),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))F.on(t,"mouseover",g);this._queueCallback(()=>{F.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1},this.tip,this._isAnimated())}hide(){if(this._isShown()&&!F.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(Si),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))F.off(t,"mouseover",g);this._activeTrigger[Pi]=!1,this._activeTrigger[Ni]=!1,this._activeTrigger[Di]=!1,this._isHovered=null,this._queueCallback(()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),F.trigger(this._element,this.constructor.eventName("hidden")))},this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove($i,Si),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add($i),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Ti({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{[Li]:this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains($i)}_isShown(){return this.tip&&this.tip.classList.contains(Si)}_createPopper(t){const e=y(this._config.placement,[this,t,this._element]),s=xi[e.toUpperCase()];return i.createPopper(this._element,t,this._getPopperConfig(s))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return y(t,[this._element,this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...y(this._config.popperConfig,[void 0,e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)F.on(this._element,this.constructor.eventName("click"),this._config.selector,t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger[Pi]=!(e._isShown()&&e._activeTrigger[Pi]),e.toggle()});else if("manual"!==e){const t=e===Di?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===Di?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");F.on(this._element,t,this._config.selector,t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?Ni:Di]=!0,e._enter()}),F.on(this._element,i,this._config.selector,t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?Ni:Di]=e._element.contains(t.relatedTarget),e._leave()})}this._hideModalHandler=()=>{this._element&&this.hide()},F.on(this._element.closest(Oi),Ii,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout(()=>{this._isHovered&&this.show()},this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout(()=>{this._isHovered||this.hide()},this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=q.getDataAttributes(this._element);for(const t of Object.keys(e))ki.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:h(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each(function(){const e=Fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}})}}v(Fi);const zi=".popover-header",Hi=".popover-body",Bi={...Fi.Default,content:"",offset:[0,8],placement:"right",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>',trigger:"click"},qi={...Fi.DefaultType,content:"(null|string|element|function)"};class Wi extends Fi{static get Default(){return Bi}static get DefaultType(){return qi}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{[zi]:this._getTitle(),[Hi]:this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each(function(){const e=Wi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}})}}v(Wi);const Ri=".bs.scrollspy",Ki=`activate${Ri}`,Vi=`click${Ri}`,Qi=`load${Ri}.data-api`,Xi="active",Yi="[href]",Ui=".nav-link",Gi=`${Ui}, .nav-item > ${Ui}, .list-group-item`,Ji={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},Zi={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class ts extends R{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return Ji}static get DefaultType(){return Zi}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=h(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map(t=>Number.parseFloat(t))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(F.off(this._config.target,Vi),F.on(this._config.target,Vi,Yi,t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,s=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:s,behavior:"smooth"});i.scrollTop=s}}))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver(t=>this._observerCallback(t),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},s=(this._rootElement||document.documentElement).scrollTop,n=s>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=s;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(n&&t){if(i(o),!s)return}else n||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=V.find(Yi,this._config.target);for(const e of t){if(!e.hash||u(e))continue;const t=V.findOne(decodeURI(e.hash),this._element);d(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(Xi),this._activateParents(t),F.trigger(this._element,Ki,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))V.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(Xi);else for(const e of V.parents(t,".nav, .list-group"))for(const t of V.prev(e,Gi))t.classList.add(Xi)}_clearActiveClass(t){t.classList.remove(Xi);const e=V.find(`${Yi}.${Xi}`,t);for(const t of e)t.classList.remove(Xi)}static jQueryInterface(t){return this.each(function(){const e=ts.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}})}}F.on(window,Qi,()=>{for(const t of V.find('[data-bs-spy="scroll"]'))ts.getOrCreateInstance(t)}),v(ts);const es=".bs.tab",is=`hide${es}`,ss=`hidden${es}`,ns=`show${es}`,os=`shown${es}`,rs=`click${es}`,as=`keydown${es}`,ls=`load${es}`,cs="ArrowLeft",hs="ArrowRight",ds="ArrowUp",us="ArrowDown",_s="Home",gs="End",fs="active",ms="fade",ps="show",bs=".dropdown-toggle",vs=`:not(${bs})`,ys='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',ws=`.nav-link${vs}, .list-group-item${vs}, [role="tab"]${vs}, ${ys}`,As=`.${fs}[data-bs-toggle="tab"], .${fs}[data-bs-toggle="pill"], .${fs}[data-bs-toggle="list"]`;class Es extends R{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),F.on(this._element,as,t=>this._keydown(t)))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?F.trigger(e,is,{relatedTarget:t}):null;F.trigger(t,ns,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(fs),this._activate(V.getElementFromSelector(t)),this._queueCallback(()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),F.trigger(t,os,{relatedTarget:e})):t.classList.add(ps)},t,t.classList.contains(ms)))}_deactivate(t,e){t&&(t.classList.remove(fs),t.blur(),this._deactivate(V.getElementFromSelector(t)),this._queueCallback(()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),F.trigger(t,ss,{relatedTarget:e})):t.classList.remove(ps)},t,t.classList.contains(ms)))}_keydown(t){if(![cs,hs,ds,us,_s,gs].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter(t=>!u(t));let i;if([_s,gs].includes(t.key))i=e[t.key===_s?0:e.length-1];else{const s=[hs,us].includes(t.key);i=A(e,t.target,s,!0)}i&&(i.focus({preventScroll:!0}),Es.getOrCreateInstance(i).show())}_getChildren(){return V.find(ws,this._parent)}_getActiveElem(){return this._getChildren().find(t=>this._elemIsActive(t))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=V.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const s=(t,s)=>{const n=V.findOne(t,i);n&&n.classList.toggle(s,e)};s(bs,fs),s(".dropdown-menu",ps),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(fs)}_getInnerElement(t){return t.matches(ws)?t:V.findOne(ws,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each(function(){const e=Es.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}})}}F.on(document,rs,ys,function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),u(this)||Es.getOrCreateInstance(this).show()}),F.on(window,ls,()=>{for(const t of V.find(As))Es.getOrCreateInstance(t)}),v(Es);const Cs=".bs.toast",Ts=`mouseover${Cs}`,ks=`mouseout${Cs}`,$s=`focusin${Cs}`,Ss=`focusout${Cs}`,Ls=`hide${Cs}`,Os=`hidden${Cs}`,Is=`show${Cs}`,Ds=`shown${Cs}`,Ns="hide",Ps="show",xs="showing",Ms={animation:"boolean",autohide:"boolean",delay:"number"},js={animation:!0,autohide:!0,delay:5e3};class Fs extends R{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return js}static get DefaultType(){return Ms}static get NAME(){return"toast"}show(){F.trigger(this._element,Is).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Ns),f(this._element),this._element.classList.add(Ps,xs),this._queueCallback(()=>{this._element.classList.remove(xs),F.trigger(this._element,Ds),this._maybeScheduleHide()},this._element,this._config.animation))}hide(){this.isShown()&&(F.trigger(this._element,Ls).defaultPrevented||(this._element.classList.add(xs),this._queueCallback(()=>{this._element.classList.add(Ns),this._element.classList.remove(xs,Ps),F.trigger(this._element,Os)},this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(Ps),super.dispose()}isShown(){return this._element.classList.contains(Ps)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout(()=>{this.hide()},this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){F.on(this._element,Ts,t=>this._onInteraction(t,!0)),F.on(this._element,ks,t=>this._onInteraction(t,!1)),F.on(this._element,$s,t=>this._onInteraction(t,!0)),F.on(this._element,Ss,t=>this._onInteraction(t,!1))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each(function(){const e=Fs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}})}}return Q(Fs),v(Fs),{Alert:G,Button:Z,Carousel:Nt,Collapse:Qt,Dropdown:be,Modal:Ze,Offcanvas:pi,Popover:Wi,ScrollSpy:ts,Tab:Es,Toast:Fs,Tooltip:Fi}}); -//# sourceMappingURL=bootstrap.min.js.map \ No newline at end of file diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.min.js.map b/extensions/pagetop-bootsier/static/js/bootstrap.min.js.map deleted file mode 100644 index df4b8491..00000000 --- a/extensions/pagetop-bootsier/static/js/bootstrap.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"names":["elementMap","Map","Data","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete","TRANSITION_END","parseSelector","selector","window","CSS","escape","replace","match","id","toType","object","Object","prototype","toString","call","toLowerCase","triggerTransitionEnd","dispatchEvent","Event","isElement","jquery","nodeType","getElement","length","document","querySelector","isVisible","getClientRects","elementIsVisible","getComputedStyle","getPropertyValue","closedDetails","closest","summary","parentNode","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","getAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","noop","reflow","offsetHeight","getjQuery","jQuery","body","DOMContentLoadedCallbacks","isRTL","dir","defineJQueryPlugin","plugin","callback","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","readyState","addEventListener","push","execute","possibleCallback","args","defaultValue","executeAfterTransition","transitionElement","waitForTransition","emulatedDuration","transitionDuration","transitionDelay","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","split","getTransitionDurationFromElement","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","listLength","index","indexOf","Math","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","nativeEvents","Set","makeEventUid","uid","getElementEvents","findHandler","events","callable","delegationSelector","values","find","event","normalizeParameters","originalTypeEvent","delegationFunction","isDelegated","typeEvent","getTypeEvent","addHandler","oneOff","wrapFunction","relatedTarget","delegateTarget","this","handlers","previousFunction","domElements","querySelectorAll","domElement","hydrateObj","EventHandler","off","type","apply","bootstrapDelegationHandler","bootstrapHandler","removeHandler","Boolean","removeNamespacedHandlers","namespace","storeElementEvent","handlerKey","entries","includes","on","one","inNamespace","isNamespace","startsWith","elementEvent","slice","keyHandlers","trigger","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","evt","cancelable","preventDefault","obj","meta","value","_unused","defineProperty","configurable","normalizeData","JSON","parse","decodeURIComponent","normalizeDataKey","chr","Manipulator","setDataAttribute","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","dataset","filter","pureKey","charAt","getDataAttribute","Config","Default","DefaultType","Error","_getConfig","config","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","jsonConfig","constructor","configTypes","property","expectedTypes","valueType","RegExp","test","TypeError","toUpperCase","BaseComponent","super","_element","_config","DATA_KEY","dispose","EVENT_KEY","propertyName","getOwnPropertyNames","_queueCallback","isAnimated","getInstance","getOrCreateInstance","VERSION","eventName","getSelector","hrefAttribute","trim","map","sel","join","SelectorEngine","concat","Element","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","el","getSelectorFromElement","getElementFromSelector","getMultipleElementsFromSelector","enableDismissTrigger","component","method","clickEvent","tagName","EVENT_CLOSE","EVENT_CLOSED","Alert","close","_destroyElement","each","data","undefined","SELECTOR_DATA_TOGGLE","Button","toggle","button","EVENT_TOUCHSTART","EVENT_TOUCHMOVE","EVENT_TOUCHEND","EVENT_POINTERDOWN","EVENT_POINTERUP","endCallback","leftCallback","rightCallback","Swipe","isSupported","_deltaX","_supportPointerEvents","PointerEvent","_initEvents","_start","_eventIsPointerPenTouch","clientX","touches","_end","_handleSwipe","_move","absDeltaX","abs","direction","add","pointerType","navigator","maxTouchPoints","DATA_API_KEY","ARROW_LEFT_KEY","ARROW_RIGHT_KEY","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","EVENT_SLIDE","EVENT_SLID","EVENT_KEYDOWN","EVENT_MOUSEENTER","EVENT_MOUSELEAVE","EVENT_DRAG_START","EVENT_LOAD_DATA_API","EVENT_CLICK_DATA_API","CLASS_NAME_CAROUSEL","CLASS_NAME_ACTIVE","SELECTOR_ACTIVE","SELECTOR_ITEM","SELECTOR_ACTIVE_ITEM","KEY_TO_DIRECTION","ARROW_LEFT_KEY$1","ARROW_RIGHT_KEY$1","interval","keyboard","pause","ride","touch","wrap","Carousel","_interval","_activeElement","_isSliding","touchTimeout","_swipeHelper","_indicatorsElement","_addEventListeners","cycle","_slide","nextWhenVisible","hidden","_clearInterval","_updateInterval","setInterval","_maybeEnableCycle","to","items","_getItems","activeIndex","_getItemIndex","_getActive","order","defaultInterval","_keydown","_addTouchEventListeners","img","swipeConfig","_directionToOrder","endCallBack","clearTimeout","_setActiveIndicatorElement","activeIndicator","newActiveIndicator","elementInterval","parseInt","isNext","nextElement","nextElementIndex","triggerEvent","_orderToDirection","isCycling","directionalClassName","orderClassName","completeCallBack","_isAnimated","clearInterval","carousel","slideIndex","carousels","EVENT_SHOW","EVENT_SHOWN","EVENT_HIDE","EVENT_HIDDEN","CLASS_NAME_SHOW","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_DEEPER_CHILDREN","parent","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElement","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activeChildren","_getFirstLevelChildren","activeInstance","dimension","_getDimension","style","scrollSize","complete","getBoundingClientRect","selected","triggerArray","isOpen","ARROW_UP_KEY","ARROW_DOWN_KEY","EVENT_KEYDOWN_DATA_API","EVENT_KEYUP_DATA_API","SELECTOR_DATA_TOGGLE_SHOWN","SELECTOR_MENU","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","autoClose","boundary","display","offset","popperConfig","reference","Dropdown","_popper","_parent","_menu","_inNavbar","_detectNavbar","_createPopper","focus","_completeHide","destroy","update","Popper","referenceElement","_getPopperConfig","createPopper","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","placement","modifiers","options","enabled","_selectMenuItem","clearMenus","openToggles","context","composedPath","isMenuTarget","dataApiKeydownHandler","isInput","isEscapeEvent","isUpOrDownEvent","getToggleButton","stopPropagation","EVENT_MOUSEDOWN","className","clickCallback","rootElement","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","EVENT_FOCUSIN","EVENT_KEYDOWN_TAB","TAB_NAV_BACKWARD","autofocus","trapElement","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","elements","shiftKey","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","PROPERTY_PADDING","PROPERTY_MARGIN","ScrollBarHelper","getWidth","documentWidth","clientWidth","innerWidth","width","_disableOverFlow","_setElementAttributes","calculatedValue","reset","_resetElementAttributes","isOverflowing","_saveInitialAttribute","overflow","styleProperty","scrollbarWidth","_applyManipulationCallback","setProperty","actualValue","removeProperty","callBack","EVENT_HIDE_PREVENTED","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_MOUSEDOWN_DISMISS","EVENT_KEYDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_scrollBar","_adjustDialog","_showElement","_hideModal","handleUpdate","scrollTop","modalBody","transitionComplete","_triggerBackdropTransition","event2","_resetAdjustments","isModalOverflowing","scrollHeight","clientHeight","initialOverflowY","overflowY","isBodyOverflowing","paddingLeft","paddingRight","showEvent","alreadyOpen","CLASS_NAME_SHOWING","CLASS_NAME_HIDING","OPEN_SELECTOR","scroll","Offcanvas","blur","completeCallback","position","DefaultAllowlist","a","area","b","br","col","code","dd","div","dl","dt","em","hr","h1","h2","h3","h4","h5","h6","i","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","uriAttributes","SAFE_URL_PATTERN","allowedAttribute","attribute","allowedAttributeList","attributeName","nodeName","nodeValue","attributeRegex","some","regex","allowList","content","extraClass","html","sanitize","sanitizeFn","template","DefaultContentType","entry","TemplateFactory","getContent","_resolvePossibleFunction","hasContent","changeContent","_checkContent","toHtml","templateWrapper","innerHTML","_maybeSanitize","text","_setContent","arg","templateElement","_putElementInTemplate","textContent","unsafeHtml","sanitizeFunction","createdDocument","DOMParser","parseFromString","elementName","attributeList","allowedAttributes","sanitizeHtml","DISALLOWED_ATTRIBUTES","CLASS_NAME_FADE","SELECTOR_TOOLTIP_INNER","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","TRIGGER_CLICK","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","animation","container","customClass","delay","fallbackPlacements","title","Tooltip","_isEnabled","_timeout","_isHovered","_activeTrigger","_templateFactory","_newContent","tip","_setListeners","_fixTitle","enable","disable","toggleEnabled","_leave","_enter","_hideModalHandler","_disposePopper","_isWithContent","isInTheDom","ownerDocument","_getTipElement","_isWithActiveTrigger","_getTitle","_createTipElement","_getContentForTemplate","_getTemplateFactory","tipId","prefix","floor","random","getElementById","getUID","setContent","_initializeOnDelegatedTarget","_getDelegateConfig","attachment","phase","state","triggers","eventIn","eventOut","_setTimeout","timeout","dataAttributes","dataAttribute","SELECTOR_TITLE","SELECTOR_CONTENT","Popover","_getContent","EVENT_ACTIVATE","EVENT_CLICK","SELECTOR_TARGET_LINKS","SELECTOR_NAV_LINKS","SELECTOR_LINK_ITEMS","rootMargin","smoothScroll","threshold","ScrollSpy","_targetLinks","_observableSections","_rootElement","_activeTarget","_observer","_previousScrollData","visibleEntryTop","parentScrollTop","refresh","_initializeTargetsAndObservables","_maybeEnableSmoothScroll","disconnect","_getNewObserver","section","observe","observableSection","hash","height","offsetTop","scrollTo","top","behavior","IntersectionObserver","_observerCallback","targetElement","_process","userScrollsDown","isIntersecting","_clearActiveClass","entryIsLowerThanPrevious","targetLinks","anchor","decodeURI","_activateParents","listGroup","item","activeNodes","node","spy","HOME_KEY","END_KEY","SELECTOR_DROPDOWN_TOGGLE","NOT_SELECTOR_DROPDOWN_TOGGLE","SELECTOR_INNER_ELEM","SELECTOR_DATA_TOGGLE_ACTIVE","Tab","_setInitialAttributes","_getChildren","innerElem","_elemIsActive","active","_getActiveElem","hideEvent","_deactivate","_activate","relatedElem","_toggleDropDown","nextActiveElement","preventScroll","_setAttributeIfNotExists","_setInitialAttributesOnChild","_getInnerElement","isActive","outerElem","_getOuterElement","_setInitialAttributesOnTargetPanel","open","EVENT_MOUSEOVER","EVENT_MOUSEOUT","EVENT_FOCUSOUT","CLASS_NAME_HIDE","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","isShown","_onInteraction","isInteracting"],"sources":["../../js/src/dom/data.js","../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/manipulator.js","../../js/src/util/config.js","../../js/src/base-component.js","../../js/src/dom/selector-engine.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/util/swipe.js","../../js/src/carousel.js","../../js/src/collapse.js","../../js/src/dropdown.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/util/scrollbar.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/util/template-factory.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1_000_000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`)\n }\n\n return selector\n}\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`\n }\n\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = object => {\n if (!object || typeof object !== 'object') {\n return false\n }\n\n if (typeof object.jquery !== 'undefined') {\n object = object[0]\n }\n\n return typeof object.nodeType !== 'undefined'\n}\n\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (isElement(object)) {\n return object.jquery ? object[0] : object\n }\n\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object))\n }\n\n return null\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])')\n\n if (!closedDetails) {\n return elementIsVisible\n }\n\n if (closedDetails !== element) {\n const summary = element.closest('summary')\n if (summary && summary.parentNode !== closedDetails) {\n return false\n }\n\n if (summary === null) {\n return false\n }\n }\n\n return elementIsVisible\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.harrytheo.com/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight // eslint-disable-line no-unused-expressions\n}\n\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback()\n }\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback.call(...args) : defaultValue\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]\n }\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n defineJQueryPlugin,\n execute,\n executeAfterTransition,\n findShadowRoot,\n getElement,\n getjQuery,\n getNextActiveElement,\n getTransitionDurationFromElement,\n getUID,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n onDOMContentLoaded,\n parseSelector,\n reflow,\n triggerTransitionEnd,\n toType\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index.js'\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\n\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getElementEvents(element) {\n const uid = makeEventUid(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, { delegateTarget: element })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue\n }\n\n hydrateObj(event, { delegateTarget: target })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n}\n\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events)\n .find(event => event.callable === callable && event.delegationSelector === delegationSelector)\n}\n\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string'\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : (handler || delegationFunction)\n let typeEvent = getTypeEvent(originalTypeEvent)\n\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent\n }\n\n return [isDelegated, callable, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n callable = wrapFunction(callable)\n }\n\n const events = getElementEvents(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)\n\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff\n\n return\n }\n\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = isDelegated ?\n bootstrapDelegationHandler(element, handler, callable) :\n bootstrapHandler(element, callable)\n\n fn.delegationSelector = isDelegated ? handler : null\n fn.callable = callable\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, isDelegated)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false)\n },\n\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getElementEvents(element)\n const storeElementEvent = events[typeEvent] || {}\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return\n }\n\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)\n return\n }\n\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n }\n }\n\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n\n let jQueryEvent = null\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value\n } catch {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value\n }\n })\n }\n }\n\n return obj\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true\n }\n\n if (value === 'false') {\n return false\n }\n\n if (value === Number(value).toString()) {\n return Number(value)\n }\n\n if (value === '' || value === 'null') {\n return null\n }\n\n if (typeof value !== 'string') {\n return value\n }\n\n try {\n return JSON.parse(decodeURIComponent(value))\n } catch {\n return value\n }\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))\n\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1)\n attributes[pureKey] = normalizeData(element.dataset[key])\n }\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport { isElement, toType } from './index.js'\n\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {}\n }\n\n static get DefaultType() {\n return {}\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n return config\n }\n\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n }\n }\n\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property]\n const valueType = isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n }\n }\n}\n\nexport default Config\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data.js'\nimport EventHandler from './dom/event-handler.js'\nimport Config from './util/config.js'\nimport { executeAfterTransition, getElement } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.8'\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super()\n\n element = getElement(element)\n if (!element) {\n return\n }\n\n this._element = element\n this._config = this._getConfig(config)\n\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null\n }\n }\n\n // Private\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible, parseSelector } from '../util/index.js'\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`\n }\n\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null\n }\n\n return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null\n}\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n let ancestor = element.parentNode.closest(selector)\n\n while (ancestor) {\n parents.push(ancestor)\n ancestor = ancestor.parentNode.closest(selector)\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n },\n\n getSelectorFromElement(element) {\n const selector = getSelector(element)\n\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null\n }\n\n return null\n },\n\n getElementFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.findOne(selector) : null\n },\n\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.find(selector) : []\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isDisabled } from './index.js'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport { execute } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'swipe'\nconst EVENT_KEY = '.bs.swipe'\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n}\n\nconst DefaultType = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n}\n\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super()\n this._element = element\n\n if (!element || !Swipe.isSupported()) {\n return\n }\n\n this._config = this._getConfig(config)\n this._deltaX = 0\n this._supportPointerEvents = Boolean(window.PointerEvent)\n this._initEvents()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY)\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX\n\n return\n }\n\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX\n }\n }\n\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX\n }\n\n this._handleSwipe()\n execute(this._config.endCallback)\n }\n\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this._deltaX\n }\n\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX)\n\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltaX / this._deltaX\n\n this._deltaX = 0\n\n if (!direction) {\n return\n }\n\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)\n }\n\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))\n }\n }\n\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n }\n}\n\nexport default Swipe\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getNextActiveElement,\n isRTL,\n isVisible,\n reflow,\n triggerTransitionEnd\n} from './util/index.js'\nimport Swipe from './util/swipe.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)', // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._interval = null\n this._activeElement = null\n this._isSliding = false\n this.touchTimeout = null\n this._swipeHelper = null\n\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._addEventListeners()\n\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element)\n }\n\n this._clearInterval()\n }\n\n cycle() {\n this._clearInterval()\n this._updateInterval()\n\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval)\n }\n\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle())\n return\n }\n\n this.cycle()\n }\n\n to(index) {\n const items = this._getItems()\n if (index > items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n const activeIndex = this._getItemIndex(this._getActive())\n if (activeIndex === index) {\n return\n }\n\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV\n\n this._slide(order, items[index])\n }\n\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose()\n }\n\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval\n return config\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause())\n EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle())\n }\n\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault())\n }\n\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n }\n\n this._swipeHelper = new Swipe(this._element, swipeConfig)\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(this._directionToOrder(direction))\n }\n }\n\n _getItemIndex(element) {\n return this._getItems().indexOf(element)\n }\n\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return\n }\n\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement)\n\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE)\n newActiveIndicator.setAttribute('aria-current', 'true')\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || this._getActive()\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n this._config.interval = elementInterval || this._config.defaultInterval\n }\n\n _slide(order, element = null) {\n if (this._isSliding) {\n return\n }\n\n const activeElement = this._getActive()\n const isNext = order === ORDER_NEXT\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap)\n\n if (nextElement === activeElement) {\n return\n }\n\n const nextElementIndex = this._getItemIndex(nextElement)\n\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n })\n }\n\n const slideEvent = triggerEvent(EVENT_SLIDE)\n\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return\n }\n\n const isCycling = Boolean(this._interval)\n this.pause()\n\n this._isSliding = true\n\n this._setActiveIndicatorElement(nextElementIndex)\n this._activeElement = nextElement\n\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n triggerEvent(EVENT_SLID)\n }\n\n this._queueCallback(completeCallBack, activeElement, this._isAnimated())\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE)\n }\n\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n }\n\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element)\n }\n\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n }\n\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config)\n\n if (typeof config === 'number') {\n data.to(config)\n return\n }\n\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n event.preventDefault()\n\n const carousel = Carousel.getOrCreateInstance(target)\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n carousel.to(slideIndex)\n carousel._maybeEnableCycle()\n return\n }\n\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next()\n carousel._maybeEnableCycle()\n return\n }\n\n carousel.prev()\n carousel._maybeEnableCycle()\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getElement,\n reflow\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\nconst Default = {\n parent: null,\n toggle: true\n}\n\nconst DefaultType = {\n parent: '(null|element)',\n toggle: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isTransitioning = false\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElement => foundElement === this._element)\n\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let activeChildren = []\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)\n .filter(element => element !== this._element)\n .map(element => Collapse.getOrCreateInstance(element, { toggle: false }))\n }\n\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n for (const activeInstance of activeChildren) {\n activeInstance.hide()\n }\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger)\n\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n // Private\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)\n\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n }\n }\n\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element))\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen)\n element.setAttribute('aria-expanded', isOpen)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n execute,\n getElement,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center'\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)'\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR = '.navbar'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\nconst PLACEMENT_TOPCENTER = 'top'\nconst PLACEMENT_BOTTOMCENTER = 'bottom'\n\nconst Default = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n}\n\nconst DefaultType = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n}\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._popper = null\n this._parent = this._element.parentNode // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.findOne(SELECTOR_MENU, this._parent)\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._createPopper()\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = super._getConfig(config)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org/docs/v2/)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = this._parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n }\n\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getPlacement() {\n const parentDropdown = this._parent\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig])\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {\n return\n }\n\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)\n\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle)\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n const relatedTarget = { relatedTarget: context._element }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName)\n const isEscapeEvent = event.key === ESCAPE_KEY\n const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)\n\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return\n }\n\n if (isInput && !isEscapeEvent) {\n return\n }\n\n event.preventDefault()\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?\n this :\n (SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode))\n\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (isUpOrDownEvent) {\n event.stopPropagation()\n instance.show()\n instance._selectMenuItem(event)\n return\n }\n\n if (instance._isShown()) { // else is escape and we check if it is shown\n event.stopPropagation()\n instance.hide()\n getToggleButton.focus()\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport {\n execute, executeAfterTransition, getElement, reflow\n} from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nconst Default = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n}\n\nconst DefaultType = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n}\n\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n const element = this._getElement()\n if (this._config.isAnimated) {\n reflow(element)\n }\n\n element.classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n const element = this._getElement()\n this._config.rootElement.append(element)\n\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nconst Default = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n}\n\nconst DefaultType = {\n autofocus: 'boolean',\n trapElement: 'element'\n}\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return\n }\n\n if (this._config.autofocus) {\n this._config.trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n _handleFocusin(event) {\n const { trapElement } = this._config\n\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\nconst PROPERTY_PADDING = 'padding-right'\nconst PROPERTY_MARGIN = 'margin-right'\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProperty)\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty)\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty)\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty)\n return\n }\n\n Manipulator.removeDataAttribute(element, styleProperty)\n element.style.setProperty(styleProperty, value)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n return\n }\n\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel)\n }\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin, isRTL, isVisible, reflow\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\nconst Default = {\n backdrop: true,\n focus: true,\n keyboard: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._isTransitioning = true\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._backdrop.show(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n this._isTransitioning = true\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated())\n }\n\n dispose() {\n EventHandler.off(window, EVENT_KEY)\n EventHandler.off(this._dialog, EVENT_KEY)\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated())\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n this._triggerBackdropTransition()\n })\n\n EventHandler.on(window, EVENT_RESIZE, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog()\n }\n })\n\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return\n }\n\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n return\n }\n\n if (this._config.backdrop) {\n this.hide()\n }\n })\n })\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const initialOverflowY = this._element.style.overflowY\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden'\n }\n\n this._element.classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY\n }, this._dialog)\n }, this._dialog)\n\n this._element.focus()\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin,\n isDisabled,\n isVisible\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\nconst CLASS_NAME_HIDING = 'hiding'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate()\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.add(CLASS_NAME_HIDING)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n return\n }\n\n this.hide()\n }\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop)\n\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n })\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show()\n }\n})\n\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide()\n }\n }\n})\n\nenableDismissTrigger(Offcanvas)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n dd: [],\n div: [],\n dl: [],\n dt: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n// js-docs-end allow-list\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n .some(regex => regex.test(attributeName))\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n }\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\nimport { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'\nimport { execute, getElement, isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'TemplateFactory'\n\nconst Default = {\n allowList: DefaultAllowlist,\n content: {}, // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '<div></div>'\n}\n\nconst DefaultType = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n}\n\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n}\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content)\n .map(config => this._resolvePossibleFunction(config))\n .filter(Boolean)\n }\n\n hasContent() {\n return this.getContent().length > 0\n }\n\n changeContent(content) {\n this._checkContent(content)\n this._config.content = { ...this._config.content, ...content }\n return this\n }\n\n toHtml() {\n const templateWrapper = document.createElement('div')\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template)\n\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector)\n }\n\n const template = templateWrapper.children[0]\n const extraClass = this._resolvePossibleFunction(this._config.extraClass)\n\n if (extraClass) {\n template.classList.add(...extraClass.split(' '))\n }\n\n return template\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config)\n this._checkContent(config.content)\n }\n\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({ selector, entry: content }, DefaultContentType)\n }\n }\n\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!templateElement) {\n return\n }\n\n content = this._resolvePossibleFunction(content)\n\n if (!content) {\n templateElement.remove()\n return\n }\n\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement)\n return\n }\n\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content)\n return\n }\n\n templateElement.textContent = content\n }\n\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [undefined, this])\n }\n\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = ''\n templateElement.append(element)\n return\n }\n\n templateElement.textContent = element.textContent\n }\n}\n\nexport default TemplateFactory\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport {\n defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop\n} from './util/index.js'\nimport { DefaultAllowlist } from './util/sanitizer.js'\nimport TemplateFactory from './util/template-factory.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\nconst EVENT_HIDE = 'hide'\nconst EVENT_HIDDEN = 'hidden'\nconst EVENT_SHOW = 'show'\nconst EVENT_SHOWN = 'shown'\nconst EVENT_INSERTED = 'inserted'\nconst EVENT_CLICK = 'click'\nconst EVENT_FOCUSIN = 'focusin'\nconst EVENT_FOCUSOUT = 'focusout'\nconst EVENT_MOUSEENTER = 'mouseenter'\nconst EVENT_MOUSELEAVE = 'mouseleave'\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '<div class=\"tooltip\" role=\"tooltip\">' +\n '<div class=\"tooltip-arrow\"></div>' +\n '<div class=\"tooltip-inner\"></div>' +\n '</div>',\n title: '',\n trigger: 'hover focus'\n}\n\nconst DefaultType = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n}\n\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org/docs/v2/)')\n }\n\n super(element, config)\n\n // Private\n this._isEnabled = true\n this._timeout = 0\n this._isHovered = null\n this._activeTrigger = {}\n this._popper = null\n this._templateFactory = null\n this._newContent = null\n\n // Protected\n this.tip = null\n\n this._setListeners()\n\n if (!this._config.selector) {\n this._fixTitle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle() {\n if (!this._isEnabled) {\n return\n }\n\n if (this._isShown()) {\n this._leave()\n return\n }\n\n this._enter()\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'))\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this._isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW))\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper()\n\n const tip = this._getTipElement()\n\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'))\n\n const { container } = this._config\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))\n }\n\n this._popper = this._createPopper(tip)\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN))\n\n if (this._isHovered === false) {\n this._leave()\n }\n\n this._isHovered = false\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n hide() {\n if (!this._isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE))\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const tip = this._getTipElement()\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n this._isHovered = null // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (!this._isHovered) {\n this._disposePopper()\n }\n\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN))\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n update() {\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle())\n }\n\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())\n }\n\n return this.tip\n }\n\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml()\n\n // TODO: remove this check in v6\n if (!tip) {\n return null\n }\n\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`)\n\n const tipId = getUID(this.constructor.NAME).toString()\n\n tip.setAttribute('id', tipId)\n\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n return tip\n }\n\n setContent(content) {\n this._newContent = content\n if (this._isShown()) {\n this._disposePopper()\n this.show()\n }\n }\n\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content)\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n })\n }\n\n return this._templateFactory\n }\n\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n }\n }\n\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title')\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _isAnimated() {\n return this._config.animation || (this.tip && this.tip.classList.contains(CLASS_NAME_FADE))\n }\n\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW)\n }\n\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element])\n const attachment = AttachmentMap[placement.toUpperCase()]\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element, this._element])\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement)\n }\n }\n ]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig])\n }\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[TRIGGER_CLICK] = !(context._isShown() && context._activeTrigger[TRIGGER_CLICK])\n context.toggle()\n })\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSEENTER) :\n this.constructor.eventName(EVENT_FOCUSIN)\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSELEAVE) :\n this.constructor.eventName(EVENT_FOCUSOUT)\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true\n context._enter()\n })\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] =\n context._element.contains(event.relatedTarget)\n\n context._leave()\n })\n }\n }\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n\n if (!title) {\n return\n }\n\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('data-bs-original-title', title) // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title')\n }\n\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true\n return\n }\n\n this._isHovered = true\n\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show()\n }\n }, this._config.delay.show)\n }\n\n _leave() {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n this._isHovered = false\n\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide()\n }\n }, this._config.delay.hide)\n }\n\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout)\n this._timeout = setTimeout(handler, timeout)\n }\n\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true)\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute]\n }\n }\n\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value\n }\n }\n\n config.selector = false\n config.trigger = 'manual'\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n\n if (this.tip) {\n this.tip.remove()\n this.tip = null\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Tooltip from './tooltip.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'popover'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Default = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>',\n trigger: 'click'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n}\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent()\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n }\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin, getElement, isDisabled, isVisible\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_CLICK = `click${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_TARGET_LINKS = '[href]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst Default = {\n offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n}\n\nconst DefaultType = {\n offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n}\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map()\n this._observableSections = new Map()\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element\n this._activeTarget = null\n this._observer = null\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n }\n this.refresh() // initialize\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables()\n this._maybeEnableSmoothScroll()\n\n if (this._observer) {\n this._observer.disconnect()\n } else {\n this._observer = this._getNewObserver()\n }\n\n for (const section of this._observableSections.values()) {\n this._observer.observe(section)\n }\n }\n\n dispose() {\n this._observer.disconnect()\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin\n\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))\n }\n\n return config\n }\n\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK)\n\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash)\n if (observableSection) {\n event.preventDefault()\n const root = this._rootElement || window\n const height = observableSection.offsetTop - this._element.offsetTop\n if (root.scrollTo) {\n root.scrollTo({ top: height, behavior: 'smooth' })\n return\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height\n }\n })\n }\n\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n }\n\n return new IntersectionObserver(entries => this._observerCallback(entries), options)\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop\n this._process(targetElement(entry))\n }\n\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop\n this._previousScrollData.parentScrollTop = parentScrollTop\n\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null\n this._clearActiveClass(targetElement(entry))\n\n continue\n }\n\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry)\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return\n }\n\n continue\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry)\n }\n }\n }\n\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map()\n this._observableSections = new Map()\n\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)\n\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue\n }\n\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor)\n this._observableSections.set(anchor.hash, observableSection)\n }\n }\n }\n\n _process(target) {\n if (this._activeTarget === target) {\n return\n }\n\n this._clearActiveClass(this._config.target)\n this._activeTarget = target\n target.classList.add(CLASS_NAME_ACTIVE)\n this._activateParents(target)\n\n EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })\n }\n\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n return\n }\n\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {\n item.classList.add(CLASS_NAME_ACTIVE)\n }\n }\n }\n\n _clearActiveClass(parent) {\n parent.classList.remove(CLASS_NAME_ACTIVE)\n\n const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent)\n for (const node of activeNodes) {\n node.classList.remove(CLASS_NAME_ACTIVE)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = ScrollSpy.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {\n ScrollSpy.getOrCreateInstance(spy)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(ScrollSpy)\n\nexport default ScrollSpy\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tab.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tab'\nconst DATA_KEY = 'bs.tab'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}`\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst HOME_KEY = 'Home'\nconst END_KEY = 'End'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_DROPDOWN = 'dropdown'\n\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\nconst SELECTOR_DROPDOWN_MENU = '.dropdown-menu'\nconst NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`\n\nconst SELECTOR_TAB_PANEL = '.list-group, .nav, [role=\"tablist\"]'\nconst SELECTOR_OUTER = '.nav-item, .list-group-item'\nconst SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role=\"tab\"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]' // TODO: could only be `tab` in v6\nconst SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`\n\nconst SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle=\"tab\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"pill\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"list\"]`\n\n/**\n * Class definition\n */\n\nclass Tab extends BaseComponent {\n constructor(element) {\n super(element)\n this._parent = this._element.closest(SELECTOR_TAB_PANEL)\n\n if (!this._parent) {\n return\n // TODO: should throw exception in v6\n // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)\n }\n\n // Set up initial aria attributes\n this._setInitialAttributes(this._parent, this._getChildren())\n\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n show() { // Shows this elem and deactivate the active sibling if exists\n const innerElem = this._element\n if (this._elemIsActive(innerElem)) {\n return\n }\n\n // Search for active tab on same parent to deactivate it\n const active = this._getActiveElem()\n\n const hideEvent = active ?\n EventHandler.trigger(active, EVENT_HIDE, { relatedTarget: innerElem }) :\n null\n\n const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, { relatedTarget: active })\n\n if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {\n return\n }\n\n this._deactivate(active, innerElem)\n this._activate(innerElem, active)\n }\n\n // Private\n _activate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.add(CLASS_NAME_ACTIVE)\n\n this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.add(CLASS_NAME_SHOW)\n return\n }\n\n element.removeAttribute('tabindex')\n element.setAttribute('aria-selected', true)\n this._toggleDropDown(element, true)\n EventHandler.trigger(element, EVENT_SHOWN, {\n relatedTarget: relatedElem\n })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _deactivate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.remove(CLASS_NAME_ACTIVE)\n element.blur()\n\n this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.remove(CLASS_NAME_SHOW)\n return\n }\n\n element.setAttribute('aria-selected', false)\n element.setAttribute('tabindex', '-1')\n this._toggleDropDown(element, false)\n EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _keydown(event) {\n if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key))) {\n return\n }\n\n event.stopPropagation()// stopPropagation/preventDefault both added to support up/down keys without scrolling the page\n event.preventDefault()\n\n const children = this._getChildren().filter(element => !isDisabled(element))\n let nextActiveElement\n\n if ([HOME_KEY, END_KEY].includes(event.key)) {\n nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]\n } else {\n const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)\n nextActiveElement = getNextActiveElement(children, event.target, isNext, true)\n }\n\n if (nextActiveElement) {\n nextActiveElement.focus({ preventScroll: true })\n Tab.getOrCreateInstance(nextActiveElement).show()\n }\n }\n\n _getChildren() { // collection of inner elements\n return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent)\n }\n\n _getActiveElem() {\n return this._getChildren().find(child => this._elemIsActive(child)) || null\n }\n\n _setInitialAttributes(parent, children) {\n this._setAttributeIfNotExists(parent, 'role', 'tablist')\n\n for (const child of children) {\n this._setInitialAttributesOnChild(child)\n }\n }\n\n _setInitialAttributesOnChild(child) {\n child = this._getInnerElement(child)\n const isActive = this._elemIsActive(child)\n const outerElem = this._getOuterElement(child)\n child.setAttribute('aria-selected', isActive)\n\n if (outerElem !== child) {\n this._setAttributeIfNotExists(outerElem, 'role', 'presentation')\n }\n\n if (!isActive) {\n child.setAttribute('tabindex', '-1')\n }\n\n this._setAttributeIfNotExists(child, 'role', 'tab')\n\n // set attributes to the related panel too\n this._setInitialAttributesOnTargetPanel(child)\n }\n\n _setInitialAttributesOnTargetPanel(child) {\n const target = SelectorEngine.getElementFromSelector(child)\n\n if (!target) {\n return\n }\n\n this._setAttributeIfNotExists(target, 'role', 'tabpanel')\n\n if (child.id) {\n this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)\n }\n }\n\n _toggleDropDown(element, open) {\n const outerElem = this._getOuterElement(element)\n if (!outerElem.classList.contains(CLASS_DROPDOWN)) {\n return\n }\n\n const toggle = (selector, className) => {\n const element = SelectorEngine.findOne(selector, outerElem)\n if (element) {\n element.classList.toggle(className, open)\n }\n }\n\n toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)\n toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)\n outerElem.setAttribute('aria-expanded', open)\n }\n\n _setAttributeIfNotExists(element, attribute, value) {\n if (!element.hasAttribute(attribute)) {\n element.setAttribute(attribute, value)\n }\n }\n\n _elemIsActive(elem) {\n return elem.classList.contains(CLASS_NAME_ACTIVE)\n }\n\n // Try to get the inner element (usually the .nav-link)\n _getInnerElement(elem) {\n return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem)\n }\n\n // Try to get the outer element (usually the .nav-item)\n _getOuterElement(elem) {\n return elem.closest(SELECTOR_OUTER) || elem\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tab.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n Tab.getOrCreateInstance(this).show()\n})\n\n/**\n * Initialize on focus\n */\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {\n Tab.getOrCreateInstance(element)\n }\n})\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tab)\n\nexport default Tab\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap toast.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin, reflow } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'toast'\nconst DATA_KEY = 'bs.toast'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\n\nconst DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n}\n\nconst Default = {\n animation: true,\n autohide: true,\n delay: 5000\n}\n\n/**\n * Class definition\n */\n\nclass Toast extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._timeout = null\n this._hasMouseInteraction = false\n this._hasKeyboardInteraction = false\n this._setListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show() {\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._clearTimeout()\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE)\n }\n\n const complete = () => {\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN)\n\n this._maybeScheduleHide()\n }\n\n this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\n reflow(this._element)\n this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)\n\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n hide() {\n if (!this.isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const complete = () => {\n this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\n this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.classList.add(CLASS_NAME_SHOWING)\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n dispose() {\n this._clearTimeout()\n\n if (this.isShown()) {\n this._element.classList.remove(CLASS_NAME_SHOW)\n }\n\n super.dispose()\n }\n\n isShown() {\n return this._element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n _maybeScheduleHide() {\n if (!this._config.autohide) {\n return\n }\n\n if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\n return\n }\n\n this._timeout = setTimeout(() => {\n this.hide()\n }, this._config.delay)\n }\n\n _onInteraction(event, isInteracting) {\n switch (event.type) {\n case 'mouseover':\n case 'mouseout': {\n this._hasMouseInteraction = isInteracting\n break\n }\n\n case 'focusin':\n case 'focusout': {\n this._hasKeyboardInteraction = isInteracting\n break\n }\n\n default: {\n break\n }\n }\n\n if (isInteracting) {\n this._clearTimeout()\n return\n }\n\n const nextElement = event.relatedTarget\n if (this._element === nextElement || this._element.contains(nextElement)) {\n return\n }\n\n this._maybeScheduleHide()\n }\n\n _setListeners() {\n EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\n EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\n }\n\n _clearTimeout() {\n clearTimeout(this._timeout)\n this._timeout = null\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Toast.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Toast)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Toast)\n\nexport default Toast\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap index.umd.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './src/alert.js'\nimport Button from './src/button.js'\nimport Carousel from './src/carousel.js'\nimport Collapse from './src/collapse.js'\nimport Dropdown from './src/dropdown.js'\nimport Modal from './src/modal.js'\nimport Offcanvas from './src/offcanvas.js'\nimport Popover from './src/popover.js'\nimport ScrollSpy from './src/scrollspy.js'\nimport Tab from './src/tab.js'\nimport Toast from './src/toast.js'\nimport Tooltip from './src/tooltip.js'\n\nexport default {\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Offcanvas,\n Popover,\n ScrollSpy,\n Tab,\n Toast,\n Tooltip\n}\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file From 175fc90775a512b05ab6043b38914da8b558434c Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 2 Nov 2025 12:42:36 +0100 Subject: [PATCH 231/244] =?UTF-8?q?=F0=9F=93=9D=20Repasa=20doc=20de=20`Dro?= =?UTF-8?q?pdown`,=20`Nav`=20y=20`Offcanvas`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pagetop-bootsier/src/theme/dropdown.rs | 17 +++ .../src/theme/dropdown/component.rs | 18 +-- .../src/theme/dropdown/item.rs | 4 +- extensions/pagetop-bootsier/src/theme/nav.rs | 20 +++ .../src/theme/nav/component.rs | 21 +-- .../pagetop-bootsier/src/theme/nav/item.rs | 6 +- .../pagetop-bootsier/src/theme/offcanvas.rs | 20 +++ .../src/theme/offcanvas/component.rs | 126 ++++++++---------- 8 files changed, 124 insertions(+), 108 deletions(-) diff --git a/extensions/pagetop-bootsier/src/theme/dropdown.rs b/extensions/pagetop-bootsier/src/theme/dropdown.rs index eb00e4c8..ed4cbec0 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown.rs @@ -6,6 +6,23 @@ //! //! Los ítems pueden estar activos, deshabilitados o abrirse en nueva ventana según su contexto y //! configuración, y permiten incluir etiquetas localizables usando [`L10n`](pagetop::locale::L10n). +//! +//! # Ejemplo +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let dd = Dropdown::new() +//! .with_title(L10n::n("Menu")) +//! .with_button_color(ButtonColor::Background(Color::Secondary)) +//! .with_auto_close(dropdown::AutoClose::ClickableInside) +//! .with_direction(dropdown::Direction::Dropend) +//! .add_item(dropdown::Item::link(L10n::n("Home"), |_| "/")) +//! .add_item(dropdown::Item::link_blank(L10n::n("External"), |_| "https://www.google.es")) +//! .add_item(dropdown::Item::divider()) +//! .add_item(dropdown::Item::header(L10n::n("User session"))) +//! .add_item(dropdown::Item::button(L10n::n("Sign out"))); +//! ``` mod props; pub use props::{AutoClose, Direction, MenuAlign, MenuPosition}; diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs index 984a3e06..c29ac145 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs @@ -17,22 +17,8 @@ use crate::LOCALES_BOOTSIER; /// cuenta **el título** (si no existe le asigna uno por defecto) y **la lista de elementos**; el /// resto de propiedades no afectarán a su representación en [`Nav`]. /// -/// # Ejemplo -/// -/// ```rust -/// # use pagetop::prelude::*; -/// # use pagetop_bootsier::prelude::*; -/// let dd = Dropdown::new() -/// .with_title(L10n::n("Menu")) -/// .with_button_color(ButtonColor::Background(Color::Secondary)) -/// .with_auto_close(dropdown::AutoClose::ClickableInside) -/// .with_direction(dropdown::Direction::Dropend) -/// .add_item(dropdown::Item::link(L10n::n("Home"), |_| "/")) -/// .add_item(dropdown::Item::link_blank(L10n::n("External"), |_| "https://www.google.es")) -/// .add_item(dropdown::Item::divider()) -/// .add_item(dropdown::Item::header(L10n::n("User session"))) -/// .add_item(dropdown::Item::button(L10n::n("Sign out"))); -/// ``` +/// Ver ejemplo en el módulo [`dropdown`]. +/// Si no contiene elementos, el componente **no se renderiza**. #[rustfmt::skip] #[derive(AutoDefault)] pub struct Dropdown { diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/item.rs b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs index 1aed83b4..a13058dd 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/item.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs @@ -79,7 +79,7 @@ impl Component for Item { } => { let path = path(cx); let current_path = cx.request().map(|request| request.path()); - let is_current = !*disabled && current_path.map_or(false, |p| p == path); + let is_current = !*disabled && (current_path == Some(path)); let mut classes = "dropdown-item".to_string(); if is_current { @@ -274,7 +274,7 @@ impl Item { &self.classes } - /// Devuelve el tipo de elemento representado por este elemento. + /// Devuelve el tipo de elemento representado. pub fn item_kind(&self) -> &ItemKind { &self.item_kind } diff --git a/extensions/pagetop-bootsier/src/theme/nav.rs b/extensions/pagetop-bootsier/src/theme/nav.rs index b540c323..c74ab3b5 100644 --- a/extensions/pagetop-bootsier/src/theme/nav.rs +++ b/extensions/pagetop-bootsier/src/theme/nav.rs @@ -6,6 +6,26 @@ //! //! Los ítems pueden estar activos, deshabilitados o abrirse en nueva ventana según su contexto y //! configuración, y permiten incluir etiquetas localizables usando [`L10n`](pagetop::locale::L10n). +//! +//! # Ejemplo +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let nav = Nav::tabs() +//! .with_layout(nav::Layout::End) +//! .add_item(nav::Item::link(L10n::n("Home"), |_| "/")) +//! .add_item(nav::Item::link_blank(L10n::n("External"), |_| "https://www.google.es")) +//! .add_item(nav::Item::dropdown( +//! Dropdown::new() +//! .with_title(L10n::n("Options")) +//! .with_items(TypedOp::AddMany(vec![ +//! Typed::with(dropdown::Item::link(L10n::n("Action"), |_| "/action")), +//! Typed::with(dropdown::Item::link(L10n::n("Another action"), |_| "/another")), +//! ])), +//! )) +//! .add_item(nav::Item::link_disabled(L10n::n("Disabled"), |_| "#")); +//! ``` mod props; pub use props::{Kind, Layout}; diff --git a/extensions/pagetop-bootsier/src/theme/nav/component.rs b/extensions/pagetop-bootsier/src/theme/nav/component.rs index 34c33b94..d4cf2c8c 100644 --- a/extensions/pagetop-bootsier/src/theme/nav/component.rs +++ b/extensions/pagetop-bootsier/src/theme/nav/component.rs @@ -8,25 +8,8 @@ use crate::prelude::*; /// como *pestañas* (`Tabs`), *botones* (`Pills`) o *subrayado* (`Underline`). También permite /// controlar su distribución y orientación ([`nav::Layout`](crate::theme::nav::Layout)). /// -/// # Ejemplo -/// -/// ```rust -/// # use pagetop::prelude::*; -/// # use pagetop_bootsier::prelude::*; -/// let nav = Nav::tabs() -/// .with_layout(nav::Layout::End) -/// .add_item(nav::Item::link(L10n::n("Home"), |_| "/")) -/// .add_item(nav::Item::link_blank(L10n::n("External"), |_| "https://www.google.es")) -/// .add_item(nav::Item::dropdown( -/// Dropdown::new() -/// .with_title(L10n::n("Options")) -/// .with_items(TypedOp::AddMany(vec![ -/// Typed::with(dropdown::Item::link(L10n::n("Action"), |_| "/action")), -/// Typed::with(dropdown::Item::link(L10n::n("Another action"), |_| "/another")), -/// ])), -/// )) -/// .add_item(nav::Item::link_disabled(L10n::n("Disabled"), |_| "#")); -/// ``` +/// Ver ejemplo en el módulo [`nav`]. +/// Si no contiene elementos, el componente **no se renderiza**. #[rustfmt::skip] #[derive(AutoDefault)] pub struct Nav { diff --git a/extensions/pagetop-bootsier/src/theme/nav/item.rs b/extensions/pagetop-bootsier/src/theme/nav/item.rs index 63248f8d..bc097e0c 100644 --- a/extensions/pagetop-bootsier/src/theme/nav/item.rs +++ b/extensions/pagetop-bootsier/src/theme/nav/item.rs @@ -72,7 +72,7 @@ impl Component for Item { ItemKind::Label(label) => PrepareMarkup::With(html! { li id=[self.id()] class=[self.classes().get()] { - span { + span class="nav-link disabled" aria-disabled="true" { (label.using(cx)) } } @@ -86,7 +86,7 @@ impl Component for Item { } => { let path = path(cx); let current_path = cx.request().map(|request| request.path()); - let is_current = !*disabled && current_path.map_or(false, |p| p == path); + let is_current = !*disabled && (current_path == Some(path)); let mut classes = "nav-link".to_string(); if is_current { @@ -250,7 +250,7 @@ impl Item { &self.classes } - /// Devuelve el tipo de elemento representado por este elemento. + /// Devuelve el tipo de elemento representado. pub fn item_kind(&self) -> &ItemKind { &self.item_kind } diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas.rs b/extensions/pagetop-bootsier/src/theme/offcanvas.rs index 560bd30a..dc905348 100644 --- a/extensions/pagetop-bootsier/src/theme/offcanvas.rs +++ b/extensions/pagetop-bootsier/src/theme/offcanvas.rs @@ -1,4 +1,24 @@ //! Definiciones para crear paneles laterales deslizantes [`Offcanvas`]. +//! +//! # Ejemplo +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let panel = Offcanvas::new() +//! .with_id("offcanvas_example") +//! .with_title(L10n::n("Offcanvas title")) +//! .with_placement(offcanvas::Placement::End) +//! .with_backdrop(offcanvas::Backdrop::Enabled) +//! .with_body_scroll(offcanvas::BodyScroll::Enabled) +//! .with_visibility(offcanvas::Visibility::Default) +//! .add_child(Dropdown::new() +//! .with_button_title(L10n::n("Menu")) +//! .add_item(dropdown::Item::label(L10n::n("Label"))) +//! .add_item(dropdown::Item::link_blank(L10n::n("Google"), |_| "https://www.google.es")) +//! .add_item(dropdown::Item::link(L10n::n("Sign out"), |_| "/signout")) +//! ); +//! ``` mod props; pub use props::{Backdrop, BodyScroll, Placement, Visibility}; diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs b/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs index 7cd7dffe..61e6fae7 100644 --- a/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs +++ b/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs @@ -18,27 +18,9 @@ use crate::LOCALES_BOOTSIER; /// ([`with_breakpoint()`](Self::with_breakpoint)). /// - Asocia título y controles de accesibilidad a un identificador único y expone atributos /// adecuados para lectores de pantalla y navegación por teclado. -/// - **No se renderiza** si no tiene contenido. /// -/// # Ejemplo -/// -/// ```rust -/// # use pagetop::prelude::*; -/// # use pagetop_bootsier::prelude::*; -/// let panel = Offcanvas::new() -/// .with_id("offcanvas_example") -/// .with_title(L10n::n("Offcanvas title")) -/// .with_placement(offcanvas::Placement::End) -/// .with_backdrop(offcanvas::Backdrop::Enabled) -/// .with_body_scroll(offcanvas::BodyScroll::Enabled) -/// .with_visibility(offcanvas::Visibility::Default) -/// .add_child(Dropdown::new() -/// .with_button_title(L10n::n("Menu")) -/// .add_item(dropdown::Item::label(L10n::n("Label"))) -/// .add_item(dropdown::Item::link_blank(L10n::n("Google"), |_| "https://www.google.es")) -/// .add_item(dropdown::Item::link(L10n::n("Sign out"), |_| "/signout")) -/// ); -/// ``` +/// Ver ejemplo en el módulo [`offcanvas`]. +/// Si no contiene elementos, el componente **no se renderiza**. #[rustfmt::skip] #[derive(AutoDefault)] pub struct Offcanvas { @@ -84,54 +66,7 @@ impl Component for Offcanvas { } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let body = self.children().render(cx); - if body.is_empty() { - return PrepareMarkup::None; - } - - let id = cx.required_id::<Self>(self.id()); - let id_label = join!(id, "-label"); - let id_target = join!("#", id); - - let body_scroll = match self.body_scroll() { - offcanvas::BodyScroll::Disabled => None, - offcanvas::BodyScroll::Enabled => Some("true"), - }; - - let backdrop = match self.backdrop() { - offcanvas::Backdrop::Disabled => Some("false"), - offcanvas::Backdrop::Enabled => None, - offcanvas::Backdrop::Static => Some("static"), - }; - - let title = self.title().using(cx); - - PrepareMarkup::With(html! { - div - id=(id) - class=[self.classes().get()] - tabindex="-1" - data-bs-scroll=[body_scroll] - data-bs-backdrop=[backdrop] - aria-labelledby=(id_label) - { - div class="offcanvas-header" { - @if !title.is_empty() { - h5 class="offcanvas-title" id=(id_label) { (title) } - } - button - type="button" - class="btn-close" - data-bs-dismiss="offcanvas" - data-bs-target=(id_target) - aria-label=[L10n::t("offcanvas_close", &LOCALES_BOOTSIER).lookup(cx)] - {} - } - div class="offcanvas-body" { - (body) - } - } - }) + PrepareMarkup::With(self.render_offcanvas(cx, None)) } } @@ -258,4 +193,59 @@ impl Offcanvas { pub fn children(&self) -> &Children { &self.children } + + // **< Offcanvas HELPERS >********************************************************************** + + pub(crate) fn render_offcanvas(&self, cx: &mut Context, extra: Option<&Children>) -> Markup { + let body = self.children().render(cx); + let body_extra = extra.map(|c| c.render(cx)).unwrap_or_else(|| html! {}); + if body.is_empty() && body_extra.is_empty() { + return html! {}; + } + + let id = cx.required_id::<Self>(self.id()); + let id_label = join!(id, "-label"); + let id_target = join!("#", id); + + let body_scroll = match self.body_scroll() { + offcanvas::BodyScroll::Disabled => None, + offcanvas::BodyScroll::Enabled => Some("true"), + }; + + let backdrop = match self.backdrop() { + offcanvas::Backdrop::Disabled => Some("false"), + offcanvas::Backdrop::Enabled => None, + offcanvas::Backdrop::Static => Some("static"), + }; + + let title = self.title().using(cx); + + html! { + div + id=(id) + class=[self.classes().get()] + tabindex="-1" + data-bs-scroll=[body_scroll] + data-bs-backdrop=[backdrop] + aria-labelledby=(id_label) + { + div class="offcanvas-header" { + @if !title.is_empty() { + h5 class="offcanvas-title" id=(id_label) { (title) } + } + button + type="button" + class="btn-close" + data-bs-dismiss="offcanvas" + data-bs-target=(id_target) + aria-label=[L10n::t("offcanvas_close", &LOCALES_BOOTSIER).lookup(cx)] + {} + } + div class="offcanvas-body" { + (body) + (body_extra) + } + } + } + } } From 1ed5ab86fe4b1b14da87e1d7697bbbe82339a47b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 2 Nov 2025 20:46:43 +0100 Subject: [PATCH 232/244] =?UTF-8?q?=E2=9A=B0=EF=B8=8F=20(menu):=20Elimina?= =?UTF-8?q?=20implementaci=C3=B3n=20base=20de=20men=C3=BAs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/component.rs | 2 - src/base/component/menu.rs | 17 -- src/base/component/menu/element.rs | 56 ---- src/base/component/menu/group.rs | 58 ---- src/base/component/menu/item.rs | 185 ------------- src/base/component/menu/megamenu.rs | 57 ---- src/base/component/menu/menu_menu.rs | 108 -------- src/base/component/menu/submenu.rs | 73 ----- static/css/menu.css | 384 --------------------------- static/js/menu.js | 95 ------- 10 files changed, 1035 deletions(-) delete mode 100644 src/base/component/menu.rs delete mode 100644 src/base/component/menu/element.rs delete mode 100644 src/base/component/menu/group.rs delete mode 100644 src/base/component/menu/item.rs delete mode 100644 src/base/component/menu/megamenu.rs delete mode 100644 src/base/component/menu/menu_menu.rs delete mode 100644 src/base/component/menu/submenu.rs delete mode 100644 static/css/menu.css delete mode 100644 static/js/menu.js diff --git a/src/base/component.rs b/src/base/component.rs index 8991d721..508a28e1 100644 --- a/src/base/component.rs +++ b/src/base/component.rs @@ -62,5 +62,3 @@ pub use poweredby::PoweredBy; mod icon; pub use icon::{Icon, IconKind}; - -pub mod menu; diff --git a/src/base/component/menu.rs b/src/base/component/menu.rs deleted file mode 100644 index 14f75898..00000000 --- a/src/base/component/menu.rs +++ /dev/null @@ -1,17 +0,0 @@ -mod menu_menu; -pub use menu_menu::Menu; - -mod item; -pub use item::{Item, ItemKind}; - -mod submenu; -pub use submenu::Submenu; - -mod megamenu; -pub use megamenu::Megamenu; - -mod group; -pub use group::Group; - -mod element; -pub use element::{Element, ElementType}; diff --git a/src/base/component/menu/element.rs b/src/base/component/menu/element.rs deleted file mode 100644 index 6d142048..00000000 --- a/src/base/component/menu/element.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::prelude::*; - -type Content = Typed<Html>; -type SubmenuItems = Typed<menu::Submenu>; - -#[derive(AutoDefault)] -pub enum ElementType { - #[default] - Void, - Html(Content), - Submenu(SubmenuItems), -} - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Element { - element_type: ElementType, -} - -impl Component for Element { - fn new() -> Self { - Element::default() - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - match self.element_type() { - ElementType::Void => PrepareMarkup::None, - ElementType::Html(content) => PrepareMarkup::With(html! { - (content.render(cx)) - }), - ElementType::Submenu(submenu) => PrepareMarkup::With(html! { - (submenu.render(cx)) - }), - } - } -} - -impl Element { - pub fn html(content: Html) -> Self { - Element { - element_type: ElementType::Html(Content::with(content)), - } - } - - pub fn submenu(submenu: menu::Submenu) -> Self { - Element { - element_type: ElementType::Submenu(SubmenuItems::with(submenu)), - } - } - - // **< Element GETTERS >************************************************************************ - - pub fn element_type(&self) -> &ElementType { - &self.element_type - } -} diff --git a/src/base/component/menu/group.rs b/src/base/component/menu/group.rs deleted file mode 100644 index ba188934..00000000 --- a/src/base/component/menu/group.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::prelude::*; - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Group { - id : AttrId, - elements: Children, -} - -impl Component for Group { - fn new() -> Self { - Group::default() - } - - fn id(&self) -> Option<String> { - self.id.get() - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - PrepareMarkup::With(html! { - div id=[self.id()] class="menu__group" { - (self.elements().render(cx)) - } - }) - } -} - -impl Group { - // **< Group BUILDER >************************************************************************** - - /// Establece el identificador único (`id`) del grupo. - #[builder_fn] - pub fn with_id(mut self, id: impl AsRef<str>) -> Self { - self.id.alter_value(id); - self - } - - /// Añade un nuevo elemento al menú. - pub fn add_element(mut self, element: menu::Element) -> Self { - self.elements - .alter_typed(TypedOp::Add(Typed::with(element))); - self - } - - /// Modifica la lista de elementos (`children`) aplicando una operación [`TypedOp`]. - #[builder_fn] - pub fn with_elements(mut self, op: TypedOp<menu::Element>) -> Self { - self.elements.alter_typed(op); - self - } - - // **< Group GETTERS >************************************************************************** - - /// Devuelve la lista de elementos (`children`) del grupo. - pub fn elements(&self) -> &Children { - &self.elements - } -} diff --git a/src/base/component/menu/item.rs b/src/base/component/menu/item.rs deleted file mode 100644 index c6342186..00000000 --- a/src/base/component/menu/item.rs +++ /dev/null @@ -1,185 +0,0 @@ -use crate::prelude::*; - -type Label = L10n; -type Content = Typed<Html>; -type SubmenuItems = Typed<menu::Submenu>; -type MegamenuGroups = Typed<menu::Megamenu>; - -#[derive(AutoDefault)] -pub enum ItemKind { - #[default] - Void, - Label(Label), - Link(Label, FnPathByContext), - LinkBlank(Label, FnPathByContext), - Html(Content), - Submenu(Label, SubmenuItems), - Megamenu(Label, MegamenuGroups), -} - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Item { - item_kind : ItemKind, - description: AttrL10n, - left_icon : Typed<Icon>, - right_icon : Typed<Icon>, -} - -impl Component for Item { - fn new() -> Self { - Item::default() - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let description = self.description().lookup(cx); - let left_icon = self.left_icon().render(cx); - let right_icon = self.right_icon().render(cx); - - match self.item_kind() { - ItemKind::Void => PrepareMarkup::None, - ItemKind::Label(label) => PrepareMarkup::With(html! { - li class="menu__item menu__item--label" { - span title=[description] { - (left_icon) - span class="menu__label" { (label.using(cx)) } - (right_icon) - } - } - }), - ItemKind::Link(label, path) => PrepareMarkup::With(html! { - li class="menu__item menu__item--link" { - a class="menu__link" href=(path(cx)) title=[description] { - (left_icon) - span class="menu__label" { (label.using(cx)) } - (right_icon) - } - } - }), - ItemKind::LinkBlank(label, path) => PrepareMarkup::With(html! { - li class="menu__item menu__item--link" { - a class="menu__link" href=(path(cx)) title=[description] target="_blank" { - (left_icon) - span class="menu__label" { (label.using(cx)) } - (right_icon) - } - } - }), - ItemKind::Html(content) => PrepareMarkup::With(html! { - li class="menu__item menu__item--html" { - (content.render(cx)) - } - }), - ItemKind::Submenu(label, submenu) => PrepareMarkup::With(html! { - li class="menu__item menu__item--children" { - button type="button" class="menu__link" title=[description] { - (left_icon) - span class="menu__label" { (label.using(cx)) } - (Icon::svg(html! { - path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708" {} - }).render(cx)) - } - div class="menu__children menu__children--submenu" { - (submenu.render(cx)) - } - } - }), - ItemKind::Megamenu(label, megamenu) => PrepareMarkup::With(html! { - li class="menu__item menu__item--children" { - button type="button" class="menu__link" title=[description] { - (left_icon) - span class="menu__label" { (label.using(cx)) } - (Icon::svg(html! { - path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708" {} - }).render(cx)) - } - div class="menu__children menu__children--mega" { - (megamenu.render(cx)) - } - } - }), - } - } -} - -impl Item { - pub fn label(label: L10n) -> Self { - Item { - item_kind: ItemKind::Label(label), - ..Default::default() - } - } - - pub fn link(label: L10n, path: FnPathByContext) -> Self { - Item { - item_kind: ItemKind::Link(label, path), - ..Default::default() - } - } - - pub fn link_blank(label: L10n, path: FnPathByContext) -> Self { - Item { - item_kind: ItemKind::LinkBlank(label, path), - ..Default::default() - } - } - - pub fn html(content: Html) -> Self { - Item { - item_kind: ItemKind::Html(Content::with(content)), - ..Default::default() - } - } - - pub fn submenu(label: L10n, submenu: menu::Submenu) -> Self { - Item { - item_kind: ItemKind::Submenu(label, SubmenuItems::with(submenu)), - ..Default::default() - } - } - - pub fn megamenu(label: L10n, megamenu: menu::Megamenu) -> Self { - Item { - item_kind: ItemKind::Megamenu(label, MegamenuGroups::with(megamenu)), - ..Default::default() - } - } - - // **< Item BUILDER >*************************************************************************** - - #[builder_fn] - pub fn with_description(mut self, text: L10n) -> Self { - self.description.alter_value(text); - self - } - - #[builder_fn] - pub fn with_left_icon<I: Into<Icon>>(mut self, icon: Option<I>) -> Self { - self.left_icon.alter_component(icon.map(Into::into)); - self - } - - #[builder_fn] - pub fn with_right_icon<I: Into<Icon>>(mut self, icon: Option<I>) -> Self { - self.right_icon.alter_component(icon.map(Into::into)); - self - } - - // **< Item GETTERS >*************************************************************************** - - pub fn item_kind(&self) -> &ItemKind { - &self.item_kind - } - - pub fn description(&self) -> &AttrL10n { - &self.description - } - - pub fn left_icon(&self) -> &Typed<Icon> { - &self.left_icon - } - - pub fn right_icon(&self) -> &Typed<Icon> { - &self.right_icon - } -} diff --git a/src/base/component/menu/megamenu.rs b/src/base/component/menu/megamenu.rs deleted file mode 100644 index e435e753..00000000 --- a/src/base/component/menu/megamenu.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::prelude::*; - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Megamenu { - id : AttrId, - groups: Children, -} - -impl Component for Megamenu { - fn new() -> Self { - Megamenu::default() - } - - fn id(&self) -> Option<String> { - self.id.get() - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - PrepareMarkup::With(html! { - div id=[self.id()] class="menu__mega" { - (self.groups().render(cx)) - } - }) - } -} - -impl Megamenu { - // **< Megamenu BUILDER >*********************************************************************** - - /// Establece el identificador único (`id`) del megamenú. - #[builder_fn] - pub fn with_id(mut self, id: impl AsRef<str>) -> Self { - self.id.alter_value(id); - self - } - - /// Añade un nuevo grupo al menú. - pub fn add_group(mut self, group: menu::Group) -> Self { - self.groups.alter_typed(TypedOp::Add(Typed::with(group))); - self - } - - /// Modifica la lista de grupos (`children`) aplicando una operación [`TypedOp`]. - #[builder_fn] - pub fn with_groups(mut self, op: TypedOp<menu::Group>) -> Self { - self.groups.alter_typed(op); - self - } - - // **< Megamenu GETTERS >*********************************************************************** - - /// Devuelve la lista de grupos (`children`) del megamenú. - pub fn groups(&self) -> &Children { - &self.groups - } -} diff --git a/src/base/component/menu/menu_menu.rs b/src/base/component/menu/menu_menu.rs deleted file mode 100644 index 58a4c21d..00000000 --- a/src/base/component/menu/menu_menu.rs +++ /dev/null @@ -1,108 +0,0 @@ -use crate::prelude::*; - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Menu { - id : AttrId, - classes: AttrClasses, - items : Children, -} - -impl Component for Menu { - fn new() -> Self { - Menu::default() - } - - fn id(&self) -> Option<String> { - self.id.get() - } - - fn setup_before_prepare(&mut self, _cx: &mut Context) { - self.alter_classes(ClassesOp::Prepend, "menu"); - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - // cx.set_param::<bool>(PARAM_BASE_INCLUDE_MENU_ASSETS, &true); - // cx.set_param::<bool>(PARAM_BASE_INCLUDE_ICONS, &true); - - PrepareMarkup::With(html! { - div id=[self.id()] class=[self.classes().get()] { - div class="menu__wrapper" { - div class="menu__panel" { - div class="menu__overlay" {} - nav class="menu__nav" { - div class="menu__header" { - button type="button" class="menu__back" { - (Icon::svg(html! { - path fill-rule="evenodd" d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0" {} - }).render(cx)) - } - div class="menu__title" {} - button type="button" class="menu__close" { - (Icon::svg(html! { - path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z" {} - }).render(cx)) - } - } - ul class="menu__list" { - (self.items().render(cx)) - } - } - } - button - type="button" - class="menu__trigger" - title=[L10n::l("menu_toggle").lookup(cx)] - { - (Icon::svg(html! { - path fill-rule="evenodd" d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5" {} - }).render(cx)) - } - } - } - }) - } -} - -impl Menu { - // **< Menu BUILDER >*************************************************************************** - - /// Establece el identificador único (`id`) del menú. - #[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 menú. - #[builder_fn] - pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { - self.classes.alter_value(op, classes); - self - } - - /// Añade un nuevo ítem al menú. - pub fn add_item(mut self, item: menu::Item) -> Self { - self.items.alter_typed(TypedOp::Add(Typed::with(item))); - self - } - - /// Modifica la lista de ítems (`children`) aplicando una operación [`TypedOp`]. - #[builder_fn] - pub fn with_items(mut self, op: TypedOp<menu::Item>) -> Self { - self.items.alter_typed(op); - self - } - - // **< Menu GETTERS >*************************************************************************** - - /// Devuelve las clases CSS asociadas al menú. - pub fn classes(&self) -> &AttrClasses { - &self.classes - } - - /// Devuelve la lista de ítems (`children`) del menú. - pub fn items(&self) -> &Children { - &self.items - } -} diff --git a/src/base/component/menu/submenu.rs b/src/base/component/menu/submenu.rs deleted file mode 100644 index a5957ef9..00000000 --- a/src/base/component/menu/submenu.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::prelude::*; - -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Submenu { - id : AttrId, - title: AttrL10n, - items: Children, -} - -impl Component for Submenu { - fn new() -> Self { - Submenu::default() - } - - fn id(&self) -> Option<String> { - self.id.get() - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - PrepareMarkup::With(html! { - div id=[self.id()] class="menu__submenu" { - @if let Some(title) = self.title().lookup(cx) { - h4 class="menu__submenu-title" { (title) } - } - ul { - (self.items().render(cx)) - } - } - }) - } -} - -impl Submenu { - // **< Submenu BUILDER >************************************************************************ - - /// Establece el identificador único (`id`) del submenú. - #[builder_fn] - pub fn with_id(mut self, id: impl AsRef<str>) -> Self { - self.id.alter_value(id); - self - } - - #[builder_fn] - pub fn with_title(mut self, title: L10n) -> Self { - self.title.alter_value(title); - self - } - - /// Añade un nuevo ítem al submenú. - pub fn add_item(mut self, item: menu::Item) -> Self { - self.items.alter_typed(TypedOp::Add(Typed::with(item))); - self - } - - /// Modifica la lista de ítems (`children`) aplicando una operación [`TypedOp`]. - #[builder_fn] - pub fn with_items(mut self, op: TypedOp<menu::Item>) -> Self { - self.items.alter_typed(op); - self - } - - // **< Submenu GETTERS >************************************************************************ - - pub fn title(&self) -> &AttrL10n { - &self.title - } - - /// Devuelve la lista de ítems (`children`) del submenú. - pub fn items(&self) -> &Children { - &self.items - } -} diff --git a/static/css/menu.css b/static/css/menu.css deleted file mode 100644 index 428ba157..00000000 --- a/static/css/menu.css +++ /dev/null @@ -1,384 +0,0 @@ -/* Aislamiento & normalización */ - -.menu { - isolation: isolate; -} -@supports (all: revert) { - .menu { - all: revert; - display: block; } -} -.menu { - box-sizing: border-box; - line-height: var(--val-menu--line-height, 1.5); - color: var(--val-color--text); - text-align: left; - text-transform: none; - letter-spacing: normal; - word-spacing: normal; - white-space: normal; - cursor: default; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - - width: 100%; - height: auto; - margin: 0; - padding: 0; - z-index: 9999; - border: 0; - background: var(--val-menu--color-bg); -} -.menu *, -.menu *::before, -.menu *::after { - box-sizing: inherit; -} -.menu :where(a, button) { - appearance: none; - background: none; - border: 0; - font: inherit; - color: inherit; - text-decoration: none; - cursor: pointer; - -webkit-tap-highlight-color: transparent; -} -.menu :where(a, button):focus-visible { - outline: 2px solid var(--val-menu--color-highlight); - outline-offset: 2px; -} -.menu :where(ul, ol) { - list-style: none; - margin: 0; - padding: 0; -} -.menu svg { - fill: currentColor; -} - -/* Estructura */ - -.menu__wrapper { - padding-right: var(--val-gap); -} - -.menu__nav li { - display: inline-block; - margin: 0; - margin-inline-start: 1.5rem; - padding: 0; - line-height: var(--val-menu--item-height); - list-style: none; -} - -.menu__item--label, -.menu__nav li > .menu__link { - position: relative; - font-weight: normal; - text-rendering: optimizeLegibility; - font-size: 1.45rem; -} -.menu__nav li > .menu__link { - transition: color 0.3s ease-in-out; -} -.menu__nav li:hover > .menu__link, -.menu__nav li > .menu__link:focus { - color: var(--val-menu--color-highlight); -} -.menu__nav li > .menu__link > svg.icon { - margin-left: 0.25rem; -} - -.menu__children { - position: absolute; - max-width: 100%; - height: auto; - padding: var(--val-gap-0-5) var(--val-gap-1-5); - border: 0; - background: var(--val-menu--color-bg); - border-top: 3px solid var(--val-menu--color-highlight); - z-index: 500; - opacity: 0; - visibility: hidden; - box-shadow: 0 4px 6px -1px var(--val-menu--color-border), 0 2px 4px -1px var(--val-menu--color-shadow); - transition: all 0.3s ease-in-out; -} - -.menu__item--children:hover > .menu__children, -.menu__item--children > .menu__link:focus + .menu__children, -.menu__item--children .menu__children:focus-within { - margin-top: 0.4rem; - opacity: 1; - visibility: visible; -} - -.menu__submenu { - min-width: var(--val-menu--item-width-min); - max-width: var(--val-menu--item-width-max); -} -.menu__submenu-title { - font-size: 1rem; - font-weight: normal; - margin: 0; - padding: var(--val-menu--line-padding) 0; - line-height: var(--val-menu--line-height); - border: 0; - color: var(--val-menu--color-highlight); - text-transform: uppercase; - text-rendering: optimizeLegibility; -} -.menu__submenu li { - display: block; - margin: 0; -} - -.menu__children--mega { - left: 50%; - transform: translateX(-50%); -} - -.menu__mega { - display: flex; - flex-wrap: nowrap; -} - -.menu__header, -.menu__trigger { - display: none; -} - -/* Responsive <= 62rem (992px) */ - -@media (max-width: 62rem) { - .menu__wrapper { - padding-right: var(--val-gap-0-5); - } - .menu__trigger { - width: var(--val-menu--trigger-width); - height: var(--val-menu--item-height); - display: flex; - flex-direction: column; - justify-content: center; - } - .menu__trigger svg.icon { - width: 2rem; - height: 2rem; - } - - .menu__nav, - .menu__children { - overscroll-behavior: contain; - -webkit-overflow-scrolling: touch; - } - - .menu__nav { - position: fixed; - top: 0; - left: 0; - width: var(--val-menu--side-width); - height: 100%; - z-index: 9099; - overflow: hidden; - background: var(--val-menu--color-bg); - transform: translate(-100%); - transition: transform .5s ease-in-out, opacity .5s ease-in-out; - will-change: transform; - backface-visibility: hidden; - visibility: hidden; - pointer-events: none; - } - .menu__nav.active { - transform: translate(0%); - visibility: visible; - pointer-events: auto; - } - - .menu__nav li { - display: block; - margin: 0; - line-height: var(--val-menu--line-height); - } - - .menu__item--label, - .menu__nav li > .menu__link { - display: block; - text-align: inherit; - width: 100%; - padding: var(--val-menu--line-padding) var(--val-menu--item-height) var(--val-menu--line-padding) var(--val-menu--item-gap); - border-bottom: 1px solid var(--val-menu--color-border); - } - .menu__nav li ul li.menu__item--label, - .menu__nav li ul li > .menu__link { - border-bottom: 0; - } - .menu__nav li > .menu__link > svg.icon { - position: absolute; - top: var(--val-menu--line-padding); - right: var(--val-menu--line-padding); - height: var(--val-menu--line-height); - font-size: 1.25rem; - transform: rotate(-90deg); - } - - .menu__children { - position: absolute; - display: none; - top: 0; - left: 0; - max-width: none; - min-width: auto; - width: 100%; - height: 100%; - margin: 0 !important; - padding: 0; - border-top: 0; - opacity: 1; - overflow-y: auto; - visibility: visible; - transform: translateX(0%); - box-shadow: none; - transition: opacity .5s ease-in-out, transform .5s ease-in-out, margin-top .5s ease-in-out; - } - .menu__children.active { - display: block; - } - .menu__children > :first-child { - margin-top: 2.675rem; - } - - .menu__submenu-title { - padding: var(--val-menu--line-padding) var(--val-menu--item-height) var(--val-menu--line-padding) var(--val-menu--item-gap); - } - - .menu__mega { - display: block; - } - - .menu__header { - position: sticky; - display: flex; - align-items: center; - justify-content: space-between; - top: 0; - height: var(--val-menu--item-height); - border-bottom: 1px solid var(--val-menu--color-border); - background: var(--val-menu--color-bg); - z-index: 501; - } - .menu__title { - padding: var(--val-menu--line-padding); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - font-size: 1.45rem; - font-weight: normal; - opacity: 0; - transform: translateY(.25rem); - transition: opacity .5s ease-in-out, transform .5s ease-in-out; - will-change: opacity, transform; - } - .menu__header.active .menu__title { - opacity: 1; - transform: translateY(0); - } - .menu__close, - .menu__back { - width: var(--val-menu--item-height); - min-width: var(--val-menu--item-height); - height: var(--val-menu--item-height); - line-height: var(--val-menu--item-height); - color: var(--val-color--text); - display: flex; - align-items: center; - justify-content: center; - background: var(--val-menu--color-bg); - } - .menu__close { - font-size: 2.25rem; - border: 1px solid var(--val-menu--color-border) !important; - border-width: 0 0 1px 1px !important; - } - .menu__back { - font-size: 1.25rem; - border: 1px solid var(--val-menu--color-border) !important; - border-width: 0 1px 1px 0 !important; - display: none; - } - .menu__header.active .menu__back { - display: flex; - } - - .menu__list { - height: 100%; - overflow-y: auto; - overflow-x: hidden; - padding: 0; - margin: 0; - } - - .menu__overlay { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 9098; - opacity: 0; - visibility: hidden; - background: rgba(0, 0, 0, 0.55); - transition: opacity .5s ease-in-out, visibility 0s linear .5s; - } - .menu__overlay.active { - opacity: 1; - visibility: visible; - transition-delay: 0s, 0s; - } -} - -@media (hover: hover) and (pointer: fine) { - .menu__item--children:hover > .menu__children { - margin-top: 0.4rem; - opacity: 1; - visibility: visible; - } - .menu.menu--closing .menu__children { - margin-top: 0 !important; - opacity: 0 !important; - visibility: hidden !important; - } -} - -@media (prefers-reduced-motion: reduce) { - .menu__nav, - .menu__children, - .menu__title, - .menu__overlay { - transition: none !important; - animation: none !important; - } -} - -/* Animaciones */ - -@keyframes slideLeft { - 0% { - opacity: 0; - transform: translateX(100%); - } - 100% { - opacity: 1; - transform: translateX(0%); - } -} - -@keyframes slideRight { - 0% { - opacity: 1; - transform: translateX(0%); - } - 100% { - opacity: 0; - transform: translateX(100%); - } -} diff --git a/static/js/menu.js b/static/js/menu.js deleted file mode 100644 index dca8e4df..00000000 --- a/static/js/menu.js +++ /dev/null @@ -1,95 +0,0 @@ -const getTitle = (li) => li.querySelector('.menu__label')?.textContent.trim() ?? ''; - -function menu__showChildren(nav, children) { - const li = children[0]; - const submenu = li.querySelector('.menu__children'); - submenu.classList.add('active'); - submenu.style.animation = 'slideLeft 0.5s ease forwards'; - - nav.querySelector('.menu__title').textContent = getTitle(li);; - nav.querySelector('.menu__header').classList.add('active'); -} - -function menu__hideChildren(nav, children) { - const submenu = children[0].querySelector('.menu__children'); - submenu.style.animation = 'slideRight 0.5s ease forwards'; - setTimeout(() => { - submenu.classList.remove('active'); - submenu.style.removeProperty('animation'); - }, 300); - - children.shift(); - if (children.length > 0) { - nav.querySelector('.menu__title').textContent = getTitle(children[0]); - } else { - nav.querySelector('.menu__header').classList.remove('active'); - nav.querySelector('.menu__title').textContent = ''; - } -} - -function menu__toggle(nav, overlay) { - nav.classList.toggle('active'); - overlay.classList.toggle('active'); -} - -function menu__reset(menu, nav, overlay) { - menu__toggle(nav, overlay); - setTimeout(() => { - nav.querySelector('.menu__header').classList.remove('active'); - nav.querySelector('.menu__title').textContent = ''; - menu.querySelectorAll('.menu__children').forEach(submenu => { - submenu.classList.remove('active'); - submenu.style.removeProperty('animation'); - }); - }, 300); - return []; -} - -document.querySelectorAll('.menu').forEach(menu => { - let menuChildren = []; - const menuNav = menu.querySelector('.menu__nav'); - const menuOverlay = menu.querySelector('.menu__overlay'); - - menu.querySelector('.menu__list').addEventListener('click', (e) => { - if (menuNav.classList.contains('active')) { - let target = e.target.closest('.menu__item--children'); - if (target && target != menuChildren[0]) { - menuChildren.unshift(target); - menu__showChildren(menuNav, menuChildren); - } - } - }); - - menu.querySelector('.menu__back').addEventListener('click', () => { - menu__hideChildren(menuNav, menuChildren); - }); - - menu.querySelector('.menu__close').addEventListener('click', () => { - menuChildren = menu__reset(menu, menuNav, menuOverlay); - }); - - menu.querySelectorAll('.menu__item--link > a[target="_blank"]').forEach(link => { - link.addEventListener('click', (e) => { - menuChildren = menu__reset(menu, menuNav, menuOverlay); - e.target.blur(); - }); - }); - - menu.querySelector('.menu__trigger').addEventListener('click', () => { - menu__toggle(menuNav, menuOverlay); - }); - - menuOverlay.addEventListener('click', () => { - menu__toggle(menuNav, menuOverlay); - }); - - let resizeTimeout; - window.addEventListener('resize', () => { - if (menuNav.classList.contains('active')) { - clearTimeout(resizeTimeout); - resizeTimeout = setTimeout(() => { - menuChildren = menu__reset(menu, menuNav, menuOverlay); - }, 150); - } - }); -}); From 0d6f975649edae10c6cf54705586a00cea710d1b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 2 Nov 2025 20:47:26 +0100 Subject: [PATCH 233/244] =?UTF-8?q?=F0=9F=93=9D=20Corrige=20ejemplo=20de?= =?UTF-8?q?=20documentaci=C3=B3n=20de`Offcanvas`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extensions/pagetop-bootsier/src/theme/offcanvas.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas.rs b/extensions/pagetop-bootsier/src/theme/offcanvas.rs index dc905348..18cc253a 100644 --- a/extensions/pagetop-bootsier/src/theme/offcanvas.rs +++ b/extensions/pagetop-bootsier/src/theme/offcanvas.rs @@ -13,7 +13,7 @@ //! .with_body_scroll(offcanvas::BodyScroll::Enabled) //! .with_visibility(offcanvas::Visibility::Default) //! .add_child(Dropdown::new() -//! .with_button_title(L10n::n("Menu")) +//! .with_title(L10n::n("Menu")) //! .add_item(dropdown::Item::label(L10n::n("Label"))) //! .add_item(dropdown::Item::link_blank(L10n::n("Google"), |_| "https://www.google.es")) //! .add_item(dropdown::Item::link(L10n::n("Sign out"), |_| "/signout")) From 9a26d579ed022a479c39cb2687407c100f649869 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sun, 2 Nov 2025 20:47:50 +0100 Subject: [PATCH 234/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20ejemplo=20de?= =?UTF-8?q?=20barra=20de=20men=C3=BA=20de=20navegaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/navbar-menus.rs | 101 ++++++++++++++++++++++++++++++++++++ src/locale/en-US/sample.ftl | 24 +++++++++ src/locale/es-ES/sample.ftl | 24 +++++++++ 3 files changed, 149 insertions(+) create mode 100644 examples/navbar-menus.rs create mode 100644 src/locale/en-US/sample.ftl create mode 100644 src/locale/es-ES/sample.ftl diff --git a/examples/navbar-menus.rs b/examples/navbar-menus.rs new file mode 100644 index 00000000..22ef336c --- /dev/null +++ b/examples/navbar-menus.rs @@ -0,0 +1,101 @@ +use pagetop::prelude::*; + +use pagetop_bootsier::prelude::*; + +struct SuperMenu; + +impl Extension for SuperMenu { + fn dependencies(&self) -> Vec<ExtensionRef> { + vec![&pagetop_aliner::Aliner, &pagetop_bootsier::Bootsier] + } + + fn initialize(&self) { + let home_path = |cx: &Context| match cx.langid().language.as_str() { + "en" => "/en", + _ => "/", + }; + + let navbar_menu = Navbar::brand_left(navbar::Brand::new().with_path(Some(home_path))) + .with_expand(BreakPoint::LG) + .add_item(navbar::Item::nav( + Nav::new() + .add_item(nav::Item::link( + L10n::l("sample_menus_item_link"), + home_path, + )) + .add_item(nav::Item::link_blank( + L10n::l("sample_menus_item_blank"), + |_| "https://docs.rs/pagetop", + )) + .add_item(nav::Item::dropdown( + Dropdown::new() + .with_title(L10n::l("sample_menus_test_title")) + .add_item(dropdown::Item::header(L10n::l("sample_menus_dev_header"))) + .add_item(dropdown::Item::link( + L10n::l("sample_menus_dev_getting_started"), + |_| "/dev/getting-started", + )) + .add_item(dropdown::Item::link( + L10n::l("sample_menus_dev_guides"), + |_| "/dev/guides", + )) + .add_item(dropdown::Item::link_blank( + L10n::l("sample_menus_dev_forum"), + |_| "https://forum.example.dev", + )) + .add_item(dropdown::Item::divider()) + .add_item(dropdown::Item::header(L10n::l("sample_menus_sdk_header"))) + .add_item(dropdown::Item::link( + L10n::l("sample_menus_sdk_rust"), + |_| "/dev/sdks/rust", + )) + .add_item(dropdown::Item::link(L10n::l("sample_menus_sdk_js"), |_| { + "/dev/sdks/js" + })) + .add_item(dropdown::Item::link( + L10n::l("sample_menus_sdk_python"), + |_| "/dev/sdks/python", + )) + .add_item(dropdown::Item::divider()) + .add_item(dropdown::Item::header(L10n::l( + "sample_menus_plugin_header", + ))) + .add_item(dropdown::Item::link( + L10n::l("sample_menus_plugin_auth"), + |_| "/dev/sdks/rust/plugins/auth", + )) + .add_item(dropdown::Item::link( + L10n::l("sample_menus_plugin_cache"), + |_| "/dev/sdks/rust/plugins/cache", + )) + .add_item(dropdown::Item::divider()) + .add_item(dropdown::Item::label(L10n::l("sample_menus_item_label"))) + .add_item(dropdown::Item::link_disabled( + L10n::l("sample_menus_item_disabled"), + |_| "#", + )), + )) + .add_item(nav::Item::link_disabled( + L10n::l("sample_menus_item_disabled"), + |_| "#", + )), + )) + .add_item(navbar::Item::nav( + Nav::new() + .add_item(nav::Item::link( + L10n::l("sample_menus_item_sign_up"), + |_| "/auth/sign-up", + )) + .add_item(nav::Item::link(L10n::l("sample_menus_item_login"), |_| { + "/auth/login" + })), + )); + + InRegion::Key("header").add(Child::with(navbar_menu)); + } +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&SuperMenu).run()?.await +} diff --git a/src/locale/en-US/sample.ftl b/src/locale/en-US/sample.ftl new file mode 100644 index 00000000..ae5b9a7f --- /dev/null +++ b/src/locale/en-US/sample.ftl @@ -0,0 +1,24 @@ +# menus.rs +sample_menus_item_label = Label +sample_menus_item_link = Link +sample_menus_item_blank = External link +sample_menus_item_disabled = Disabled link + +sample_menus_test_title = Dropdown + +sample_menus_dev_header = Intro +sample_menus_dev_getting_started = Getting started +sample_menus_dev_guides = Development guides +sample_menus_dev_forum = Developers forum + +sample_menus_sdk_header = Software Development Kits +sample_menus_sdk_rust = SDKs Rust +sample_menus_sdk_js = SDKs JavaScript +sample_menus_sdk_python = SDKs Python + +sample_menus_plugin_header = Plugins +sample_menus_plugin_auth = Rust Plugin Auth +sample_menus_plugin_cache = Rust Plugin Cache + +sample_menus_item_sign_up = Sign up +sample_menus_item_login = Login diff --git a/src/locale/es-ES/sample.ftl b/src/locale/es-ES/sample.ftl new file mode 100644 index 00000000..65785972 --- /dev/null +++ b/src/locale/es-ES/sample.ftl @@ -0,0 +1,24 @@ +# menus.rs +sample_menus_item_label = Etiqueta +sample_menus_item_link = Enlace +sample_menus_item_blank = Enlace externo +sample_menus_item_disabled = Enlace deshabilitado + +sample_menus_test_title = Desplegable + +sample_menus_dev_header = Introducción +sample_menus_dev_getting_started = Primeros pasos +sample_menus_dev_guides = Guías de desarrollo +sample_menus_dev_forum = Foro de desarrolladores + +sample_menus_sdk_header = Kits de Desarrollo Software +sample_menus_sdk_rust = SDKs de Rust +sample_menus_sdk_js = SDKs de JavaScript +sample_menus_sdk_python = SDKs de Python + +sample_menus_plugin_header = Plugins +sample_menus_plugin_auth = Plugin Rust de autenticación +sample_menus_plugin_cache = Plugin Rust de caché + +sample_menus_item_sign_up = Registrarse +sample_menus_item_login = Iniciar sesión From d5f0d83939f31ffcd20121e32b34b6a7346dadca Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 3 Nov 2025 22:43:31 +0100 Subject: [PATCH 235/244] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(bootsier):=20Refa?= =?UTF-8?q?ctoriza=20y=20renombra=20estilos=20`aux`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extensions/pagetop-bootsier/src/theme/aux.rs | 9 +- .../pagetop-bootsier/src/theme/aux/border.rs | 39 ++- .../pagetop-bootsier/src/theme/aux/color.rs | 226 ++++++++++++++---- .../pagetop-bootsier/src/theme/aux/opacity.rs | 109 --------- .../pagetop-bootsier/src/theme/aux/rounded.rs | 2 +- .../pagetop-bootsier/src/theme/aux/size.rs | 9 +- .../pagetop-bootsier/src/theme/container.rs | 40 ++-- .../pagetop-bootsier/src/theme/dropdown.rs | 2 +- .../src/theme/dropdown/component.rs | 6 +- .../src/theme/navbar/component.rs | 48 +++- 10 files changed, 267 insertions(+), 223 deletions(-) delete mode 100644 extensions/pagetop-bootsier/src/theme/aux/opacity.rs diff --git a/extensions/pagetop-bootsier/src/theme/aux.rs b/extensions/pagetop-bootsier/src/theme/aux.rs index f3cc127d..a56b14e9 100644 --- a/extensions/pagetop-bootsier/src/theme/aux.rs +++ b/extensions/pagetop-bootsier/src/theme/aux.rs @@ -4,12 +4,9 @@ mod breakpoint; pub use breakpoint::BreakPoint; mod color; -pub use color::Color; -pub use color::{BgColor, BorderColor, ButtonColor, TextColor}; - -mod opacity; -pub use opacity::Opacity; -pub use opacity::{BgOpacity, BorderOpacity, TextOpacity}; +pub use color::{Color, Opacity}; +pub use color::{ColorBg, ColorBorder, ColorButton, ColorText}; +pub use color::{StyleBg, StyleBorder, StyleText}; mod border; pub use border::{Border, BorderSize}; diff --git a/extensions/pagetop-bootsier/src/theme/aux/border.rs b/extensions/pagetop-bootsier/src/theme/aux/border.rs index 840f03c7..de3df81e 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/border.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/border.rs @@ -6,7 +6,7 @@ use std::fmt; // **< BorderSize >********************************************************************************* -/// Tamaño (**ancho**) para los bordes ([`Border`]). +/// Tamaño para el ancho de los bordes ([`Border`]). /// /// Mapea a `border`, `border-0` y `border-{1..5}`: /// @@ -58,7 +58,7 @@ impl fmt::Display for BorderSize { /// - Definir un tamaño **global** para todo el borde (`size`). /// - Ajustar el tamaño de cada **lado lógico** (`top`, `end`, `bottom`, `start`, **en este orden**, /// respetando LTR/RTL). -/// - Aplicar un **color** al borde (`BorderColor`). +/// - Aplicar un **color** al borde (`ColorBorder`). /// - Aplicar un nivel de **opacidad** (`BorderOpacity`). /// /// # Comportamiento aditivo / sustractivo @@ -107,21 +107,19 @@ impl fmt::Display for BorderSize { /// let b = Border::with(BorderSize::Default) // Borde global por defecto. /// .with_top(BorderSize::Zero) // Quita borde superior. /// .with_end(BorderSize::Scale3) // Ancho 3 para el lado lógico final. -/// .with_color(BorderColor::Theme(Color::Primary)) -/// .with_opacity(BorderOpacity::Theme(Opacity::Half)); +/// .with_style(StyleBorder::Both(ColorBorder::Theme(Color::Primary), Opacity::Half)); /// /// assert_eq!(b.to_string(), "border border-top-0 border-end-3 border-primary border-opacity-50"); /// ``` #[rustfmt::skip] #[derive(AutoDefault)] pub struct Border { - size : BorderSize, - top : BorderSize, - end : BorderSize, - bottom : BorderSize, - start : BorderSize, - color : BorderColor, - opacity: BorderOpacity, + size : BorderSize, + top : BorderSize, + end : BorderSize, + bottom: BorderSize, + start : BorderSize, + style : StyleBorder, } impl Border { @@ -167,22 +165,16 @@ impl Border { self } - /// Establece el **color** del borde. - pub fn with_color(mut self, color: BorderColor) -> Self { - self.color = color; - self - } - - /// Establece la **opacidad** del borde. - pub fn with_opacity(mut self, opacity: BorderOpacity) -> Self { - self.opacity = opacity; + /// Establece el estilo de color/opacidad del borde. + pub fn with_style(mut self, style: StyleBorder) -> Self { + self.style = style; self } } impl fmt::Display for Border { - /// Concatena cada definición en el orden: *global*, `top`, `end`, `bottom`, `start`, *color* y - /// *opacidad*; respetando LTR/RTL y omitiendo las definiciones vacías. + /// Concatena cada definición en el orden: *global*, `top`, `end`, `bottom`, `start` y + /// *color*/*opacidad*; respetando LTR/RTL y omitiendo las definiciones vacías. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, @@ -193,8 +185,7 @@ impl fmt::Display for Border { self.end.to_class("border-end"), self.bottom.to_class("border-bottom"), self.start.to_class("border-start"), - self.color.to_string(), - self.opacity.to_string(), + self.style.to_string(), ]; " ") .unwrap_or_default() ) diff --git a/extensions/pagetop-bootsier/src/theme/aux/color.rs b/extensions/pagetop-bootsier/src/theme/aux/color.rs index c071e407..17d192dd 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/color.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/color.rs @@ -4,11 +4,11 @@ use std::fmt; // **< Color >************************************************************************************** -/// Paleta de colores **temáticos**. +/// Paleta de colores temáticos. /// -/// Equivalente a los nombres estándar de Bootstrap (`primary`, `secondary`, `success`, etc.). Sirve -/// como base para componer clases de fondo ([`BgColor`]), borde ([`BorderColor`]) y texto -/// ([`TextColor`]). +/// Equivalen a los nombres estándar definidos por Bootstrap (`primary`, `secondary`, `success`, +/// etc.). Este tipo enumerado sirve de base para componer clases de color para el fondo +/// ([`ColorBg`]), bordes ([`ColorBorder`]) y texto ([`ColorText`]). #[derive(AutoDefault)] pub enum Color { #[default] @@ -38,32 +38,34 @@ impl fmt::Display for Color { } } -// **< BgColor >************************************************************************************ +// **< ColorBg >************************************************************************************ -/// Colores de fondo (`bg-*`). -/// -/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). -/// - `Body*` usa fondos predefinidos del tema (`bg-body`, `bg-body-secondary`, `bg-body-tertiary`). -/// - `Theme(Color)` genera `bg-{color}` (p. ej., `bg-primary`). -/// - `Subtle(Color)` genera `bg-{color}-subtle` (tono suave). -/// - `Black` y `White` son colores explícitos. -/// - `Transparent` no aplica color de fondo (`bg-transparent`). +/// Colores `bg-*` para el fondo. #[derive(AutoDefault)] -pub enum BgColor { +pub enum ColorBg { + /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). #[default] Default, + /// Fondo predefinido del tema (`bg-body`). Body, + /// Fondo predefinido del tema (`bg-body-secondary`). BodySecondary, + /// Fondo predefinido del tema (`bg-body-tertiary`). BodyTertiary, + /// Genera internamente clases `bg-{color}` (p. ej., `bg-primary`). Theme(Color), + /// Genera internamente clases `bg-{color}-subtle` (un tono suavizado del color). Subtle(Color), + /// Color negro. Black, + /// Color blanco. White, + /// No aplica ningún color de fondo (`bg-transparent`). Transparent, } #[rustfmt::skip] -impl fmt::Display for BgColor { +impl fmt::Display for ColorBg { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Default => Ok(()), @@ -79,26 +81,26 @@ impl fmt::Display for BgColor { } } -// **< BorderColor >******************************************************************************** +// **< ColorBorder >******************************************************************************** -/// Colores (`border-*`) para los bordes ([`Border`](crate::theme::aux::Border)). -/// -/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). -/// - `Theme(Color)` genera `border-{color}`. -/// - `Subtle(Color)` genera `border-{color}-subtle` (versión suavizada). -/// - `Black` y `White` son colores explícitos. +/// Colores `border-*` para los bordes ([`Border`](crate::theme::aux::Border)). #[derive(AutoDefault)] -pub enum BorderColor { +pub enum ColorBorder { + /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). #[default] Default, + /// Genera internamente clases `border-{color}`. Theme(Color), + /// Genera internamente clases `border-{color}-subtle` (un tono suavizado del color). Subtle(Color), + /// Color negro. Black, + /// Color blanco. White, } #[rustfmt::skip] -impl fmt::Display for BorderColor { +impl fmt::Display for ColorBorder { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Default => Ok(()), @@ -110,25 +112,24 @@ impl fmt::Display for BorderColor { } } -// **< ButtonColor >******************************************************************************** +// **< ColorButton >******************************************************************************** -/// Variantes de color (`btn-*`) para **botones**. -/// -/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). -/// - `Background(Color)` genera `btn-{color}` (botón relleno). -/// - `Outline(Color)` genera `btn-outline-{color}` (contorno: texto y borde, fondo transparente). -/// - `Link` aplica estilo de enlace (`btn-link`), sin caja ni fondo, heredando el color de texto. +/// Variantes de color `btn-*` para botones. #[derive(AutoDefault)] -pub enum ButtonColor { +pub enum ColorButton { + /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). #[default] Default, + /// Genera internamente clases `btn-{color}` (botón relleno). Background(Color), + /// Genera `btn-outline-{color}` (fondo transparente y contorno con borde). Outline(Color), + /// Aplica estilo de los enlaces (`btn-link`), sin caja ni fondo, heredando el color de texto. Link, } #[rustfmt::skip] -impl fmt::Display for ButtonColor { +impl fmt::Display for ColorButton { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Default => Ok(()), @@ -139,34 +140,34 @@ impl fmt::Display for ButtonColor { } } -// **< TextColor >********************************************************************************** +// **< ColorText >********************************************************************************** -/// Colores de texto y fondos de texto (`text-*`). -/// -/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). -/// - `Body*` aplica colores predefinidos del tema (`text-body`, `text-body-emphasis`, -/// `text-body-secondary`, `text-body-tertiary`). -/// - `Theme(Color)` genera `text-{color}`. -/// - `Emphasis(Color)` genera `text-{color}-emphasis` (contraste mayor acorde al tema). -/// - `Background(Color)` genera `text-bg-{color}` (para color de fondo del texto). -/// - `Black` y `White` son colores explícitos. +/// Colores `text-*` para el texto. #[derive(AutoDefault)] -pub enum TextColor { +pub enum ColorText { + /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). #[default] Default, + /// Color predefinido del tema (`text-body`). Body, + /// Color predefinido del tema (`text-body-emphasis`). BodyEmphasis, + /// Color predefinido del tema (`text-body-secondary`). BodySecondary, + /// Color predefinido del tema (`text-body-tertiary`). BodyTertiary, + /// Genera internamente clases `text-{color}`. Theme(Color), + /// Genera internamente clases `text-{color}-emphasis` (mayor contraste acorde al tema). Emphasis(Color), - Background(Color), + /// Color negro. Black, + /// Color blanco. White, } #[rustfmt::skip] -impl fmt::Display for TextColor { +impl fmt::Display for ColorText { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Default => Ok(()), @@ -176,9 +177,140 @@ impl fmt::Display for TextColor { Self::BodyTertiary => f.write_str("text-body-tertiary"), Self::Theme(c) => write!(f, "text-{c}"), Self::Emphasis(c) => write!(f, "text-{c}-emphasis"), - Self::Background(c) => write!(f, "text-bg-{c}"), Self::Black => f.write_str("text-black"), Self::White => f.write_str("text-white"), } } } + +// **< Opacity >************************************************************************************ + +/// Niveles de opacidad (`opacity-*`). +/// +/// Se usa normalmente para graduar la transparencia del color de fondo `bg-opacity-*` +/// ([`StyleBg`]), de los bordes `border-opacity-*` ([`StyleBorder`]) o del texto `text-opacity-*` +/// ([`StyleText`]). +#[rustfmt::skip] +#[derive(AutoDefault)] +pub enum Opacity { + /// Genera internamente clases `opacity-100` (100% de opacidad). + #[default] + Opaque, + /// Genera internamente clases `opacity-75` (75%). + SemiOpaque, + /// Genera internamente clases `opacity-50` (50%). + Half, + /// Genera internamente clases `opacity-25` (25%). + SemiTransparent, + /// Genera internamente clases `opacity-10` (10%). + AlmostTransparent, + /// Genera internamente clases `opacity-0` (0%, totalmente transparente). + Transparent, +} + +#[rustfmt::skip] +impl fmt::Display for Opacity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Opaque => f.write_str("opacity-100"), + Self::SemiOpaque => f.write_str("opacity-75"), + Self::Half => f.write_str("opacity-50"), + Self::SemiTransparent => f.write_str("opacity-25"), + Self::AlmostTransparent => f.write_str("opacity-10"), + Self::Transparent => f.write_str("opacity-0"), + } + } +} + +// **< StyleBg >*********************************************************************************** + +/// Estilos de color/opacidad para el fondo. +#[derive(AutoDefault)] +pub enum StyleBg { + /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). + #[default] + Default, + /// Genera internamente clases `bg-*`. + Color(ColorBg), + /// Genera internamente clases `bg-opacity-*`. + Opacity(Opacity), + /// Genera internamente clases `bg-* bg-opacity-*`. + Both(ColorBg, Opacity), +} + +#[rustfmt::skip] +impl fmt::Display for StyleBg { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Color(c) => write!(f, "{c}"), + Self::Opacity(o) => write!(f, "bg-{o}"), + Self::Both(c, o) => write!(f, "{c} bg-{o}"), + } + } +} + +// **< StyleBorder >******************************************************************************* + +/// Estilos de color/opacidad para los bordes ([`Border`](crate::theme::aux::Border)). +#[derive(AutoDefault)] +pub enum StyleBorder { + /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). + #[default] + Default, + /// Genera internamente clases `border-*`. + Color(ColorBorder), + /// Genera internamente clases `border-opacity-*`. + Opacity(Opacity), + /// Genera internamente clases `border-* border-opacity-*`. + Both(ColorBorder, Opacity), +} + +#[rustfmt::skip] +impl fmt::Display for StyleBorder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Color(c) => write!(f, "{c}"), + Self::Opacity(o) => write!(f, "border-{o}"), + Self::Both(c, o) => write!(f, "{c} border-{o}"), + } + } +} + +// **< StyleText >********************************************************************************* + +/// Estilos de color/opacidad para texto y fondo del texto. +#[derive(AutoDefault)] +pub enum StyleText { + /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). + #[default] + Default, + /// Genera internamente clases `text-*`. + Color(ColorText), + /// Genera internamente clases `text-opacity-*`. + Opacity(Opacity), + /// Genera internamente clases `text-* text-opacity-*`. + Both(ColorText, Opacity), + /// Genera internamente clases `text-bg-*` (para el color de fondo del texto). + Bg(Color), + /// Genera internamente clases `text-bg-* text-*`. + BgAndColor(Color, ColorText), + /// Genera internamente clases `text-bg-* text-* text-opacity-*`. + All(Color, ColorText, Opacity), +} + +#[rustfmt::skip] +impl fmt::Display for StyleText { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Color(c) => write!(f, "{c}"), + Self::Opacity(o) => write!(f, "text-{o}"), + Self::Both(c, o) => write!(f, "{c} text-{o}"), + Self::Bg(bg) => write!(f, "text-bg-{bg}"), + Self::BgAndColor(bg, c) => write!(f, "text-bg-{bg} {c}"), + Self::All(bg, c, o) => write!(f, "text-bg-{bg} {c} text-{o}"), + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/aux/opacity.rs b/extensions/pagetop-bootsier/src/theme/aux/opacity.rs deleted file mode 100644 index 96724d91..00000000 --- a/extensions/pagetop-bootsier/src/theme/aux/opacity.rs +++ /dev/null @@ -1,109 +0,0 @@ -use pagetop::prelude::*; - -use std::fmt; - -// **< Opacity >************************************************************************************ - -/// Niveles de **opacidad** (`opacity-*`). -/// -/// Se usa para modular la transparencia del color de fondo `bg-opacity-*` ([`BgOpacity`]), borde -/// `border-opacity-*` ([`BorderOpacity`]) o texto `text-opacity-*` ([`TextOpacity`]), según las -/// siguientes equivalencias: -/// -/// - `Opaque` => `opacity-100` (100% de opacidad). -/// - `SemiOpaque` => `opacity-75` (75%). -/// - `Half` => `opacity-50` (50%). -/// - `SemiTransparent` => `opacity-25` (25%). -/// - `AlmostTransparent` => `opacity-10` (10%). -/// - `Transparent` => `opacity-0` (0%, totalmente transparente). -#[rustfmt::skip] -#[derive(AutoDefault)] -pub enum Opacity { - #[default] - Opaque, // 100% - SemiOpaque, // 75% - Half, // 50% - SemiTransparent, // 25% - AlmostTransparent, // 10% - Transparent, // 0% -} - -#[rustfmt::skip] -impl fmt::Display for Opacity { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Opaque => f.write_str("opacity-100"), - Self::SemiOpaque => f.write_str("opacity-75"), - Self::Half => f.write_str("opacity-50"), - Self::SemiTransparent => f.write_str("opacity-25"), - Self::AlmostTransparent => f.write_str("opacity-10"), - Self::Transparent => f.write_str("opacity-0"), - } - } -} - -// **< BgOpacity >********************************************************************************** - -/// Opacidad para el fondo (`bg-opacity-*`). -/// -/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). -/// - `Theme(Opacity)` genera `bg-{opacity}` (p. ej., `bg-opacity-50`). -#[derive(AutoDefault)] -pub enum BgOpacity { - #[default] - Default, - Theme(Opacity), -} - -impl fmt::Display for BgOpacity { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Default => Ok(()), - Self::Theme(o) => write!(f, "bg-{o}"), - } - } -} - -// **< BorderOpacity >****************************************************************************** - -/// Opacidad (`border-opacity-*`) para los bordes ([`Border`](crate::theme::aux::Border)). -/// -/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). -/// - `Theme(Opacity)` genera `border-{opacity}` (p. ej., `border-opacity-25`). -#[derive(AutoDefault)] -pub enum BorderOpacity { - #[default] - Default, - Theme(Opacity), -} - -impl fmt::Display for BorderOpacity { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Default => Ok(()), - Self::Theme(o) => write!(f, "border-{o}"), - } - } -} - -// **< TextOpacity >******************************************************************************** - -/// Opacidad para el texto (`text-opacity-*`). -/// -/// - `Default` no añade clase (devuelve `""` para facilitar la composición de clases). -/// - `Theme(Opacity)` genera `text-{opacity}` (p. ej., `text-opacity-100`). -#[derive(AutoDefault)] -pub enum TextOpacity { - #[default] - Default, - Theme(Opacity), -} - -impl fmt::Display for TextOpacity { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Default => Ok(()), - Self::Theme(o) => write!(f, "text-{o}"), - } - } -} diff --git a/extensions/pagetop-bootsier/src/theme/aux/rounded.rs b/extensions/pagetop-bootsier/src/theme/aux/rounded.rs index f7f6e3fe..470a48a3 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/rounded.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/rounded.rs @@ -4,7 +4,7 @@ use std::fmt; // **< RoundedRadius >****************************************************************************** -/// Radio (**redondeo**) para las esquinas ([`Rounded`]). +/// Radio para el redondeo de esquinas ([`Rounded`]). /// /// Mapea a `rounded`, `rounded-0`, `rounded-{1..5}`, `rounded-circle` y `rounded-pill`. /// diff --git a/extensions/pagetop-bootsier/src/theme/aux/size.rs b/extensions/pagetop-bootsier/src/theme/aux/size.rs index e5cff63c..d0abdb51 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/size.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/size.rs @@ -5,17 +5,14 @@ use std::fmt; // **< ButtonSize >********************************************************************************* /// Tamaño visual de un botón. -/// -/// Controla la escala del botón según el diseño del tema: -/// -/// - `Default`, tamaño por defecto del tema (no añade clase). -/// - `Small`, botón compacto. -/// - `Large`, botón destacado/grande. #[derive(AutoDefault)] pub enum ButtonSize { + /// Tamaño por defecto del tema (no añade clase). #[default] Default, + /// Botón compacto. Small, + /// Botón destacado/grande. Large, } diff --git a/extensions/pagetop-bootsier/src/theme/container.rs b/extensions/pagetop-bootsier/src/theme/container.rs index 17512505..411eb0aa 100644 --- a/extensions/pagetop-bootsier/src/theme/container.rs +++ b/extensions/pagetop-bootsier/src/theme/container.rs @@ -56,8 +56,8 @@ pub struct Container { classes : AttrClasses, container_type : ContainerType, container_width: ContainerWidth, - bg_color : BgColor, - text_color : TextColor, + style_bg : StyleBg, + style_text : StyleText, border : Border, rounded : Rounded, children : Children, @@ -86,8 +86,8 @@ impl Component for Container { ContainerWidth::FluidMax(_) => "fluid".to_string(), } ), - self.bg_color().to_string(), - self.text_color().to_string(), + self.style_bg().to_string(), + self.style_text().to_string(), self.border().to_string(), self.rounded().to_string(), ] @@ -205,25 +205,25 @@ impl Container { self } - /// Establece el color de fondo ([`BgColor`]). + /// Establece el estilo del fondo ([`StyleBg`]). #[builder_fn] - pub fn with_bg_color(mut self, color: BgColor) -> Self { - self.bg_color = color; + pub fn with_style_bg(mut self, style: StyleBg) -> Self { + self.style_bg = style; self } - /// Establece el color del texto ([`TextColor`]). + /// Establece el estilo del texto ([`StyleText`]). #[builder_fn] - pub fn with_text_color(mut self, color: TextColor) -> Self { - self.text_color = color; + pub fn with_style_text(mut self, style: StyleText) -> Self { + self.style_text = style; self } - /// Atajo para definir los colores de fondo y texto a la vez. + /// Atajo para definir los estilos de fondo y texto a la vez. #[builder_fn] - pub fn with_colors(mut self, bg_color: BgColor, text_color: TextColor) -> Self { - self.bg_color = bg_color; - self.text_color = text_color; + pub fn with_styles(mut self, style_bg: StyleBg, style_text: StyleText) -> Self { + self.style_bg = style_bg; + self.style_text = style_text; self } @@ -272,14 +272,14 @@ impl Container { &self.container_width } - /// Devuelve el color de fondo del contenedor. - pub fn bg_color(&self) -> &BgColor { - &self.bg_color + /// Devuelve el estilo del fondo del contenedor. + pub fn style_bg(&self) -> &StyleBg { + &self.style_bg } - /// Devuelve el color del texto del contenedor. - pub fn text_color(&self) -> &TextColor { - &self.text_color + /// Devuelve el estilo del texto del contenedor. + pub fn style_text(&self) -> &StyleText { + &self.style_text } /// Devuelve el borde configurado del contenedor. diff --git a/extensions/pagetop-bootsier/src/theme/dropdown.rs b/extensions/pagetop-bootsier/src/theme/dropdown.rs index ed4cbec0..bbad2d3f 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown.rs @@ -14,7 +14,7 @@ //! # use pagetop_bootsier::prelude::*; //! let dd = Dropdown::new() //! .with_title(L10n::n("Menu")) -//! .with_button_color(ButtonColor::Background(Color::Secondary)) +//! .with_button_color(ColorButton::Background(Color::Secondary)) //! .with_auto_close(dropdown::AutoClose::ClickableInside) //! .with_direction(dropdown::Direction::Dropend) //! .add_item(dropdown::Item::link(L10n::n("Home"), |_| "/")) diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs index c29ac145..57e30713 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs @@ -26,7 +26,7 @@ pub struct Dropdown { classes : AttrClasses, title : L10n, button_size : ButtonSize, - button_color : ButtonColor, + button_color : ColorButton, button_split : bool, button_grouped: bool, auto_close : dropdown::AutoClose, @@ -212,7 +212,7 @@ impl Dropdown { /// Define el color/estilo del botón. #[builder_fn] - pub fn with_button_color(mut self, color: ButtonColor) -> Self { + pub fn with_button_color(mut self, color: ColorButton) -> Self { self.button_color = color; self } @@ -291,7 +291,7 @@ impl Dropdown { } /// Devuelve el color/estilo configurado del botón. - pub fn button_color(&self) -> &ButtonColor { + pub fn button_color(&self) -> &ColorButton { &self.button_color } diff --git a/extensions/pagetop-bootsier/src/theme/navbar/component.rs b/extensions/pagetop-bootsier/src/theme/navbar/component.rs index fc46175a..6362b9d6 100644 --- a/extensions/pagetop-bootsier/src/theme/navbar/component.rs +++ b/extensions/pagetop-bootsier/src/theme/navbar/component.rs @@ -17,12 +17,14 @@ const TOGGLE_OFFCANVAS: &str = "offcanvas"; #[rustfmt::skip] #[derive(AutoDefault)] pub struct Navbar { - id : AttrId, - classes : AttrClasses, - expand : BreakPoint, - layout : navbar::Layout, - position: navbar::Position, - items : Children, + id : AttrId, + classes : AttrClasses, + expand : BreakPoint, + layout : navbar::Layout, + position : navbar::Position, + style_bg : StyleBg, + style_text: StyleText, + items : Children, } impl Component for Navbar { @@ -48,6 +50,8 @@ impl Component for Navbar { navbar::Position::StickyBottom => "sticky-bottom", } .to_string(), + self.style_bg().to_string(), + self.style_text().to_string(), ] .join(" "), ); @@ -255,6 +259,28 @@ impl Navbar { self } + /// Establece el estilo del fondo ([`StyleBg`]). + #[builder_fn] + pub fn with_style_bg(mut self, style: StyleBg) -> Self { + self.style_bg = style; + self + } + + /// Establece el estilo del texto ([`StyleText`]). + #[builder_fn] + pub fn with_style_text(mut self, style: StyleText) -> Self { + self.style_text = style; + self + } + + /// Atajo para definir los estilos de fondo y texto a la vez. + #[builder_fn] + pub fn with_styles(mut self, style_bg: StyleBg, style_text: StyleText) -> Self { + self.style_bg = style_bg; + self.style_text = style_text; + self + } + /// Añade un nuevo contenido hijo. #[inline] pub fn add_item(mut self, item: navbar::Item) -> Self { @@ -291,6 +317,16 @@ impl Navbar { &self.position } + /// Devuelve el estilo del fondo del contenedor. + pub fn style_bg(&self) -> &StyleBg { + &self.style_bg + } + + /// Devuelve el estilo del texto del contenedor. + pub fn style_text(&self) -> &StyleText { + &self.style_text + } + /// Devuelve la lista de contenidos (`children`). pub fn items(&self) -> &Children { &self.items From 5ec69345b3db07afa46cfba2f169e8b1e29a7d5d Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 8 Nov 2025 08:07:59 +0100 Subject: [PATCH 236/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20trait=20`JoinC?= =?UTF-8?q?lasses`=20para=20unir=20clases=20CSS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit También elimina macros sin uso `join_op!` y `join_strict!` (KISS). --- src/html.rs | 3 + src/html/assets/javascript.rs | 6 +- src/html/assets/stylesheet.rs | 2 +- src/html/join_classes.rs | 67 ++++++++++++++++++++++ src/prelude.rs | 6 +- src/util.rs | 103 +++++----------------------------- 6 files changed, 90 insertions(+), 97 deletions(-) create mode 100644 src/html/join_classes.rs diff --git a/src/html.rs b/src/html.rs index 5f5b833a..f8709dc5 100644 --- a/src/html.rs +++ b/src/html.rs @@ -87,6 +87,9 @@ use crate::{core, AutoDefault}; #[allow(type_alias_bounds)] pub type OptionComponent<C: core::component::Component> = core::component::Typed<C>; +mod join_classes; +pub use join_classes::JoinClasses; + mod unit; pub use unit::UnitValue; diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs index 0e86f0d4..6394842a 100644 --- a/src/html/assets/javascript.rs +++ b/src/html/assets/javascript.rs @@ -215,13 +215,13 @@ impl Asset for JavaScript { fn render(&self, cx: &mut Context) -> Markup { match &self.source { Source::From(path) => html! { - script src=(join_pair!(path, "?v=", self.version.as_str())) {}; + script src=(join_pair!(path, "?v=", &self.version)) {}; }, Source::Defer(path) => html! { - script src=(join_pair!(path, "?v=", self.version.as_str())) defer {}; + script src=(join_pair!(path, "?v=", &self.version)) defer {}; }, Source::Async(path) => html! { - script src=(join_pair!(path, "?v=", self.version.as_str())) async {}; + script src=(join_pair!(path, "?v=", &self.version)) async {}; }, Source::Inline(_, f) => html! { script { (PreEscaped((f)(cx))) }; diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index 5f0eaaa0..68a13da6 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -170,7 +170,7 @@ impl Asset for StyleSheet { Source::From(path) => html! { link rel="stylesheet" - href=(join_pair!(path, "?v=", self.version.as_str())) + href=(join_pair!(path, "?v=", &self.version)) media=[self.media.as_str_opt()]; }, Source::Inline(_, f) => html! { diff --git a/src/html/join_classes.rs b/src/html/join_classes.rs new file mode 100644 index 00000000..3f7d7e70 --- /dev/null +++ b/src/html/join_classes.rs @@ -0,0 +1,67 @@ +/// Añade a los *slices* de elementos [`AsRef<str>`] un método para unir clases CSS. +/// +/// El método es [`join_classes()`](JoinClasses::join_classes), que une las cadenas **no vacías** +/// del *slice* usando un espacio como separador. +pub trait JoinClasses { + /// Une las cadenas **no vacías** de un *slice* usando un espacio como separador. + /// + /// Son cadenas vacías únicamente los elementos del *slice* cuya longitud es `0` (p. ej., `""`); + /// no se realiza recorte ni normalización, por lo que elementos como `" "` no se consideran + /// vacíos. + /// + /// Si todas las cadenas están vacías, devuelve una cadena vacía. Acepta elementos que + /// implementen [`AsRef<str>`] como `&str`, [`String`] o `Cow<'_, str>`. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop::prelude::*; + /// let classes = ["btn", "", "btn-primary"]; + /// assert_eq!(classes.join_classes(), "btn btn-primary"); + /// + /// let empty: [&str; 3] = ["", "", ""]; + /// assert_eq!(empty.join_classes(), ""); + /// + /// let border = String::from("border"); + /// let border_top = String::from("border-top-0"); + /// let v = vec![&border, "", "", "", &border_top]; + /// assert_eq!(v.as_slice().join_classes(), "border border-top-0"); + /// + /// // Elementos con espacios afectan al resultado. + /// let spaced = ["btn", " ", "primary "]; + /// assert_eq!(spaced.join_classes(), "btn primary "); + /// ``` + fn join_classes(&self) -> String; +} + +impl<T> JoinClasses for [T] +where + T: AsRef<str>, +{ + #[inline] + fn join_classes(&self) -> String { + let mut count = 0usize; + let mut total = 0usize; + for s in self.iter().map(T::as_ref).filter(|s| !s.is_empty()) { + count += 1; + total += s.len(); + } + if count == 0 { + return String::new(); + } + let separator = " "; + let mut result = String::with_capacity(total + separator.len() * count.saturating_sub(1)); + for (i, s) in self + .iter() + .map(T::as_ref) + .filter(|s| !s.is_empty()) + .enumerate() + { + if i > 0 { + result.push_str(separator); + } + result.push_str(s); + } + result + } +} diff --git a/src/prelude.rs b/src/prelude.rs index 377dcdfd..0919e991 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -9,7 +9,7 @@ pub use crate::{AutoDefault, StaticResources, UniqueId, Weight}; // MACROS. // crate::util -pub use crate::{hm, join, join_opt, join_pair, join_strict}; +pub use crate::{hm, join, join_pair}; // crate::config pub use crate::include_config; // crate::locale @@ -33,8 +33,8 @@ pub use crate::trace; // alias obsoletos se volverá a declarar como `pub use crate::html::*;`. pub use crate::html::{ display, html_private, Asset, Assets, AttrClasses, AttrId, AttrL10n, AttrName, AttrValue, - ClassesOp, Escaper, Favicon, JavaScript, Markup, PageTopSvg, PreEscaped, PrepareMarkup, - StyleSheet, TargetMedia, UnitValue, DOCTYPE, + ClassesOp, Escaper, Favicon, JavaScript, JoinClasses, Markup, PageTopSvg, PreEscaped, + PrepareMarkup, StyleSheet, TargetMedia, UnitValue, DOCTYPE, }; pub use crate::locale::*; diff --git a/src/util.rs b/src/util.rs index 3d07361a..30b994f2 100644 --- a/src/util.rs +++ b/src/util.rs @@ -65,53 +65,11 @@ macro_rules! hm { /// ``` #[macro_export] macro_rules! join { - ($($arg:tt)*) => { - $crate::util::concat_string!($($arg)*) + ($($arg:expr),+) => { + $crate::util::concat_string!($($arg),+) }; } -/// Concatena los fragmentos **no vacíos** en un [`Option<String>`] con un separador opcional. -/// -/// Acepta cualquier número de fragmentos que implementen [`AsRef<str>`]. Si todos los fragmentos -/// están vacíos, devuelve `None`. -/// -/// # Ejemplos -/// -/// ```rust -/// # use pagetop::prelude::*; -/// // Concatena los fragmentos no vacíos con un espacio como separador. -/// let result_with_separator = join_opt!(["Hello", "", "World"]; " "); -/// assert_eq!(result_with_separator, Some("Hello World".to_string())); -/// -/// // Concatena los fragmentos no vacíos sin un separador. -/// let result_without_separator = join_opt!(["Hello", "", "World"]); -/// assert_eq!(result_without_separator, Some("HelloWorld".to_string())); -/// -/// // Devuelve `None` si todos los fragmentos están vacíos. -/// let result_empty = join_opt!(["", "", ""]; ","); -/// assert_eq!(result_empty, None); -/// ``` -#[macro_export] -macro_rules! join_opt { - ([$($arg:expr),* $(,)?]) => {{ - let s = $crate::util::concat_string!($($arg),*); - (!s.is_empty()).then_some(s) - }}; - ([$($arg:expr),* $(,)?]; $separator:expr) => {{ - let sep = ($separator).as_ref(); - let mut s = String::new(); - for part in [ $( ($arg).as_ref() ),* ] { - if !(part as &str).is_empty() { - if !s.is_empty() { - s.push_str(sep); - } - s.push_str(part); - } - } - (!s.is_empty()).then_some(s) - }}; -} - /// Concatena dos fragmentos en un [`String`] usando un separador. /// /// Une los dos fragmentos, que deben implementar [`AsRef<str>`], usando el separador proporcionado. @@ -145,54 +103,19 @@ macro_rules! join_opt { #[macro_export] macro_rules! join_pair { ($first:expr, $separator:expr, $second:expr) => {{ - if $first.is_empty() { - String::from($second) - } else if $second.is_empty() { - String::from($first) - } else { - $crate::util::concat_string!($first, $separator, $second) - } - }}; -} + let first_val = $first; + let second_val = $second; + let separator_val = $separator; -/// Concatena varios fragmentos en un [`Option<String>`] **si ninguno está vacío**. -/// -/// Si alguno de los fragmentos, que deben implementar [`AsRef<str>`], está vacío, devuelve -/// [`None`]. Opcionalmente se puede indicar un separador entre los fragmentos concatenados. -/// -/// # Ejemplo -/// -/// ```rust -/// # use pagetop::prelude::*; -/// // Concatena los fragmentos. -/// let result = join_strict!(["Hello", "World"]); -/// assert_eq!(result, Some("HelloWorld".to_string())); -/// -/// // Concatena los fragmentos con un separador. -/// let result_with_separator = join_strict!(["Hello", "World"]; " "); -/// assert_eq!(result_with_separator, Some("Hello World".to_string())); -/// -/// // Devuelve `None` si alguno de los fragmentos está vacío. -/// let result_with_empty = join_strict!(["Hello", "", "World"]); -/// assert_eq!(result_with_empty, None); -/// ``` -#[macro_export] -macro_rules! join_strict { - ([$($arg:expr),* $(,)?]) => {{ - let fragments = [$($arg),*]; - if fragments.iter().any(|&item| item.is_empty()) { - None + let first = AsRef::<str>::as_ref(&first_val); + let second = AsRef::<str>::as_ref(&second_val); + let separator = if first.is_empty() || second.is_empty() { + "" } else { - Some(fragments.concat()) - } - }}; - ([$($arg:expr),* $(,)?]; $separator:expr) => {{ - let fragments = [$($arg),*]; - if fragments.iter().any(|&item| item.is_empty()) { - None - } else { - Some(fragments.join($separator)) - } + AsRef::<str>::as_ref(&separator_val) + }; + + $crate::util::concat_string!(first, separator, second) }}; } From 748bd81bf14f17d012f36b45d01b87a32da788b1 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 10 Nov 2025 07:45:05 +0100 Subject: [PATCH 237/244] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20clases=20de=20?= =?UTF-8?q?fondo,=20texto,=20bordes=20y=20esquinas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Refactoriza el componente contenedor `Container` para usar estas clases y aplicar los nuevos enums `Kind` y `Width` para mejorar el comportamiento semántico y *responsive*. - Actualiza los componentes `Dropdown`, `Image`, `Nav`, `Navbar` y `Offcanvas` para usar los nuevos métodos de unión de clases. - Elimina propiedades de estilo redundantes de los componentes `Navbar` e `Image`, simplificando sus interfaces. --- extensions/pagetop-bootsier/src/lib.rs | 1 - extensions/pagetop-bootsier/src/theme.rs | 14 +- extensions/pagetop-bootsier/src/theme/aux.rs | 11 +- .../pagetop-bootsier/src/theme/aux/border.rs | 182 ++-------- .../src/theme/aux/breakpoint.rs | 77 ++--- .../pagetop-bootsier/src/theme/aux/button.rs | 58 ++++ .../pagetop-bootsier/src/theme/aux/color.rs | 258 ++++---------- .../pagetop-bootsier/src/theme/aux/rounded.rs | 186 +--------- .../pagetop-bootsier/src/theme/aux/size.rs | 28 -- .../pagetop-bootsier/src/theme/classes.rs | 10 + .../src/theme/classes/border.rs | 155 +++++++++ .../src/theme/classes/color.rs | 207 ++++++++++++ .../src/theme/classes/rounded.rs | 163 +++++++++ .../pagetop-bootsier/src/theme/container.rs | 319 ++---------------- .../src/theme/container/component.rs | 197 +++++++++++ .../src/theme/container/props.rs | 44 +++ .../pagetop-bootsier/src/theme/dropdown.rs | 2 +- .../src/theme/dropdown/component.rs | 10 +- .../src/theme/image/component.rs | 52 +-- .../src/theme/nav/component.rs | 2 +- .../src/theme/navbar/component.rs | 55 +-- .../pagetop-bootsier/src/theme/navbar/item.rs | 2 +- .../src/theme/offcanvas/component.rs | 2 +- 23 files changed, 1041 insertions(+), 994 deletions(-) create mode 100644 extensions/pagetop-bootsier/src/theme/aux/button.rs delete mode 100644 extensions/pagetop-bootsier/src/theme/aux/size.rs create mode 100644 extensions/pagetop-bootsier/src/theme/classes.rs create mode 100644 extensions/pagetop-bootsier/src/theme/classes/border.rs create mode 100644 extensions/pagetop-bootsier/src/theme/classes/color.rs create mode 100644 extensions/pagetop-bootsier/src/theme/classes/rounded.rs create mode 100644 extensions/pagetop-bootsier/src/theme/container/component.rs create mode 100644 extensions/pagetop-bootsier/src/theme/container/props.rs diff --git a/extensions/pagetop-bootsier/src/lib.rs b/extensions/pagetop-bootsier/src/lib.rs index 6df5341c..4cb35a27 100644 --- a/extensions/pagetop-bootsier/src/lib.rs +++ b/extensions/pagetop-bootsier/src/lib.rs @@ -98,7 +98,6 @@ pub mod theme; /// *Prelude* del tema. pub mod prelude { pub use crate::config::*; - pub use crate::theme::aux::*; pub use crate::theme::*; } diff --git a/extensions/pagetop-bootsier/src/theme.rs b/extensions/pagetop-bootsier/src/theme.rs index 4c547f6a..2c6b5757 100644 --- a/extensions/pagetop-bootsier/src/theme.rs +++ b/extensions/pagetop-bootsier/src/theme.rs @@ -1,10 +1,18 @@ //! Definiciones y componentes del tema. +//! +//! En esta página, el apartado **Modules** incluye las definiciones necesarias para los componentes +//! que se muestran en el apartado **Structs**, mientras que en **Enums** se listan los elementos +//! auxiliares del tema utilizados en clases y componentes. -pub mod aux; +mod aux; +pub use aux::*; + +pub mod classes; // Container. -mod container; -pub use container::{Container, ContainerType, ContainerWidth}; +pub mod container; +#[doc(inline)] +pub use container::Container; // Dropdown. pub mod dropdown; diff --git a/extensions/pagetop-bootsier/src/theme/aux.rs b/extensions/pagetop-bootsier/src/theme/aux.rs index a56b14e9..528126de 100644 --- a/extensions/pagetop-bootsier/src/theme/aux.rs +++ b/extensions/pagetop-bootsier/src/theme/aux.rs @@ -5,14 +5,13 @@ pub use breakpoint::BreakPoint; mod color; pub use color::{Color, Opacity}; -pub use color::{ColorBg, ColorBorder, ColorButton, ColorText}; -pub use color::{StyleBg, StyleBorder, StyleText}; +pub use color::{ColorBg, ColorText}; mod border; -pub use border::{Border, BorderSize}; +pub use border::{BorderColor, BorderSize}; mod rounded; -pub use rounded::{Rounded, RoundedRadius}; +pub use rounded::RoundedRadius; -mod size; -pub use size::ButtonSize; +mod button; +pub use button::{ButtonColor, ButtonSize}; diff --git a/extensions/pagetop-bootsier/src/theme/aux/border.rs b/extensions/pagetop-bootsier/src/theme/aux/border.rs index de3df81e..47547c30 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/border.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/border.rs @@ -1,16 +1,47 @@ use pagetop::prelude::*; -use crate::prelude::*; +use crate::theme::aux::Color; use std::fmt; +// **< BorderColor >******************************************************************************** + +/// Colores `border-*` para los bordes ([`classes::Border`](crate::theme::classes::Border)). +#[derive(AutoDefault)] +pub enum BorderColor { + /// No define ninguna clase. + #[default] + Default, + /// Genera internamente clases `border-{color}`. + Theme(Color), + /// Genera internamente clases `border-{color}-subtle` (un tono suavizado del color). + Subtle(Color), + /// Color negro. + Black, + /// Color blanco. + White, +} + +#[rustfmt::skip] +impl fmt::Display for BorderColor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Theme(c) => write!(f, "border-{c}"), + Self::Subtle(c) => write!(f, "border-{c}-subtle"), + Self::Black => f.write_str("border-black"), + Self::White => f.write_str("border-white"), + } + } +} + // **< BorderSize >********************************************************************************* -/// Tamaño para el ancho de los bordes ([`Border`]). +/// Tamaño para el ancho de los bordes ([`classes::Border`](crate::theme::classes::Border)). /// /// Mapea a `border`, `border-0` y `border-{1..5}`: /// -/// - `None` no añade clase (devuelve `""`). +/// - `None` no añade ninguna clase. /// - `Default` genera `border` (borde por defecto del tema). /// - `Zero` genera `border-0` (sin borde). /// - `Scale{1..5}` genera `border-{1..5}` (ancho creciente). @@ -29,7 +60,7 @@ pub enum BorderSize { impl BorderSize { #[rustfmt::skip] - fn to_class(&self, prefix: impl AsRef<str>) -> String { + pub(crate) fn to_class(&self, prefix: impl AsRef<str>) -> String { match self { Self::None => String::new(), Self::Default => String::from(prefix.as_ref()), @@ -48,146 +79,3 @@ impl fmt::Display for BorderSize { write!(f, "{}", self.to_class("border")) } } - -// **< Border >************************************************************************************* - -/// Agrupa propiedades para crear **bordes**. -/// -/// Permite: -/// -/// - Definir un tamaño **global** para todo el borde (`size`). -/// - Ajustar el tamaño de cada **lado lógico** (`top`, `end`, `bottom`, `start`, **en este orden**, -/// respetando LTR/RTL). -/// - Aplicar un **color** al borde (`ColorBorder`). -/// - Aplicar un nivel de **opacidad** (`BorderOpacity`). -/// -/// # Comportamiento aditivo / sustractivo -/// -/// - **Aditivo**: basta con crear un borde sin tamaño con `Border::new()` para ir añadiendo cada -/// lado lógico con el tamaño deseado usando `BorderSize::Scale{1..5}`. -/// -/// - **Sustractivo**: se crea un borde con tamaño predefinido, p. ej. utilizando -/// `Border::with(BorderSize::Scale2)` y eliminar los lados deseados con `BorderSize::Zero`. -/// -/// - **Anchos diferentes por lado**: usando `BorderSize::Scale{1..5}` en cada lado deseado. -/// -/// # Ejemplos -/// -/// **Borde global:** -/// ```rust -/// # use pagetop_bootsier::prelude::*; -/// let b = Border::with(BorderSize::Scale2); -/// assert_eq!(b.to_string(), "border-2"); -/// ``` -/// -/// **Aditivo (solo borde superior):** -/// ```rust -/// # use pagetop_bootsier::prelude::*; -/// let b = Border::new().with_top(BorderSize::Scale1); -/// assert_eq!(b.to_string(), "border-top-1"); -/// ``` -/// -/// **Sustractivo (borde global menos el superior):** -/// ```rust -/// # use pagetop_bootsier::prelude::*; -/// let b = Border::with(BorderSize::Default).with_top(BorderSize::Zero); -/// assert_eq!(b.to_string(), "border border-top-0"); -/// ``` -/// -/// **Ancho por lado (lado lógico inicial a 2 y final a 4):** -/// ```rust -/// # use pagetop_bootsier::prelude::*; -/// let b = Border::new().with_start(BorderSize::Scale2).with_end(BorderSize::Scale4); -/// assert_eq!(b.to_string(), "border-end-4 border-start-2"); -/// ``` -/// -/// **Combinado (ejemplo completo):** -/// ```rust -/// # use pagetop_bootsier::prelude::*; -/// let b = Border::with(BorderSize::Default) // Borde global por defecto. -/// .with_top(BorderSize::Zero) // Quita borde superior. -/// .with_end(BorderSize::Scale3) // Ancho 3 para el lado lógico final. -/// .with_style(StyleBorder::Both(ColorBorder::Theme(Color::Primary), Opacity::Half)); -/// -/// assert_eq!(b.to_string(), "border border-top-0 border-end-3 border-primary border-opacity-50"); -/// ``` -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Border { - size : BorderSize, - top : BorderSize, - end : BorderSize, - bottom: BorderSize, - start : BorderSize, - style : StyleBorder, -} - -impl Border { - /// Prepara un borde **sin tamaño global** de partida. - pub fn new() -> Self { - Self::default() - } - - /// Crea un borde **con tamaño global** (`size`). - pub fn with(size: BorderSize) -> Self { - Self::default().with_size(size) - } - - // **< Border BUILDER >************************************************************************* - - /// Establece el tamaño global del borde (`border*`). - pub fn with_size(mut self, size: BorderSize) -> Self { - self.size = size; - self - } - - /// Establece el tamaño del borde superior (`border-top-*`). - pub fn with_top(mut self, size: BorderSize) -> Self { - self.top = size; - self - } - - /// Establece el tamaño del borde en el lado lógico final (`border-end-*`). Respeta LTR/RTL. - pub fn with_end(mut self, size: BorderSize) -> Self { - self.end = size; - self - } - - /// Establece el tamaño del borde inferior (`border-bottom-*`). - pub fn with_bottom(mut self, size: BorderSize) -> Self { - self.bottom = size; - self - } - - /// Establece el tamaño del borde en el lado lógico inicial (`border-start-*`). Respeta LTR/RTL. - pub fn with_start(mut self, size: BorderSize) -> Self { - self.start = size; - self - } - - /// Establece el estilo de color/opacidad del borde. - pub fn with_style(mut self, style: StyleBorder) -> Self { - self.style = style; - self - } -} - -impl fmt::Display for Border { - /// Concatena cada definición en el orden: *global*, `top`, `end`, `bottom`, `start` y - /// *color*/*opacidad*; respetando LTR/RTL y omitiendo las definiciones vacías. - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - join_opt!([ - self.size.to_string(), - self.top.to_class("border-top"), - self.end.to_class("border-end"), - self.bottom.to_class("border-bottom"), - self.start.to_class("border-start"), - self.style.to_string(), - ]; " ") - .unwrap_or_default() - ) - } -} diff --git a/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs b/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs index 601aa547..27d7c29f 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs @@ -3,25 +3,6 @@ use pagetop::prelude::*; use std::fmt; /// Define los puntos de ruptura (*breakpoints*) para aplicar diseño *responsive*. -/// -/// - `"sm"`, `"md"`, `"lg"`, `"xl"` o `"xxl"` para los puntos de ruptura `SM`, `MD`, `LG`, `XL` o -/// `XXL`, respectivamente. -/// - `""` (cadena vacía) para `None`. -/// -/// # Ejemplos -/// -/// ```rust -/// # use pagetop_bootsier::prelude::*; -/// assert_eq!(BreakPoint::MD.to_string(), "md"); -/// assert_eq!(BreakPoint::None.to_string(), ""); -/// -/// // Forma correcta para clases con prefijo: -/// assert_eq!(BreakPoint::MD.to_class("col"), "col-md"); -/// assert_eq!(BreakPoint::None.to_class("offcanvas"), "offcanvas"); -/// -/// assert_eq!(BreakPoint::XXL.try_class("col"), Some("col-xxl".to_string())); -/// assert_eq!(BreakPoint::None.try_class("offcanvas"), None); -/// ``` #[derive(AutoDefault)] pub enum BreakPoint { /// **Menos de 576px**. Dispositivos muy pequeños: teléfonos en modo vertical. @@ -40,46 +21,43 @@ pub enum BreakPoint { } impl BreakPoint { - /// Comprueba si es un punto de ruptura efectivo. - /// - /// Devuelve `true` si el valor es `SM`, `MD`, `LG`, `XL` o `XXL`; y `false` en otro caso. + #[rustfmt::skip] #[inline] - pub const fn is_breakpoint(&self) -> bool { - !matches!(self, Self::None) + const fn suffix(&self) -> Option<&'static str> { + match self { + Self::None => None, + Self::SM => Some("sm"), + Self::MD => Some("md"), + Self::LG => Some("lg"), + Self::XL => Some("xl"), + Self::XXL => Some("xxl"), + } } /// Genera un nombre de clase CSS basado en el punto de ruptura. /// - /// Si es un punto de ruptura efectivo (ver [`is_breakpoint()`](Self::is_breakpoint), concatena - /// el prefijo, un guion (`-`) y el sufijo asociado. En otro caso devuelve únicamente el - /// prefijo. + /// Si es un punto de ruptura efectivo concatena el prefijo, un guion (`-`) y el sufijo + /// asociado. Para `None` devuelve sólo el prefijo. /// /// # Ejemplo /// /// ```rust /// # use pagetop_bootsier::prelude::*; /// let breakpoint = BreakPoint::MD; - /// let class = breakpoint.to_class("col"); - /// assert_eq!(class, "col-md".to_string()); + /// assert_eq!(breakpoint.to_class("col"), "col-md"); /// /// let breakpoint = BreakPoint::None; - /// let class = breakpoint.to_class("offcanvas"); - /// assert_eq!(class, "offcanvas".to_string()); + /// assert_eq!(breakpoint.to_class("offcanvas"), "offcanvas"); /// ``` #[inline] pub fn to_class(&self, prefix: impl AsRef<str>) -> String { - if self.is_breakpoint() { - join!(prefix, "-", self.to_string()) - } else { - String::from(prefix.as_ref()) - } + join_pair!(prefix, "-", self.suffix().unwrap_or_default()) } /// Intenta generar un nombre de clase CSS basado en el punto de ruptura. /// - /// Si es un punto de ruptura efectivo (ver [`is_breakpoint()`](Self::is_breakpoint), devuelve - /// `Some(String)` concatenando el prefijo, un guion (`-`) y el sufijo asociado. En otro caso - /// devuelve `None`. + /// Si es un punto de ruptura efectivo devuelve `Some(String)` concatenando el prefijo, un guion + /// (`-`) y el sufijo asociado. En otro caso devuelve `None`. /// /// # Ejemplo /// @@ -95,24 +73,19 @@ impl BreakPoint { /// ``` #[inline] pub fn try_class(&self, prefix: impl AsRef<str>) -> Option<String> { - if self.is_breakpoint() { - Some(join!(prefix, "-", self.to_string())) - } else { - None - } + self.suffix().map(|suffix| join_pair!(prefix, "-", suffix)) } } -#[rustfmt::skip] impl fmt::Display for BreakPoint { + /// Implementa [`Display`](std::fmt::Display) para asociar `"sm"`, `"md"`, `"lg"`, `"xl"` o + /// `"xxl"` a los puntos de ruptura `BreakPoint::SM`, `MD`, `LG`, `XL` o `XXL`, respectivamente. + /// Y `""` (cadena vacía) a `BreakPoint::None`. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::None => Ok(()), - Self::SM => f.write_str("sm"), - Self::MD => f.write_str("md"), - Self::LG => f.write_str("lg"), - Self::XL => f.write_str("xl"), - Self::XXL => f.write_str("xxl"), + if let Some(suffix) = self.suffix() { + f.write_str(suffix) + } else { + Ok(()) } } } diff --git a/extensions/pagetop-bootsier/src/theme/aux/button.rs b/extensions/pagetop-bootsier/src/theme/aux/button.rs new file mode 100644 index 00000000..a2f2efb9 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/button.rs @@ -0,0 +1,58 @@ +use pagetop::prelude::*; + +use crate::theme::aux::Color; + +use std::fmt; + +// **< ButtonColor >******************************************************************************** + +/// Variantes de color `btn-*` para botones. +#[derive(AutoDefault)] +pub enum ButtonColor { + /// No define ninguna clase. + #[default] + Default, + /// Genera internamente clases `btn-{color}` (botón relleno). + Background(Color), + /// Genera `btn-outline-{color}` (fondo transparente y contorno con borde). + Outline(Color), + /// Aplica estilo de los enlaces (`btn-link`), sin caja ni fondo, heredando el color de texto. + Link, +} + +#[rustfmt::skip] +impl fmt::Display for ButtonColor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Background(c) => write!(f, "btn-{c}"), + Self::Outline(c) => write!(f, "btn-outline-{c}"), + Self::Link => f.write_str("btn-link"), + } + } +} + +// **< ButtonSize >********************************************************************************* + +/// Tamaño visual de un botón. +#[derive(AutoDefault)] +pub enum ButtonSize { + /// Tamaño por defecto del tema (no añade clase). + #[default] + Default, + /// Botón compacto. + Small, + /// Botón destacado/grande. + Large, +} + +#[rustfmt::skip] +impl fmt::Display for ButtonSize { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => Ok(()), + Self::Small => f.write_str("btn-sm"), + Self::Large => f.write_str("btn-lg"), + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/aux/color.rs b/extensions/pagetop-bootsier/src/theme/aux/color.rs index 17d192dd..d0f1da00 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/color.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/color.rs @@ -7,8 +7,10 @@ use std::fmt; /// Paleta de colores temáticos. /// /// Equivalen a los nombres estándar definidos por Bootstrap (`primary`, `secondary`, `success`, -/// etc.). Este tipo enumerado sirve de base para componer clases de color para el fondo -/// ([`ColorBg`]), bordes ([`ColorBorder`]) y texto ([`ColorText`]). +/// etc.). Este tipo enumerado sirve de base para componer las clases de color para fondo +/// ([`classes::Background`](crate::theme::classes::Background)), bordes +/// ([`classes::Border`](crate::theme::classes::Border)) y texto +/// ([`classes::Text`](crate::theme::classes::Text)). #[derive(AutoDefault)] pub enum Color { #[default] @@ -38,12 +40,69 @@ impl fmt::Display for Color { } } +// **< Opacity >************************************************************************************ + +/// Niveles de opacidad (`opacity-*`). +/// +/// Se usa normalmente para graduar la transparencia del color de fondo `bg-opacity-*` +/// ([`classes::Background`](crate::theme::classes::Background)), de los bordes `border-opacity-*` +/// ([`classes::Border`](crate::theme::classes::Border)) o del texto `text-opacity-*` +/// ([`classes::Text`](crate::theme::classes::Text)). +#[derive(AutoDefault)] +pub enum Opacity { + /// No define ninguna clase. + #[default] + Default, + /// Permite generar clases `*-opacity-100` (100% de opacidad). + Opaque, + /// Permite generar clases `*-opacity-75` (75%). + SemiOpaque, + /// Permite generar clases `*-opacity-50` (50%). + Half, + /// Permite generar clases `*-opacity-25` (25%). + SemiTransparent, + /// Permite generar clases `*-opacity-10` (10%). + AlmostTransparent, + /// Permite generar clases `*-opacity-0` (0%, totalmente transparente). + Transparent, +} + +impl Opacity { + #[rustfmt::skip] + #[inline] + const fn suffix(&self) -> &'static str { + match self { + Self::Default => "", + Self::Opaque => "opacity-100", + Self::SemiOpaque => "opacity-75", + Self::Half => "opacity-50", + Self::SemiTransparent => "opacity-25", + Self::AlmostTransparent => "opacity-10", + Self::Transparent => "opacity-0", + } + } + + #[inline] + pub(crate) fn to_class(&self, prefix: impl AsRef<str>) -> String { + match self { + Self::Default => String::new(), + _ => join_pair!(prefix, "-", self.suffix()), + } + } +} + +impl fmt::Display for Opacity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.suffix()) + } +} + // **< ColorBg >************************************************************************************ /// Colores `bg-*` para el fondo. #[derive(AutoDefault)] pub enum ColorBg { - /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). + /// No define ninguna clase. #[default] Default, /// Fondo predefinido del tema (`bg-body`). @@ -81,71 +140,12 @@ impl fmt::Display for ColorBg { } } -// **< ColorBorder >******************************************************************************** - -/// Colores `border-*` para los bordes ([`Border`](crate::theme::aux::Border)). -#[derive(AutoDefault)] -pub enum ColorBorder { - /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). - #[default] - Default, - /// Genera internamente clases `border-{color}`. - Theme(Color), - /// Genera internamente clases `border-{color}-subtle` (un tono suavizado del color). - Subtle(Color), - /// Color negro. - Black, - /// Color blanco. - White, -} - -#[rustfmt::skip] -impl fmt::Display for ColorBorder { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Default => Ok(()), - Self::Theme(c) => write!(f, "border-{c}"), - Self::Subtle(c) => write!(f, "border-{c}-subtle"), - Self::Black => f.write_str("border-black"), - Self::White => f.write_str("border-white"), - } - } -} - -// **< ColorButton >******************************************************************************** - -/// Variantes de color `btn-*` para botones. -#[derive(AutoDefault)] -pub enum ColorButton { - /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). - #[default] - Default, - /// Genera internamente clases `btn-{color}` (botón relleno). - Background(Color), - /// Genera `btn-outline-{color}` (fondo transparente y contorno con borde). - Outline(Color), - /// Aplica estilo de los enlaces (`btn-link`), sin caja ni fondo, heredando el color de texto. - Link, -} - -#[rustfmt::skip] -impl fmt::Display for ColorButton { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Default => Ok(()), - Self::Background(c) => write!(f, "btn-{c}"), - Self::Outline(c) => write!(f, "btn-outline-{c}"), - Self::Link => f.write_str("btn-link"), - } - } -} - // **< ColorText >********************************************************************************** /// Colores `text-*` para el texto. #[derive(AutoDefault)] pub enum ColorText { - /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). + /// No define ninguna clase. #[default] Default, /// Color predefinido del tema (`text-body`). @@ -182,135 +182,3 @@ impl fmt::Display for ColorText { } } } - -// **< Opacity >************************************************************************************ - -/// Niveles de opacidad (`opacity-*`). -/// -/// Se usa normalmente para graduar la transparencia del color de fondo `bg-opacity-*` -/// ([`StyleBg`]), de los bordes `border-opacity-*` ([`StyleBorder`]) o del texto `text-opacity-*` -/// ([`StyleText`]). -#[rustfmt::skip] -#[derive(AutoDefault)] -pub enum Opacity { - /// Genera internamente clases `opacity-100` (100% de opacidad). - #[default] - Opaque, - /// Genera internamente clases `opacity-75` (75%). - SemiOpaque, - /// Genera internamente clases `opacity-50` (50%). - Half, - /// Genera internamente clases `opacity-25` (25%). - SemiTransparent, - /// Genera internamente clases `opacity-10` (10%). - AlmostTransparent, - /// Genera internamente clases `opacity-0` (0%, totalmente transparente). - Transparent, -} - -#[rustfmt::skip] -impl fmt::Display for Opacity { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Opaque => f.write_str("opacity-100"), - Self::SemiOpaque => f.write_str("opacity-75"), - Self::Half => f.write_str("opacity-50"), - Self::SemiTransparent => f.write_str("opacity-25"), - Self::AlmostTransparent => f.write_str("opacity-10"), - Self::Transparent => f.write_str("opacity-0"), - } - } -} - -// **< StyleBg >*********************************************************************************** - -/// Estilos de color/opacidad para el fondo. -#[derive(AutoDefault)] -pub enum StyleBg { - /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). - #[default] - Default, - /// Genera internamente clases `bg-*`. - Color(ColorBg), - /// Genera internamente clases `bg-opacity-*`. - Opacity(Opacity), - /// Genera internamente clases `bg-* bg-opacity-*`. - Both(ColorBg, Opacity), -} - -#[rustfmt::skip] -impl fmt::Display for StyleBg { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Default => Ok(()), - Self::Color(c) => write!(f, "{c}"), - Self::Opacity(o) => write!(f, "bg-{o}"), - Self::Both(c, o) => write!(f, "{c} bg-{o}"), - } - } -} - -// **< StyleBorder >******************************************************************************* - -/// Estilos de color/opacidad para los bordes ([`Border`](crate::theme::aux::Border)). -#[derive(AutoDefault)] -pub enum StyleBorder { - /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). - #[default] - Default, - /// Genera internamente clases `border-*`. - Color(ColorBorder), - /// Genera internamente clases `border-opacity-*`. - Opacity(Opacity), - /// Genera internamente clases `border-* border-opacity-*`. - Both(ColorBorder, Opacity), -} - -#[rustfmt::skip] -impl fmt::Display for StyleBorder { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Default => Ok(()), - Self::Color(c) => write!(f, "{c}"), - Self::Opacity(o) => write!(f, "border-{o}"), - Self::Both(c, o) => write!(f, "{c} border-{o}"), - } - } -} - -// **< StyleText >********************************************************************************* - -/// Estilos de color/opacidad para texto y fondo del texto. -#[derive(AutoDefault)] -pub enum StyleText { - /// No define ninguna clase (devuelve `""` para facilitar la composición de clases). - #[default] - Default, - /// Genera internamente clases `text-*`. - Color(ColorText), - /// Genera internamente clases `text-opacity-*`. - Opacity(Opacity), - /// Genera internamente clases `text-* text-opacity-*`. - Both(ColorText, Opacity), - /// Genera internamente clases `text-bg-*` (para el color de fondo del texto). - Bg(Color), - /// Genera internamente clases `text-bg-* text-*`. - BgAndColor(Color, ColorText), - /// Genera internamente clases `text-bg-* text-* text-opacity-*`. - All(Color, ColorText, Opacity), -} - -#[rustfmt::skip] -impl fmt::Display for StyleText { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Default => Ok(()), - Self::Color(c) => write!(f, "{c}"), - Self::Opacity(o) => write!(f, "text-{o}"), - Self::Both(c, o) => write!(f, "{c} text-{o}"), - Self::Bg(bg) => write!(f, "text-bg-{bg}"), - Self::BgAndColor(bg, c) => write!(f, "text-bg-{bg} {c}"), - Self::All(bg, c, o) => write!(f, "text-bg-{bg} {c} text-{o}"), - } - } -} diff --git a/extensions/pagetop-bootsier/src/theme/aux/rounded.rs b/extensions/pagetop-bootsier/src/theme/aux/rounded.rs index 470a48a3..8eac7c53 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/rounded.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/rounded.rs @@ -2,13 +2,11 @@ use pagetop::prelude::*; use std::fmt; -// **< RoundedRadius >****************************************************************************** - -/// Radio para el redondeo de esquinas ([`Rounded`]). +/// Radio para el redondeo de esquinas ([`classes::Rounded`](crate::theme::classes::Rounded)). /// /// Mapea a `rounded`, `rounded-0`, `rounded-{1..5}`, `rounded-circle` y `rounded-pill`. /// -/// - `None` no añade clase (devuelve `""`). +/// - `None` no añade ninguna clase. /// - `Default` genera `rounded` (radio por defecto del tema). /// - `Zero` genera `rounded-0` (sin redondeo). /// - `Scale{1..5}` genera `rounded-{1..5}` (radio creciente). @@ -31,18 +29,18 @@ pub enum RoundedRadius { impl RoundedRadius { #[rustfmt::skip] - fn to_class(&self, base: impl AsRef<str>) -> String { + pub(crate) fn to_class(&self, prefix: impl AsRef<str>) -> String { match self { RoundedRadius::None => String::new(), - RoundedRadius::Default => String::from(base.as_ref()), - RoundedRadius::Zero => join!(base, "-0"), - RoundedRadius::Scale1 => join!(base, "-1"), - RoundedRadius::Scale2 => join!(base, "-2"), - RoundedRadius::Scale3 => join!(base, "-3"), - RoundedRadius::Scale4 => join!(base, "-4"), - RoundedRadius::Scale5 => join!(base, "-5"), - RoundedRadius::Circle => join!(base, "-circle"), - RoundedRadius::Pill => join!(base, "-pill"), + RoundedRadius::Default => String::from(prefix.as_ref()), + RoundedRadius::Zero => join!(prefix, "-0"), + RoundedRadius::Scale1 => join!(prefix, "-1"), + RoundedRadius::Scale2 => join!(prefix, "-2"), + RoundedRadius::Scale3 => join!(prefix, "-3"), + RoundedRadius::Scale4 => join!(prefix, "-4"), + RoundedRadius::Scale5 => join!(prefix, "-5"), + RoundedRadius::Circle => join!(prefix, "-circle"), + RoundedRadius::Pill => join!(prefix, "-pill"), } } } @@ -52,163 +50,3 @@ impl fmt::Display for RoundedRadius { write!(f, "{}", self.to_class("rounded")) } } - -// **< Rounded >************************************************************************************ - -/// Agrupa propiedades para crear **esquinas redondeadas**. -/// -/// Permite: -/// -/// - Definir un radio **global para todas las esquinas** (`radius`). -/// - Ajustar el radio asociado a las **esquinas de cada lado lógico** (`top`, `end`, `bottom`, -/// `start`, **en este orden**, respetando LTR/RTL). -/// - Ajustar el radio de las **esquinas concretas** (`top-start`, `top-end`, `bottom-start`, -/// `bottom-end`, **en este orden**, respetando LTR/RTL). -/// -/// # Ejemplos -/// -/// **Radio global:** -/// ```rust -/// # use pagetop_bootsier::prelude::*; -/// let r = Rounded::with(RoundedRadius::Default); -/// assert_eq!(r.to_string(), "rounded"); -/// ``` -/// -/// **Sin redondeo:** -/// ```rust -/// # use pagetop_bootsier::prelude::*; -/// let r = Rounded::new(); -/// assert_eq!(r.to_string(), ""); -/// ``` -/// -/// **Radio en las esquinas de un lado lógico:** -/// ```rust -/// # use pagetop_bootsier::prelude::*; -/// let r = Rounded::new().with_end(RoundedRadius::Scale2); -/// assert_eq!(r.to_string(), "rounded-end-2"); -/// ``` -/// -/// **Radio en una esquina concreta:** -/// ```rust -/// # use pagetop_bootsier::prelude::*; -/// let r = Rounded::new().with_top_start(RoundedRadius::Scale3); -/// assert_eq!(r.to_string(), "rounded-top-start-3"); -/// ``` -/// -/// **Combinado (ejemplo completo):** -/// ```rust -/// # use pagetop_bootsier::prelude::*; -/// let r = Rounded::new() -/// .with_top(RoundedRadius::Default) // Añade redondeo arriba. -/// .with_bottom_start(RoundedRadius::Scale4) // Añade una esquina redondeada concreta. -/// .with_bottom_end(RoundedRadius::Circle); // Añade redondeo extremo en otra esquina. -/// -/// assert_eq!(r.to_string(), "rounded-top rounded-bottom-start-4 rounded-bottom-end-circle"); -/// ``` -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Rounded { - radius : RoundedRadius, - top : RoundedRadius, - end : RoundedRadius, - bottom : RoundedRadius, - start : RoundedRadius, - top_start : RoundedRadius, - top_end : RoundedRadius, - bottom_start: RoundedRadius, - bottom_end : RoundedRadius, -} - -impl Rounded { - /// Prepara las esquinas **sin redondeo global** de partida. - pub fn new() -> Self { - Self::default() - } - - /// Crea las esquinas **con redondeo global** (`radius`). - pub fn with(radius: RoundedRadius) -> Self { - Self::default().with_radius(radius) - } - - // **< Rounded BUILDER >************************************************************************ - - /// Establece el radio global de las esquinas (`rounded*`). - pub fn with_radius(mut self, radius: RoundedRadius) -> Self { - self.radius = radius; - self - } - - /// Establece el radio en las esquinas del lado superior (`rounded-top-*`). - pub fn with_top(mut self, radius: RoundedRadius) -> Self { - self.top = radius; - self - } - - /// Establece el radio en las esquinas del lado lógico final (`rounded-end-*`). Respeta LTR/RTL. - pub fn with_end(mut self, radius: RoundedRadius) -> Self { - self.end = radius; - self - } - - /// Establece el radio en las esquinas del lado inferior (`rounded-bottom-*`). - pub fn with_bottom(mut self, radius: RoundedRadius) -> Self { - self.bottom = radius; - self - } - - /// Establece el radio en las esquinas del lado lógico inicial (`rounded-start-*`). Respeta - /// LTR/RTL. - pub fn with_start(mut self, radius: RoundedRadius) -> Self { - self.start = radius; - self - } - - /// Establece el radio en la esquina superior-inicial (`rounded-top-start-*`). Respeta LTR/RTL. - pub fn with_top_start(mut self, radius: RoundedRadius) -> Self { - self.top_start = radius; - self - } - - /// Establece el radio en la esquina superior-final (`rounded-top-end-*`). Respeta LTR/RTL. - pub fn with_top_end(mut self, radius: RoundedRadius) -> Self { - self.top_end = radius; - self - } - - /// Establece el radio en la esquina inferior-inicial (`rounded-bottom-start-*`). Respeta - /// LTR/RTL. - pub fn with_bottom_start(mut self, radius: RoundedRadius) -> Self { - self.bottom_start = radius; - self - } - - /// Establece el radio en la esquina inferior-final (`rounded-bottom-end-*`). Respeta LTR/RTL. - pub fn with_bottom_end(mut self, radius: RoundedRadius) -> Self { - self.bottom_end = radius; - self - } -} - -impl fmt::Display for Rounded { - /// Concatena cada definición en el orden: *global*, `top`, `end`, `bottom`, `start`, - /// `top-start`, `top-end`, `bottom-start` y `bottom-end`; respetando LTR/RTL y omitiendo las - /// definiciones vacías. - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - join_opt!([ - self.radius.to_string(), - self.top.to_class("rounded-top"), - self.end.to_class("rounded-end"), - self.bottom.to_class("rounded-bottom"), - self.start.to_class("rounded-start"), - self.top_start.to_class("rounded-top-start"), - self.top_end.to_class("rounded-top-end"), - self.bottom_start.to_class("rounded-bottom-start"), - self.bottom_end.to_class("rounded-bottom-end"), - ]; " ") - .unwrap_or_default() - ) - } -} diff --git a/extensions/pagetop-bootsier/src/theme/aux/size.rs b/extensions/pagetop-bootsier/src/theme/aux/size.rs deleted file mode 100644 index d0abdb51..00000000 --- a/extensions/pagetop-bootsier/src/theme/aux/size.rs +++ /dev/null @@ -1,28 +0,0 @@ -use pagetop::prelude::*; - -use std::fmt; - -// **< ButtonSize >********************************************************************************* - -/// Tamaño visual de un botón. -#[derive(AutoDefault)] -pub enum ButtonSize { - /// Tamaño por defecto del tema (no añade clase). - #[default] - Default, - /// Botón compacto. - Small, - /// Botón destacado/grande. - Large, -} - -#[rustfmt::skip] -impl fmt::Display for ButtonSize { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Default => Ok(()), - Self::Small => f.write_str("btn-sm"), - Self::Large => f.write_str("btn-lg"), - } - } -} diff --git a/extensions/pagetop-bootsier/src/theme/classes.rs b/extensions/pagetop-bootsier/src/theme/classes.rs new file mode 100644 index 00000000..4e586e11 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/classes.rs @@ -0,0 +1,10 @@ +//! Conjunto de clases para aplicar en componentes del tema. + +mod color; +pub use color::{Background, Text}; + +mod border; +pub use border::Border; + +mod rounded; +pub use rounded::Rounded; diff --git a/extensions/pagetop-bootsier/src/theme/classes/border.rs b/extensions/pagetop-bootsier/src/theme/classes/border.rs new file mode 100644 index 00000000..f49c75c6 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/classes/border.rs @@ -0,0 +1,155 @@ +use pagetop::prelude::*; + +use crate::theme::aux::{BorderColor, BorderSize, Opacity}; + +use std::fmt; + +/// Clases para crear **bordes**. +/// +/// Permite: +/// +/// - Definir un tamaño **global** para todo el borde (`size`). +/// - Ajustar el tamaño de cada **lado lógico** (`top`, `end`, `bottom`, `start`, **en este orden**, +/// respetando LTR/RTL). +/// - Aplicar un **color** al borde (`BorderColor`). +/// - Aplicar un nivel de **opacidad** (`Opacity`). +/// +/// # Comportamiento aditivo / sustractivo +/// +/// - **Aditivo**: basta con crear un borde sin tamaño con `classes::Border::new()` para ir +/// añadiendo cada lado lógico con el tamaño deseado usando `BorderSize::Scale{1..5}`. +/// +/// - **Sustractivo**: se crea un borde con tamaño predefinido, p. ej. utilizando +/// `classes::Border::with(BorderSize::Scale2)` y eliminar los lados deseados con `BorderSize::Zero`. +/// +/// - **Anchos diferentes por lado**: usando `BorderSize::Scale{1..5}` en cada lado deseado. +/// +/// # Ejemplos +/// +/// **Borde global:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = classes::Border::with(BorderSize::Scale2); +/// assert_eq!(b.to_string(), "border-2"); +/// ``` +/// +/// **Aditivo (solo borde superior):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = classes::Border::new().with_top(BorderSize::Scale1); +/// assert_eq!(b.to_string(), "border-top-1"); +/// ``` +/// +/// **Sustractivo (borde global menos el superior):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = classes::Border::with(BorderSize::Default).with_top(BorderSize::Zero); +/// assert_eq!(b.to_string(), "border border-top-0"); +/// ``` +/// +/// **Ancho por lado (lado lógico inicial a 2 y final a 4):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = classes::Border::new().with_start(BorderSize::Scale2).with_end(BorderSize::Scale4); +/// assert_eq!(b.to_string(), "border-end-4 border-start-2"); +/// ``` +/// +/// **Combinado (ejemplo completo):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = classes::Border::with(BorderSize::Default) // Borde global por defecto. +/// .with_top(BorderSize::Zero) // Quita borde superior. +/// .with_end(BorderSize::Scale3) // Ancho 3 para el lado lógico final. +/// .with_color(BorderColor::Theme(Color::Primary)) +/// .with_opacity(Opacity::Half); +/// +/// assert_eq!(b.to_string(), "border border-top-0 border-end-3 border-primary border-opacity-50"); +/// ``` +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Border { + size : BorderSize, + top : BorderSize, + end : BorderSize, + bottom : BorderSize, + start : BorderSize, + color : BorderColor, + opacity: Opacity, +} + +impl Border { + /// Prepara un borde **sin tamaño global** de partida. + pub fn new() -> Self { + Self::default() + } + + /// Crea un borde **con tamaño global** (`size`). + pub fn with(size: BorderSize) -> Self { + Self::default().with_size(size) + } + + // **< Border BUILDER >************************************************************************* + + /// Establece el tamaño global del borde (`border*`). + pub fn with_size(mut self, size: BorderSize) -> Self { + self.size = size; + self + } + + /// Establece el tamaño del borde superior (`border-top-*`). + pub fn with_top(mut self, size: BorderSize) -> Self { + self.top = size; + self + } + + /// Establece el tamaño del borde en el lado lógico final (`border-end-*`). Respeta LTR/RTL. + pub fn with_end(mut self, size: BorderSize) -> Self { + self.end = size; + self + } + + /// Establece el tamaño del borde inferior (`border-bottom-*`). + pub fn with_bottom(mut self, size: BorderSize) -> Self { + self.bottom = size; + self + } + + /// Establece el tamaño del borde en el lado lógico inicial (`border-start-*`). Respeta LTR/RTL. + pub fn with_start(mut self, size: BorderSize) -> Self { + self.start = size; + self + } + + /// Establece el color del borde. + pub fn with_color(mut self, color: BorderColor) -> Self { + self.color = color; + self + } + + /// Establece la opacidad del borde. + pub fn with_opacity(mut self, opacity: Opacity) -> Self { + self.opacity = opacity; + self + } +} + +impl fmt::Display for Border { + /// Concatena, en este orden, las clases para *global*, `top`, `end`, `bottom`, `start`, *color* + /// y *opacidad*; respetando LTR/RTL y omitiendo las definiciones vacías. + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + [ + self.size.to_string(), + self.top.to_class("border-top"), + self.end.to_class("border-end"), + self.bottom.to_class("border-bottom"), + self.start.to_class("border-start"), + self.color.to_string(), + self.opacity.to_class("border"), + ] + .join_classes() + ) + } +} diff --git a/extensions/pagetop-bootsier/src/theme/classes/color.rs b/extensions/pagetop-bootsier/src/theme/classes/color.rs new file mode 100644 index 00000000..6579d21c --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/classes/color.rs @@ -0,0 +1,207 @@ +use pagetop::prelude::*; + +use crate::theme::aux::{ColorBg, ColorText, Opacity}; + +use std::fmt; + +// **< Bg >***************************************************************************************** + +/// Clases para establecer **color/opacidad del fondo**. +/// +/// # Ejemplos +/// +/// ``` +/// # use pagetop_bootsier::prelude::*; +/// // Sin clases. +/// let s = classes::Background::new(); +/// assert_eq!(s.to_string(), ""); +/// +/// // Sólo color de fondo. +/// let s = classes::Background::with(ColorBg::Theme(Color::Primary)); +/// assert_eq!(s.to_string(), "bg-primary"); +/// +/// // Color más opacidad. +/// let s = classes::Background::with(ColorBg::BodySecondary).with_opacity(Opacity::Half); +/// assert_eq!(s.to_string(), "bg-body-secondary bg-opacity-50"); +/// +/// // Usando `From<ColorBg>`. +/// let s: classes::Background = ColorBg::Black.into(); +/// assert_eq!(s.to_string(), "bg-black"); +/// +/// // Usando `From<(ColorBg, Opacity)>`. +/// let s: classes::Background = (ColorBg::White, Opacity::SemiTransparent).into(); +/// assert_eq!(s.to_string(), "bg-white bg-opacity-25"); +/// ``` +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Background { + color : ColorBg, + opacity: Opacity, +} + +impl Background { + /// Prepara un nuevo estilo para aplicar al fondo. + pub fn new() -> Self { + Self::default() + } + + /// Crea un estilo fijando el color de fondo (`bg-*`). + pub fn with(color: ColorBg) -> Self { + Self::default().with_color(color) + } + + // **< Bg BUILDER >***************************************************************************** + + /// Establece el color de fondo (`bg-*`). + pub fn with_color(mut self, color: ColorBg) -> Self { + self.color = color; + self + } + + /// Establece la opacidad del fondo (`bg-opacity-*`). + pub fn with_opacity(mut self, opacity: Opacity) -> Self { + self.opacity = opacity; + self + } +} + +impl fmt::Display for Background { + /// Concatena, en este orden, color del fondo (`bg-*`) y opacidad (`bg-opacity-*`), omitiendo + /// las definiciones vacías. + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let classes = [self.color.to_string(), self.opacity.to_class("bg")].join_classes(); + write!(f, "{classes}") + } +} + +impl From<(ColorBg, Opacity)> for Background { + /// Atajo para crear un [`classes::Background`](crate::theme::classes::Background) a partir del color de fondo y + /// la opacidad. + /// + /// # Ejemplo + /// + /// ``` + /// # use pagetop_bootsier::prelude::*; + /// let s: classes::Background = (ColorBg::White, Opacity::SemiTransparent).into(); + /// assert_eq!(s.to_string(), "bg-white bg-opacity-25"); + /// ``` + fn from((color, opacity): (ColorBg, Opacity)) -> Self { + Background::with(color).with_opacity(opacity) + } +} + +impl From<ColorBg> for Background { + /// Atajo para crear un [`classes::Background`](crate::theme::classes::Background) a partir del color de fondo. + /// + /// # Ejemplo + /// + /// ``` + /// # use pagetop_bootsier::prelude::*; + /// let s: classes::Background = ColorBg::Black.into(); + /// assert_eq!(s.to_string(), "bg-black"); + /// ``` + fn from(color: ColorBg) -> Self { + Background::with(color) + } +} + +// **< Text >*************************************************************************************** + +/// Clases para establecer **color/opacidad del texto**. +/// +/// # Ejemplos +/// +/// ``` +/// # use pagetop_bootsier::prelude::*; +/// // Sin clases. +/// let s = classes::Text::new(); +/// assert_eq!(s.to_string(), ""); +/// +/// // Sólo color del texto. +/// let s = classes::Text::with(ColorText::Theme(Color::Primary)); +/// assert_eq!(s.to_string(), "text-primary"); +/// +/// // Color del texto y opacidad. +/// let s = classes::Text::new().with_color(ColorText::White).with_opacity(Opacity::SemiTransparent); +/// assert_eq!(s.to_string(), "text-white text-opacity-25"); +/// +/// // Usando `From<ColorText>`. +/// let s: classes::Text = ColorText::Black.into(); +/// assert_eq!(s.to_string(), "text-black"); +/// +/// // Usando `From<(ColorText, Opacity)>`. +/// let s: classes::Text = (ColorText::Theme(Color::Danger), Opacity::Opaque).into(); +/// assert_eq!(s.to_string(), "text-danger text-opacity-100"); +/// ``` +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Text { + color : ColorText, + opacity: Opacity, +} + +impl Text { + /// Prepara un nuevo estilo para aplicar al texto. + pub fn new() -> Self { + Self::default() + } + + /// Crea un estilo fijando el color del texto (`text-*`). + pub fn with(color: ColorText) -> Self { + Self::default().with_color(color) + } + + // **< Text BUILDER >*************************************************************************** + + /// Establece el color del texto (`text-*`). + pub fn with_color(mut self, color: ColorText) -> Self { + self.color = color; + self + } + + /// Establece la opacidad del texto (`text-opacity-*`). + pub fn with_opacity(mut self, opacity: Opacity) -> Self { + self.opacity = opacity; + self + } +} + +impl fmt::Display for Text { + /// Concatena, en este orden, `text-*` y `text-opacity-*`, omitiendo las definiciones vacías. + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let classes = [self.color.to_string(), self.opacity.to_class("text")].join_classes(); + write!(f, "{classes}") + } +} + +impl From<(ColorText, Opacity)> for Text { + /// Atajo para crear un [`classes::Text`](crate::theme::classes::Text) a partir del color del + /// texto y su opacidad. + /// + /// # Ejemplo + /// + /// ``` + /// # use pagetop_bootsier::prelude::*; + /// let s: classes::Text = (ColorText::Theme(Color::Danger), Opacity::Opaque).into(); + /// assert_eq!(s.to_string(), "text-danger text-opacity-100"); + /// ``` + fn from((color, opacity): (ColorText, Opacity)) -> Self { + Text::with(color).with_opacity(opacity) + } +} + +impl From<ColorText> for Text { + /// Atajo para crear un [`classes::Text`](crate::theme::classes::Text) a partir del color del + /// texto. + /// + /// # Ejemplo + /// + /// ``` + /// # use pagetop_bootsier::prelude::*; + /// let s: classes::Text = ColorText::Black.into(); + /// assert_eq!(s.to_string(), "text-black"); + /// ``` + fn from(color: ColorText) -> Self { + Text::with(color) + } +} diff --git a/extensions/pagetop-bootsier/src/theme/classes/rounded.rs b/extensions/pagetop-bootsier/src/theme/classes/rounded.rs new file mode 100644 index 00000000..b7510c14 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/classes/rounded.rs @@ -0,0 +1,163 @@ +use pagetop::prelude::*; + +use crate::theme::aux::RoundedRadius; + +use std::fmt; + +/// Clases para definir **esquinas redondeadas**. +/// +/// Permite: +/// +/// - Definir un radio **global para todas las esquinas** (`radius`). +/// - Ajustar el radio asociado a las **esquinas de cada lado lógico** (`top`, `end`, `bottom`, +/// `start`, **en este orden**, respetando LTR/RTL). +/// - Ajustar el radio de las **esquinas concretas** (`top-start`, `top-end`, `bottom-start`, +/// `bottom-end`, **en este orden**, respetando LTR/RTL). +/// +/// # Ejemplos +/// +/// **Radio global:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = classes::Rounded::with(RoundedRadius::Default); +/// assert_eq!(r.to_string(), "rounded"); +/// ``` +/// +/// **Sin redondeo:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = classes::Rounded::new(); +/// assert_eq!(r.to_string(), ""); +/// ``` +/// +/// **Radio en las esquinas de un lado lógico:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = classes::Rounded::new().with_end(RoundedRadius::Scale2); +/// assert_eq!(r.to_string(), "rounded-end-2"); +/// ``` +/// +/// **Radio en una esquina concreta:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = classes::Rounded::new().with_top_start(RoundedRadius::Scale3); +/// assert_eq!(r.to_string(), "rounded-top-start-3"); +/// ``` +/// +/// **Combinado (ejemplo completo):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = classes::Rounded::new() +/// .with_top(RoundedRadius::Default) // Añade redondeo arriba. +/// .with_bottom_start(RoundedRadius::Scale4) // Añade una esquina redondeada concreta. +/// .with_bottom_end(RoundedRadius::Circle); // Añade redondeo extremo en otra esquina. +/// +/// assert_eq!(r.to_string(), "rounded-top rounded-bottom-start-4 rounded-bottom-end-circle"); +/// ``` +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Rounded { + radius : RoundedRadius, + top : RoundedRadius, + end : RoundedRadius, + bottom : RoundedRadius, + start : RoundedRadius, + top_start : RoundedRadius, + top_end : RoundedRadius, + bottom_start: RoundedRadius, + bottom_end : RoundedRadius, +} + +impl Rounded { + /// Prepara las esquinas **sin redondeo global** de partida. + pub fn new() -> Self { + Self::default() + } + + /// Crea las esquinas **con redondeo global** (`radius`). + pub fn with(radius: RoundedRadius) -> Self { + Self::default().with_radius(radius) + } + + // **< Rounded BUILDER >************************************************************************ + + /// Establece el radio global de las esquinas (`rounded*`). + pub fn with_radius(mut self, radius: RoundedRadius) -> Self { + self.radius = radius; + self + } + + /// Establece el radio en las esquinas del lado superior (`rounded-top-*`). + pub fn with_top(mut self, radius: RoundedRadius) -> Self { + self.top = radius; + self + } + + /// Establece el radio en las esquinas del lado lógico final (`rounded-end-*`). Respeta LTR/RTL. + pub fn with_end(mut self, radius: RoundedRadius) -> Self { + self.end = radius; + self + } + + /// Establece el radio en las esquinas del lado inferior (`rounded-bottom-*`). + pub fn with_bottom(mut self, radius: RoundedRadius) -> Self { + self.bottom = radius; + self + } + + /// Establece el radio en las esquinas del lado lógico inicial (`rounded-start-*`). Respeta + /// LTR/RTL. + pub fn with_start(mut self, radius: RoundedRadius) -> Self { + self.start = radius; + self + } + + /// Establece el radio en la esquina superior-inicial (`rounded-top-start-*`). Respeta LTR/RTL. + pub fn with_top_start(mut self, radius: RoundedRadius) -> Self { + self.top_start = radius; + self + } + + /// Establece el radio en la esquina superior-final (`rounded-top-end-*`). Respeta LTR/RTL. + pub fn with_top_end(mut self, radius: RoundedRadius) -> Self { + self.top_end = radius; + self + } + + /// Establece el radio en la esquina inferior-inicial (`rounded-bottom-start-*`). Respeta + /// LTR/RTL. + pub fn with_bottom_start(mut self, radius: RoundedRadius) -> Self { + self.bottom_start = radius; + self + } + + /// Establece el radio en la esquina inferior-final (`rounded-bottom-end-*`). Respeta LTR/RTL. + pub fn with_bottom_end(mut self, radius: RoundedRadius) -> Self { + self.bottom_end = radius; + self + } +} + +impl fmt::Display for Rounded { + /// Concatena, en este orden, las clases para *global*, `top`, `end`, `bottom`, `start`, + /// `top-start`, `top-end`, `bottom-start` y `bottom-end`; respetando LTR/RTL y omitiendo las + /// definiciones vacías. + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + [ + self.radius.to_string(), + self.top.to_class("rounded-top"), + self.end.to_class("rounded-end"), + self.bottom.to_class("rounded-bottom"), + self.start.to_class("rounded-start"), + self.top_start.to_class("rounded-top-start"), + self.top_end.to_class("rounded-top-end"), + self.bottom_start.to_class("rounded-bottom-start"), + self.bottom_end.to_class("rounded-bottom-end"), + ] + .join_classes() + ) + } +} diff --git a/extensions/pagetop-bootsier/src/theme/container.rs b/extensions/pagetop-bootsier/src/theme/container.rs index 411eb0aa..a860110f 100644 --- a/extensions/pagetop-bootsier/src/theme/container.rs +++ b/extensions/pagetop-bootsier/src/theme/container.rs @@ -1,299 +1,24 @@ -use pagetop::prelude::*; +//! Definiciones para crear contenedores de componentes ([`Container`]). +//! +//! Cada contenedor envuelve contenido usando la etiqueta semántica indicada por +//! [`container::Kind`](crate::theme::container::Kind). +//! +//! Con [`container::Width`](crate::theme::container::Width) se puede definir el ancho y el +//! comportamiento *responsive* del contenedor. También permite aplicar utilidades de estilo para el +//! fondo, texto, borde o esquinas redondeadas. +//! +//! # Ejemplo +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let main = Container::main() +//! .with_id("main-page") +//! .with_width(container::Width::From(BreakPoint::LG)); +//! ``` -use crate::prelude::*; +mod props; +pub use props::{Kind, Width}; -// **< ContainerType >****************************************************************************** - -/// Tipo de contenedor ([`Container`]). -/// -/// Permite aplicar la etiqueta HTML apropiada (`<main>`, `<header>`, etc.) manteniendo una API -/// común a todos los contenedores. -#[derive(AutoDefault)] -pub enum ContainerType { - /// Contenedor genérico (`<div>`). - #[default] - Default, - /// Contenido principal de la página (`<main>`). - Main, - /// Encabezado de la página o de sección (`<header>`). - Header, - /// Pie de la página o de sección (`<footer>`). - Footer, - /// Sección de contenido (`<section>`). - Section, - /// Artículo de contenido (`<article>`). - Article, -} - -// **< ContainerWidth >***************************************************************************** - -/// Define el comportamiento para ajustar el ancho de un contenedor ([`Container`]). -#[derive(AutoDefault)] -pub enum ContainerWidth { - /// Comportamiento por defecto, aplica los anchos máximos predefinidos para cada punto de - /// ruptura. Por debajo del menor punto de ruptura ocupa el 100% del ancho disponible. - #[default] - Default, - /// Aplica los anchos máximos predefinidos a partir del punto de ruptura indicado. Por debajo de - /// ese punto de ruptura ocupa el 100% del ancho disponible. - From(BreakPoint), - /// Ocupa el 100% del ancho disponible siempre. - Fluid, - /// Ocupa el 100% del ancho disponible hasta un ancho máximo explícito. - FluidMax(UnitValue), -} - -// **< Container >********************************************************************************** - -/// Componente para crear un **contenedor de componentes**. -/// -/// Envuelve el contenido con la etiqueta HTML indicada por [`ContainerType`]. Sólo se renderiza si -/// existen componentes hijos (*children*). -#[rustfmt::skip] -#[derive(AutoDefault)] -pub struct Container { - id : AttrId, - classes : AttrClasses, - container_type : ContainerType, - container_width: ContainerWidth, - style_bg : StyleBg, - style_text : StyleText, - border : Border, - rounded : Rounded, - children : Children, -} - -impl Component for Container { - fn new() -> Self { - Container::default() - } - - fn id(&self) -> Option<String> { - self.id.get() - } - - fn setup_before_prepare(&mut self, _cx: &mut Context) { - self.alter_classes( - ClassesOp::Prepend, - [ - join_pair!( - "container", - "-", - match self.width() { - ContainerWidth::Default => String::new(), - ContainerWidth::From(bp) => bp.to_string(), - ContainerWidth::Fluid => "fluid".to_string(), - ContainerWidth::FluidMax(_) => "fluid".to_string(), - } - ), - self.style_bg().to_string(), - self.style_text().to_string(), - self.border().to_string(), - self.rounded().to_string(), - ] - .join(" "), - ); - } - - fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let output = self.children().render(cx); - if output.is_empty() { - return PrepareMarkup::None; - } - let style = match self.width() { - ContainerWidth::FluidMax(w) if w.is_measurable() => { - Some(join!("max-width: ", w.to_string(), ";")) - } - _ => None, - }; - match self.container_type() { - ContainerType::Default => PrepareMarkup::With(html! { - div id=[self.id()] class=[self.classes().get()] style=[style] { - (output) - } - }), - ContainerType::Main => PrepareMarkup::With(html! { - main id=[self.id()] class=[self.classes().get()] style=[style] { - (output) - } - }), - ContainerType::Header => PrepareMarkup::With(html! { - header id=[self.id()] class=[self.classes().get()] style=[style] { - (output) - } - }), - ContainerType::Footer => PrepareMarkup::With(html! { - footer id=[self.id()] class=[self.classes().get()] style=[style] { - (output) - } - }), - ContainerType::Section => PrepareMarkup::With(html! { - section id=[self.id()] class=[self.classes().get()] style=[style] { - (output) - } - }), - ContainerType::Article => PrepareMarkup::With(html! { - article id=[self.id()] class=[self.classes().get()] style=[style] { - (output) - } - }), - } - } -} - -impl Container { - /// Crea un contenedor de tipo `Main` (`<main>`). - pub fn main() -> Self { - Container { - container_type: ContainerType::Main, - ..Default::default() - } - } - - /// Crea un contenedor de tipo `Header` (`<header>`). - pub fn header() -> Self { - Container { - container_type: ContainerType::Header, - ..Default::default() - } - } - - /// Crea un contenedor de tipo `Footer` (`<footer>`). - pub fn footer() -> Self { - Container { - container_type: ContainerType::Footer, - ..Default::default() - } - } - - /// Crea un contenedor de tipo `Section` (`<section>`). - pub fn section() -> Self { - Container { - container_type: ContainerType::Section, - ..Default::default() - } - } - - /// Crea un contenedor de tipo `Article` (`<article>`). - pub fn article() -> Self { - Container { - container_type: ContainerType::Article, - ..Default::default() - } - } - - // **< Container BUILDER >********************************************************************** - - /// Establece el identificador único (`id`) del contenedor. - #[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 contenedor. - #[builder_fn] - pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { - self.classes.alter_value(op, classes); - self - } - - /// Establece el comportamiento del ancho para el contenedor. - #[builder_fn] - pub fn with_width(mut self, width: ContainerWidth) -> Self { - self.container_width = width; - self - } - - /// Establece el estilo del fondo ([`StyleBg`]). - #[builder_fn] - pub fn with_style_bg(mut self, style: StyleBg) -> Self { - self.style_bg = style; - self - } - - /// Establece el estilo del texto ([`StyleText`]). - #[builder_fn] - pub fn with_style_text(mut self, style: StyleText) -> Self { - self.style_text = style; - self - } - - /// Atajo para definir los estilos de fondo y texto a la vez. - #[builder_fn] - pub fn with_styles(mut self, style_bg: StyleBg, style_text: StyleText) -> Self { - self.style_bg = style_bg; - self.style_text = style_text; - self - } - - /// Establece el borde del contenedor ([`Border`]). - #[builder_fn] - pub fn with_border(mut self, border: Border) -> Self { - self.border = border; - self - } - - /// Establece esquinas redondeadas para el contenedor ([`Rounded`]). - #[builder_fn] - pub fn with_rounded(mut self, rounded: Rounded) -> Self { - self.rounded = rounded; - self - } - - /// Añade un nuevo componente hijo al contenedor. - #[inline] - pub fn add_child(mut self, component: impl Component) -> Self { - self.children.add(Child::with(component)); - self - } - - /// Modifica la lista de componentes (`children`) aplicando una operación [`ChildOp`]. - #[builder_fn] - pub fn with_child(mut self, op: ChildOp) -> Self { - self.children.alter_child(op); - self - } - - // **< Container GETTERS >********************************************************************** - - /// Devuelve las clases CSS asociadas al contenedor. - pub fn classes(&self) -> &AttrClasses { - &self.classes - } - - /// Devuelve el tipo semántico del contenedor. - pub fn container_type(&self) -> &ContainerType { - &self.container_type - } - - /// Devuelve el comportamiento para el ancho del contenedor. - pub fn width(&self) -> &ContainerWidth { - &self.container_width - } - - /// Devuelve el estilo del fondo del contenedor. - pub fn style_bg(&self) -> &StyleBg { - &self.style_bg - } - - /// Devuelve el estilo del texto del contenedor. - pub fn style_text(&self) -> &StyleText { - &self.style_text - } - - /// Devuelve el borde configurado del contenedor. - pub fn border(&self) -> &Border { - &self.border - } - - /// Devuelve las esquinas redondeadas configuradas para el contenedor. - pub fn rounded(&self) -> &Rounded { - &self.rounded - } - - /// Devuelve la lista de componentes (`children`) del contenedor. - pub fn children(&self) -> &Children { - &self.children - } -} +mod component; +pub use component::Container; diff --git a/extensions/pagetop-bootsier/src/theme/container/component.rs b/extensions/pagetop-bootsier/src/theme/container/component.rs new file mode 100644 index 00000000..1bcf1006 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/container/component.rs @@ -0,0 +1,197 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +/// Componente para crear un **contenedor de componentes**. +/// +/// Envuelve un contenido con la etiqueta HTML indicada por [`container::Kind`]. Sólo se renderiza +/// si existen componentes hijos (*children*). +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Container { + id : AttrId, + classes : AttrClasses, + container_kind : container::Kind, + container_width: container::Width, + children : Children, +} + +impl Component for Container { + fn new() -> Self { + Container::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes( + ClassesOp::Prepend, + [join_pair!( + "container", + "-", + match self.width() { + container::Width::Default => String::new(), + container::Width::From(bp) => bp.to_string(), + container::Width::Fluid => "fluid".to_string(), + container::Width::FluidMax(_) => "fluid".to_string(), + } + )] + .join_classes(), + ); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let output = self.children().render(cx); + if output.is_empty() { + return PrepareMarkup::None; + } + let style = match self.width() { + container::Width::FluidMax(w) if w.is_measurable() => { + Some(join!("max-width: ", w.to_string(), ";")) + } + _ => None, + }; + match self.container_kind() { + container::Kind::Default => PrepareMarkup::With(html! { + div id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + container::Kind::Main => PrepareMarkup::With(html! { + main id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + container::Kind::Header => PrepareMarkup::With(html! { + header id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + container::Kind::Footer => PrepareMarkup::With(html! { + footer id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + container::Kind::Section => PrepareMarkup::With(html! { + section id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + container::Kind::Article => PrepareMarkup::With(html! { + article id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + } + } +} + +impl Container { + /// Crea un contenedor de tipo `Main` (`<main>`). + pub fn main() -> Self { + Container { + container_kind: container::Kind::Main, + ..Default::default() + } + } + + /// Crea un contenedor de tipo `Header` (`<header>`). + pub fn header() -> Self { + Container { + container_kind: container::Kind::Header, + ..Default::default() + } + } + + /// Crea un contenedor de tipo `Footer` (`<footer>`). + pub fn footer() -> Self { + Container { + container_kind: container::Kind::Footer, + ..Default::default() + } + } + + /// Crea un contenedor de tipo `Section` (`<section>`). + pub fn section() -> Self { + Container { + container_kind: container::Kind::Section, + ..Default::default() + } + } + + /// Crea un contenedor de tipo `Article` (`<article>`). + pub fn article() -> Self { + Container { + container_kind: container::Kind::Article, + ..Default::default() + } + } + + // **< Container BUILDER >********************************************************************** + + /// Establece el identificador único (`id`) del contenedor. + #[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 contenedor. + /// + /// También acepta clases predefinidas para: + /// + /// - Modificar el color de fondo ([`classes::Background`]). + /// - Definir la apariencia del texto ([`classes::Text`]). + /// - Establecer bordes ([`classes::Border`]). + /// - Redondear las esquinas ([`classes::Rounded`]). + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + /// Establece el comportamiento del ancho para el contenedor. + #[builder_fn] + pub fn with_width(mut self, width: container::Width) -> Self { + self.container_width = width; + self + } + + /// Añade un nuevo componente hijo al contenedor. + #[inline] + pub fn add_child(mut self, component: impl Component) -> Self { + self.children.add(Child::with(component)); + self + } + + /// Modifica la lista de componentes (`children`) aplicando una operación [`ChildOp`]. + #[builder_fn] + pub fn with_child(mut self, op: ChildOp) -> Self { + self.children.alter_child(op); + self + } + + // **< Container GETTERS >********************************************************************** + + /// Devuelve las clases CSS asociadas al contenedor. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el tipo semántico del contenedor. + pub fn container_kind(&self) -> &container::Kind { + &self.container_kind + } + + /// Devuelve el comportamiento para el ancho del contenedor. + pub fn width(&self) -> &container::Width { + &self.container_width + } + + /// Devuelve la lista de componentes (`children`) del contenedor. + pub fn children(&self) -> &Children { + &self.children + } +} diff --git a/extensions/pagetop-bootsier/src/theme/container/props.rs b/extensions/pagetop-bootsier/src/theme/container/props.rs new file mode 100644 index 00000000..796e32f4 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/container/props.rs @@ -0,0 +1,44 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +// **< Kind >*************************************************************************************** + +/// Tipo de contenedor ([`Container`]). +/// +/// Permite aplicar la etiqueta HTML apropiada (`<main>`, `<header>`, etc.) manteniendo una API +/// común a todos los contenedores. +#[derive(AutoDefault)] +pub enum Kind { + /// Contenedor genérico (`<div>`). + #[default] + Default, + /// Contenido principal de la página (`<main>`). + Main, + /// Encabezado de la página o de sección (`<header>`). + Header, + /// Pie de la página o de sección (`<footer>`). + Footer, + /// Sección de contenido (`<section>`). + Section, + /// Artículo de contenido (`<article>`). + Article, +} + +// **< Width >************************************************************************************** + +/// Define el comportamiento para ajustar el ancho de un contenedor ([`Container`]). +#[derive(AutoDefault)] +pub enum Width { + /// Comportamiento por defecto, aplica los anchos máximos predefinidos para cada punto de + /// ruptura. Por debajo del menor punto de ruptura ocupa el 100% del ancho disponible. + #[default] + Default, + /// Aplica los anchos máximos predefinidos a partir del punto de ruptura indicado. Por debajo de + /// ese punto de ruptura ocupa el 100% del ancho disponible. + From(BreakPoint), + /// Ocupa el 100% del ancho disponible siempre. + Fluid, + /// Ocupa el 100% del ancho disponible hasta un ancho máximo explícito. + FluidMax(UnitValue), +} diff --git a/extensions/pagetop-bootsier/src/theme/dropdown.rs b/extensions/pagetop-bootsier/src/theme/dropdown.rs index bbad2d3f..ed4cbec0 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown.rs @@ -14,7 +14,7 @@ //! # use pagetop_bootsier::prelude::*; //! let dd = Dropdown::new() //! .with_title(L10n::n("Menu")) -//! .with_button_color(ColorButton::Background(Color::Secondary)) +//! .with_button_color(ButtonColor::Background(Color::Secondary)) //! .with_auto_close(dropdown::AutoClose::ClickableInside) //! .with_direction(dropdown::Direction::Dropend) //! .add_item(dropdown::Item::link(L10n::n("Home"), |_| "/")) diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs index 57e30713..450edff2 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs @@ -26,7 +26,7 @@ pub struct Dropdown { classes : AttrClasses, title : L10n, button_size : ButtonSize, - button_color : ColorButton, + button_color : ButtonColor, button_split : bool, button_grouped: bool, auto_close : dropdown::AutoClose, @@ -59,7 +59,7 @@ impl Component for Dropdown { dropdown::Direction::Dropend => "dropend", dropdown::Direction::Dropstart => "dropstart", } - ].join(" ")); + ].join_classes()); } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { @@ -79,7 +79,7 @@ impl Component for Dropdown { "btn", &self.button_size().to_string(), &self.button_color().to_string(), - ].join(" ")); + ].join_classes()); @let (offset, reference) = match self.menu_position() { dropdown::MenuPosition::Default => (None, None), dropdown::MenuPosition::Offset(x, y) => (Some(format!("{x},{y}")), None), @@ -212,7 +212,7 @@ impl Dropdown { /// Define el color/estilo del botón. #[builder_fn] - pub fn with_button_color(mut self, color: ColorButton) -> Self { + pub fn with_button_color(mut self, color: ButtonColor) -> Self { self.button_color = color; self } @@ -291,7 +291,7 @@ impl Dropdown { } /// Devuelve el color/estilo configurado del botón. - pub fn button_color(&self) -> &ColorButton { + pub fn button_color(&self) -> &ButtonColor { &self.button_color } diff --git a/extensions/pagetop-bootsier/src/theme/image/component.rs b/extensions/pagetop-bootsier/src/theme/image/component.rs index 0345adb2..2eda4302 100644 --- a/extensions/pagetop-bootsier/src/theme/image/component.rs +++ b/extensions/pagetop-bootsier/src/theme/image/component.rs @@ -6,8 +6,8 @@ use crate::prelude::*; /// /// - Ajusta su disposición según el origen definido en [`image::Source`]. /// - Permite configurar **dimensiones** ([`with_size()`](Self::with_size)), **borde** -/// ([`with_border()`](Self::with_border)) y **redondeo de esquinas** -/// ([`with_rounded()`](Self::with_rounded)). +/// ([`classes::Border`](crate::theme::classes::Border)) y **redondeo de esquinas** +/// ([`classes::Rounded`](crate::theme::classes::Rounded)). /// - Resuelve el texto alternativo `alt` con **localización** mediante [`L10n`]. #[rustfmt::skip] #[derive(AutoDefault)] @@ -17,8 +17,6 @@ pub struct Image { size : image::Size, source : image::Source, alt : AttrL10n, - border : Border, - rounded: Rounded, } impl Component for Image { @@ -33,17 +31,12 @@ impl Component for Image { fn setup_before_prepare(&mut self, _cx: &mut Context) { self.alter_classes( ClassesOp::Prepend, - [ - String::from(match self.source() { - image::Source::Logo(_) => "img-fluid", - image::Source::Responsive(_) => "img-fluid", - image::Source::Thumbnail(_) => "img-thumbnail", - image::Source::Plain(_) => "", - }), - self.border().to_string(), - self.rounded().to_string(), - ] - .join(" "), + match self.source() { + image::Source::Logo(_) => "img-fluid", + image::Source::Responsive(_) => "img-fluid", + image::Source::Thumbnail(_) => "img-thumbnail", + image::Source::Plain(_) => "", + }, ); } @@ -116,6 +109,11 @@ impl Image { } /// Modifica la lista de clases CSS aplicadas a la imagen. + /// + /// También acepta clases predefinidas para: + /// + /// - Establecer bordes ([`classes::Border`]). + /// - Redondear las esquinas ([`classes::Rounded`]). #[builder_fn] pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { self.classes.alter_value(op, classes); @@ -146,20 +144,6 @@ impl Image { self } - /// Establece el borde de la imagen ([`Border`]). - #[builder_fn] - pub fn with_border(mut self, border: Border) -> Self { - self.border = border; - self - } - - /// Establece esquinas redondeadas para la imagen ([`Rounded`]). - #[builder_fn] - pub fn with_rounded(mut self, rounded: Rounded) -> Self { - self.rounded = rounded; - self - } - // **< Image GETTERS >************************************************************************** /// Devuelve las clases CSS asociadas a la imagen. @@ -181,14 +165,4 @@ impl Image { pub fn alternative(&self) -> &AttrL10n { &self.alt } - - /// Devuelve el borde configurado de la imagen. - pub fn border(&self) -> &Border { - &self.border - } - - /// Devuelve las esquinas redondeadas configuradas para la imagen. - pub fn rounded(&self) -> &Rounded { - &self.rounded - } } diff --git a/extensions/pagetop-bootsier/src/theme/nav/component.rs b/extensions/pagetop-bootsier/src/theme/nav/component.rs index d4cf2c8c..fe886bdd 100644 --- a/extensions/pagetop-bootsier/src/theme/nav/component.rs +++ b/extensions/pagetop-bootsier/src/theme/nav/component.rs @@ -50,7 +50,7 @@ impl Component for Nav { nav::Layout::Justified => "nav-justified", }, ] - .join(" "), + .join_classes(), ); } diff --git a/extensions/pagetop-bootsier/src/theme/navbar/component.rs b/extensions/pagetop-bootsier/src/theme/navbar/component.rs index 6362b9d6..ac592439 100644 --- a/extensions/pagetop-bootsier/src/theme/navbar/component.rs +++ b/extensions/pagetop-bootsier/src/theme/navbar/component.rs @@ -17,14 +17,12 @@ const TOGGLE_OFFCANVAS: &str = "offcanvas"; #[rustfmt::skip] #[derive(AutoDefault)] pub struct Navbar { - id : AttrId, - classes : AttrClasses, - expand : BreakPoint, - layout : navbar::Layout, - position : navbar::Position, - style_bg : StyleBg, - style_text: StyleText, - items : Children, + id : AttrId, + classes : AttrClasses, + expand : BreakPoint, + layout : navbar::Layout, + position : navbar::Position, + items : Children, } impl Component for Navbar { @@ -50,10 +48,8 @@ impl Component for Navbar { navbar::Position::StickyBottom => "sticky-bottom", } .to_string(), - self.style_bg().to_string(), - self.style_text().to_string(), ] - .join(" "), + .join_classes(), ); } @@ -232,6 +228,11 @@ impl Navbar { } /// Modifica la lista de clases CSS aplicadas a la barra de navegación. + /// + /// También acepta clases predefinidas para: + /// + /// - Modificar el color de fondo ([`classes::Background`]). + /// - Definir la apariencia del texto ([`classes::Text`]). #[builder_fn] pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { self.classes.alter_value(op, classes); @@ -259,28 +260,6 @@ impl Navbar { self } - /// Establece el estilo del fondo ([`StyleBg`]). - #[builder_fn] - pub fn with_style_bg(mut self, style: StyleBg) -> Self { - self.style_bg = style; - self - } - - /// Establece el estilo del texto ([`StyleText`]). - #[builder_fn] - pub fn with_style_text(mut self, style: StyleText) -> Self { - self.style_text = style; - self - } - - /// Atajo para definir los estilos de fondo y texto a la vez. - #[builder_fn] - pub fn with_styles(mut self, style_bg: StyleBg, style_text: StyleText) -> Self { - self.style_bg = style_bg; - self.style_text = style_text; - self - } - /// Añade un nuevo contenido hijo. #[inline] pub fn add_item(mut self, item: navbar::Item) -> Self { @@ -317,16 +296,6 @@ impl Navbar { &self.position } - /// Devuelve el estilo del fondo del contenedor. - pub fn style_bg(&self) -> &StyleBg { - &self.style_bg - } - - /// Devuelve el estilo del texto del contenedor. - pub fn style_text(&self) -> &StyleText { - &self.style_text - } - /// Devuelve la lista de contenidos (`children`). pub fn items(&self) -> &Children { &self.items diff --git a/extensions/pagetop-bootsier/src/theme/navbar/item.rs b/extensions/pagetop-bootsier/src/theme/navbar/item.rs index f0646406..07f52be6 100644 --- a/extensions/pagetop-bootsier/src/theme/navbar/item.rs +++ b/extensions/pagetop-bootsier/src/theme/navbar/item.rs @@ -67,7 +67,7 @@ impl Component for Item { nav::Layout::Justified => "nav-justified", }, ] - .join(" "), + .join_classes(), ); PrepareMarkup::With(html! { ul id=[nav.id()] class=[classes.get()] { diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs b/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs index 61e6fae7..7516238b 100644 --- a/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs +++ b/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs @@ -61,7 +61,7 @@ impl Component for Offcanvas { offcanvas::Visibility::Show => "show", }.to_string(), ] - .join(" "), + .join_classes(), ); } From 2e39af0856a57e8c6e2bd77aaab72e55169eb703 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 15 Nov 2025 13:16:15 +0100 Subject: [PATCH 238/244] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(bootsier):=20Refa?= =?UTF-8?q?ctoriza=20la=20gesti=C3=B3n=20de=20clases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Mejora la legibilidad del código. - Simplifica las alteraciones de clases en los componentes `Container`, `Dropdown`, `Image`, `Nav`, `Navbar` y `Offcanvas` usando métodos dedicados para generar clases en función de sus propiedades. - Mejora los enums añadiendo métodos que devuelven sus clases asociadas, reduciendo código repetitivo. - Elimina el trait `JoinClasses` y su implementación, integrando la lógica de unión de clases directamente en los componentes. --- extensions/pagetop-bootsier/src/theme/aux.rs | 5 +- .../pagetop-bootsier/src/theme/aux/border.rs | 114 +++---- .../src/theme/aux/breakpoint.rs | 145 +++++---- .../pagetop-bootsier/src/theme/aux/button.rs | 119 ++++++- .../pagetop-bootsier/src/theme/aux/color.rs | 305 ++++++++++++++---- .../pagetop-bootsier/src/theme/aux/layout.rs | 104 ++++++ .../pagetop-bootsier/src/theme/aux/rounded.rs | 119 +++++-- .../pagetop-bootsier/src/theme/classes.rs | 3 + .../src/theme/classes/border.rs | 178 +++++----- .../src/theme/classes/color.rs | 97 +++--- .../src/theme/classes/layout.rs | 205 ++++++++++++ .../src/theme/classes/rounded.rs | 60 ++-- .../src/theme/container/component.rs | 15 +- .../src/theme/container/props.rs | 38 ++- .../src/theme/dropdown/component.rs | 68 ++-- .../src/theme/dropdown/item.rs | 2 +- .../src/theme/dropdown/props.rs | 148 ++++++++- .../src/theme/image/component.rs | 31 +- .../pagetop-bootsier/src/theme/image/props.rs | 59 +++- .../src/theme/nav/component.rs | 28 +- .../pagetop-bootsier/src/theme/nav/item.rs | 51 ++- .../pagetop-bootsier/src/theme/nav/props.rs | 85 ++++- .../src/theme/navbar/component.rs | 22 +- .../pagetop-bootsier/src/theme/navbar/item.rs | 31 +- .../src/theme/navbar/props.rs | 36 ++- .../src/theme/offcanvas/component.rs | 25 +- .../src/theme/offcanvas/props.rs | 67 +++- src/base/component.rs | 12 +- src/html.rs | 3 - src/html/assets/stylesheet.rs | 6 +- src/html/join_classes.rs | 67 ---- src/html/logo.rs | 2 +- src/prelude.rs | 4 +- 33 files changed, 1607 insertions(+), 647 deletions(-) create mode 100644 extensions/pagetop-bootsier/src/theme/aux/layout.rs create mode 100644 extensions/pagetop-bootsier/src/theme/classes/layout.rs delete mode 100644 src/html/join_classes.rs diff --git a/extensions/pagetop-bootsier/src/theme/aux.rs b/extensions/pagetop-bootsier/src/theme/aux.rs index 528126de..99431fe3 100644 --- a/extensions/pagetop-bootsier/src/theme/aux.rs +++ b/extensions/pagetop-bootsier/src/theme/aux.rs @@ -7,8 +7,11 @@ mod color; pub use color::{Color, Opacity}; pub use color::{ColorBg, ColorText}; +mod layout; +pub use layout::{ScaleSize, Side}; + mod border; -pub use border::{BorderColor, BorderSize}; +pub use border::BorderColor; mod rounded; pub use rounded::RoundedRadius; diff --git a/extensions/pagetop-bootsier/src/theme/aux/border.rs b/extensions/pagetop-bootsier/src/theme/aux/border.rs index 47547c30..43882767 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/border.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/border.rs @@ -2,12 +2,8 @@ use pagetop::prelude::*; use crate::theme::aux::Color; -use std::fmt; - -// **< BorderColor >******************************************************************************** - /// Colores `border-*` para los bordes ([`classes::Border`](crate::theme::classes::Border)). -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum BorderColor { /// No define ninguna clase. #[default] @@ -22,60 +18,70 @@ pub enum BorderColor { White, } -#[rustfmt::skip] -impl fmt::Display for BorderColor { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Default => Ok(()), - Self::Theme(c) => write!(f, "border-{c}"), - Self::Subtle(c) => write!(f, "border-{c}-subtle"), - Self::Black => f.write_str("border-black"), - Self::White => f.write_str("border-white"), - } - } -} +impl BorderColor { + const BORDER: &str = "border"; + const BORDER_PREFIX: &str = "border-"; -// **< BorderSize >********************************************************************************* - -/// Tamaño para el ancho de los bordes ([`classes::Border`](crate::theme::classes::Border)). -/// -/// Mapea a `border`, `border-0` y `border-{1..5}`: -/// -/// - `None` no añade ninguna clase. -/// - `Default` genera `border` (borde por defecto del tema). -/// - `Zero` genera `border-0` (sin borde). -/// - `Scale{1..5}` genera `border-{1..5}` (ancho creciente). -#[derive(AutoDefault)] -pub enum BorderSize { - #[default] - None, - Default, - Zero, - Scale1, - Scale2, - Scale3, - Scale4, - Scale5, -} - -impl BorderSize { + // Devuelve el sufijo de la clase `border-*`, o `None` si no define ninguna clase. #[rustfmt::skip] - pub(crate) fn to_class(&self, prefix: impl AsRef<str>) -> String { + #[inline] + const fn suffix(self) -> Option<&'static str> { match self { - Self::None => String::new(), - Self::Default => String::from(prefix.as_ref()), - Self::Zero => join!(prefix, "-0"), - Self::Scale1 => join!(prefix, "-1"), - Self::Scale2 => join!(prefix, "-2"), - Self::Scale3 => join!(prefix, "-3"), - Self::Scale4 => join!(prefix, "-4"), - Self::Scale5 => join!(prefix, "-5"), + Self::Default => None, + Self::Theme(_) => Some(""), + Self::Subtle(_) => Some("-subtle"), + Self::Black => Some("-black"), + Self::White => Some("-white"), } } -} -impl fmt::Display for BorderSize { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.to_class("border")) + // Añade la clase `border-*` a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if let Some(suffix) = self.suffix() { + if !classes.is_empty() { + classes.push(' '); + } + match self { + Self::Theme(c) | Self::Subtle(c) => { + classes.push_str(Self::BORDER_PREFIX); + classes.push_str(c.as_str()); + } + _ => classes.push_str(Self::BORDER), + } + classes.push_str(suffix); + } + } + + /// Devuelve la clase `border-*` correspondiente al color de borde. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(BorderColor::Theme(Color::Primary).to_class(), "border-primary"); + /// assert_eq!(BorderColor::Subtle(Color::Warning).to_class(), "border-warning-subtle"); + /// assert_eq!(BorderColor::Black.to_class(), "border-black"); + /// assert_eq!(BorderColor::Default.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + if let Some(suffix) = self.suffix() { + let base_len = match self { + Self::Theme(c) | Self::Subtle(c) => Self::BORDER_PREFIX.len() + c.as_str().len(), + _ => Self::BORDER.len(), + }; + let mut class = String::with_capacity(base_len + suffix.len()); + match self { + Self::Theme(c) | Self::Subtle(c) => { + class.push_str(Self::BORDER_PREFIX); + class.push_str(c.as_str()); + } + _ => class.push_str(Self::BORDER), + } + class.push_str(suffix); + return class; + } + String::new() } } diff --git a/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs b/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs index 27d7c29f..4d9a7626 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs @@ -1,9 +1,7 @@ use pagetop::prelude::*; -use std::fmt; - /// Define los puntos de ruptura (*breakpoints*) para aplicar diseño *responsive*. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum BreakPoint { /// **Menos de 576px**. Dispositivos muy pequeños: teléfonos en modo vertical. #[default] @@ -21,71 +19,96 @@ pub enum BreakPoint { } impl BreakPoint { + // Devuelve la identificación del punto de ruptura. #[rustfmt::skip] #[inline] - const fn suffix(&self) -> Option<&'static str> { + pub(crate) const fn as_str(self) -> &'static str { match self { - Self::None => None, - Self::SM => Some("sm"), - Self::MD => Some("md"), - Self::LG => Some("lg"), - Self::XL => Some("xl"), - Self::XXL => Some("xxl"), + Self::None => "", + Self::SM => "sm", + Self::MD => "md", + Self::LG => "lg", + Self::XL => "xl", + Self::XXL => "xxl", } } - /// Genera un nombre de clase CSS basado en el punto de ruptura. - /// - /// Si es un punto de ruptura efectivo concatena el prefijo, un guion (`-`) y el sufijo - /// asociado. Para `None` devuelve sólo el prefijo. - /// - /// # Ejemplo - /// - /// ```rust - /// # use pagetop_bootsier::prelude::*; - /// let breakpoint = BreakPoint::MD; - /// assert_eq!(breakpoint.to_class("col"), "col-md"); - /// - /// let breakpoint = BreakPoint::None; - /// assert_eq!(breakpoint.to_class("offcanvas"), "offcanvas"); - /// ``` + // Añade el punto de ruptura con un prefijo y un sufijo (opcional) separados por un guion `-` a + // la cadena de clases. + // + // - Para `None` - `prefix` o `prefix-suffix` (si `suffix` no está vacío). + // - Para `SM..XXL` - `prefix-{breakpoint}` o `prefix-{breakpoint}-{suffix}`. #[inline] - pub fn to_class(&self, prefix: impl AsRef<str>) -> String { - join_pair!(prefix, "-", self.suffix().unwrap_or_default()) - } - - /// Intenta generar un nombre de clase CSS basado en el punto de ruptura. - /// - /// Si es un punto de ruptura efectivo devuelve `Some(String)` concatenando el prefijo, un guion - /// (`-`) y el sufijo asociado. En otro caso devuelve `None`. - /// - /// # Ejemplo - /// - /// ```rust - /// # use pagetop_bootsier::prelude::*; - /// let breakpoint = BreakPoint::MD; - /// let class = breakpoint.try_class("col"); - /// assert_eq!(class, Some("col-md".to_string())); - /// - /// let breakpoint = BreakPoint::None; - /// let class = breakpoint.try_class("navbar-expand"); - /// assert_eq!(class, None); - /// ``` - #[inline] - pub fn try_class(&self, prefix: impl AsRef<str>) -> Option<String> { - self.suffix().map(|suffix| join_pair!(prefix, "-", suffix)) - } -} - -impl fmt::Display for BreakPoint { - /// Implementa [`Display`](std::fmt::Display) para asociar `"sm"`, `"md"`, `"lg"`, `"xl"` o - /// `"xxl"` a los puntos de ruptura `BreakPoint::SM`, `MD`, `LG`, `XL` o `XXL`, respectivamente. - /// Y `""` (cadena vacía) a `BreakPoint::None`. - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(suffix) = self.suffix() { - f.write_str(suffix) - } else { - Ok(()) + pub(crate) fn push_class(self, classes: &mut String, prefix: &str, suffix: &str) { + if prefix.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + match self { + Self::None => classes.push_str(prefix), + _ => { + classes.push_str(prefix); + classes.push('-'); + classes.push_str(self.as_str()); + } + } + if !suffix.is_empty() { + classes.push('-'); + classes.push_str(suffix); } } + + // Devuelve la clase para el punto de ruptura, con un prefijo y un sufijo opcional, separados + // por un guion `-`. + // + // - Para `None` - `prefix` o `prefix-suffix` (si `suffix` no está vacío). + // - Para `SM..XXL` - `prefix-{breakpoint}` o `prefix-{breakpoint}-{suffix}`. + // - Si `prefix` está vacío devuelve `""`. + // + // # Ejemplos + // + // ```rust + // # use pagetop_bootsier::prelude::*; + // let bp = BreakPoint::MD; + // assert_eq!(bp.class_with("col", ""), "col-md"); + // assert_eq!(bp.class_with("col", "6"), "col-md-6"); + // + // let bp = BreakPoint::None; + // assert_eq!(bp.class_with("offcanvas", ""), "offcanvas"); + // assert_eq!(bp.class_with("col", "12"), "col-12"); + // + // let bp = BreakPoint::LG; + // assert_eq!(bp.class_with("", "3"), ""); + // ``` + #[inline] + pub(crate) fn class_with(self, prefix: &str, suffix: &str) -> String { + if prefix.is_empty() { + return String::new(); + } + + let bp = self.as_str(); + let has_bp = !bp.is_empty(); + let has_suffix = !suffix.is_empty(); + + let mut len = prefix.len(); + if has_bp { + len += 1 + bp.len(); + } + if has_suffix { + len += 1 + suffix.len(); + } + let mut class = String::with_capacity(len); + class.push_str(prefix); + if has_bp { + class.push('-'); + class.push_str(bp); + } + if has_suffix { + class.push('-'); + class.push_str(suffix); + } + class + } } diff --git a/extensions/pagetop-bootsier/src/theme/aux/button.rs b/extensions/pagetop-bootsier/src/theme/aux/button.rs index a2f2efb9..0d1df87d 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/button.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/button.rs @@ -2,12 +2,10 @@ use pagetop::prelude::*; use crate::theme::aux::Color; -use std::fmt; - // **< ButtonColor >******************************************************************************** /// Variantes de color `btn-*` para botones. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum ButtonColor { /// No define ninguna clase. #[default] @@ -20,14 +18,72 @@ pub enum ButtonColor { Link, } -#[rustfmt::skip] -impl fmt::Display for ButtonColor { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl ButtonColor { + const BTN_PREFIX: &str = "btn-"; + const BTN_OUTLINE_PREFIX: &str = "btn-outline-"; + const BTN_LINK: &str = "btn-link"; + + // Añade la clase `btn-*` a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if let Self::Default = self { + return; + } + if !classes.is_empty() { + classes.push(' '); + } match self { - Self::Default => Ok(()), - Self::Background(c) => write!(f, "btn-{c}"), - Self::Outline(c) => write!(f, "btn-outline-{c}"), - Self::Link => f.write_str("btn-link"), + Self::Default => unreachable!(), + Self::Background(c) => { + classes.push_str(Self::BTN_PREFIX); + classes.push_str(c.as_str()); + } + Self::Outline(c) => { + classes.push_str(Self::BTN_OUTLINE_PREFIX); + classes.push_str(c.as_str()); + } + Self::Link => { + classes.push_str(Self::BTN_LINK); + } + } + } + + /// Devuelve la clase `btn-*` correspondiente al color del botón. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!( + /// ButtonColor::Background(Color::Primary).to_class(), + /// "btn-primary" + /// ); + /// assert_eq!( + /// ButtonColor::Outline(Color::Danger).to_class(), + /// "btn-outline-danger" + /// ); + /// assert_eq!(ButtonColor::Link.to_class(), "btn-link"); + /// assert_eq!(ButtonColor::Default.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + match self { + Self::Default => String::new(), + Self::Background(c) => { + let color = c.as_str(); + let mut class = String::with_capacity(Self::BTN_PREFIX.len() + color.len()); + class.push_str(Self::BTN_PREFIX); + class.push_str(color); + class + } + Self::Outline(c) => { + let color = c.as_str(); + let mut class = String::with_capacity(Self::BTN_OUTLINE_PREFIX.len() + color.len()); + class.push_str(Self::BTN_OUTLINE_PREFIX); + class.push_str(color); + class + } + Self::Link => Self::BTN_LINK.to_string(), } } } @@ -35,7 +91,7 @@ impl fmt::Display for ButtonColor { // **< ButtonSize >********************************************************************************* /// Tamaño visual de un botón. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum ButtonSize { /// Tamaño por defecto del tema (no añade clase). #[default] @@ -46,13 +102,42 @@ pub enum ButtonSize { Large, } -#[rustfmt::skip] -impl fmt::Display for ButtonSize { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl ButtonSize { + const BTN_SM: &str = "btn-sm"; + const BTN_LG: &str = "btn-lg"; + + // Añade la clase de tamaño `btn-sm` o `btn-lg` a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if let Self::Default = self { + return; + } + if !classes.is_empty() { + classes.push(' '); + } match self { - Self::Default => Ok(()), - Self::Small => f.write_str("btn-sm"), - Self::Large => f.write_str("btn-lg"), + Self::Default => unreachable!(), + Self::Small => classes.push_str(Self::BTN_SM), + Self::Large => classes.push_str(Self::BTN_LG), + } + } + + /// Devuelve la clase `btn-sm` o `btn-lg` correspondiente al tamaño del botón. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(ButtonSize::Small.to_class(), "btn-sm"); + /// assert_eq!(ButtonSize::Large.to_class(), "btn-lg"); + /// assert_eq!(ButtonSize::Default.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + match self { + Self::Default => String::new(), + Self::Small => Self::BTN_SM.to_string(), + Self::Large => Self::BTN_LG.to_string(), } } } diff --git a/extensions/pagetop-bootsier/src/theme/aux/color.rs b/extensions/pagetop-bootsier/src/theme/aux/color.rs index d0f1da00..480ff3d8 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/color.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/color.rs @@ -1,7 +1,5 @@ use pagetop::prelude::*; -use std::fmt; - // **< Color >************************************************************************************** /// Paleta de colores temáticos. @@ -11,7 +9,7 @@ use std::fmt; /// ([`classes::Background`](crate::theme::classes::Background)), bordes /// ([`classes::Border`](crate::theme::classes::Border)) y texto /// ([`classes::Text`](crate::theme::classes::Text)). -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum Color { #[default] Primary, @@ -24,20 +22,45 @@ pub enum Color { Dark, } -#[rustfmt::skip] -impl fmt::Display for Color { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl Color { + // Devuelve el nombre del color. + #[rustfmt::skip] + #[inline] + pub(crate) const fn as_str(self) -> &'static str { match self { - Self::Primary => f.write_str("primary"), - Self::Secondary => f.write_str("secondary"), - Self::Success => f.write_str("success"), - Self::Info => f.write_str("info"), - Self::Warning => f.write_str("warning"), - Self::Danger => f.write_str("danger"), - Self::Light => f.write_str("light"), - Self::Dark => f.write_str("dark"), + Self::Primary => "primary", + Self::Secondary => "secondary", + Self::Success => "success", + Self::Info => "info", + Self::Warning => "warning", + Self::Danger => "danger", + Self::Light => "light", + Self::Dark => "dark", } } + + /* Añade el nombre del color a la cadena de clases (reservado). + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(self.as_str()); + } */ + + /// Devuelve la clase correspondiente al color. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(Color::Primary.to_class(), "primary"); + /// assert_eq!(Color::Danger.to_class(), "danger"); + /// ``` + #[inline] + pub fn to_class(self) -> String { + self.as_str().to_owned() + } } // **< Opacity >************************************************************************************ @@ -48,7 +71,7 @@ impl fmt::Display for Color { /// ([`classes::Background`](crate::theme::classes::Background)), de los bordes `border-opacity-*` /// ([`classes::Border`](crate::theme::classes::Border)) o del texto `text-opacity-*` /// ([`classes::Text`](crate::theme::classes::Text)). -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum Opacity { /// No define ninguna clase. #[default] @@ -68,39 +91,95 @@ pub enum Opacity { } impl Opacity { + const OPACITY: &str = "opacity"; + const OPACITY_PREFIX: &str = "-opacity"; + + // Devuelve el sufijo para `*opacity-*`, o `None` si no define ninguna clase. #[rustfmt::skip] #[inline] - const fn suffix(&self) -> &'static str { + const fn suffix(self) -> Option<&'static str> { match self { - Self::Default => "", - Self::Opaque => "opacity-100", - Self::SemiOpaque => "opacity-75", - Self::Half => "opacity-50", - Self::SemiTransparent => "opacity-25", - Self::AlmostTransparent => "opacity-10", - Self::Transparent => "opacity-0", + Self::Default => None, + Self::Opaque => Some("-100"), + Self::SemiOpaque => Some("-75"), + Self::Half => Some("-50"), + Self::SemiTransparent => Some("-25"), + Self::AlmostTransparent => Some("-10"), + Self::Transparent => Some("-0"), } } + // Añade la opacidad a la cadena de clases usando el prefijo dado (`bg`, `border`, `text`, o + // vacío para `opacity-*`). #[inline] - pub(crate) fn to_class(&self, prefix: impl AsRef<str>) -> String { - match self { - Self::Default => String::new(), - _ => join_pair!(prefix, "-", self.suffix()), + pub(crate) fn push_class(self, classes: &mut String, prefix: &str) { + if let Some(suffix) = self.suffix() { + if !classes.is_empty() { + classes.push(' '); + } + if prefix.is_empty() { + classes.push_str(Self::OPACITY); + } else { + classes.push_str(prefix); + classes.push_str(Self::OPACITY_PREFIX); + } + classes.push_str(suffix); } } -} -impl fmt::Display for Opacity { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.suffix()) + // Devuelve la clase de opacidad con el prefijo dado (`bg`, `border`, `text`, o vacío para + // `opacity-*`). + // + // # Ejemplos + // + // ```rust + // # use pagetop_bootsier::prelude::*; + // assert_eq!(Opacity::Opaque.class_with(""), "opacity-100"); + // assert_eq!(Opacity::Half.class_with("bg"), "bg-opacity-50"); + // assert_eq!(Opacity::SemiTransparent.class_with("text"), "text-opacity-25"); + // assert_eq!(Opacity::Default.class_with("bg"), ""); + // ``` + #[inline] + pub(crate) fn class_with(self, prefix: &str) -> String { + if let Some(suffix) = self.suffix() { + let base_len = if prefix.is_empty() { + Self::OPACITY.len() + } else { + prefix.len() + Self::OPACITY_PREFIX.len() + }; + let mut class = String::with_capacity(base_len + suffix.len()); + if prefix.is_empty() { + class.push_str(Self::OPACITY); + } else { + class.push_str(prefix); + class.push_str(Self::OPACITY_PREFIX); + } + class.push_str(suffix); + return class; + } + String::new() + } + + /// Devuelve la clase de opacidad `opacity-*`. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(Opacity::Opaque.to_class(), "opacity-100"); + /// assert_eq!(Opacity::Half.to_class(), "opacity-50"); + /// assert_eq!(Opacity::Default.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + self.class_with("") } } // **< ColorBg >************************************************************************************ /// Colores `bg-*` para el fondo. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum ColorBg { /// No define ninguna clase. #[default] @@ -123,27 +202,83 @@ pub enum ColorBg { Transparent, } -#[rustfmt::skip] -impl fmt::Display for ColorBg { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl ColorBg { + const BG: &str = "bg"; + const BG_PREFIX: &str = "bg-"; + + // Devuelve el sufijo de la clase `bg-*`, o `None` si no define ninguna clase. + #[rustfmt::skip] + #[inline] + const fn suffix(self) -> Option<&'static str> { match self { - Self::Default => Ok(()), - Self::Body => f.write_str("bg-body"), - Self::BodySecondary => f.write_str("bg-body-secondary"), - Self::BodyTertiary => f.write_str("bg-body-tertiary"), - Self::Theme(c) => write!(f, "bg-{c}"), - Self::Subtle(c) => write!(f, "bg-{c}-subtle"), - Self::Black => f.write_str("bg-black"), - Self::White => f.write_str("bg-white"), - Self::Transparent => f.write_str("bg-transparent"), + Self::Default => None, + Self::Body => Some("-body"), + Self::BodySecondary => Some("-body-secondary"), + Self::BodyTertiary => Some("-body-tertiary"), + Self::Theme(_) => Some(""), + Self::Subtle(_) => Some("-subtle"), + Self::Black => Some("-black"), + Self::White => Some("-white"), + Self::Transparent => Some("-transparent"), } } + + // Añade la clase de fondo `bg-*` a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if let Some(suffix) = self.suffix() { + if !classes.is_empty() { + classes.push(' '); + } + match self { + Self::Theme(c) | Self::Subtle(c) => { + classes.push_str(Self::BG_PREFIX); + classes.push_str(c.as_str()); + } + _ => classes.push_str(Self::BG), + } + classes.push_str(suffix); + } + } + + /// Devuelve la clase `bg-*` correspondiente al fondo. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(ColorBg::Body.to_class(), "bg-body"); + /// assert_eq!(ColorBg::Theme(Color::Primary).to_class(), "bg-primary"); + /// assert_eq!(ColorBg::Subtle(Color::Warning).to_class(), "bg-warning-subtle"); + /// assert_eq!(ColorBg::Transparent.to_class(), "bg-transparent"); + /// assert_eq!(ColorBg::Default.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + if let Some(suffix) = self.suffix() { + let base_len = match self { + Self::Theme(c) | Self::Subtle(c) => Self::BG_PREFIX.len() + c.as_str().len(), + _ => Self::BG.len(), + }; + let mut class = String::with_capacity(base_len + suffix.len()); + match self { + Self::Theme(c) | Self::Subtle(c) => { + class.push_str(Self::BG_PREFIX); + class.push_str(c.as_str()); + } + _ => class.push_str(Self::BG), + } + class.push_str(suffix); + return class; + } + String::new() + } } // **< ColorText >********************************************************************************** /// Colores `text-*` para el texto. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum ColorText { /// No define ninguna clase. #[default] @@ -166,19 +301,75 @@ pub enum ColorText { White, } -#[rustfmt::skip] -impl fmt::Display for ColorText { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl ColorText { + const TEXT: &str = "text"; + const TEXT_PREFIX: &str = "text-"; + + // Devuelve el sufijo de la clase `text-*`, o `None` si no define ninguna clase. + #[rustfmt::skip] + #[inline] + const fn suffix(self) -> Option<&'static str> { match self { - Self::Default => Ok(()), - Self::Body => f.write_str("text-body"), - Self::BodyEmphasis => f.write_str("text-body-emphasis"), - Self::BodySecondary => f.write_str("text-body-secondary"), - Self::BodyTertiary => f.write_str("text-body-tertiary"), - Self::Theme(c) => write!(f, "text-{c}"), - Self::Emphasis(c) => write!(f, "text-{c}-emphasis"), - Self::Black => f.write_str("text-black"), - Self::White => f.write_str("text-white"), + Self::Default => None, + Self::Body => Some("-body"), + Self::BodyEmphasis => Some("-body-emphasis"), + Self::BodySecondary => Some("-body-secondary"), + Self::BodyTertiary => Some("-body-tertiary"), + Self::Theme(_) => Some(""), + Self::Emphasis(_) => Some("-emphasis"), + Self::Black => Some("-black"), + Self::White => Some("-white"), } } + + // Añade la clase de texto `text-*` a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if let Some(suffix) = self.suffix() { + if !classes.is_empty() { + classes.push(' '); + } + match self { + Self::Theme(c) | Self::Emphasis(c) => { + classes.push_str(Self::TEXT_PREFIX); + classes.push_str(c.as_str()); + } + _ => classes.push_str(Self::TEXT), + } + classes.push_str(suffix); + } + } + + /// Devuelve la clase `text-*` correspondiente al color del texto. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(ColorText::Body.to_class(), "text-body"); + /// assert_eq!(ColorText::Theme(Color::Primary).to_class(), "text-primary"); + /// assert_eq!(ColorText::Emphasis(Color::Danger).to_class(), "text-danger-emphasis"); + /// assert_eq!(ColorText::Black.to_class(), "text-black"); + /// assert_eq!(ColorText::Default.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + if let Some(suffix) = self.suffix() { + let base_len = match self { + Self::Theme(c) | Self::Emphasis(c) => Self::TEXT_PREFIX.len() + c.as_str().len(), + _ => Self::TEXT.len(), + }; + let mut class = String::with_capacity(base_len + suffix.len()); + match self { + Self::Theme(c) | Self::Emphasis(c) => { + class.push_str(Self::TEXT_PREFIX); + class.push_str(c.as_str()); + } + _ => class.push_str(Self::TEXT), + } + class.push_str(suffix); + return class; + } + String::new() + } } diff --git a/extensions/pagetop-bootsier/src/theme/aux/layout.rs b/extensions/pagetop-bootsier/src/theme/aux/layout.rs new file mode 100644 index 00000000..1d351582 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/layout.rs @@ -0,0 +1,104 @@ +use pagetop::prelude::*; + +// **< ScaleSize >********************************************************************************** + +/// Escala discreta de tamaños para definir clases utilitarias. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum ScaleSize { + /// Sin tamaño (no define ninguna clase). + #[default] + None, + /// Tamaño automático. + Auto, + /// Escala cero. + Zero, + /// Escala uno. + One, + /// Escala dos. + Two, + /// Escala tres. + Three, + /// Escala cuatro. + Four, + /// Escala cinco. + Five, +} + +impl ScaleSize { + // Devuelve el sufijo para el tamaño (`"-0"`, `"-1"`, etc.), o `None` si no define ninguna + // clase, o `""` para el tamaño automático. + #[rustfmt::skip] + #[inline] + const fn suffix(self) -> Option<&'static str> { + match self { + Self::None => None, + Self::Auto => Some(""), + Self::Zero => Some("-0"), + Self::One => Some("-1"), + Self::Two => Some("-2"), + Self::Three => Some("-3"), + Self::Four => Some("-4"), + Self::Five => Some("-5"), + } + } + + // Añade el tamaño a la cadena de clases usando el prefijo dado. + #[inline] + pub(crate) fn push_class(self, classes: &mut String, prefix: &str) { + if !prefix.is_empty() { + if let Some(suffix) = self.suffix() { + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(prefix); + classes.push_str(suffix); + } + } + } + + /* Devuelve la clase del tamaño para el prefijo, o una cadena vacía si no aplica (reservado). + // + // # Ejemplo + // + // ```rust + // # use pagetop_bootsier::prelude::*; + // assert_eq!(ScaleSize::Auto.class_with("border"), "border"); + // assert_eq!(ScaleSize::Zero.class_with("m"), "m-0"); + // assert_eq!(ScaleSize::Three.class_with("p"), "p-3"); + // assert_eq!(ScaleSize::None.class_with("border"), ""); + // ``` + #[inline] + pub(crate) fn class_with(self, prefix: &str) -> String { + if !prefix.is_empty() { + if let Some(suffix) = self.suffix() { + let mut class = String::with_capacity(prefix.len() + suffix.len()); + class.push_str(prefix); + class.push_str(suffix); + return class; + } + } + String::new() + } */ +} + +// **< Side >*************************************************************************************** + +/// Lados sobre los que aplicar una clase utilitaria (respetando LTR/RTL). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Side { + /// Todos los lados. + #[default] + All, + /// Lado superior. + Top, + /// Lado inferior. + Bottom, + /// Lado lógico de inicio (respetando RTL). + Start, + /// Lado lógico de fin (respetando RTL). + End, + /// Lados lógicos laterales (abreviatura *x*). + LeftAndRight, + /// Lados superior e inferior (abreviatura *y*). + TopAndBottom, +} diff --git a/extensions/pagetop-bootsier/src/theme/aux/rounded.rs b/extensions/pagetop-bootsier/src/theme/aux/rounded.rs index 8eac7c53..20e061d6 100644 --- a/extensions/pagetop-bootsier/src/theme/aux/rounded.rs +++ b/extensions/pagetop-bootsier/src/theme/aux/rounded.rs @@ -1,52 +1,117 @@ use pagetop::prelude::*; -use std::fmt; - /// Radio para el redondeo de esquinas ([`classes::Rounded`](crate::theme::classes::Rounded)). -/// -/// Mapea a `rounded`, `rounded-0`, `rounded-{1..5}`, `rounded-circle` y `rounded-pill`. -/// -/// - `None` no añade ninguna clase. -/// - `Default` genera `rounded` (radio por defecto del tema). -/// - `Zero` genera `rounded-0` (sin redondeo). -/// - `Scale{1..5}` genera `rounded-{1..5}` (radio creciente). -/// - `Circle` genera `rounded-circle`. -/// - `Pill` genera `rounded-pill`. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum RoundedRadius { + /// No define ninguna clase. #[default] None, + /// Genera `rounded` (radio por defecto del tema). Default, + /// Genera `rounded-0` (sin redondeo). Zero, + /// Genera `rounded-1`. Scale1, + /// Genera `rounded-2`. Scale2, + /// Genera `rounded-3`. Scale3, + /// Genera `rounded-4`. Scale4, + /// Genera `rounded-5`. Scale5, + /// Genera `rounded-circle`. Circle, + /// Genera `rounded-pill`. Pill, } impl RoundedRadius { + const ROUNDED: &str = "rounded"; + + // Devuelve el sufijo para `*rounded-*`, o `None` si no define ninguna clase, o `""` para el + // redondeo por defecto. #[rustfmt::skip] - pub(crate) fn to_class(&self, prefix: impl AsRef<str>) -> String { + #[inline] + const fn suffix(self) -> Option<&'static str> { match self { - RoundedRadius::None => String::new(), - RoundedRadius::Default => String::from(prefix.as_ref()), - RoundedRadius::Zero => join!(prefix, "-0"), - RoundedRadius::Scale1 => join!(prefix, "-1"), - RoundedRadius::Scale2 => join!(prefix, "-2"), - RoundedRadius::Scale3 => join!(prefix, "-3"), - RoundedRadius::Scale4 => join!(prefix, "-4"), - RoundedRadius::Scale5 => join!(prefix, "-5"), - RoundedRadius::Circle => join!(prefix, "-circle"), - RoundedRadius::Pill => join!(prefix, "-pill"), + Self::None => None, + Self::Default => Some(""), + Self::Zero => Some("-0"), + Self::Scale1 => Some("-1"), + Self::Scale2 => Some("-2"), + Self::Scale3 => Some("-3"), + Self::Scale4 => Some("-4"), + Self::Scale5 => Some("-5"), + Self::Circle => Some("-circle"), + Self::Pill => Some("-pill"), } } -} -impl fmt::Display for RoundedRadius { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.to_class("rounded")) + // Añade el redondeo de esquinas a la cadena de clases usando el prefijo dado (`rounded-top`, + // `rounded-bottom-start`, o vacío para `rounded-*`). + #[inline] + pub(crate) fn push_class(self, classes: &mut String, prefix: &str) { + if let Some(suffix) = self.suffix() { + if !classes.is_empty() { + classes.push(' '); + } + if prefix.is_empty() { + classes.push_str(Self::ROUNDED); + } else { + classes.push_str(prefix); + } + classes.push_str(suffix); + } + } + + // Devuelve la clase para el redondeo de esquinas con el prefijo dado (`rounded-top`, + // `rounded-bottom-start`, o vacío para `rounded-*`). + // + // # Ejemplos + // + // ```rust + // # use pagetop_bootsier::prelude::*; + // assert_eq!(RoundedRadius::Scale2.class_with(""), "rounded-2"); + // assert_eq!(RoundedRadius::Zero.class_with("rounded-top"), "rounded-top-0"); + // assert_eq!(RoundedRadius::Scale3.class_with("rounded-top-end"), "rounded-top-end-3"); + // assert_eq!(RoundedRadius::Circle.class_with(""), "rounded-circle"); + // assert_eq!(RoundedRadius::None.class_with("rounded-bottom-start"), ""); + // ``` + #[inline] + pub(crate) fn class_with(self, prefix: &str) -> String { + if let Some(suffix) = self.suffix() { + let base_len = if prefix.is_empty() { + Self::ROUNDED.len() + } else { + prefix.len() + }; + let mut class = String::with_capacity(base_len + suffix.len()); + if prefix.is_empty() { + class.push_str(Self::ROUNDED); + } else { + class.push_str(prefix); + } + class.push_str(suffix); + return class; + } + String::new() + } + + /// Devuelve la clase `rounded-*` para el redondeo de esquinas. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(RoundedRadius::Default.to_class(), "rounded"); + /// assert_eq!(RoundedRadius::Zero.to_class(), "rounded-0"); + /// assert_eq!(RoundedRadius::Scale3.to_class(), "rounded-3"); + /// assert_eq!(RoundedRadius::Circle.to_class(), "rounded-circle"); + /// assert_eq!(RoundedRadius::None.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + self.class_with("") } } diff --git a/extensions/pagetop-bootsier/src/theme/classes.rs b/extensions/pagetop-bootsier/src/theme/classes.rs index 4e586e11..9e6c234d 100644 --- a/extensions/pagetop-bootsier/src/theme/classes.rs +++ b/extensions/pagetop-bootsier/src/theme/classes.rs @@ -8,3 +8,6 @@ pub use border::Border; mod rounded; pub use rounded::Rounded; + +mod layout; +pub use layout::{Margin, Padding}; diff --git a/extensions/pagetop-bootsier/src/theme/classes/border.rs b/extensions/pagetop-bootsier/src/theme/classes/border.rs index f49c75c6..3095498c 100644 --- a/extensions/pagetop-bootsier/src/theme/classes/border.rs +++ b/extensions/pagetop-bootsier/src/theme/classes/border.rs @@ -1,122 +1,113 @@ use pagetop::prelude::*; -use crate::theme::aux::{BorderColor, BorderSize, Opacity}; - -use std::fmt; +use crate::theme::aux::{BorderColor, Opacity, ScaleSize, Side}; /// Clases para crear **bordes**. /// /// Permite: /// +/// - Iniciar un borde sin tamaño inicial (`Border::default()`). +/// - Crear un borde con tamaño por defecto (`Border::new()`). +/// - Ajustar el tamaño de cada **lado lógico** (`side`, respetando LTR/RTL). /// - Definir un tamaño **global** para todo el borde (`size`). -/// - Ajustar el tamaño de cada **lado lógico** (`top`, `end`, `bottom`, `start`, **en este orden**, -/// respetando LTR/RTL). /// - Aplicar un **color** al borde (`BorderColor`). /// - Aplicar un nivel de **opacidad** (`Opacity`). /// /// # Comportamiento aditivo / sustractivo /// -/// - **Aditivo**: basta con crear un borde sin tamaño con `classes::Border::new()` para ir -/// añadiendo cada lado lógico con el tamaño deseado usando `BorderSize::Scale{1..5}`. +/// - **Aditivo**: basta con crear un borde sin tamaño con `classes::Border::default()` para ir +/// añadiendo cada lado lógico con el tamaño deseado usando `ScaleSize::{One..Five}`. /// -/// - **Sustractivo**: se crea un borde con tamaño predefinido, p. ej. utilizando -/// `classes::Border::with(BorderSize::Scale2)` y eliminar los lados deseados con `BorderSize::Zero`. +/// - **Sustractivo**: se crea un borde con tamaño predefinido, p. ej. usando +/// `classes::Border::new()` o `classes::Border::with(ScaleSize::Two)` y eliminar los lados +/// deseados con `ScaleSize::Zero`. /// -/// - **Anchos diferentes por lado**: usando `BorderSize::Scale{1..5}` en cada lado deseado. +/// - **Anchos diferentes por lado**: usando `ScaleSize::{Zero..Five}` en cada lado deseado. /// /// # Ejemplos /// /// **Borde global:** /// ```rust /// # use pagetop_bootsier::prelude::*; -/// let b = classes::Border::with(BorderSize::Scale2); -/// assert_eq!(b.to_string(), "border-2"); +/// let b = classes::Border::with(ScaleSize::Two); +/// assert_eq!(b.to_class(), "border-2"); /// ``` /// /// **Aditivo (solo borde superior):** /// ```rust /// # use pagetop_bootsier::prelude::*; -/// let b = classes::Border::new().with_top(BorderSize::Scale1); -/// assert_eq!(b.to_string(), "border-top-1"); +/// let b = classes::Border::default().with_side(Side::Top, ScaleSize::One); +/// assert_eq!(b.to_class(), "border-top-1"); /// ``` /// /// **Sustractivo (borde global menos el superior):** /// ```rust /// # use pagetop_bootsier::prelude::*; -/// let b = classes::Border::with(BorderSize::Default).with_top(BorderSize::Zero); -/// assert_eq!(b.to_string(), "border border-top-0"); +/// let b = classes::Border::new().with_side(Side::Top, ScaleSize::Zero); +/// assert_eq!(b.to_class(), "border border-top-0"); /// ``` /// /// **Ancho por lado (lado lógico inicial a 2 y final a 4):** /// ```rust /// # use pagetop_bootsier::prelude::*; -/// let b = classes::Border::new().with_start(BorderSize::Scale2).with_end(BorderSize::Scale4); -/// assert_eq!(b.to_string(), "border-end-4 border-start-2"); +/// let b = classes::Border::default() +/// .with_side(Side::Start, ScaleSize::Two) +/// .with_side(Side::End, ScaleSize::Four); +/// assert_eq!(b.to_class(), "border-end-4 border-start-2"); /// ``` /// /// **Combinado (ejemplo completo):** /// ```rust /// # use pagetop_bootsier::prelude::*; -/// let b = classes::Border::with(BorderSize::Default) // Borde global por defecto. -/// .with_top(BorderSize::Zero) // Quita borde superior. -/// .with_end(BorderSize::Scale3) // Ancho 3 para el lado lógico final. +/// let b = classes::Border::new() // Borde por defecto. +/// .with_side(Side::Top, ScaleSize::Zero) // Quita borde superior. +/// .with_side(Side::End, ScaleSize::Three) // Ancho 3 para el lado lógico final. /// .with_color(BorderColor::Theme(Color::Primary)) /// .with_opacity(Opacity::Half); /// -/// assert_eq!(b.to_string(), "border border-top-0 border-end-3 border-primary border-opacity-50"); +/// assert_eq!(b.to_class(), "border border-top-0 border-end-3 border-primary border-opacity-50"); /// ``` #[rustfmt::skip] -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub struct Border { - size : BorderSize, - top : BorderSize, - end : BorderSize, - bottom : BorderSize, - start : BorderSize, + all : ScaleSize, + top : ScaleSize, + end : ScaleSize, + bottom : ScaleSize, + start : ScaleSize, color : BorderColor, opacity: Opacity, } impl Border { - /// Prepara un borde **sin tamaño global** de partida. + /// Prepara un borde del tamaño predefinido. Equivale a `border` (ancho por defecto del tema). pub fn new() -> Self { - Self::default() + Self::with(ScaleSize::Auto) } - /// Crea un borde **con tamaño global** (`size`). - pub fn with(size: BorderSize) -> Self { - Self::default().with_size(size) + /// Crea un borde **con un tamaño global** (`size`). + pub fn with(size: ScaleSize) -> Self { + Self::default().with_side(Side::All, size) } // **< Border BUILDER >************************************************************************* - /// Establece el tamaño global del borde (`border*`). - pub fn with_size(mut self, size: BorderSize) -> Self { - self.size = size; - self - } - - /// Establece el tamaño del borde superior (`border-top-*`). - pub fn with_top(mut self, size: BorderSize) -> Self { - self.top = size; - self - } - - /// Establece el tamaño del borde en el lado lógico final (`border-end-*`). Respeta LTR/RTL. - pub fn with_end(mut self, size: BorderSize) -> Self { - self.end = size; - self - } - - /// Establece el tamaño del borde inferior (`border-bottom-*`). - pub fn with_bottom(mut self, size: BorderSize) -> Self { - self.bottom = size; - self - } - - /// Establece el tamaño del borde en el lado lógico inicial (`border-start-*`). Respeta LTR/RTL. - pub fn with_start(mut self, size: BorderSize) -> Self { - self.start = size; + pub fn with_side(mut self, side: Side, size: ScaleSize) -> Self { + match side { + Side::All => self.all = size, + Side::Top => self.top = size, + Side::Bottom => self.bottom = size, + Side::Start => self.start = size, + Side::End => self.end = size, + Side::LeftAndRight => { + self.start = size; + self.end = size; + } + Side::TopAndBottom => { + self.top = size; + self.bottom = size; + } + }; self } @@ -131,25 +122,54 @@ impl Border { self.opacity = opacity; self } -} -impl fmt::Display for Border { - /// Concatena, en este orden, las clases para *global*, `top`, `end`, `bottom`, `start`, *color* - /// y *opacidad*; respetando LTR/RTL y omitiendo las definiciones vacías. - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - [ - self.size.to_string(), - self.top.to_class("border-top"), - self.end.to_class("border-end"), - self.bottom.to_class("border-bottom"), - self.start.to_class("border-start"), - self.color.to_string(), - self.opacity.to_class("border"), - ] - .join_classes() - ) + // **< Border HELPERS >************************************************************************* + + /// Añade las clases de borde a la cadena de clases. + /// + /// Concatena, en este orden, las clases para *global*, `top`, `end`, `bottom`, `start`, + /// *color* y *opacidad*; respetando LTR/RTL y omitiendo las definiciones vacías. + #[rustfmt::skip] + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + self.all .push_class(classes, "border"); + self.top .push_class(classes, "border-top"); + self.end .push_class(classes, "border-end"); + self.bottom .push_class(classes, "border-bottom"); + self.start .push_class(classes, "border-start"); + self.color .push_class(classes); + self.opacity.push_class(classes, "border"); + } + + /// Devuelve las clases de borde como cadena (`"border-2"`, + /// `"border border-top-0 border-end-3 border-primary border-opacity-50"`, etc.). + /// + /// Si no se define ningún tamaño, color ni opacidad, devuelve `""`. + #[inline] + pub fn to_class(self) -> String { + let mut classes = String::new(); + self.push_class(&mut classes); + classes + } +} + +/// Atajo para crear un [`classes::Border`](crate::theme::classes::Border) a partir de un tamaño +/// [`ScaleSize`] aplicado a todo el borde. +/// +/// # Ejemplos +/// +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// // Convertir explícitamente con `From::from`: +/// let b = classes::Border::from(ScaleSize::Two); +/// assert_eq!(b.to_class(), "border-2"); +/// +/// // Convertir implícitamente con `into()`: +/// let b: classes::Border = ScaleSize::Auto.into(); +/// assert_eq!(b.to_class(), "border"); +/// ``` +impl From<ScaleSize> for Border { + fn from(size: ScaleSize) -> Self { + Self::with(size) } } diff --git a/extensions/pagetop-bootsier/src/theme/classes/color.rs b/extensions/pagetop-bootsier/src/theme/classes/color.rs index 6579d21c..162b7849 100644 --- a/extensions/pagetop-bootsier/src/theme/classes/color.rs +++ b/extensions/pagetop-bootsier/src/theme/classes/color.rs @@ -2,9 +2,7 @@ use pagetop::prelude::*; use crate::theme::aux::{ColorBg, ColorText, Opacity}; -use std::fmt; - -// **< Bg >***************************************************************************************** +// **< Background >********************************************************************************* /// Clases para establecer **color/opacidad del fondo**. /// @@ -14,28 +12,27 @@ use std::fmt; /// # use pagetop_bootsier::prelude::*; /// // Sin clases. /// let s = classes::Background::new(); -/// assert_eq!(s.to_string(), ""); +/// assert_eq!(s.to_class(), ""); /// /// // Sólo color de fondo. /// let s = classes::Background::with(ColorBg::Theme(Color::Primary)); -/// assert_eq!(s.to_string(), "bg-primary"); +/// assert_eq!(s.to_class(), "bg-primary"); /// /// // Color más opacidad. /// let s = classes::Background::with(ColorBg::BodySecondary).with_opacity(Opacity::Half); -/// assert_eq!(s.to_string(), "bg-body-secondary bg-opacity-50"); +/// assert_eq!(s.to_class(), "bg-body-secondary bg-opacity-50"); /// /// // Usando `From<ColorBg>`. /// let s: classes::Background = ColorBg::Black.into(); -/// assert_eq!(s.to_string(), "bg-black"); +/// assert_eq!(s.to_class(), "bg-black"); /// /// // Usando `From<(ColorBg, Opacity)>`. /// let s: classes::Background = (ColorBg::White, Opacity::SemiTransparent).into(); -/// assert_eq!(s.to_string(), "bg-white bg-opacity-25"); +/// assert_eq!(s.to_class(), "bg-white bg-opacity-25"); /// ``` -#[rustfmt::skip] -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub struct Background { - color : ColorBg, + color: ColorBg, opacity: Opacity, } @@ -50,7 +47,7 @@ impl Background { Self::default().with_color(color) } - // **< Bg BUILDER >***************************************************************************** + // **< Background BUILDER >********************************************************************* /// Establece el color de fondo (`bg-*`). pub fn with_color(mut self, color: ColorBg) -> Self { @@ -63,14 +60,27 @@ impl Background { self.opacity = opacity; self } -} -impl fmt::Display for Background { - /// Concatena, en este orden, color del fondo (`bg-*`) y opacidad (`bg-opacity-*`), omitiendo - /// las definiciones vacías. - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let classes = [self.color.to_string(), self.opacity.to_class("bg")].join_classes(); - write!(f, "{classes}") + // **< Background HELPERS >********************************************************************* + + /// Añade las clases de fondo a la cadena de clases. + /// + /// Concatena, en este orden, color del fondo (`bg-*`) y opacidad (`bg-opacity-*`), + /// omitiendo los fragmentos vacíos. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + self.color.push_class(classes); + self.opacity.push_class(classes, "bg"); + } + + /// Devuelve las clases de fondo como cadena (`"bg-primary"`, `"bg-body-secondary bg-opacity-50"`, etc.). + /// + /// Si no se define ni color ni opacidad, devuelve `""`. + #[inline] + pub fn to_class(self) -> String { + let mut classes = String::new(); + self.push_class(&mut classes); + classes } } @@ -83,7 +93,7 @@ impl From<(ColorBg, Opacity)> for Background { /// ``` /// # use pagetop_bootsier::prelude::*; /// let s: classes::Background = (ColorBg::White, Opacity::SemiTransparent).into(); - /// assert_eq!(s.to_string(), "bg-white bg-opacity-25"); + /// assert_eq!(s.to_class(), "bg-white bg-opacity-25"); /// ``` fn from((color, opacity): (ColorBg, Opacity)) -> Self { Background::with(color).with_opacity(opacity) @@ -98,7 +108,7 @@ impl From<ColorBg> for Background { /// ``` /// # use pagetop_bootsier::prelude::*; /// let s: classes::Background = ColorBg::Black.into(); - /// assert_eq!(s.to_string(), "bg-black"); + /// assert_eq!(s.to_class(), "bg-black"); /// ``` fn from(color: ColorBg) -> Self { Background::with(color) @@ -115,28 +125,27 @@ impl From<ColorBg> for Background { /// # use pagetop_bootsier::prelude::*; /// // Sin clases. /// let s = classes::Text::new(); -/// assert_eq!(s.to_string(), ""); +/// assert_eq!(s.to_class(), ""); /// /// // Sólo color del texto. /// let s = classes::Text::with(ColorText::Theme(Color::Primary)); -/// assert_eq!(s.to_string(), "text-primary"); +/// assert_eq!(s.to_class(), "text-primary"); /// /// // Color del texto y opacidad. /// let s = classes::Text::new().with_color(ColorText::White).with_opacity(Opacity::SemiTransparent); -/// assert_eq!(s.to_string(), "text-white text-opacity-25"); +/// assert_eq!(s.to_class(), "text-white text-opacity-25"); /// /// // Usando `From<ColorText>`. /// let s: classes::Text = ColorText::Black.into(); -/// assert_eq!(s.to_string(), "text-black"); +/// assert_eq!(s.to_class(), "text-black"); /// /// // Usando `From<(ColorText, Opacity)>`. /// let s: classes::Text = (ColorText::Theme(Color::Danger), Opacity::Opaque).into(); -/// assert_eq!(s.to_string(), "text-danger text-opacity-100"); +/// assert_eq!(s.to_class(), "text-danger text-opacity-100"); /// ``` -#[rustfmt::skip] -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub struct Text { - color : ColorText, + color: ColorText, opacity: Opacity, } @@ -164,13 +173,27 @@ impl Text { self.opacity = opacity; self } -} -impl fmt::Display for Text { - /// Concatena, en este orden, `text-*` y `text-opacity-*`, omitiendo las definiciones vacías. - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let classes = [self.color.to_string(), self.opacity.to_class("text")].join_classes(); - write!(f, "{classes}") + // **< Text HELPERS >*************************************************************************** + + /// Añade las clases de texto a la cadena de clases. + /// + /// Concatena, en este orden, `text-*` y `text-opacity-*`, omitiendo los fragmentos vacíos. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + self.color.push_class(classes); + self.opacity.push_class(classes, "text"); + } + + /// Devuelve las clases de texto como cadena (`"text-primary"`, `"text-white text-opacity-25"`, + /// etc.). + /// + /// Si no se define ni color ni opacidad, devuelve `""`. + #[inline] + pub fn to_class(self) -> String { + let mut classes = String::new(); + self.push_class(&mut classes); + classes } } @@ -183,7 +206,7 @@ impl From<(ColorText, Opacity)> for Text { /// ``` /// # use pagetop_bootsier::prelude::*; /// let s: classes::Text = (ColorText::Theme(Color::Danger), Opacity::Opaque).into(); - /// assert_eq!(s.to_string(), "text-danger text-opacity-100"); + /// assert_eq!(s.to_class(), "text-danger text-opacity-100"); /// ``` fn from((color, opacity): (ColorText, Opacity)) -> Self { Text::with(color).with_opacity(opacity) @@ -199,7 +222,7 @@ impl From<ColorText> for Text { /// ``` /// # use pagetop_bootsier::prelude::*; /// let s: classes::Text = ColorText::Black.into(); - /// assert_eq!(s.to_string(), "text-black"); + /// assert_eq!(s.to_class(), "text-black"); /// ``` fn from(color: ColorText) -> Self { Text::with(color) diff --git a/extensions/pagetop-bootsier/src/theme/classes/layout.rs b/extensions/pagetop-bootsier/src/theme/classes/layout.rs new file mode 100644 index 00000000..e9d7e248 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/classes/layout.rs @@ -0,0 +1,205 @@ +use pagetop::prelude::*; + +use crate::theme::aux::{ScaleSize, Side}; +use crate::theme::BreakPoint; + +// **< Margin >************************************************************************************* + +/// Clases para establecer **margin** por lado, tamaño y punto de ruptura. +/// +/// # Ejemplos +/// +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let m = classes::Margin::with(Side::Top, ScaleSize::Three); +/// assert_eq!(m.to_class(), "mt-3"); +/// +/// let m = classes::Margin::with(Side::Start, ScaleSize::Auto).with_breakpoint(BreakPoint::LG); +/// assert_eq!(m.to_class(), "ms-lg-auto"); +/// +/// let m = classes::Margin::with(Side::All, ScaleSize::None); +/// assert_eq!(m.to_class(), ""); +/// ``` +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub struct Margin { + side: Side, + size: ScaleSize, + breakpoint: BreakPoint, +} + +impl Margin { + /// Crea un **margin** indicando lado(s) y tamaño. Por defecto no se aplica a ningún punto de + /// ruptura. + pub fn with(side: Side, size: ScaleSize) -> Self { + Margin { + side, + size, + breakpoint: BreakPoint::None, + } + } + + // **< Margin BUILDER >************************************************************************* + + /// Establece el punto de ruptura a partir del cual se empieza a aplicar el **margin**. + pub fn with_breakpoint(mut self, breakpoint: BreakPoint) -> Self { + self.breakpoint = breakpoint; + self + } + + // **< Margin HELPERS >************************************************************************* + + // Devuelve el prefijo `m*` según el lado. + #[rustfmt::skip] + #[inline] + const fn side_prefix(&self) -> &'static str { + match self.side { + Side::All => "m", + Side::Top => "mt", + Side::Bottom => "mb", + Side::Start => "ms", + Side::End => "me", + Side::LeftAndRight => "mx", + Side::TopAndBottom => "my", + } + } + + // Devuelve el sufijo del tamaño (`auto`, `0`..`5`), o `None` si no define clase. + #[rustfmt::skip] + #[inline] + const fn size_suffix(&self) -> Option<&'static str> { + match self.size { + ScaleSize::None => None, + ScaleSize::Auto => Some("auto"), + ScaleSize::Zero => Some("0"), + ScaleSize::One => Some("1"), + ScaleSize::Two => Some("2"), + ScaleSize::Three => Some("3"), + ScaleSize::Four => Some("4"), + ScaleSize::Five => Some("5"), + } + } + + /* Añade la clase de **margin** a la cadena de clases (reservado). + // + // No añade nada si `size` es `ScaleSize::None`. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + let Some(size) = self.size_suffix() else { + return; + }; + self.breakpoint + .push_class(classes, self.side_prefix(), size); + } */ + + /// Devuelve la clase de **margin** como cadena (`"mt-3"`, `"ms-lg-auto"`, etc.). + /// + /// Si `size` es `ScaleSize::None`, devuelve `""`. + #[inline] + pub fn to_class(self) -> String { + let Some(size) = self.size_suffix() else { + return String::new(); + }; + self.breakpoint.class_with(self.side_prefix(), size) + } +} + +// **< Padding >************************************************************************************ + +/// Clases para establecer **padding** por lado, tamaño y punto de ruptura. +/// +/// # Ejemplos +/// +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let p = classes::Padding::with(Side::LeftAndRight, ScaleSize::Two); +/// assert_eq!(p.to_class(), "px-2"); +/// +/// let p = classes::Padding::with(Side::End, ScaleSize::Four).with_breakpoint(BreakPoint::SM); +/// assert_eq!(p.to_class(), "pe-sm-4"); +/// +/// let p = classes::Padding::with(Side::All, ScaleSize::Auto); +/// assert_eq!(p.to_class(), ""); // `Auto` no aplica a padding. +/// ``` +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub struct Padding { + side: Side, + size: ScaleSize, + breakpoint: BreakPoint, +} + +impl Padding { + /// Crea un **padding** indicando lado(s) y tamaño. Por defecto no se aplica a ningún punto de + /// ruptura. + pub fn with(side: Side, size: ScaleSize) -> Self { + Padding { + side, + size, + breakpoint: BreakPoint::None, + } + } + + // **< Padding BUILDER >************************************************************************ + + /// Establece el punto de ruptura a partir del cual se empieza a aplicar el **padding**. + pub fn with_breakpoint(mut self, breakpoint: BreakPoint) -> Self { + self.breakpoint = breakpoint; + self + } + + // **< Padding HELPERS >************************************************************************ + + // Devuelve el prefijo `p*` según el lado. + #[rustfmt::skip] + #[inline] + const fn prefix(&self) -> &'static str { + match self.side { + Side::All => "p", + Side::Top => "pt", + Side::Bottom => "pb", + Side::Start => "ps", + Side::End => "pe", + Side::LeftAndRight => "px", + Side::TopAndBottom => "py", + } + } + + // Devuelve el sufijo del tamaño (`0`..`5`), o `None` si no define clase. + // + // Nota: `ScaleSize::Auto` **no aplica** a padding ⇒ devuelve `None`. + #[rustfmt::skip] + #[inline] + const fn suffix(&self) -> Option<&'static str> { + match self.size { + ScaleSize::None => None, + ScaleSize::Auto => None, + ScaleSize::Zero => Some("0"), + ScaleSize::One => Some("1"), + ScaleSize::Two => Some("2"), + ScaleSize::Three => Some("3"), + ScaleSize::Four => Some("4"), + ScaleSize::Five => Some("5"), + } + } + + /* Añade la clase de **padding** a la cadena de clases (reservado). + // + // No añade nada si `size` es `ScaleSize::None` o `ScaleSize::Auto`. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + let Some(size) = self.suffix() else { + return; + }; + self.breakpoint.push_class(classes, self.prefix(), size); + } */ + + // Devuelve la clase de **padding** como cadena (`"px-2"`, `"pe-sm-4"`, etc.). + // + // Si `size` es `ScaleSize::None` o `ScaleSize::Auto`, devuelve `""`. + #[inline] + pub fn to_class(self) -> String { + let Some(size) = self.suffix() else { + return String::new(); + }; + self.breakpoint.class_with(self.prefix(), size) + } +} diff --git a/extensions/pagetop-bootsier/src/theme/classes/rounded.rs b/extensions/pagetop-bootsier/src/theme/classes/rounded.rs index b7510c14..58d50b86 100644 --- a/extensions/pagetop-bootsier/src/theme/classes/rounded.rs +++ b/extensions/pagetop-bootsier/src/theme/classes/rounded.rs @@ -2,8 +2,6 @@ use pagetop::prelude::*; use crate::theme::aux::RoundedRadius; -use std::fmt; - /// Clases para definir **esquinas redondeadas**. /// /// Permite: @@ -20,28 +18,28 @@ use std::fmt; /// ```rust /// # use pagetop_bootsier::prelude::*; /// let r = classes::Rounded::with(RoundedRadius::Default); -/// assert_eq!(r.to_string(), "rounded"); +/// assert_eq!(r.to_class(), "rounded"); /// ``` /// /// **Sin redondeo:** /// ```rust /// # use pagetop_bootsier::prelude::*; /// let r = classes::Rounded::new(); -/// assert_eq!(r.to_string(), ""); +/// assert_eq!(r.to_class(), ""); /// ``` /// /// **Radio en las esquinas de un lado lógico:** /// ```rust /// # use pagetop_bootsier::prelude::*; /// let r = classes::Rounded::new().with_end(RoundedRadius::Scale2); -/// assert_eq!(r.to_string(), "rounded-end-2"); +/// assert_eq!(r.to_class(), "rounded-end-2"); /// ``` /// /// **Radio en una esquina concreta:** /// ```rust /// # use pagetop_bootsier::prelude::*; /// let r = classes::Rounded::new().with_top_start(RoundedRadius::Scale3); -/// assert_eq!(r.to_string(), "rounded-top-start-3"); +/// assert_eq!(r.to_class(), "rounded-top-start-3"); /// ``` /// /// **Combinado (ejemplo completo):** @@ -52,10 +50,10 @@ use std::fmt; /// .with_bottom_start(RoundedRadius::Scale4) // Añade una esquina redondeada concreta. /// .with_bottom_end(RoundedRadius::Circle); // Añade redondeo extremo en otra esquina. /// -/// assert_eq!(r.to_string(), "rounded-top rounded-bottom-start-4 rounded-bottom-end-circle"); +/// assert_eq!(r.to_class(), "rounded-top rounded-bottom-start-4 rounded-bottom-end-circle"); /// ``` #[rustfmt::skip] -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub struct Rounded { radius : RoundedRadius, top : RoundedRadius, @@ -136,28 +134,36 @@ impl Rounded { self.bottom_end = radius; self } -} -impl fmt::Display for Rounded { + // **< Rounded HELPERS >************************************************************************ + + /// Añade las clases de redondeo a la cadena de clases. + /// /// Concatena, en este orden, las clases para *global*, `top`, `end`, `bottom`, `start`, /// `top-start`, `top-end`, `bottom-start` y `bottom-end`; respetando LTR/RTL y omitiendo las /// definiciones vacías. - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - [ - self.radius.to_string(), - self.top.to_class("rounded-top"), - self.end.to_class("rounded-end"), - self.bottom.to_class("rounded-bottom"), - self.start.to_class("rounded-start"), - self.top_start.to_class("rounded-top-start"), - self.top_end.to_class("rounded-top-end"), - self.bottom_start.to_class("rounded-bottom-start"), - self.bottom_end.to_class("rounded-bottom-end"), - ] - .join_classes() - ) + #[rustfmt::skip] + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + self.radius .push_class(classes, ""); + self.top .push_class(classes, "rounded-top"); + self.end .push_class(classes, "rounded-end"); + self.bottom .push_class(classes, "rounded-bottom"); + self.start .push_class(classes, "rounded-start"); + self.top_start .push_class(classes, "rounded-top-start"); + self.top_end .push_class(classes, "rounded-top-end"); + self.bottom_start.push_class(classes, "rounded-bottom-start"); + self.bottom_end .push_class(classes, "rounded-bottom-end"); + } + + /// Devuelve las clases de redondeo como cadena (`"rounded"`, + /// `"rounded-top rounded-bottom-start-4 rounded-bottom-end-circle"`, etc.). + /// + /// Si no se define ningún radio, devuelve `""`. + #[inline] + pub fn to_class(self) -> String { + let mut classes = String::new(); + self.push_class(&mut classes); + classes } } diff --git a/extensions/pagetop-bootsier/src/theme/container/component.rs b/extensions/pagetop-bootsier/src/theme/container/component.rs index 1bcf1006..068d24a3 100644 --- a/extensions/pagetop-bootsier/src/theme/container/component.rs +++ b/extensions/pagetop-bootsier/src/theme/container/component.rs @@ -26,20 +26,7 @@ impl Component for Container { } fn setup_before_prepare(&mut self, _cx: &mut Context) { - self.alter_classes( - ClassesOp::Prepend, - [join_pair!( - "container", - "-", - match self.width() { - container::Width::Default => String::new(), - container::Width::From(bp) => bp.to_string(), - container::Width::Fluid => "fluid".to_string(), - container::Width::FluidMax(_) => "fluid".to_string(), - } - )] - .join_classes(), - ); + self.alter_classes(ClassesOp::Prepend, self.width().to_class()); } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { diff --git a/extensions/pagetop-bootsier/src/theme/container/props.rs b/extensions/pagetop-bootsier/src/theme/container/props.rs index 796e32f4..2010ba8e 100644 --- a/extensions/pagetop-bootsier/src/theme/container/props.rs +++ b/extensions/pagetop-bootsier/src/theme/container/props.rs @@ -1,14 +1,14 @@ use pagetop::prelude::*; -use crate::prelude::*; +use crate::theme::aux::BreakPoint; // **< Kind >*************************************************************************************** -/// Tipo de contenedor ([`Container`]). +/// Tipo de contenedor ([`Container`](crate::theme::Container)). /// /// Permite aplicar la etiqueta HTML apropiada (`<main>`, `<header>`, etc.) manteniendo una API /// común a todos los contenedores. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum Kind { /// Contenedor genérico (`<div>`). #[default] @@ -27,8 +27,8 @@ pub enum Kind { // **< Width >************************************************************************************** -/// Define el comportamiento para ajustar el ancho de un contenedor ([`Container`]). -#[derive(AutoDefault)] +/// Define cómo se comporta el ancho de un contenedor ([`Container`](crate::theme::Container)). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum Width { /// Comportamiento por defecto, aplica los anchos máximos predefinidos para cada punto de /// ruptura. Por debajo del menor punto de ruptura ocupa el 100% del ancho disponible. @@ -42,3 +42,31 @@ pub enum Width { /// Ocupa el 100% del ancho disponible hasta un ancho máximo explícito. FluidMax(UnitValue), } + +impl Width { + const CONTAINER: &str = "container"; + + /* Añade el comportamiento del contenedor a la cadena de clases según ancho (reservado). + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + match self { + Self::Default => BreakPoint::None.push_class(classes, Self::CONTAINER, ""), + Self::From(bp) => bp.push_class(classes, Self::CONTAINER, ""), + Self::Fluid | Self::FluidMax(_) => { + BreakPoint::None.push_class(classes, Self::CONTAINER, "fluid") + } + } + } */ + + /// Devuelve la clase asociada al comportamiento del contenedor según el ajuste de su ancho. + #[inline] + pub fn to_class(self) -> String { + match self { + Self::Default => BreakPoint::None.class_with(Self::CONTAINER, ""), + Self::From(bp) => bp.class_with(Self::CONTAINER, ""), + Self::Fluid | Self::FluidMax(_) => { + BreakPoint::None.class_with(Self::CONTAINER, "fluid") + } + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs index 450edff2..5d27daf5 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs @@ -45,21 +45,11 @@ impl Component for Dropdown { self.id.get() } - #[rustfmt::skip] fn setup_before_prepare(&mut self, _cx: &mut Context) { - let g = self.button_grouped(); - self.alter_classes(ClassesOp::Prepend, [ - if g { "btn-group" } else { "" }, - match self.direction() { - dropdown::Direction::Default if g => "", - dropdown::Direction::Default => "dropdown", - dropdown::Direction::Centered => "dropdown-center", - dropdown::Direction::Dropup => "dropup", - dropdown::Direction::DropupCentered => "dropup-center", - dropdown::Direction::Dropend => "dropend", - dropdown::Direction::Dropstart => "dropstart", - } - ].join_classes()); + self.alter_classes( + ClassesOp::Prepend, + self.direction().class_with(self.button_grouped()), + ); } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { @@ -75,41 +65,21 @@ impl Component for Dropdown { PrepareMarkup::With(html! { div id=[self.id()] class=[self.classes().get()] { @if !title.is_empty() { - @let mut btn_classes = AttrClasses::new([ - "btn", - &self.button_size().to_string(), - &self.button_color().to_string(), - ].join_classes()); - @let (offset, reference) = match self.menu_position() { - dropdown::MenuPosition::Default => (None, None), - dropdown::MenuPosition::Offset(x, y) => (Some(format!("{x},{y}")), None), - dropdown::MenuPosition::Parent => (None, Some("parent")), - }; - @let auto_close = match self.auto_close { - dropdown::AutoClose::Default => None, - dropdown::AutoClose::ClickableInside => Some("inside"), - dropdown::AutoClose::ClickableOutside => Some("outside"), - dropdown::AutoClose::ManualClose => Some("false"), - }; - @let menu_classes = AttrClasses::new("dropdown-menu") - .with_value(ClassesOp::Add, match self.menu_align() { - dropdown::MenuAlign::Start => String::new(), - dropdown::MenuAlign::StartAt(bp) => bp.try_class("dropdown-menu") - .map_or(String::new(), |class| join!(class, "-start")), - dropdown::MenuAlign::StartAndEnd(bp) => bp.try_class("dropdown-menu") - .map_or( - "dropdown-menu-start".into(), - |class| join!("dropdown-menu-start ", class, "-end") - ), - dropdown::MenuAlign::End => "dropdown-menu-end".into(), - dropdown::MenuAlign::EndAt(bp) => bp.try_class("dropdown-menu") - .map_or(String::new(), |class| join!(class, "-end")), - dropdown::MenuAlign::EndAndStart(bp) => bp.try_class("dropdown-menu") - .map_or( - "dropdown-menu-end".into(), - |class| join!("dropdown-menu-end ", class, "-start") - ), - }); + @let mut btn_classes = AttrClasses::new({ + let mut classes = "btn".to_string(); + self.button_size().push_class(&mut classes); + self.button_color().push_class(&mut classes); + classes + }); + @let pos = self.menu_position(); + @let offset = pos.data_offset(); + @let reference = pos.data_reference(); + @let auto_close = self.auto_close.as_str(); + @let menu_classes = AttrClasses::new({ + let mut classes = "dropdown-menu".to_string(); + self.menu_align().push_class(&mut classes); + classes + }); // Renderizado en modo split (dos botones) o simple (un botón). @if self.button_split() { diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/item.rs b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs index a13058dd..2f62f286 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/item.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs @@ -115,7 +115,7 @@ impl Component for Item { } ItemKind::Button { label, disabled } => { - let mut classes = "dropdown-item".to_owned(); + let mut classes = "dropdown-item".to_string(); if *disabled { classes.push_str(" disabled"); } diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/props.rs b/extensions/pagetop-bootsier/src/theme/dropdown/props.rs index da305ea7..7571332b 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/props.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/props.rs @@ -7,7 +7,7 @@ use crate::prelude::*; /// Estrategia para el cierre automático de un menú [`Dropdown`]. /// /// Define cuándo se cierra el menú desplegado según la interacción del usuario. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum AutoClose { /// Comportamiento por defecto, se cierra con clics dentro y fuera del menú, o pulsando `Esc`. #[default] @@ -21,12 +21,26 @@ pub enum AutoClose { ManualClose, } +impl AutoClose { + // Devuelve el valor para `data-bs-auto-close`, o `None` si es el comportamiento por defecto. + #[rustfmt::skip] + #[inline] + pub(crate) const fn as_str(self) -> Option<&'static str> { + match self { + Self::Default => None, + Self::ClickableInside => Some("inside"), + Self::ClickableOutside => Some("outside"), + Self::ManualClose => Some("false"), + } + } +} + // **< Direction >********************************************************************************** /// Dirección de despliegue de un menú [`Dropdown`]. /// /// Controla desde qué posición se muestra el menú respecto al botón. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum Direction { /// Comportamiento por defecto (despliega el menú hacia abajo desde la posición inicial, /// respetando LTR/RTL). @@ -44,13 +58,58 @@ pub enum Direction { Dropstart, } +impl Direction { + // Mapea la dirección teniendo en cuenta si se agrupa con otros menús [`Dropdown`]. + #[rustfmt::skip ] + #[inline] + const fn as_str(self, grouped: bool) -> &'static str { + match self { + Self::Default if grouped => "", + Self::Default => "dropdown", + Self::Centered => "dropdown-center", + Self::Dropup => "dropup", + Self::DropupCentered => "dropup-center", + Self::Dropend => "dropend", + Self::Dropstart => "dropstart", + } + } + + // Añade la dirección de despliegue a la cadena de clases teniendo en cuenta si se agrupa con + // otros menús [`Dropdown`]. + #[inline] + pub(crate) fn push_class(self, classes: &mut String, grouped: bool) { + if grouped { + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str("btn-group"); + } + let class = self.as_str(grouped); + if !class.is_empty() { + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } + } + + // Devuelve la clase asociada a la dirección teniendo en cuenta si se agrupa con otros menús + // [`Dropdown`], o `""` si no corresponde ninguna. + #[inline] + pub(crate) fn class_with(self, grouped: bool) -> String { + let mut classes = String::new(); + self.push_class(&mut classes, grouped); + classes + } +} + // **< MenuAlign >********************************************************************************** /// Alineación horizontal del menú desplegable [`Dropdown`]. /// /// Permite alinear el menú al inicio o al final del botón (respetando LTR/RTL) y añadirle una /// alineación diferente a partir de un punto de ruptura ([`BreakPoint`]). -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum MenuAlign { /// Alineación al inicio (comportamiento por defecto). #[default] @@ -67,13 +126,74 @@ pub enum MenuAlign { EndAndStart(BreakPoint), } +impl MenuAlign { + #[inline] + fn push_one(classes: &mut String, class: &str) { + if class.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } + + // Añade las clases de alineación a `classes` (sin incluir la base `dropdown-menu`). + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + match self { + // Alineación por defecto (start), no añade clases extra. + Self::Start => {} + + // `dropdown-menu-{bp}-start` + Self::StartAt(bp) => { + let class = bp.class_with("dropdown-menu", "start"); + Self::push_one(classes, &class); + } + + // `dropdown-menu-start` + `dropdown-menu-{bp}-end` + Self::StartAndEnd(bp) => { + Self::push_one(classes, "dropdown-menu-start"); + let bp_class = bp.class_with("dropdown-menu", "end"); + Self::push_one(classes, &bp_class); + } + + // `dropdown-menu-end` + Self::End => { + Self::push_one(classes, "dropdown-menu-end"); + } + + // `dropdown-menu-{bp}-end` + Self::EndAt(bp) => { + let class = bp.class_with("dropdown-menu", "end"); + Self::push_one(classes, &class); + } + + // `dropdown-menu-end` + `dropdown-menu-{bp}-start` + Self::EndAndStart(bp) => { + Self::push_one(classes, "dropdown-menu-end"); + let bp_class = bp.class_with("dropdown-menu", "start"); + Self::push_one(classes, &bp_class); + } + } + } + + /* Devuelve las clases de alineación sin incluir `dropdown-menu` (reservado). + #[inline] + pub(crate) fn to_class(self) -> String { + let mut classes = String::new(); + self.push_class(&mut classes); + classes + } */ +} + // **< MenuPosition >******************************************************************************* /// Posición relativa del menú desplegable [`Dropdown`]. /// /// Permite indicar un desplazamiento (*offset*) manual o referenciar al elemento padre para el /// cálculo de la posición. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum MenuPosition { /// Posicionamiento automático por defecto. #[default] @@ -84,3 +204,23 @@ pub enum MenuPosition { /// [`button_split()`](crate::theme::Dropdown::button_split) es `true`. Parent, } + +impl MenuPosition { + // Devuelve el valor para `data-bs-offset` o `None` si no aplica. + #[inline] + pub(crate) fn data_offset(self) -> Option<String> { + match self { + Self::Offset(x, y) => Some(format!("{x},{y}")), + _ => None, + } + } + + // Devuelve el valor para `data-bs-reference` o `None` si no aplica. + #[inline] + pub(crate) fn data_reference(self) -> Option<&'static str> { + match self { + Self::Parent => Some("parent"), + _ => None, + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/image/component.rs b/extensions/pagetop-bootsier/src/theme/image/component.rs index 2eda4302..bc3f2c9d 100644 --- a/extensions/pagetop-bootsier/src/theme/image/component.rs +++ b/extensions/pagetop-bootsier/src/theme/image/component.rs @@ -29,38 +29,11 @@ impl Component for Image { } fn setup_before_prepare(&mut self, _cx: &mut Context) { - self.alter_classes( - ClassesOp::Prepend, - match self.source() { - image::Source::Logo(_) => "img-fluid", - image::Source::Responsive(_) => "img-fluid", - image::Source::Thumbnail(_) => "img-thumbnail", - image::Source::Plain(_) => "", - }, - ); + self.alter_classes(ClassesOp::Prepend, self.source().to_class()); } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { - let dimensions = match self.size() { - image::Size::Auto => None, - image::Size::Dimensions(w, h) => { - let w = w.to_string(); - let h = h.to_string(); - Some(join!("width: ", w, "; height: ", h, ";")) - } - image::Size::Width(w) => { - let w = w.to_string(); - Some(join!("width: ", w, ";")) - } - image::Size::Height(h) => { - let h = h.to_string(); - Some(join!("height: ", h, ";")) - } - image::Size::Both(v) => { - let v = v.to_string(); - Some(join!("width: ", v, "; height: ", v, ";")) - } - }; + let dimensions = self.size().to_style(); let alt_text = self.alternative().lookup(cx).unwrap_or_default(); let is_decorative = alt_text.is_empty(); let source = match self.source() { diff --git a/extensions/pagetop-bootsier/src/theme/image/props.rs b/extensions/pagetop-bootsier/src/theme/image/props.rs index f871de70..e9b1286a 100644 --- a/extensions/pagetop-bootsier/src/theme/image/props.rs +++ b/extensions/pagetop-bootsier/src/theme/image/props.rs @@ -3,7 +3,7 @@ use pagetop::prelude::*; // **< Size >*************************************************************************************** /// Define las **dimensiones** de una imagen ([`Image`](crate::theme::Image)). -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum Size { /// Ajuste automático por defecto. /// @@ -30,10 +30,24 @@ pub enum Size { Both(UnitValue), } +impl Size { + // Devuelve el valor del atributo `style` en función del tamaño, o `None` si no aplica. + #[inline] + pub(crate) fn to_style(self) -> Option<String> { + match self { + Self::Auto => None, + Self::Dimensions(w, h) => Some(format!("width: {w}; height: {h};")), + Self::Width(w) => Some(format!("width: {w};")), + Self::Height(h) => Some(format!("height: {h};")), + Self::Both(v) => Some(format!("width: {v}; height: {v};")), + } + } +} + // **< Source >************************************************************************************* /// Especifica la **fuente** para publicar una imagen ([`Image`](crate::theme::Image)). -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Debug, PartialEq)] pub enum Source { /// Imagen con el logotipo de PageTop. #[default] @@ -51,3 +65,44 @@ pub enum Source { /// El `String` asociado es la URL (o ruta) de la imagen. Plain(String), } + +impl Source { + const IMG_FLUID: &str = "img-fluid"; + const IMG_THUMBNAIL: &str = "img-thumbnail"; + + // Devuelve la clase base asociada a la imagen según la fuente. + #[inline] + fn as_str(&self) -> &'static str { + match self { + Source::Logo(_) | Source::Responsive(_) => Self::IMG_FLUID, + Source::Thumbnail(_) => Self::IMG_THUMBNAIL, + Source::Plain(_) => "", + } + } + + /* Añade la clase base asociada a la imagen según la fuente a la cadena de clases (reservado). + #[inline] + pub(crate) fn push_class(&self, classes: &mut String) { + let s = self.as_str(); + if s.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(s); + } */ + + // Devuelve la clase asociada a la imagen según la fuente. + #[inline] + pub(crate) fn to_class(&self) -> String { + let s = self.as_str(); + if s.is_empty() { + String::new() + } else { + let mut class = String::with_capacity(s.len()); + class.push_str(s); + class + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/nav/component.rs b/extensions/pagetop-bootsier/src/theme/nav/component.rs index fe886bdd..2bd43774 100644 --- a/extensions/pagetop-bootsier/src/theme/nav/component.rs +++ b/extensions/pagetop-bootsier/src/theme/nav/component.rs @@ -30,28 +30,12 @@ impl Component for Nav { } fn setup_before_prepare(&mut self, _cx: &mut Context) { - self.alter_classes( - ClassesOp::Prepend, - [ - "nav", - match self.nav_kind() { - nav::Kind::Default => "", - nav::Kind::Tabs => "nav-tabs", - nav::Kind::Pills => "nav-pills", - nav::Kind::Underline => "nav-underline", - }, - match self.nav_layout() { - nav::Layout::Default => "", - nav::Layout::Start => "justify-content-start", - nav::Layout::Center => "justify-content-center", - nav::Layout::End => "justify-content-end", - nav::Layout::Vertical => "flex-column", - nav::Layout::Fill => "nav-fill", - nav::Layout::Justified => "nav-justified", - }, - ] - .join_classes(), - ); + self.alter_classes(ClassesOp::Prepend, { + let mut classes = "nav".to_string(); + self.nav_kind().push_class(&mut classes); + self.nav_layout().push_class(&mut classes); + classes + }); } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { diff --git a/extensions/pagetop-bootsier/src/theme/nav/item.rs b/extensions/pagetop-bootsier/src/theme/nav/item.rs index bc097e0c..a79947cd 100644 --- a/extensions/pagetop-bootsier/src/theme/nav/item.rs +++ b/extensions/pagetop-bootsier/src/theme/nav/item.rs @@ -29,6 +29,40 @@ pub enum ItemKind { Dropdown(Typed<Dropdown>), } +impl ItemKind { + const ITEM: &str = "nav-item"; + const DROPDOWN: &str = "nav-item dropdown"; + + // Devuelve las clases base asociadas al tipo de elemento. + #[inline] + const fn as_str(&self) -> &'static str { + match self { + Self::Void => "", + Self::Dropdown(_) => Self::DROPDOWN, + _ => Self::ITEM, + } + } + + /* Añade las clases asociadas al tipo de elemento a la cadena de clases (reservado). + #[inline] + pub(crate) fn push_class(&self, classes: &mut String) { + let class = self.as_str(); + if class.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } */ + + // Devuelve las clases asociadas al tipo de elemento. + #[inline] + pub(crate) fn to_class(&self) -> String { + self.as_str().to_owned() + } +} + // **< Item >*************************************************************************************** /// Representa un **elemento individual** de un menú [`Nav`](crate::theme::Nav). @@ -56,14 +90,7 @@ impl Component for Item { } fn setup_before_prepare(&mut self, _cx: &mut Context) { - self.alter_classes( - ClassesOp::Prepend, - if matches!(self.item_kind(), ItemKind::Dropdown(_)) { - "nav-item dropdown" - } else { - "nav-item" - }, - ); + self.alter_classes(ClassesOp::Prepend, self.item_kind().to_class()); } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { @@ -96,12 +123,12 @@ impl Component for Item { classes.push_str(" disabled"); } - let href = (!disabled).then_some(path); - let target = (!disabled && *blank).then_some("_blank"); - let rel = (!disabled && *blank).then_some("noopener noreferrer"); + let href = (!*disabled).then_some(path); + let target = (!*disabled && *blank).then_some("_blank"); + let rel = (!*disabled && *blank).then_some("noopener noreferrer"); let aria_current = (href.is_some() && is_current).then_some("page"); - let aria_disabled = disabled.then_some("true"); + let aria_disabled = (*disabled).then_some("true"); PrepareMarkup::With(html! { li id=[self.id()] class=[self.classes().get()] { diff --git a/extensions/pagetop-bootsier/src/theme/nav/props.rs b/extensions/pagetop-bootsier/src/theme/nav/props.rs index bd8ac1e1..46a4e2bc 100644 --- a/extensions/pagetop-bootsier/src/theme/nav/props.rs +++ b/extensions/pagetop-bootsier/src/theme/nav/props.rs @@ -3,7 +3,7 @@ use pagetop::prelude::*; // **< Kind >*************************************************************************************** /// Define la variante de presentación de un menú [`Nav`](crate::theme::Nav). -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum Kind { /// Estilo por defecto, lista de enlaces flexible y minimalista. #[default] @@ -16,10 +16,47 @@ pub enum Kind { Underline, } +impl Kind { + const TABS: &str = "nav-tabs"; + const PILLS: &str = "nav-pills"; + const UNDERLINE: &str = "nav-underline"; + + // Devuelve la clase base asociada al tipo de menú, o una cadena vacía si no aplica. + #[rustfmt::skip] + #[inline] + const fn as_str(self) -> &'static str { + match self { + Self::Default => "", + Self::Tabs => Self::TABS, + Self::Pills => Self::PILLS, + Self::Underline => Self::UNDERLINE, + } + } + + // Añade la clase asociada al tipo de menú a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + let class = self.as_str(); + if class.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } + + /* Devuelve la clase asociada al tipo de menú, o una cadena vacía si no aplica (reservado). + #[inline] + pub(crate) fn to_class(self) -> String { + self.as_str().to_owned() + } */ +} + // **< Layout >************************************************************************************* /// Distribución y orientación de un menú [`Nav`](crate::theme::Nav). -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum Layout { /// Comportamiento por defecto, ancho definido por el contenido y sin alineación forzada. #[default] @@ -37,3 +74,47 @@ pub enum Layout { /// Todos los elementos ocupan el mismo ancho rellenando la fila. Justified, } + +impl Layout { + const START: &str = "justify-content-start"; + const CENTER: &str = "justify-content-center"; + const END: &str = "justify-content-end"; + const VERTICAL: &str = "flex-column"; + const FILL: &str = "nav-fill"; + const JUSTIFIED: &str = "nav-justified"; + + // Devuelve la clase base asociada a la distribución y orientación del menú. + #[rustfmt::skip] + #[inline] + const fn as_str(self) -> &'static str { + match self { + Self::Default => "", + Self::Start => Self::START, + Self::Center => Self::CENTER, + Self::End => Self::END, + Self::Vertical => Self::VERTICAL, + Self::Fill => Self::FILL, + Self::Justified => Self::JUSTIFIED, + } + } + + // Añade la clase asociada a la distribución y orientación del menú a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + let class = self.as_str(); + if class.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } + + /* Devuelve la clase asociada a la distribución y orientación del menú, o una cadena vacía si no + // aplica (reservado). + #[inline] + pub(crate) fn to_class(self) -> String { + self.as_str().to_owned() + } */ +} diff --git a/extensions/pagetop-bootsier/src/theme/navbar/component.rs b/extensions/pagetop-bootsier/src/theme/navbar/component.rs index ac592439..b40d06c2 100644 --- a/extensions/pagetop-bootsier/src/theme/navbar/component.rs +++ b/extensions/pagetop-bootsier/src/theme/navbar/component.rs @@ -35,22 +35,12 @@ impl Component for Navbar { } fn setup_before_prepare(&mut self, _cx: &mut Context) { - self.alter_classes( - ClassesOp::Prepend, - [ - "navbar".to_string(), - self.expand().try_class("navbar-expand").unwrap_or_default(), - match self.position() { - navbar::Position::Static => "", - navbar::Position::FixedTop => "fixed-top", - navbar::Position::FixedBottom => "fixed-bottom", - navbar::Position::StickyTop => "sticky-top", - navbar::Position::StickyBottom => "sticky-bottom", - } - .to_string(), - ] - .join_classes(), - ); + self.alter_classes(ClassesOp::Prepend, { + let mut classes = "navbar".to_string(); + self.expand().push_class(&mut classes, "navbar-expand", ""); + self.position().push_class(&mut classes); + classes + }); } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { diff --git a/extensions/pagetop-bootsier/src/theme/navbar/item.rs b/extensions/pagetop-bootsier/src/theme/navbar/item.rs index 07f52be6..7e912a49 100644 --- a/extensions/pagetop-bootsier/src/theme/navbar/item.rs +++ b/extensions/pagetop-bootsier/src/theme/navbar/item.rs @@ -38,6 +38,14 @@ impl Component for Item { } } + fn setup_before_prepare(&mut self, _cx: &mut Context) { + if let Self::Nav(nav) = self { + if let Some(mut nav) = nav.borrow_mut() { + nav.alter_classes(ClassesOp::Prepend, "navbar-nav"); + } + } + } + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { match self { Self::Void => PrepareMarkup::None, @@ -48,29 +56,8 @@ impl Component for Item { if items.is_empty() { return PrepareMarkup::None; } - let classes = AttrClasses::new( - [ - "navbar-nav", - match nav.nav_kind() { - nav::Kind::Default => "", - nav::Kind::Tabs => "nav-tabs", - nav::Kind::Pills => "nav-pills", - nav::Kind::Underline => "nav-underline", - }, - match nav.nav_layout() { - nav::Layout::Default => "", - nav::Layout::Start => "justify-content-start", - nav::Layout::Center => "justify-content-center", - nav::Layout::End => "justify-content-end", - nav::Layout::Vertical => "flex-column", - nav::Layout::Fill => "nav-fill", - nav::Layout::Justified => "nav-justified", - }, - ] - .join_classes(), - ); PrepareMarkup::With(html! { - ul id=[nav.id()] class=[classes.get()] { + ul id=[nav.id()] class=[nav.classes().get()] { (items) } }) diff --git a/extensions/pagetop-bootsier/src/theme/navbar/props.rs b/extensions/pagetop-bootsier/src/theme/navbar/props.rs index 86326574..1aeb6170 100644 --- a/extensions/pagetop-bootsier/src/theme/navbar/props.rs +++ b/extensions/pagetop-bootsier/src/theme/navbar/props.rs @@ -42,7 +42,7 @@ pub enum Layout { // **< Position >*********************************************************************************** /// Posición global de una barra de navegación [`Navbar`] en el documento. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum Position { /// Barra normal, fluye con el documento. #[default] @@ -62,3 +62,37 @@ pub enum Position { /// La barra de navegación se fija en la parte inferior al hacer *scroll*. StickyBottom, } + +impl Position { + // Devuelve la clase base asociada a la posición de la barra de navegación. + #[inline] + const fn as_str(self) -> &'static str { + match self { + Self::Static => "", + Self::FixedTop => "fixed-top", + Self::FixedBottom => "fixed-bottom", + Self::StickyTop => "sticky-top", + Self::StickyBottom => "sticky-bottom", + } + } + + // Añade la clase asociada a la posición de la barra de navegación a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + let class = self.as_str(); + if class.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } + + /* Devuelve la clase asociada a la posición de la barra de navegación, o cadena vacía si no + // aplica (reservado). + #[inline] + pub(crate) fn to_class(self) -> String { + self.as_str().to_string() + } */ +} diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs b/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs index 7516238b..f17fe97a 100644 --- a/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs +++ b/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs @@ -44,25 +44,14 @@ impl Component for Offcanvas { self.id.get() } - #[rustfmt::skip] fn setup_before_prepare(&mut self, _cx: &mut Context) { - self.alter_classes( - ClassesOp::Prepend, - [ - self.breakpoint().to_class("offcanvas"), - match self.placement() { - offcanvas::Placement::Start => "offcanvas-start", - offcanvas::Placement::End => "offcanvas-end", - offcanvas::Placement::Top => "offcanvas-top", - offcanvas::Placement::Bottom => "offcanvas-bottom", - }.to_string(), - match self.visibility() { - offcanvas::Visibility::Default => "", - offcanvas::Visibility::Show => "show", - }.to_string(), - ] - .join_classes(), - ); + self.alter_classes(ClassesOp::Prepend, { + let mut classes = "offcanvas".to_string(); + self.breakpoint().push_class(&mut classes, "offcanvas", ""); + self.placement().push_class(&mut classes); + self.visibility().push_class(&mut classes); + classes + }); } fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas/props.rs b/extensions/pagetop-bootsier/src/theme/offcanvas/props.rs index cbacbd74..cdfe8623 100644 --- a/extensions/pagetop-bootsier/src/theme/offcanvas/props.rs +++ b/extensions/pagetop-bootsier/src/theme/offcanvas/props.rs @@ -4,7 +4,7 @@ use pagetop::prelude::*; /// Comportamiento de la capa de fondo (*backdrop*) de un panel /// [`Offcanvas`](crate::theme::Offcanvas) al deslizarse. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum Backdrop { /// Sin capa de fondo, la página principal permanece visible e interactiva. Disabled, @@ -20,7 +20,7 @@ pub enum Backdrop { /// Controla si la página principal puede desplazarse al abrir un panel /// [`Offcanvas`](crate::theme::Offcanvas). -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum BodyScroll { /// Opción por defecto, la página principal se bloquea centrando la interacción en el panel. #[default] @@ -34,7 +34,7 @@ pub enum BodyScroll { /// Posición de aparición de un panel [`Offcanvas`](crate::theme::Offcanvas) al deslizarse. /// /// Define desde qué borde de la ventana entra y se ancla el panel. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum Placement { /// Opción por defecto, desde el borde inicial según dirección de lectura (respetando LTR/RTL). #[default] @@ -47,10 +47,39 @@ pub enum Placement { Bottom, } +impl Placement { + // Devuelve la clase base asociada a la posición de aparición del panel. + #[rustfmt::skip] + #[inline] + const fn as_str(self) -> &'static str { + match self { + Placement::Start => "offcanvas-start", + Placement::End => "offcanvas-end", + Placement::Top => "offcanvas-top", + Placement::Bottom => "offcanvas-bottom", + } + } + + // Añade la clase asociada a la posición de aparición del panel a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(self.as_str()); + } + + /* Devuelve la clase asociada a la posición de aparición del panel (reservado). + #[inline] + pub(crate) fn to_class(self) -> String { + self.as_str().to_owned() + } */ +} + // **< Visibility >********************************************************************************* /// Estado inicial de un panel [`Offcanvas`](crate::theme::Offcanvas). -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum Visibility { /// El panel permanece oculto desde el principio. #[default] @@ -58,3 +87,33 @@ pub enum Visibility { /// El panel se muestra abierto al cargar. Show, } + +impl Visibility { + // Devuelve la clase base asociada al estado inicial del panel. + #[inline] + const fn as_str(self) -> &'static str { + match self { + Visibility::Default => "", + Visibility::Show => "show", + } + } + + // Añade la clase asociada al estado inicial del panel a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + let class = self.as_str(); + if class.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } + + /* Devuelve la clase asociada al estado inicial, o una cadena vacía si no aplica (reservado). + #[inline] + pub(crate) fn to_class(self) -> String { + self.as_str().to_owned() + } */ +} diff --git a/src/base/component.rs b/src/base/component.rs index 508a28e1..bdab35c6 100644 --- a/src/base/component.rs +++ b/src/base/component.rs @@ -2,11 +2,9 @@ use crate::prelude::*; -use std::fmt; - // **< FontSize >*********************************************************************************** -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum FontSize { ExtraLarge, XxLarge, @@ -24,7 +22,7 @@ pub enum FontSize { #[rustfmt::skip] impl FontSize { #[inline] - pub const fn as_str(&self) -> &'static str { + pub const fn as_str(self) -> &'static str { match self { FontSize::ExtraLarge => "fs__x3l", FontSize::XxLarge => "fs__x2l", @@ -40,12 +38,6 @@ impl FontSize { } } -impl fmt::Display for FontSize { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - // ************************************************************************************************* mod html; diff --git a/src/html.rs b/src/html.rs index f8709dc5..5f5b833a 100644 --- a/src/html.rs +++ b/src/html.rs @@ -87,9 +87,6 @@ use crate::{core, AutoDefault}; #[allow(type_alias_bounds)] pub type OptionComponent<C: core::component::Component> = core::component::Typed<C>; -mod join_classes; -pub use join_classes::JoinClasses; - mod unit; pub use unit::UnitValue; diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index 68a13da6..abadef8a 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -23,7 +23,7 @@ enum Source { /// /// Permite especificar en qué contexto se aplica el CSS, adaptándose a diferentes dispositivos o /// situaciones de impresión. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum TargetMedia { /// Se aplica en todos los casos (el atributo `media` se omite). #[default] @@ -39,7 +39,7 @@ pub enum TargetMedia { /// Devuelve el valor para el atributo `media` (`Some(...)`) o `None` para `Default`. #[rustfmt::skip] impl TargetMedia { - fn as_str_opt(&self) -> Option<&str> { + const fn as_str(self) -> Option<&'static str> { match self { TargetMedia::Default => None, TargetMedia::Print => Some("print"), @@ -171,7 +171,7 @@ impl Asset for StyleSheet { link rel="stylesheet" href=(join_pair!(path, "?v=", &self.version)) - media=[self.media.as_str_opt()]; + media=[self.media.as_str()]; }, Source::Inline(_, f) => html! { style { (PreEscaped((f)(cx))) }; diff --git a/src/html/join_classes.rs b/src/html/join_classes.rs deleted file mode 100644 index 3f7d7e70..00000000 --- a/src/html/join_classes.rs +++ /dev/null @@ -1,67 +0,0 @@ -/// Añade a los *slices* de elementos [`AsRef<str>`] un método para unir clases CSS. -/// -/// El método es [`join_classes()`](JoinClasses::join_classes), que une las cadenas **no vacías** -/// del *slice* usando un espacio como separador. -pub trait JoinClasses { - /// Une las cadenas **no vacías** de un *slice* usando un espacio como separador. - /// - /// Son cadenas vacías únicamente los elementos del *slice* cuya longitud es `0` (p. ej., `""`); - /// no se realiza recorte ni normalización, por lo que elementos como `" "` no se consideran - /// vacíos. - /// - /// Si todas las cadenas están vacías, devuelve una cadena vacía. Acepta elementos que - /// implementen [`AsRef<str>`] como `&str`, [`String`] o `Cow<'_, str>`. - /// - /// # Ejemplos - /// - /// ```rust - /// # use pagetop::prelude::*; - /// let classes = ["btn", "", "btn-primary"]; - /// assert_eq!(classes.join_classes(), "btn btn-primary"); - /// - /// let empty: [&str; 3] = ["", "", ""]; - /// assert_eq!(empty.join_classes(), ""); - /// - /// let border = String::from("border"); - /// let border_top = String::from("border-top-0"); - /// let v = vec![&border, "", "", "", &border_top]; - /// assert_eq!(v.as_slice().join_classes(), "border border-top-0"); - /// - /// // Elementos con espacios afectan al resultado. - /// let spaced = ["btn", " ", "primary "]; - /// assert_eq!(spaced.join_classes(), "btn primary "); - /// ``` - fn join_classes(&self) -> String; -} - -impl<T> JoinClasses for [T] -where - T: AsRef<str>, -{ - #[inline] - fn join_classes(&self) -> String { - let mut count = 0usize; - let mut total = 0usize; - for s in self.iter().map(T::as_ref).filter(|s| !s.is_empty()) { - count += 1; - total += s.len(); - } - if count == 0 { - return String::new(); - } - let separator = " "; - let mut result = String::with_capacity(total + separator.len() * count.saturating_sub(1)); - for (i, s) in self - .iter() - .map(T::as_ref) - .filter(|s| !s.is_empty()) - .enumerate() - { - if i > 0 { - result.push_str(separator); - } - result.push_str(s); - } - result - } -} diff --git a/src/html/logo.rs b/src/html/logo.rs index f5057d94..fd604414 100644 --- a/src/html/logo.rs +++ b/src/html/logo.rs @@ -27,7 +27,7 @@ use crate::AutoDefault; /// }; /// ``` -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum PageTopSvg { /// Versión por defecto con el logotipo a color. #[default] diff --git a/src/prelude.rs b/src/prelude.rs index 0919e991..47fbbf64 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -33,8 +33,8 @@ pub use crate::trace; // alias obsoletos se volverá a declarar como `pub use crate::html::*;`. pub use crate::html::{ display, html_private, Asset, Assets, AttrClasses, AttrId, AttrL10n, AttrName, AttrValue, - ClassesOp, Escaper, Favicon, JavaScript, JoinClasses, Markup, PageTopSvg, PreEscaped, - PrepareMarkup, StyleSheet, TargetMedia, UnitValue, DOCTYPE, + ClassesOp, Escaper, Favicon, JavaScript, Markup, PageTopSvg, PreEscaped, PrepareMarkup, + StyleSheet, TargetMedia, UnitValue, DOCTYPE, }; pub use crate::locale::*; From 9e960c75735841cbb1227bb64a22efe2a011c592 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 15 Nov 2025 18:37:30 +0100 Subject: [PATCH 239/244] =?UTF-8?q?=F0=9F=9A=A7=20Aplica=20nuevas=20utilid?= =?UTF-8?q?ades=20para=20componer=20el=20men=C3=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/navbar-menus.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/navbar-menus.rs b/examples/navbar-menus.rs index 22ef336c..071d24b1 100644 --- a/examples/navbar-menus.rs +++ b/examples/navbar-menus.rs @@ -82,6 +82,10 @@ impl Extension for SuperMenu { )) .add_item(navbar::Item::nav( Nav::new() + .with_classes( + ClassesOp::Add, + classes::Margin::with(Side::Start, ScaleSize::Auto).to_class(), + ) .add_item(nav::Item::link( L10n::l("sample_menus_item_sign_up"), |_| "/auth/sign-up", @@ -91,7 +95,11 @@ impl Extension for SuperMenu { })), )); - InRegion::Key("header").add(Child::with(navbar_menu)); + InRegion::Key("header").add(Child::with( + Container::new() + .with_width(container::Width::FluidMax(UnitValue::RelRem(75.0))) + .add_child(navbar_menu), + )); } } From ceaee54484928a47a543f46579fc1379a00d4957 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 17 Nov 2025 22:47:47 +0100 Subject: [PATCH 240/244] =?UTF-8?q?=F0=9F=8E=A8=20Protege=20el=20uso=20de?= =?UTF-8?q?=20`render`=20en=20PrepareMarkup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/html.rs | 17 +++-- tests/component_html.rs | 31 +++------ tests/component_poweredby.rs | 28 +++----- tests/html_pm.rs | 126 ++++++++++++++++++++++------------- 4 files changed, 112 insertions(+), 90 deletions(-) diff --git a/src/html.rs b/src/html.rs index 5f5b833a..82fdcd73 100644 --- a/src/html.rs +++ b/src/html.rs @@ -104,11 +104,11 @@ pub use unit::UnitValue; /// # use pagetop::prelude::*; /// // Texto normal, se escapa automáticamente para evitar inyección de HTML. /// let fragment = PrepareMarkup::Escaped("Hola <b>mundo</b>".to_string()); -/// assert_eq!(fragment.render().into_string(), "Hola &lt;b&gt;mundo&lt;/b&gt;"); +/// assert_eq!(fragment.into_string(), "Hola &lt;b&gt;mundo&lt;/b&gt;"); /// /// // HTML literal, se inserta directamente, sin escapado adicional. /// let raw_html = PrepareMarkup::Raw("<b>negrita</b>".to_string()); -/// assert_eq!(raw_html.render().into_string(), "<b>negrita</b>"); +/// assert_eq!(raw_html.into_string(), "<b>negrita</b>"); /// /// // Fragmento ya preparado con la macro `html!`. /// let prepared = PrepareMarkup::With(html! { @@ -116,11 +116,11 @@ pub use unit::UnitValue; /// p { "Este es un párrafo con contenido dinámico." } /// }); /// assert_eq!( -/// prepared.render().into_string(), +/// prepared.into_string(), /// "<h2>Título de ejemplo</h2><p>Este es un párrafo con contenido dinámico.</p>" /// ); /// ``` -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone)] pub enum PrepareMarkup { /// No se genera contenido HTML (equivale a `html! {}`). #[default] @@ -152,8 +152,13 @@ impl PrepareMarkup { } } - /// Integra el renderizado fácilmente en la macro [`html!`]. - pub fn render(&self) -> Markup { + /// Convierte el contenido en una cadena HTML renderizada. Usar sólo para pruebas o depuración. + pub fn into_string(&self) -> String { + self.render().into_string() + } + + // Integra el renderizado fácilmente en la macro [`html!`]. + pub(crate) fn render(&self) -> Markup { match self { PrepareMarkup::None => html! {}, PrepareMarkup::Escaped(text) => html! { (text) }, diff --git a/tests/component_html.rs b/tests/component_html.rs index 851315a9..06d77ec9 100644 --- a/tests/component_html.rs +++ b/tests/component_html.rs @@ -2,32 +2,28 @@ use pagetop::prelude::*; #[pagetop::test] async fn component_html_renders_static_markup() { - let component = Html::with(|_| { + let mut component = Html::with(|_| { html! { p { "Test" } } }); - let markup = component - .prepare_component(&mut Context::new(None)) - .render(); - + let markup = component.render(&mut Context::default()); assert_eq!(markup.0, "<p>Test</p>"); } #[pagetop::test] async fn component_html_renders_using_context_param() { - let mut cx = Context::new(None).with_param("username", "Alice".to_string()); + let mut cx = Context::default().with_param("username", "Alice".to_string()); - let component = Html::with(|cx| { + let mut component = Html::with(|cx| { let name = cx.param::<String>("username").cloned().unwrap_or_default(); html! { span { (name) } } }); - let markup = component.prepare_component(&mut cx).render(); - + let markup = component.render(&mut cx); assert_eq!(markup.0, "<span>Alice</span>"); } @@ -37,21 +33,15 @@ async fn component_html_allows_replacing_render_function() { component.alter_fn(|_| html! { div { "Modified" } }); - let markup = component - .prepare_component(&mut Context::new(None)) - .render(); - + let markup = component.render(&mut Context::default()); assert_eq!(markup.0, "<div>Modified</div>"); } #[pagetop::test] async fn component_html_default_renders_empty_markup() { - let component = Html::default(); - - let markup = component - .prepare_component(&mut Context::new(None)) - .render(); + let mut component = Html::default(); + let markup = component.render(&mut Context::default()); assert_eq!(markup.0, ""); } @@ -60,7 +50,7 @@ async fn component_html_can_access_http_method() { let req = service::test::TestRequest::with_uri("/").to_http_request(); let mut cx = Context::new(Some(req)); - let component = Html::with(|cx| { + let mut component = Html::with(|cx| { let method = cx .request() .map(|r| r.method().to_string()) @@ -68,7 +58,6 @@ async fn component_html_can_access_http_method() { html! { span { (method) } } }); - let markup = component.prepare_component(&mut cx).render(); - + let markup = component.render(&mut cx); assert_eq!(markup.0, "<span>GET</span>"); } diff --git a/tests/component_poweredby.rs b/tests/component_poweredby.rs index 27683d95..7e5a062c 100644 --- a/tests/component_poweredby.rs +++ b/tests/component_poweredby.rs @@ -4,8 +4,8 @@ use pagetop::prelude::*; async fn poweredby_default_shows_only_pagetop_recognition() { let _app = service::test::init_service(Application::new().test()).await; - let p = PoweredBy::default(); - let html = render_component(&p); + let mut p = PoweredBy::default(); + let html = p.render(&mut Context::default()); // Debe mostrar el bloque de reconocimiento a PageTop. assert!(html.as_str().contains("poweredby__pagetop")); @@ -18,8 +18,8 @@ async fn poweredby_default_shows_only_pagetop_recognition() { async fn poweredby_new_includes_current_year_and_app_name() { let _app = service::test::init_service(Application::new().test()).await; - let p = PoweredBy::new(); - let html = render_component(&p); + let mut p = PoweredBy::new(); + let html = p.render(&mut Context::default()); let year = Utc::now().format("%Y").to_string(); assert!( @@ -43,8 +43,8 @@ async fn poweredby_with_copyright_overrides_text() { let _app = service::test::init_service(Application::new().test()).await; let custom = "2001 © FooBar Inc."; - let p = PoweredBy::default().with_copyright(Some(custom)); - let html = render_component(&p); + let mut p = PoweredBy::default().with_copyright(Some(custom)); + let html = p.render(&mut Context::default()); assert!(html.as_str().contains(custom)); assert!(html.as_str().contains("poweredby__copyright")); @@ -54,8 +54,8 @@ async fn poweredby_with_copyright_overrides_text() { async fn poweredby_with_copyright_none_hides_text() { let _app = service::test::init_service(Application::new().test()).await; - let p = PoweredBy::new().with_copyright(None::<String>); - let html = render_component(&p); + let mut p = PoweredBy::new().with_copyright(None::<String>); + let html = p.render(&mut Context::default()); assert!(!html.as_str().contains("poweredby__copyright")); // El reconocimiento a PageTop siempre debe aparecer. @@ -66,8 +66,8 @@ async fn poweredby_with_copyright_none_hides_text() { async fn poweredby_link_points_to_crates_io() { let _app = service::test::init_service(Application::new().test()).await; - let p = PoweredBy::default(); - let html = render_component(&p); + let mut p = PoweredBy::default(); + let html = p.render(&mut Context::default()); assert!( html.as_str().contains("https://pagetop.cillero.es"), @@ -89,11 +89,3 @@ async fn poweredby_getter_reflects_internal_state() { assert!(c1.contains(&Utc::now().format("%Y").to_string())); assert!(c1.contains(&global::SETTINGS.app.name)); } - -// **< HELPERS >************************************************************************************ - -fn render_component<C: Component>(c: &C) -> Markup { - let mut cx = Context::default(); - let pm = c.prepare_component(&mut cx); - pm.render() -} diff --git a/tests/html_pm.rs b/tests/html_pm.rs index ae4517bc..615ea470 100644 --- a/tests/html_pm.rs +++ b/tests/html_pm.rs @@ -1,70 +1,69 @@ use pagetop::prelude::*; -#[pagetop::test] -async fn prepare_markup_render_none_is_empty_string() { - assert_eq!(PrepareMarkup::None.render().as_str(), ""); +/// Componente mínimo para probar `PrepareMarkup` pasando por el ciclo real +/// de renderizado de componentes (`ComponentRender`). +#[derive(AutoDefault)] +struct TestPrepareComponent { + pm: PrepareMarkup, +} + +impl Component for TestPrepareComponent { + fn new() -> Self { + Self { + pm: PrepareMarkup::None, + } + } + + fn prepare_component(&self, _cx: &mut Context) -> PrepareMarkup { + self.pm.clone() + } +} + +impl TestPrepareComponent { + fn render_pm(pm: PrepareMarkup) -> String { + let mut c = TestPrepareComponent { pm }; + c.render(&mut Context::default()).into_string() + } } #[pagetop::test] -async fn prepare_markup_render_escaped_escapes_html_and_ampersands() { +async fn prepare_markup_none_is_empty_string() { + assert_eq!(PrepareMarkup::None.into_string(), ""); +} + +#[pagetop::test] +async fn prepare_markup_escaped_escapes_html_and_ampersands() { let pm = PrepareMarkup::Escaped("<b>& \" ' </b>".to_string()); - assert_eq!(pm.render().as_str(), "&lt;b&gt;&amp; &quot; ' &lt;/b&gt;"); + assert_eq!(pm.into_string(), "&lt;b&gt;&amp; &quot; ' &lt;/b&gt;"); } #[pagetop::test] -async fn prepare_markup_render_raw_is_inserted_verbatim() { +async fn prepare_markup_raw_is_inserted_verbatim() { let pm = PrepareMarkup::Raw("<b>bold</b><script>1<2</script>".to_string()); - assert_eq!(pm.render().as_str(), "<b>bold</b><script>1<2</script>"); + assert_eq!(pm.into_string(), "<b>bold</b><script>1<2</script>"); } #[pagetop::test] -async fn prepare_markup_render_with_keeps_structure() { +async fn prepare_markup_with_keeps_structure() { let pm = PrepareMarkup::With(html! { h2 { "Sample title" } - p { "This is a paragraph." } + p { "This is a paragraph." } }); assert_eq!( - pm.render().as_str(), + pm.into_string(), "<h2>Sample title</h2><p>This is a paragraph.</p>" ); } -#[pagetop::test] -async fn prepare_markup_does_not_double_escape_when_wrapped_in_html_macro() { - // Escaped: dentro de `html!` no debe volver a escaparse. - let escaped = PrepareMarkup::Escaped("<i>x</i>".into()); - let wrapped_escaped = html! { div { (escaped.render()) } }; - assert_eq!( - wrapped_escaped.into_string(), - "<div>&lt;i&gt;x&lt;/i&gt;</div>" - ); - - // Raw: tampoco debe escaparse al integrarlo. - let raw = PrepareMarkup::Raw("<i>x</i>".into()); - let wrapped_raw = html! { div { (raw.render()) } }; - assert_eq!(wrapped_raw.into_string(), "<div><i>x</i></div>"); - - // With: debe incrustar el Markup tal cual. - let with = PrepareMarkup::With(html! { span.title { "ok" } }); - let wrapped_with = html! { div { (with.render()) } }; - assert_eq!( - wrapped_with.into_string(), - "<div><span class=\"title\">ok</span></div>" - ); -} - #[pagetop::test] async fn prepare_markup_unicode_is_preserved() { // Texto con acentos y emojis debe conservarse (salvo el escape HTML de signos). let esc = PrepareMarkup::Escaped("Hello, tomorrow coffee ☕ & donuts!".into()); - assert_eq!( - esc.render().as_str(), - "Hello, tomorrow coffee ☕ &amp; donuts!" - ); + assert_eq!(esc.into_string(), "Hello, tomorrow coffee ☕ &amp; donuts!"); // Raw debe pasar íntegro. let raw = PrepareMarkup::Raw("Title — section © 2025".into()); - assert_eq!(raw.render().as_str(), "Title — section © 2025"); + assert_eq!(raw.into_string(), "Title — section © 2025"); } #[pagetop::test] @@ -88,7 +87,36 @@ async fn prepare_markup_is_empty_semantics() { } #[pagetop::test] -async fn prepare_markup_equivalence_between_render_and_inline_in_html_macro() { +async fn prepare_markup_does_not_double_escape_when_markup_is_reinjected_in_html_macro() { + let mut cx = Context::default(); + + // Escaped: dentro de `html!` no debe volver a escaparse. + let mut comp = TestPrepareComponent { + pm: PrepareMarkup::Escaped("<i>x</i>".into()), + }; + let markup = comp.render(&mut cx); // Markup + let wrapped_escaped = html! { div { (markup) } }.into_string(); + assert_eq!(wrapped_escaped, "<div>&lt;i&gt;x&lt;/i&gt;</div>"); + + // Raw: tampoco debe escaparse al integrarlo. + let mut comp = TestPrepareComponent { + pm: PrepareMarkup::Raw("<i>x</i>".into()), + }; + let markup = comp.render(&mut cx); + let wrapped_raw = html! { div { (markup) } }.into_string(); + assert_eq!(wrapped_raw, "<div><i>x</i></div>"); + + // With: debe incrustar el Markup tal cual. + let mut comp = TestPrepareComponent { + pm: PrepareMarkup::With(html! { span.title { "ok" } }), + }; + let markup = comp.render(&mut cx); + let wrapped_with = html! { div { (markup) } }.into_string(); + assert_eq!(wrapped_with, "<div><span class=\"title\">ok</span></div>"); +} + +#[pagetop::test] +async fn prepare_markup_equivalence_between_component_render_and_markup_reinjected_in_html_macro() { let cases = [ PrepareMarkup::None, PrepareMarkup::Escaped("<b>x</b>".into()), @@ -97,12 +125,20 @@ async fn prepare_markup_equivalence_between_render_and_inline_in_html_macro() { ]; for pm in cases { - let rendered = pm.render(); - let in_macro = html! { (rendered) }.into_string(); + // Vía 1: renderizamos y obtenemos directamente el String. + let via_component = TestPrepareComponent::render_pm(pm.clone()); + + // Vía 2: renderizamos, reinyectamos el Markup en `html!` y volvemos a obtener String. + let via_macro = { + let mut cx = Context::default(); + let mut comp = TestPrepareComponent { pm }; + let markup = comp.render(&mut cx); + html! { (markup) }.into_string() + }; + assert_eq!( - rendered.as_str(), - in_macro, - "The output of Render and (pm) inside html! must match" + via_component, via_macro, + "The output of component render and (Markup) inside html! must match" ); } } From 77c4005b4e1dc10213dd8db5f8357dc610a10fdd Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 17 Nov 2025 22:50:56 +0100 Subject: [PATCH 241/244] =?UTF-8?q?=E2=9C=A8=20Incorpora=20`is=5Frenderabl?= =?UTF-8?q?e`=20en=20`Component`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/base/action/component.rs | 3 - src/base/action/component/is_renderable.rs | 96 ---------------------- src/core/component.rs | 53 ++++++++++++ src/core/component/definition.rs | 36 +++++--- 4 files changed, 78 insertions(+), 110 deletions(-) delete mode 100644 src/base/action/component/is_renderable.rs diff --git a/src/base/action/component.rs b/src/base/action/component.rs index aaef1ce9..30c7ba4a 100644 --- a/src/base/action/component.rs +++ b/src/base/action/component.rs @@ -1,8 +1,5 @@ //! Acciones que operan sobre componentes. -mod is_renderable; -pub use is_renderable::*; - mod before_render_component; pub use before_render_component::*; diff --git a/src/base/action/component/is_renderable.rs b/src/base/action/component/is_renderable.rs deleted file mode 100644 index 5a0e244e..00000000 --- a/src/base/action/component/is_renderable.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::prelude::*; - -/// Tipo de función para determinar si un componente se renderiza o no. -/// -/// Se usa en la acción [`IsRenderable`] para controlar dinámicamente la visibilidad del componente -/// `component` según el contexto `cx`. El componente **no se renderiza** en cuanto una de las -/// funciones devuelva `false`. -pub type FnIsRenderable<C> = fn(component: &C, cx: &Context) -> bool; - -/// Con la función [`FnIsRenderable`] se puede decidir si se renderiza o no un componente. -pub struct IsRenderable<C: Component> { - f: FnIsRenderable<C>, - referer_type_id: Option<UniqueId>, - referer_id: AttrId, - weight: Weight, -} - -/// Filtro para despachar [`FnIsRenderable`] para decidir si se renderiza o no un componente `C`. -impl<C: Component> ActionDispatcher for IsRenderable<C> { - /// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`. - fn referer_type_id(&self) -> Option<UniqueId> { - self.referer_type_id - } - - /// Devuelve el identificador del componente. - fn referer_id(&self) -> Option<String> { - self.referer_id.get() - } - - /// Devuelve el peso para definir el orden de ejecución. - fn weight(&self) -> Weight { - self.weight - } -} - -impl<C: Component> IsRenderable<C> { - /// Permite [registrar](Extension::actions) una nueva acción [`FnIsRenderable`]. - pub fn new(f: FnIsRenderable<C>) -> Self { - IsRenderable { - f, - referer_type_id: Some(UniqueId::of::<C>()), - referer_id: AttrId::default(), - weight: 0, - } - } - - /// Afina el registro para ejecutar la acción [`FnIsRenderable`] sólo para el componente `C` - /// con identificador `id`. - pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self { - self.referer_id.alter_value(id); - self - } - - /// Opcional. Acciones con pesos más bajos se aplican antes. Se pueden usar valores negativos. - pub fn with_weight(mut self, value: Weight) -> Self { - self.weight = value; - self - } - - // Despacha las acciones. Se detiene en cuanto una [`FnIsRenderable`] devuelve `false`. - #[inline] - pub(crate) fn dispatch(component: &C, cx: &mut Context) -> bool { - let mut renderable = true; - dispatch_actions( - &ActionKey::new( - UniqueId::of::<Self>(), - None, - Some(UniqueId::of::<C>()), - None, - ), - |action: &Self| { - if renderable && !(action.f)(component, cx) { - renderable = false; - } - }, - ); - if renderable { - if let Some(id) = component.id() { - dispatch_actions( - &ActionKey::new( - UniqueId::of::<Self>(), - None, - Some(UniqueId::of::<C>()), - Some(id), - ), - |action: &Self| { - if renderable && !(action.f)(component, cx) { - renderable = false; - } - }, - ); - } - } - renderable - } -} diff --git a/src/core/component.rs b/src/core/component.rs index a7faa2fb..9c9ade2e 100644 --- a/src/core/component.rs +++ b/src/core/component.rs @@ -11,6 +11,59 @@ pub use children::{Typed, TypedOp}; mod context; pub use context::{Context, ContextError, ContextOp, Contextual}; +/// Alias de función (*callback*) para **determinar si un componente se renderiza o no**. +/// +/// Puede usarse para permitir que una instancia concreta de un tipo de componente dado decida +/// dinámicamente durante el proceso de renderizado ([`Component::is_renderable()`]) si se renderiza +/// o no. +/// +/// # Ejemplo +/// +/// ```rust +/// # use pagetop::prelude::*; +/// #[derive(AutoDefault)] +/// struct SampleComponent { +/// renderable: Option<FnIsRenderable>, +/// } +/// +/// impl Component for SampleComponent { +/// fn new() -> Self { +/// Self::default() +/// } +/// +/// fn is_renderable(&self, cx: &mut Context) -> bool { +/// // Si hay callback, se usa; en caso contrario, se renderiza por defecto. +/// self.renderable.map_or(true, |f| f(cx)) +/// } +/// +/// fn prepare_component(&self, _cx: &mut Context) -> PrepareMarkup { +/// PrepareMarkup::Escaped("Visible component".into()) +/// } +/// } +/// +/// impl SampleComponent { +/// /// Asigna una función que decidirá si el componente se renderiza o no. +/// #[builder_fn] +/// pub fn with_renderable(mut self, f: Option<FnIsRenderable>) -> Self { +/// self.renderable = f; +/// self +/// } +/// } +/// +/// fn sample() { +/// let mut cx = Context::default().with_param("user_logged_in", true); +/// +/// // Se instancia un componente que sólo se renderiza si `user_logged_in` es `true`. +/// let mut component = SampleComponent::new().with_renderable(Some(|cx: &Context| { +/// cx.param::<bool>("user_logged_in").copied().unwrap_or(false) +/// })); +/// +/// // Aquí simplemente se comprueba que compila y se puede invocar. +/// let _markup = component.render(&mut cx); +/// } +/// ``` +pub type FnIsRenderable = fn(cx: &Context) -> bool; + /// Alias de función (*callback*) para **resolver una URL** según el contexto de renderizado. /// /// Se usa para generar enlaces dinámicos en función del contexto (petición, idioma, etc.). Debe diff --git a/src/core/component/definition.rs b/src/core/component/definition.rs index c0573b44..13b03851 100644 --- a/src/core/component/definition.rs +++ b/src/core/component/definition.rs @@ -45,6 +45,20 @@ pub trait Component: AnyInfo + ComponentRender + Send + Sync { None } + /// Indica si el componente es renderizable. + /// + /// Por defecto, todos los componentes son renderizables (`true`). Sin embargo, este método + /// puede sobrescribirse para decidir dinámicamente si los componentes de este tipo se + /// renderizan o no en función del contexto de renderizado. + /// + /// También puede usarse junto con un alias de función como + /// ([`FnIsRenderable`](crate::core::component::FnIsRenderable)) para permitir que instancias + /// concretas del componente decidan si se renderizan o no. + #[allow(unused_variables)] + fn is_renderable(&self, cx: &mut Context) -> bool { + true + } + /// Configura el componente justo antes de preparar el renderizado. /// /// Este método puede sobrescribirse para modificar la estructura interna del componente o el @@ -72,30 +86,30 @@ pub trait Component: AnyInfo + ComponentRender + Send + Sync { /// Implementa [`render()`](ComponentRender::render) para todos los componentes. /// -/// Y para cada componente ejecuta la siguiente secuencia: +/// El proceso de renderizado de cada componente sigue esta secuencia: /// -/// 1. Despacha [`action::component::IsRenderable`](crate::base::action::component::IsRenderable) -/// para ver si se puede renderizar. Si no es así, devuelve un [`Markup`] vacío. +/// 1. Ejecuta [`is_renderable()`](Component::is_renderable) para ver si puede renderizarse en el +/// contexto actual. Si no es así, devuelve un [`Markup`] vacío. /// 2. Ejecuta [`setup_before_prepare()`](Component::setup_before_prepare) para que el componente /// pueda ajustar su estructura interna o modificar el contexto. /// 3. Despacha [`action::theme::BeforeRender<C>`](crate::base::action::theme::BeforeRender) para -/// que el tema pueda hacer ajustes en el componente o el contexto. +/// permitir que el tema realice ajustes previos. /// 4. Despacha [`action::component::BeforeRender<C>`](crate::base::action::component::BeforeRender) -/// para que otras extensiones puedan hacer ajustes. +/// para que otras extensiones puedan también hacer ajustes previos. /// 5. **Prepara el renderizado del componente**: /// - Despacha [`action::theme::PrepareRender<C>`](crate::base::action::theme::PrepareRender) -/// para permitir al tema preparar un renderizado diferente al predefinido. -/// - Si no es así, ejecuta [`prepare_component()`](Component::prepare_component) para preparar -/// el renderizado predefinido del componente. +/// para permitir al tema generar un renderizado alternativo. +/// - Si el tema no lo modifica, llama a [`prepare_component()`](Component::prepare_component) +/// para obtener el renderizado por defecto del componente. /// 6. Despacha [`action::theme::AfterRender<C>`](crate::base::action::theme::AfterRender) para -/// que el tema pueda hacer sus últimos ajustes. +/// que el tema pueda aplicar ajustes finales. /// 7. Despacha [`action::component::AfterRender<C>`](crate::base::action::component::AfterRender) /// para que otras extensiones puedan hacer sus últimos ajustes. -/// 8. Finalmente devuelve un [`Markup`] del renderizado preparado en el paso 5. +/// 8. Devuelve el [`Markup`] generado en el paso 5. impl<C: Component> ComponentRender for C { fn render(&mut self, cx: &mut Context) -> Markup { // Si no es renderizable, devuelve un bloque HTML vacío. - if !action::component::IsRenderable::dispatch(self, cx) { + if !self.is_renderable(cx) { return html! {}; } From 64264f234d1c2b1a5373eb716cb260a28baa98c5 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Mon, 17 Nov 2025 22:51:34 +0100 Subject: [PATCH 242/244] =?UTF-8?q?=F0=9F=9A=9A=20Renombra=20`ThemeRegion`?= =?UTF-8?q?=20por=20`DefaultRegions`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extensions/pagetop-aliner/src/lib.rs | 6 ++-- extensions/pagetop-bootsier/src/lib.rs | 4 +-- src/base/theme.rs | 2 +- src/base/theme/basic.rs | 4 +-- src/core/theme.rs | 11 ++++---- src/core/theme/definition.rs | 39 ++++++++++++++------------ src/core/theme/regions.rs | 16 +++++------ 7 files changed, 43 insertions(+), 39 deletions(-) diff --git a/extensions/pagetop-aliner/src/lib.rs b/extensions/pagetop-aliner/src/lib.rs index edbb5040..cbc0f526 100644 --- a/extensions/pagetop-aliner/src/lib.rs +++ b/extensions/pagetop-aliner/src/lib.rs @@ -82,13 +82,13 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { use pagetop::prelude::*; -/// El tema usa las mismas regiones predefinidas por [`ThemeRegion`]. -pub type AlinerRegion = ThemeRegion; +/// El tema usa las mismas regiones predefinidas por [`DefaultRegions`]. +pub type AlinerRegions = DefaultRegions; /// Implementa el tema para usar en pruebas que muestran el esquema de páginas HTML. /// /// Tema mínimo ideal para **pruebas y demos** que renderiza el **esqueleto HTML** con las mismas -/// regiones básicas definidas por [`ThemeRegion`]. No pretende ser un tema para producción, está +/// regiones básicas definidas por [`DefaultRegions`]. No pretende ser un tema para producción, está /// pensado para: /// /// - Verificar integración de componentes y composiciones (*layouts*) sin estilos complejos. diff --git a/extensions/pagetop-bootsier/src/lib.rs b/extensions/pagetop-bootsier/src/lib.rs index 4cb35a27..76f9d1e2 100644 --- a/extensions/pagetop-bootsier/src/lib.rs +++ b/extensions/pagetop-bootsier/src/lib.rs @@ -101,8 +101,8 @@ pub mod prelude { pub use crate::theme::*; } -/// El tema usa las mismas regiones predefinidas por [`ThemeRegion`]. -pub type BootsierRegion = ThemeRegion; +/// El tema usa las mismas regiones predefinidas por [`DefaultRegions`]. +pub type BootsierRegions = DefaultRegions; /// Implementa el tema. pub struct Bootsier; diff --git a/src/base/theme.rs b/src/base/theme.rs index a4b2df5b..1e5b1a85 100644 --- a/src/base/theme.rs +++ b/src/base/theme.rs @@ -1,4 +1,4 @@ //! Temas básicos soportados por PageTop. mod basic; -pub use basic::{Basic, BasicRegion}; +pub use basic::{Basic, BasicRegions}; diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index a6711859..2d713e37 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -1,8 +1,8 @@ /// Es el tema básico que incluye PageTop por defecto. use crate::prelude::*; -/// El tema básico usa las mismas regiones predefinidas por [`ThemeRegion`]. -pub type BasicRegion = ThemeRegion; +/// El tema básico usa las mismas regiones predefinidas por [`DefaultRegions`]. +pub type BasicRegions = DefaultRegions; /// Tema básico por defecto que extiende el funcionamiento predeterminado de [`Theme`]. pub struct Basic; diff --git a/src/core/theme.rs b/src/core/theme.rs index 64f40f33..28638ba6 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -9,13 +9,14 @@ //! tipografías, espaciados y cualquier otro detalle visual o de comportamiento (como animaciones, //! scripts de interfaz, etc.). //! -//! Los temas son extensiones que implementan [`Extension`](crate::core::extension::Extension); por -//! lo que se instancian, declaran sus dependencias y se inician igual que el resto de extensiones; -//! pero serán temas si además implementan [`theme()`](crate::core::extension::Extension::theme) y -//! [`Theme`]. +//! Los temas son extensiones que implementan [`Extension`](crate::core::extension::Extension), por +//! lo que se instancian, declaran dependencias y se inician igual que cualquier otra extensión. +//! También deben implementar [`Theme`] y sobrescribir el método +//! [`Extension::theme()`](crate::core::extension::Extension::theme) para que PageTop pueda +//! registrarlos como temas mod definition; -pub use definition::{Theme, ThemePage, ThemeRef, ThemeRegion}; +pub use definition::{Theme, ThemePage, ThemeRef, DefaultRegions}; mod regions; pub(crate) use regions::{ChildrenInRegions, REGION_CONTENT}; diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 2a20c078..7d21c146 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -4,7 +4,7 @@ use crate::core::theme::{Region, RegionRef, REGION_CONTENT}; use crate::html::{html, Markup, StyleSheet}; use crate::locale::L10n; use crate::response::page::Page; -use crate::{global, join}; +use crate::{global, join, AutoDefault}; use std::sync::LazyLock; @@ -14,16 +14,17 @@ use std::sync::LazyLock; /// implementen [`Theme`] y, a su vez, [`Extension`]. pub type ThemeRef = &'static dyn Theme; -/// Conjunto de regiones que los temas pueden exponer para el renderizado. +/// Conjunto de regiones predefinidas que los temas pueden exponer para el renderizado. /// -/// `ThemeRegion` define un conjunto de regiones predefinidas para estructurar un documento HTML. +/// `DefaultRegions` define un conjunto de regiones predefinidas para estructurar un documento HTML. /// Proporciona **identificadores estables** (vía [`Region::key()`]) y **etiquetas localizables** /// (vía [`Region::label()`]) a las regiones donde se añadirán los componentes. /// /// Se usa por defecto en [`Theme::page_regions()`](crate::core::theme::Theme::page_regions) y sus /// variantes representan el conjunto mínimo recomendado para cualquier tema. Sin embargo, cada tema /// podría exponer su propio conjunto de regiones. -pub enum ThemeRegion { +#[derive(AutoDefault)] +pub enum DefaultRegions { /// Cabecera de la página. /// /// Clave: `"header"`. Suele contener *branding*, navegación principal o avisos globales. @@ -32,6 +33,7 @@ pub enum ThemeRegion { /// Contenido principal de la página (**obligatoria**). /// /// Clave: `"content"`. Es el destino por defecto para insertar componentes a nivel de página. + #[default] Content, /// Pie de página. @@ -40,12 +42,12 @@ pub enum ThemeRegion { Footer, } -impl Region for ThemeRegion { +impl Region for DefaultRegions { fn key(&self) -> &str { match self { - ThemeRegion::Header => "header", - ThemeRegion::Content => REGION_CONTENT, - ThemeRegion::Footer => "footer", + Self::Header => "header", + Self::Content => REGION_CONTENT, + Self::Footer => "footer", } } @@ -60,16 +62,17 @@ impl Region for ThemeRegion { /// implementa automáticamente para cualquier tipo que implemente [`Theme`], por lo que normalmente /// no requiere implementación explícita. /// -/// Si un tema **sobrescribe** uno o más de estos métodos de [`Theme`]: +/// Si un tema **sobrescribe** uno o más de los siguientes métodos de [`Theme`]: /// /// - [`render_page_region()`](Theme::render_page_region), /// - [`render_page_head()`](Theme::render_page_head), o /// - [`render_page_body()`](Theme::render_page_body); /// -/// es posible volver al comportamiento por defecto usando FQS (*Fully Qualified Syntax*): +/// puede volver al comportamiento por defecto con una llamada FQS (*Fully Qualified Syntax*) a: /// -/// - `<Self as ThemePage>::render_body(self, page, self.page_regions())` -/// - `<Self as ThemePage>::render_head(self, page)` +/// - `<Self as ThemePage>::render_region(self, page, region)`, +/// - `<Self as ThemePage>::render_body(self, page, self.page_regions())`, o +/// - `<Self as ThemePage>::render_head(self, page)`. pub trait ThemePage { /// Renderiza el **contenedor** de una región concreta del `<body>` de la página. /// @@ -206,9 +209,9 @@ pub trait Theme: Extension + ThemePage + Send + Sync { /// fn page_regions(&self) -> &'static [RegionRef] { /// static REGIONS: LazyLock<[RegionRef; 4]> = LazyLock::new(|| { /// [ - /// &ThemeRegion::Header, - /// &ThemeRegion::Content, - /// &ThemeRegion::Footer, + /// &DefaultRegions::Header, + /// &DefaultRegions::Content, + /// &DefaultRegions::Footer, /// ] /// }); /// &*REGIONS @@ -217,9 +220,9 @@ pub trait Theme: Extension + ThemePage + Send + Sync { fn page_regions(&self) -> &'static [RegionRef] { static REGIONS: LazyLock<[RegionRef; 3]> = LazyLock::new(|| { [ - &ThemeRegion::Header, - &ThemeRegion::Content, - &ThemeRegion::Footer, + &DefaultRegions::Header, + &DefaultRegions::Content, + &DefaultRegions::Footer, ] }); &*REGIONS diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index 8e386f55..17e15436 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -31,25 +31,25 @@ pub const REGION_CONTENT: &str = "content"; /// `aria-label` o en descripciones semánticas del contenedor). /// /// Las implementaciones típicas son *enumeraciones estáticas* declaradas por cada tema (ver como -/// ejemplo [`ThemeRegion`](crate::core::theme::ThemeRegion)), de modo que las claves y etiquetas -/// permanecen inmutables y fácilmente referenciables. +/// ejemplo [`DefaultRegions`](crate::core::theme::DefaultRegions)), de modo que las claves y +/// etiquetas permanecen inmutables y fácilmente referenciables. /// /// # Ejemplo /// /// ```rust /// # use pagetop::prelude::*; -/// pub enum MyThemeRegion { +/// pub enum MyThemeRegions { /// Header, /// Content, /// Footer, /// } /// -/// impl Region for MyThemeRegion { +/// impl Region for MyThemeRegions { /// fn key(&self) -> &str { /// match self { -/// MyThemeRegion::Header => "header", -/// MyThemeRegion::Content => "content", -/// MyThemeRegion::Footer => "footer", +/// Self::Header => "header", +/// Self::Content => "content", +/// Self::Footer => "footer", /// } /// } /// @@ -111,7 +111,7 @@ impl ChildrenInRegions { } } -/// Punto de acceso para añadir componentes a regiones globales o específicas de un tema. +/// Permite añadir componentes a regiones globales o específicas de un tema. /// /// Según la variante, se pueden añadir componentes ([`add()`](Self::add)) que permanecerán /// disponibles durante toda la ejecución. From 4a3244d0e402d124047d92154e78bf8bfa86f80b Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Fri, 21 Nov 2025 05:57:10 +0100 Subject: [PATCH 243/244] =?UTF-8?q?=F0=9F=93=9D=20Mejora=20doc=20de=20`Aut?= =?UTF-8?q?oDefault`=20y=20`builder=5Ffn`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/pagetop-macros/src/lib.rs | 91 ++++++++++++++++++++++++------- 1 file changed, 72 insertions(+), 19 deletions(-) diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 732bbad7..194cd378 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -54,6 +54,56 @@ pub fn html(input: TokenStream) -> TokenStream { /// [`Default`]. Aunque, a diferencia de un simple `#[derive(Default)]`, el atributo /// `#[derive(AutoDefault)]` permite usar anotaciones en los campos como `#[default = "..."]`, /// funcionando incluso en estructuras con campos que no implementan [`Default`] o en *enums*. +/// +/// # Ejemplos +/// +/// ```rust +/// # use pagetop_macros::AutoDefault; +/// # fn main() { +/// #[derive(AutoDefault)] +/// # #[derive(PartialEq)] +/// # #[allow(dead_code)] +/// enum Foo { +/// Bar, +/// #[default] +/// Baz { +/// #[default = 12] +/// a: i32, +/// b: i32, +/// #[default(Some(Default::default()))] +/// c: Option<i32>, +/// #[default(_code = "vec![1, 2, 3]")] +/// d: Vec<u32>, +/// #[default = "four"] +/// e: String, +/// }, +/// Qux(i32), +/// } +/// +/// assert!(Foo::default() == Foo::Baz { +/// a: 12, +/// b: 0, +/// c: Some(0), +/// d: vec![1, 2, 3], +/// e: "four".to_owned(), +/// }); +/// # } +/// ``` +/// +/// * `Baz` tiene el atributo `#[default]`. Esto significa que el valor por defecto de `Foo` es +/// `Foo::Baz`. Solo una variante puede tener el atributo `#[default]`, y dicho atributo no debe +/// tener ningún valor asociado. +/// * `a` tiene el atributo `#[default = 12]`. Esto significa que su valor por defecto es `12`. +/// * `b` no tiene ningún atributo `#[default = ...]`. Su valor por defecto será, por tanto, el +/// valor por defecto de `i32`, es decir, `0`. +/// * `c` es un `Option<i32>`, y su valor por defecto es `Some(Default::default())`. Rust no puede +/// (actualmente) analizar `#[default = Some(Default::default())]`, pero podemos escribir +/// `#[default(Some(Default::default))]`. +/// * `d` contiene el token `!`, que (actualmente) no puede ser analizado ni siquiera usando +/// `#[default(...)]`, así que debemos codificarlo como una cadena y marcarlo con `_code =`. +/// * `e` es un `String`, por lo que el literal de cadena `"four"` se convierte automáticamente en +/// él. Esta conversión automática **solo** ocurre con literales de cadena (o de bytes), y solo si +/// no se usa `_code`. #[proc_macro_derive(AutoDefault, attributes(default))] pub fn derive_auto_default(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -65,46 +115,49 @@ pub fn derive_auto_default(input: TokenStream) -> TokenStream { /// Macro (*attribute*) que asocia un método *builder* `with_` con un método `alter_`. /// -/// La macro añade automáticamente un método `alter_` para modificar la instancia actual usando -/// `&mut self`, y redefine el método *builder* `with_`, que consume la instancia (`mut self`), para -/// delegar la lógica de la modificación al nuevo método `alter_`, reutilizando así la misma -/// implementación. +/// La macro añade automáticamente un método `alter_` que permite modificar la instancia actual +/// usando `&mut self`; y redefine el método *builder* `with_`, que consume `mut self`, para delegar +/// la lógica al nuevo método `alter_`, reutilizando así la misma implementación. /// /// Esta macro emitirá un error en tiempo de compilación si la función anotada no cumple con la /// firma esperada para el método *builder*: `pub fn with_...(mut self, ...) -> Self`. /// -/// # Ejemplos +/// # Ejemplo /// /// Si defines un método `with_` como este: /// -/// ```rust,ignore +/// ```rust +/// # use pagetop_macros::builder_fn; +/// # struct Example {value: Option<String>}; +/// # impl Example { /// #[builder_fn] /// pub fn with_example(mut self, value: impl Into<String>) -> Self { /// self.value = Some(value.into()); /// self /// } +/// # } /// ``` /// -/// la macro generará automáticamente el siguiente método `alter_`: +/// la macro rescribirá el método `with_` y generará un nuevo método `alter_`: /// -/// ```rust,ignore -/// pub fn alter_example(&mut self, value: impl Into<String>) -> &mut Self { -/// self.value = Some(value.into()); -/// self -/// } -/// ``` -/// -/// y reescribirá el método `with_` para delegar la modificación al método `alter_`: -/// -/// ```rust,ignore +/// ```rust +/// # struct Example {value: Option<String>}; +/// # impl Example { +/// #[inline] /// pub fn with_example(mut self, value: impl Into<String>) -> Self { /// self.alter_example(value); /// self /// } +/// +/// pub fn alter_example(&mut self, value: impl Into<String>) -> &mut Self { +/// self.value = Some(value.into()); +/// self +/// } +/// # } /// ``` /// -/// Así, cada método *builder* `with_...()` generará automáticamente su correspondiente método -/// `alter_...()`, que permitirá más adelante modificar instancias existentes. +/// De esta forma, cada método *builder* `with_...()` generará automáticamente su correspondiente +/// método `alter_...()` para dejar modificar instancias existentes. #[proc_macro_attribute] pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { use syn::{parse2, FnArg, Ident, ImplItemFn, Pat, ReturnType, TraitItemFn, Type}; From f0e5f50a7f4d622e5fd8548e094516e28d3f35e5 Mon Sep 17 00:00:00 2001 From: Manuel Cillero <manuel@cillero.es> Date: Sat, 22 Nov 2025 09:11:16 +0100 Subject: [PATCH 244/244] =?UTF-8?q?=E2=9C=A8=20(theme):=20A=C3=B1ade=20com?= =?UTF-8?q?ponentes=20`Region`=20y=20`Template`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Incluye un componente base `Template` para gestionar la estructura del documento y sus regiones (`Region`). - Actualiza el *trait* `Contextual` para permitir la selección de la plantilla de renderizado. - Modifica `Page` y `Context`, y refactoriza el manejo de temas, para dar soporte al nuevo sistema de plantillas y eliminar la gestión obsoleta de regiones. --- examples/navbar-menus.rs | 2 +- extensions/pagetop-aliner/README.md | 3 +- extensions/pagetop-aliner/src/lib.rs | 11 +- extensions/pagetop-bootsier/README.md | 3 +- extensions/pagetop-bootsier/src/lib.rs | 6 +- .../pagetop-bootsier/src/theme}/icon.rs | 0 src/base/component.rs | 81 ++-- src/base/component/poweredby.rs | 2 +- src/base/component/region.rs | 150 ++++++++ src/base/component/template.rs | 84 +++++ src/base/theme.rs | 4 +- src/base/theme/basic.rs | 3 - src/core/action/all.rs | 2 +- src/core/component/children.rs | 2 +- src/core/component/context.rs | 77 ++-- src/core/theme.rs | 21 +- src/core/theme/definition.rs | 356 ++++++------------ src/core/theme/regions.rs | 130 ++----- src/response/page.rs | 38 +- src/response/page/error.rs | 6 +- 20 files changed, 506 insertions(+), 475 deletions(-) rename {src/base/component => extensions/pagetop-bootsier/src/theme}/icon.rs (100%) create mode 100644 src/base/component/region.rs create mode 100644 src/base/component/template.rs diff --git a/examples/navbar-menus.rs b/examples/navbar-menus.rs index 071d24b1..341d394a 100644 --- a/examples/navbar-menus.rs +++ b/examples/navbar-menus.rs @@ -95,7 +95,7 @@ impl Extension for SuperMenu { })), )); - InRegion::Key("header").add(Child::with( + InRegion::Named("header").add(Child::with( Container::new() .with_width(container::Width::FluidMax(UnitValue::RelRem(75.0))) .add_child(navbar_menu), diff --git a/extensions/pagetop-aliner/README.md b/extensions/pagetop-aliner/README.md index 43fb65a5..f4670aae 100644 --- a/extensions/pagetop-aliner/README.md +++ b/extensions/pagetop-aliner/README.md @@ -63,10 +63,11 @@ theme = "Aliner" ```rust,no_run use pagetop::prelude::*; +use pagetop_aliner::Aliner; async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(request) - .with_theme("Aliner") + .with_theme(&Aliner) .add_child( Block::new() .with_title(L10n::l("sample_title")) diff --git a/extensions/pagetop-aliner/src/lib.rs b/extensions/pagetop-aliner/src/lib.rs index cbc0f526..4ae4121e 100644 --- a/extensions/pagetop-aliner/src/lib.rs +++ b/extensions/pagetop-aliner/src/lib.rs @@ -64,10 +64,11 @@ theme = "Aliner" ```rust,no_run use pagetop::prelude::*; +use pagetop_aliner::Aliner; async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(request) - .with_theme("Aliner") + .with_theme(&Aliner) .add_child( Block::new() .with_title(L10n::l("sample_title")) @@ -82,15 +83,11 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { use pagetop::prelude::*; -/// El tema usa las mismas regiones predefinidas por [`DefaultRegions`]. -pub type AlinerRegions = DefaultRegions; - /// Implementa el tema para usar en pruebas que muestran el esquema de páginas HTML. /// -/// Tema mínimo ideal para **pruebas y demos** que renderiza el **esqueleto HTML** con las mismas -/// regiones básicas definidas por [`DefaultRegions`]. No pretende ser un tema para producción, está -/// pensado para: +/// Define un tema mínimo útil para: /// +/// - Comprobar el funcionamiento de temas, plantillas y regiones. /// - Verificar integración de componentes y composiciones (*layouts*) sin estilos complejos. /// - Realizar pruebas de renderizado rápido con salida estable y predecible. /// - Preparar ejemplos y documentación, sin dependencias visuales (CSS/JS) innecesarias. diff --git a/extensions/pagetop-bootsier/README.md b/extensions/pagetop-bootsier/README.md index 84e11b57..d6e1666a 100644 --- a/extensions/pagetop-bootsier/README.md +++ b/extensions/pagetop-bootsier/README.md @@ -63,10 +63,11 @@ theme = "Bootsier" ```rust,no_run use pagetop::prelude::*; +use pagetop_bootsier::Bootsier; async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(request) - .with_theme("Bootsier") + .with_theme(&Bootsier) .add_child( Block::new() .with_title(L10n::l("sample_title")) diff --git a/extensions/pagetop-bootsier/src/lib.rs b/extensions/pagetop-bootsier/src/lib.rs index 76f9d1e2..0bf94f47 100644 --- a/extensions/pagetop-bootsier/src/lib.rs +++ b/extensions/pagetop-bootsier/src/lib.rs @@ -64,10 +64,11 @@ theme = "Bootsier" ```rust,no_run use pagetop::prelude::*; +use pagetop_bootsier::Bootsier; async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(request) - .with_theme("Bootsier") + .with_theme(&Bootsier) .add_child( Block::new() .with_title(L10n::l("sample_title")) @@ -101,9 +102,6 @@ pub mod prelude { pub use crate::theme::*; } -/// El tema usa las mismas regiones predefinidas por [`DefaultRegions`]. -pub type BootsierRegions = DefaultRegions; - /// Implementa el tema. pub struct Bootsier; diff --git a/src/base/component/icon.rs b/extensions/pagetop-bootsier/src/theme/icon.rs similarity index 100% rename from src/base/component/icon.rs rename to extensions/pagetop-bootsier/src/theme/icon.rs diff --git a/src/base/component.rs b/src/base/component.rs index bdab35c6..fa9ed2ad 100644 --- a/src/base/component.rs +++ b/src/base/component.rs @@ -1,48 +1,46 @@ //! Componentes nativos proporcionados por PageTop. - -use crate::prelude::*; - -// **< FontSize >*********************************************************************************** - -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -pub enum FontSize { - ExtraLarge, - XxLarge, - XLarge, - Large, - Medium, - #[default] - Normal, - Small, - XSmall, - XxSmall, - ExtraSmall, -} - -#[rustfmt::skip] -impl FontSize { - #[inline] - pub const fn as_str(self) -> &'static str { - match self { - FontSize::ExtraLarge => "fs__x3l", - FontSize::XxLarge => "fs__x2l", - FontSize::XLarge => "fs__xl", - FontSize::Large => "fs__l", - FontSize::Medium => "fs__m", - FontSize::Normal => "", - FontSize::Small => "fs__s", - FontSize::XSmall => "fs__xs", - FontSize::XxSmall => "fs__x2s", - FontSize::ExtraSmall => "fs__x3s", - } - } -} - -// ************************************************************************************************* +//! +//! Conviene destacar que PageTop distingue entre: +//! +//! - **Componentes estructurales** que definen el esqueleto de un documento HTML, como [`Template`] +//! y [`Region`], utilizados por [`Page`](crate::response::page::Page) para generar la estructura +//! final. +//! - **Componentes de contenido** (menús, barras, tarjetas, etc.), que se incluyen en las regiones +//! gestionadas por los componentes estructurales. +//! +//! El componente [`Template`] describe cómo maquetar el cuerpo del documento a partir de varias +//! regiones lógicas ([`Region`]). En función de la plantilla seleccionada, determina qué regiones +//! se renderizan y en qué orden. Por ejemplo, la plantilla predeterminada [`Template::DEFAULT`] +//! utiliza las regiones [`Region::HEADER`], [`Region::CONTENT`] y [`Region::FOOTER`]. +//! +//! Un componente [`Region`] es un contenedor lógico asociado a un nombre de región. Su contenido se +//! obtiene del [`Context`](crate::core::component::Context), donde los componentes se registran +//! mediante [`Contextual::with_child_in()`](crate::core::component::Contextual::with_child_in) y +//! otros mecanismos similares, y se integra en el documento a través de [`Template`]. +//! +//! Por su parte, una página ([`Page`](crate::response::page::Page)) representa un documento HTML +//! completo. Implementa [`Contextual`](crate::core::component::Contextual) para mantener su propio +//! [`Context`](crate::core::component::Context), donde gestiona el tema activo, la plantilla +//! seleccionada y los componentes asociados a cada región, y se encarga de generar la estructura +//! final de la página. +//! +//! De este modo, temas y extensiones colaboran sobre una estructura común: las aplicaciones +//! registran componentes en el [`Context`](crate::core::component::Context), las plantillas +//! organizan las regiones y las páginas generan el documento HTML resultante. +//! +//! Los temas pueden sobrescribir [`Template`] para exponer nuevas plantillas o adaptar las +//! predeterminadas, y lo mismo con [`Region`] para añadir regiones adicionales o personalizar su +//! representación. mod html; pub use html::Html; +mod region; +pub use region::Region; + +mod template; +pub use template::Template; + mod block; pub use block::Block; @@ -51,6 +49,3 @@ pub use intro::{Intro, IntroOpening}; mod poweredby; pub use poweredby::PoweredBy; - -mod icon; -pub use icon::{Icon, IconKind}; diff --git a/src/base/component/poweredby.rs b/src/base/component/poweredby.rs index 51ab79d8..797253dc 100644 --- a/src/base/component/poweredby.rs +++ b/src/base/component/poweredby.rs @@ -3,7 +3,7 @@ use crate::prelude::*; // Enlace a la página oficial de PageTop. const LINK: &str = "<a href=\"https://pagetop.cillero.es\" rel=\"noopener noreferrer\">PageTop</a>"; -/// Componente que renderiza la sección 'Powered by' (*Funciona con*) típica del pie de página. +/// Componente que informa del 'Powered by' (*Funciona con*) típica del pie de página. /// /// Por defecto, usando [`default()`](Self::default) sólo se muestra un reconocimiento a PageTop. /// Sin embargo, se puede usar [`new()`](Self::new) para crear una instancia con un texto de diff --git a/src/base/component/region.rs b/src/base/component/region.rs new file mode 100644 index 00000000..5dfa25ce --- /dev/null +++ b/src/base/component/region.rs @@ -0,0 +1,150 @@ +use crate::prelude::*; + +/// Componente estructural que renderiza el contenido de una región del documento. +/// +/// `Region` actúa como un contenedor lógico asociado a un nombre de región. Su contenido se obtiene +/// del contexto de renderizado ([`Context`]), donde los componentes suelen registrarse con métodos +/// como [`Contextual::with_child_in()`]. Cada región puede integrarse posteriormente en el cuerpo +/// del documento mediante [`Template`], normalmente desde una página ([`Page`]). +#[derive(AutoDefault)] +pub struct Region { + #[default(AttrName::new(Self::DEFAULT))] + name: AttrName, + #[default(L10n::l("region-content"))] + label: L10n, +} + +impl Component for Region { + fn new() -> Self { + Region::default() + } + + fn id(&self) -> Option<String> { + self.name.get() + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let Some(name) = self.name().get() else { + return PrepareMarkup::None; + }; + let output = cx.render_region(&name); + if output.is_empty() { + return PrepareMarkup::None; + } + PrepareMarkup::With(html! { + div + id=[self.id()] + class=(join!("region region-", &name)) + role="region" + aria-label=[self.label().lookup(cx)] + { + (output) + } + }) + } +} + +impl Region { + /// Región especial situada al **inicio del documento**. + /// + /// Su función es proporcionar un punto estable donde las extensiones puedan inyectar contenido + /// global antes de renderizar el resto de regiones principales (cabecera, contenido, etc.). + /// + /// No suele utilizarse en los temas como una región “visible” dentro del maquetado habitual, + /// sino como punto de anclaje para elementos auxiliares, marcadores técnicos, inicializadores o + /// contenido de depuración que deban situarse en la parte superior del documento. + /// + /// Se considera una región **reservada** para este tipo de usos globales. + pub const PAGETOP: &str = "page-top"; + + /// Región estándar para la **cabecera** del documento. + /// + /// Suele emplearse para mostrar un logotipo, navegación principal, barras superiores, etc. + pub const HEADER: &str = "header"; + + /// Región principal de **contenido**. + /// + /// Es la región donde se espera que se renderice el contenido principal de la página (p. ej. + /// cuerpo de la ruta actual, bloques centrales, vistas principales, etc.). En muchos temas será + /// la región mínima imprescindible para que la página tenga sentido. + pub const CONTENT: &str = "content"; + + /// Región estándar para el **pie de página**. + /// + /// Suele contener información legal, enlaces secundarios, créditos, etc. + pub const FOOTER: &str = "footer"; + + /// Región especial situada al **final del documento**. + /// + /// Pensada para proporcionar un punto estable donde las extensiones puedan inyectar contenido + /// global después de renderizar el resto de regiones principales (cabecera, contenido, etc.). + /// + /// No suele utilizarse en los temas como una región “visible” dentro del maquetado habitual, + /// sino como punto de anclaje para elementos auxiliares asociados a comportamientos dinámicos + /// que deban situarse en la parte inferior del documento. + /// + /// Igual que [`Self::PAGETOP`], se considera una región **reservada** para este tipo de usos + /// globales. + pub const PAGEBOTTOM: &str = "page-bottom"; + + /// Región por defecto que se asigna cuando no se especifica ningún nombre. + /// + /// Por diseño, la región por defecto es la de contenido principal ([`Self::CONTENT`]), de + /// manera que un tema sencillo pueda limitarse a definir una sola región funcional. + pub const DEFAULT: &str = Self::CONTENT; + + /// Prepara una región para el nombre indicado. + /// + /// El valor de `name` se utiliza como nombre de la región y como identificador (`id`) del + /// contenedor. Al renderizarse, este componente mostrará el contenido registrado en el contexto + /// bajo ese nombre. + pub fn named(name: impl AsRef<str>) -> Self { + Region { + name: AttrName::new(name), + label: L10n::default(), + } + } + + /// Prepara una región para el nombre indicado con una etiqueta de accesibilidad. + /// + /// El valor de `name` se utiliza como nombre de la región y como identificador (`id`) del + /// contenedor, mientras que `label` será el texto localizado que se usará como `aria-label` del + /// contenedor. + pub fn labeled(name: impl AsRef<str>, label: L10n) -> Self { + Region { + name: AttrName::new(name), + label, + } + } + + // **< Region BUILDER >************************************************************************* + + /// Establece o modifica el nombre de la región. + #[builder_fn] + pub fn with_name(mut self, name: impl AsRef<str>) -> Self { + self.name.alter_value(name); + self + } + + /// Establece la etiqueta localizada de la región. + /// + /// Esta etiqueta se utiliza como `aria-label` del contenedor predefinido `<div role="region">`, + /// lo que mejora la accesibilidad para lectores de pantalla y otras tecnologías de apoyo. + #[builder_fn] + pub fn with_label(mut self, label: L10n) -> Self { + self.label = label; + self + } + + // **< Region GETTERS >************************************************************************* + + /// Devuelve el nombre de la región. + pub fn name(&self) -> &AttrName { + &self.name + } + + /// Devuelve la etiqueta localizada asociada a la región. + pub fn label(&self) -> &L10n { + &self.label + } +} diff --git a/src/base/component/template.rs b/src/base/component/template.rs new file mode 100644 index 00000000..6c70d00e --- /dev/null +++ b/src/base/component/template.rs @@ -0,0 +1,84 @@ +use crate::prelude::*; + +/// Componente estructural para renderizar plantillas de contenido. +/// +/// `Template` describe cómo se compone el cuerpo del documento a partir de varias regiones lógicas +/// ([`Region`]). En función de su nombre, decide qué regiones se renderizan y en qué orden. +/// +/// Normalmente se invoca desde una página ([`Page`]), que consulta el nombre de plantilla guardado +/// en el [`Context`] y delega en `Template` la composición de las regiones que forman el cuerpo del +/// documento. +/// +/// Los temas pueden sobrescribir este componente para exponer sus propias plantillas o adaptar las +/// plantillas predeterminadas. +#[derive(AutoDefault)] +pub struct Template { + #[default(AttrName::new(Self::DEFAULT))] + name: AttrName, +} + +impl Component for Template { + fn new() -> Self { + Template::default() + } + + fn id(&self) -> Option<String> { + self.name.get() + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let Some(name) = self.name().get() else { + return PrepareMarkup::None; + }; + match name.as_str() { + Self::DEFAULT | Self::ERROR => PrepareMarkup::With(html! { + (Region::labeled(Region::HEADER, L10n::l("region-header")).render(cx)) + (Region::default().render(cx)) + (Region::labeled(Region::FOOTER, L10n::l("region-footer")).render(cx)) + }), + _ => PrepareMarkup::None, + } + } +} + +impl Template { + /// Nombre de la plantilla predeterminada. + /// + /// Por defecto define una estructura básica con las regiones [`Region::HEADER`], + /// [`Region::CONTENT`] y [`Region::FOOTER`], en ese orden. Esta plantilla se usa cuando no se + /// selecciona ninguna otra de forma explícita (ver [`Contextual::with_template()`]). + pub const DEFAULT: &str = "default"; + + /// Nombre de la plantilla de error. + /// + /// Se utiliza para páginas de error u otros estados excepcionales. Por defecto reutiliza + /// la misma estructura que [`Self::DEFAULT`], pero permite a temas y extensiones distinguir + /// el contexto de error para aplicar estilos o contenidos específicos. + pub const ERROR: &str = "error"; + + /// Selecciona la plantilla asociada al nombre indicado. + /// + /// El valor de `name` se utiliza como nombre de la plantilla y como identificador (`id`) del + /// componente. + pub fn named(name: impl AsRef<str>) -> Self { + Template { + name: AttrName::new(name), + } + } + + // **< Template BUILDER >*********************************************************************** + + /// Establece o modifica el nombre de la plantilla seleccionada. + #[builder_fn] + pub fn with_name(mut self, name: impl AsRef<str>) -> Self { + self.name.alter_value(name); + self + } + + // **< Template GETTERS >*********************************************************************** + + /// Devuelve el nombre de la plantilla seleccionada. + pub fn name(&self) -> &AttrName { + &self.name + } +} diff --git a/src/base/theme.rs b/src/base/theme.rs index 1e5b1a85..4a13a4e4 100644 --- a/src/base/theme.rs +++ b/src/base/theme.rs @@ -1,4 +1,4 @@ -//! Temas básicos soportados por PageTop. +//! Tema básico soportados por PageTop. mod basic; -pub use basic::{Basic, BasicRegions}; +pub use basic::Basic; diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index 2d713e37..eb2274f6 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -1,9 +1,6 @@ /// Es el tema básico que incluye PageTop por defecto. use crate::prelude::*; -/// El tema básico usa las mismas regiones predefinidas por [`DefaultRegions`]. -pub type BasicRegions = DefaultRegions; - /// Tema básico por defecto que extiende el funcionamiento predeterminado de [`Theme`]. pub struct Basic; diff --git a/src/core/action/all.rs b/src/core/action/all.rs index fbbf8427..2a3dfd2d 100644 --- a/src/core/action/all.rs +++ b/src/core/action/all.rs @@ -19,7 +19,7 @@ static ACTIONS: LazyLock<RwLock<HashMap<ActionKey, ActionsList>>> = // // Las extensiones llamarán a esta función durante su inicialización para instalar acciones // personalizadas que modifiquen el comportamiento del *core* o de otros componentes. -pub fn add_action(action: ActionBox) { +pub(crate) fn add_action(action: ActionBox) { let key = ActionKey::new( action.type_id(), action.theme_type_id(), diff --git a/src/core/component/children.rs b/src/core/component/children.rs index 3b8f2abf..b3670433 100644 --- a/src/core/component/children.rs +++ b/src/core/component/children.rs @@ -200,7 +200,7 @@ pub enum TypedOp<C: Component> { /// Esta lista permite añadir, modificar, renderizar y consultar componentes hijo en orden de /// inserción, soportando operaciones avanzadas como inserción relativa o reemplazo por /// identificador. -#[derive(Clone, Default)] +#[derive(AutoDefault, Clone)] pub struct Children(Vec<Child>); impl Children { diff --git a/src/core/component/context.rs b/src/core/component/context.rs index 8c4e47e1..5cc5d2e8 100644 --- a/src/core/component/context.rs +++ b/src/core/component/context.rs @@ -1,5 +1,6 @@ +use crate::base::component::Template; use crate::core::component::ChildOp; -use crate::core::theme::all::{theme_by_short_name, DEFAULT_THEME}; +use crate::core::theme::all::DEFAULT_THEME; use crate::core::theme::{ChildrenInRegions, ThemeRef}; use crate::core::TypeInfo; use crate::html::{html, Markup}; @@ -13,19 +14,16 @@ use std::collections::HashMap; /// Operaciones para modificar recursos asociados al contexto ([`Context`]) de un documento. pub enum ContextOp { - // Favicon. /// Define el *favicon* del documento. Sobrescribe cualquier valor anterior. SetFavicon(Option<Favicon>), /// Define el *favicon* solo si no se ha establecido previamente. SetFaviconIfNone(Favicon), - // Stylesheets. /// Añade una hoja de estilos CSS al documento. AddStyleSheet(StyleSheet), /// Elimina una hoja de estilos por su ruta o identificador. RemoveStyleSheet(&'static str), - // JavaScripts. /// Añade un script JavaScript al documento. AddJavaScript(JavaScript), /// Elimina un script por su ruta o identificador. @@ -50,27 +48,27 @@ pub enum ContextError { /// Interfaz para gestionar el **contexto de renderizado** de un documento HTML. /// -/// `Contextual` extiende [`LangId`] y define los métodos para: +/// `Contextual` extiende [`LangId`] para establecer el idioma del documento y añade métodos para: /// -/// - Establecer el **idioma** del documento. /// - Almacenar la **solicitud HTTP** de origen. -/// - Seleccionar **tema** y **composición** (*layout*) de renderizado. +/// - Seleccionar el **tema** y la **plantilla** de renderizado. /// - Administrar **recursos** del documento como el icono [`Favicon`], las hojas de estilo /// [`StyleSheet`] o los scripts [`JavaScript`] mediante [`ContextOp`]. /// - Leer y mantener **parámetros dinámicos tipados** de contexto. /// - Generar **identificadores únicos** por tipo de componente. /// -/// Lo implementan, típicamente, estructuras que representan el contexto de renderizado, como +/// Lo implementan, típicamente, estructuras que manejan el contexto de renderizado, como /// [`Context`](crate::core::component::Context) o [`Page`](crate::response::page::Page). /// /// # Ejemplo /// /// ```rust /// # use pagetop::prelude::*; +/// # use pagetop_aliner::Aliner; /// fn prepare_context<C: Contextual>(cx: C) -> C { /// cx.with_langid(&LangMatch::resolve("es-ES")) -/// .with_theme("aliner") -/// .with_layout("default") +/// .with_theme(&Aliner) +/// .with_template(Template::DEFAULT) /// .with_assets(ContextOp::SetFavicon(Some(Favicon::new().with_icon("/favicon.ico")))) /// .with_assets(ContextOp::AddStyleSheet(StyleSheet::from("/css/app.css"))) /// .with_assets(ContextOp::AddJavaScript(JavaScript::defer("/js/app.js"))) @@ -90,11 +88,11 @@ pub trait Contextual: LangId { /// Especifica el tema para renderizar el documento. #[builder_fn] - fn with_theme(self, theme_name: &'static str) -> Self; + fn with_theme(self, theme: ThemeRef) -> Self; - /// Especifica la composición para renderizar el documento. + /// Especifica la plantilla para renderizar el documento. #[builder_fn] - fn with_layout(self, layout_name: &'static str) -> Self; + fn with_template(self, template_name: &'static str) -> Self; /// Añade o modifica un parámetro dinámico del contexto. #[builder_fn] @@ -104,9 +102,9 @@ pub trait Contextual: LangId { #[builder_fn] fn with_assets(self, op: ContextOp) -> Self; - /// Opera con [`ChildOp`] en una región (`region_key`) de la página. + /// Opera con [`ChildOp`] en una región (`region_name`) del documento. #[builder_fn] - fn with_child_in(self, region_key: &'static str, op: ChildOp) -> Self; + fn with_child_in(self, region_name: impl AsRef<str>, op: ChildOp) -> Self; // **< Contextual GETTERS >********************************************************************* @@ -116,8 +114,8 @@ pub trait Contextual: LangId { /// Devuelve el tema que se usará para renderizar el documento. fn theme(&self) -> ThemeRef; - /// Devuelve la composición para renderizar el documento. Por defecto es `"default"`. - fn layout(&self) -> &str; + /// Devuelve el nombre de la plantilla usada para renderizar el documento. + fn template(&self) -> &str; /// Recupera un parámetro como [`Option`]. fn param<T: 'static>(&self, key: &'static str) -> Option<&T>; @@ -168,12 +166,13 @@ pub trait Contextual: LangId { /// /// ```rust /// # use pagetop::prelude::*; +/// # use pagetop_aliner::Aliner; /// fn new_context(request: HttpRequest) -> Context { /// Context::new(Some(request)) /// // Establece el idioma del documento a español. /// .with_langid(&LangMatch::resolve("es-ES")) -/// // Selecciona un tema (por su nombre corto). -/// .with_theme("aliner") +/// // Establece el tema para renderizar. +/// .with_theme(&Aliner) /// // Asigna un favicon. /// .with_assets(ContextOp::SetFavicon(Some(Favicon::new().with_icon("/favicon.ico")))) /// // Añade una hoja de estilo externa. @@ -208,8 +207,8 @@ pub trait Contextual: LangId { pub struct Context { request : Option<HttpRequest>, // Solicitud HTTP de origen. langid : &'static LanguageIdentifier, // Identificador de idioma. - theme : ThemeRef, // Referencia al tema para renderizar. - layout : &'static str, // Composición del documento para renderizar. + theme : ThemeRef, // Referencia al tema usado para renderizar. + template : &'static str, // Nombre de la plantilla usada para renderizar. favicon : Option<Favicon>, // Favicon, si se ha definido. stylesheets: Assets<StyleSheet>, // Hojas de estilo CSS. javascripts: Assets<JavaScript>, // Scripts JavaScript. @@ -227,8 +226,8 @@ impl Default for Context { impl Context { /// Crea un nuevo contexto asociado a una solicitud HTTP. /// - /// El contexto inicializa el idioma, tema y composición por defecto, sin favicon ni recursos - /// cargados. + /// El contexto inicializa el idioma, el tema y la plantilla por defecto, sin favicon ni otros + /// recursos cargados. #[rustfmt::skip] pub fn new(request: Option<HttpRequest>) -> Self { // Se intenta DEFAULT_LANGID. @@ -249,7 +248,7 @@ impl Context { request, langid, theme : *DEFAULT_THEME, - layout : "default", + template : Template::DEFAULT, favicon : None, stylesheets: Assets::<StyleSheet>::new(), javascripts: Assets::<JavaScript>::new(), @@ -287,10 +286,10 @@ impl Context { markup } - /// Renderiza los componentes de una región (`region_key`). - pub fn render_components_of(&mut self, region_key: &'static str) -> Markup { + /// Renderiza los componentes de la región `region_name`. + pub fn render_region(&mut self, region_name: impl AsRef<str>) -> Markup { self.regions - .merge_all_components(self.theme, region_key) + .children_for(self.theme, region_name) .render(self) } @@ -364,7 +363,7 @@ impl Context { /// Elimina un parámetro del contexto. Devuelve `true` si la clave existía y se eliminó. /// - /// Devuelve `false` en caso contrario. Usar cuando solo interesa borrar la entrada. + /// Devuelve `false` en caso contrario. Usar cuando sólo interesa borrar la entrada. /// /// # Ejemplos /// @@ -411,19 +410,15 @@ impl Contextual for Context { self } - /// Asigna el tema para renderizar el documento. - /// - /// Localiza el tema por su [`short_name()`](crate::core::AnyInfo::short_name), y si no aplica - /// ninguno entonces usará el tema por defecto. #[builder_fn] - fn with_theme(mut self, theme_name: &'static str) -> Self { - self.theme = theme_by_short_name(theme_name).unwrap_or(*DEFAULT_THEME); + fn with_theme(mut self, theme: ThemeRef) -> Self { + self.theme = theme; self } #[builder_fn] - fn with_layout(mut self, layout_name: &'static str) -> Self { - self.layout = layout_name; + fn with_template(mut self, template_name: &'static str) -> Self { + self.template = template_name; self } @@ -467,7 +462,7 @@ impl Contextual for Context { ContextOp::RemoveStyleSheet(path) => { self.stylesheets.remove(path); } - // JavaScripts. + // Scripts JavaScript. ContextOp::AddJavaScript(js) => { self.javascripts.add(js); } @@ -479,8 +474,8 @@ impl Contextual for Context { } #[builder_fn] - fn with_child_in(mut self, region_key: &'static str, op: ChildOp) -> Self { - self.regions.alter_child_in(region_key, op); + fn with_child_in(mut self, region_name: impl AsRef<str>, op: ChildOp) -> Self { + self.regions.alter_child_in(region_name, op); self } @@ -494,8 +489,8 @@ impl Contextual for Context { self.theme } - fn layout(&self) -> &str { - self.layout + fn template(&self) -> &str { + self.template } /// Recupera un parámetro como [`Option`], simplificando el acceso. diff --git a/src/core/theme.rs b/src/core/theme.rs index 28638ba6..8774276e 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -1,25 +1,24 @@ //! API para añadir y gestionar nuevos temas. //! -//! En PageTop un tema es la *piel* de la aplicación, decide cómo se muestra cada documento HTML, -//! especialmente las páginas de contenido ([`Page`](crate::response::page::Page)), sin alterar la -//! lógica interna de sus componentes. +//! En PageTop un tema es la *piel* de la aplicación. Es responsable último de los estilos, +//! tipografías, espaciados y cualquier otro detalle visual o interactivo (animaciones, scripts de +//! interfaz, etc.). //! -//! Un tema **declara las regiones** (*cabecera*, *barra lateral*, *pie*, etc.) que estarán -//! disponibles para colocar contenido. Los temas son responsables últimos de los estilos, -//! tipografías, espaciados y cualquier otro detalle visual o de comportamiento (como animaciones, -//! scripts de interfaz, etc.). +//! Un tema determina el aspecto final de un documento HTML sin alterar la lógica interna de los +//! componentes ni la estructura del documento, que queda definida por la plantilla +//! ([`Template`](crate::base::component::Template)) utilizada por cada página. //! //! Los temas son extensiones que implementan [`Extension`](crate::core::extension::Extension), por //! lo que se instancian, declaran dependencias y se inician igual que cualquier otra extensión. //! También deben implementar [`Theme`] y sobrescribir el método //! [`Extension::theme()`](crate::core::extension::Extension::theme) para que PageTop pueda -//! registrarlos como temas +//! registrarlos como temas. mod definition; -pub use definition::{Theme, ThemePage, ThemeRef, DefaultRegions}; +pub use definition::{Theme, ThemeRef}; mod regions; -pub(crate) use regions::{ChildrenInRegions, REGION_CONTENT}; -pub use regions::{InRegion, Region, RegionRef}; +pub(crate) use regions::ChildrenInRegions; +pub use regions::InRegion; pub(crate) mod all; diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 7d21c146..de11d1ba 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -1,129 +1,136 @@ -use crate::core::component::{ContextOp, Contextual}; +use crate::base::component::Template; +use crate::core::component::{ComponentRender, ContextOp, Contextual}; use crate::core::extension::Extension; -use crate::core::theme::{Region, RegionRef, REGION_CONTENT}; +use crate::global; use crate::html::{html, Markup, StyleSheet}; use crate::locale::L10n; use crate::response::page::Page; -use crate::{global, join, AutoDefault}; - -use std::sync::LazyLock; /// Referencia estática a un tema. /// /// Los temas son también extensiones. Por tanto, deben declararse como **instancias estáticas** que -/// implementen [`Theme`] y, a su vez, [`Extension`]. +/// implementen [`Theme`] y, a su vez, [`Extension`]. Estas instancias se exponen usando +/// [`Extension::theme()`](crate::core::extension::Extension::theme). pub type ThemeRef = &'static dyn Theme; -/// Conjunto de regiones predefinidas que los temas pueden exponer para el renderizado. +/// Interfaz común que debe implementar cualquier tema de PageTop. /// -/// `DefaultRegions` define un conjunto de regiones predefinidas para estructurar un documento HTML. -/// Proporciona **identificadores estables** (vía [`Region::key()`]) y **etiquetas localizables** -/// (vía [`Region::label()`]) a las regiones donde se añadirán los componentes. +/// Un tema es una [`Extension`](crate::core::extension::Extension) que define el aspecto general de +/// las páginas: cómo se renderiza el `<head>`, cómo se presenta el `<body>` mediante plantillas +/// ([`Template`]) y qué contenido mostrar en las páginas de error. /// -/// Se usa por defecto en [`Theme::page_regions()`](crate::core::theme::Theme::page_regions) y sus -/// variantes representan el conjunto mínimo recomendado para cualquier tema. Sin embargo, cada tema -/// podría exponer su propio conjunto de regiones. -#[derive(AutoDefault)] -pub enum DefaultRegions { - /// Cabecera de la página. +/// Todos los métodos de este *trait* tienen una implementación por defecto, por lo que pueden +/// sobrescribirse selectivamente para crear nuevos temas con comportamientos distintos a los +/// predeterminados. +/// +/// El único método **obligatorio** de `Extension` para un tema es [`theme()`](Extension::theme), +/// que debe devolver una referencia estática al propio tema: +/// +/// ```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 + Send + Sync { + /// Acciones específicas del tema antes de renderizar el `<body>` de la página. /// - /// Clave: `"header"`. Suele contener *branding*, navegación principal o avisos globales. - Header, - - /// Contenido principal de la página (**obligatoria**). + /// Se invoca antes de que se procese la plantilla ([`Template`]) asociada a la página + /// ([`Page::template()`](crate::response::page::Page::template)). Es un buen lugar para + /// inicializar o ajustar recursos en función del contexto de la página, por ejemplo: /// - /// Clave: `"content"`. Es el destino por defecto para insertar componentes a nivel de página. - #[default] - Content, + /// - Añadir metadatos o propiedades a la página. + /// - Preparar atributos compartidos. + /// - Registrar *assets* condicionales en el contexto. + #[allow(unused_variables)] + fn before_render_page_body(&self, page: &mut Page) {} - /// Pie de página. + /// Renderiza el contenido del `<body>` de la página. /// - /// Clave: `"footer"`. Suele contener enlaces legales, créditos o navegación secundaria. - Footer, -} + /// Por defecto, delega en la plantilla ([`Template`]) asociada a la página + /// ([`Page::template()`](crate::response::page::Page::template)). La plantilla se encarga de + /// procesar las regiones y renderizar los componentes registrados en el contexto. + /// + /// Los temas pueden sobrescribir este método para: + /// + /// - Forzar una plantilla concreta en determinadas páginas. + /// - Envolver el contenido en marcadores adicionales. + /// - Implementar lógicas de composición alternativas. + #[inline] + fn render_page_body(&self, page: &mut Page) -> Markup { + Template::named(page.template()).render(page.context()) + } -impl Region for DefaultRegions { - fn key(&self) -> &str { - match self { - Self::Header => "header", - Self::Content => REGION_CONTENT, - Self::Footer => "footer", + /// Acciones específicas del tema después de renderizar el `<body>` de la página. + /// + /// Se invoca tras la generación del contenido del `<body>`. Es útil para: + /// + /// - Ajustar o registrar recursos en función de lo que se haya renderizado. + /// - Realizar *tracing* o recopilar métricas. + /// - Aplicar ajustes finales al estado de la página antes de producir el `<head>` o la + /// respuesta final. + /// + /// La implementación por defecto añade una serie de hojas de estilo básicas (`normalize.css`, + /// `root.css`, `basic.css`) cuando el parámetro `include_basic_assets` de la página está + /// activado. + #[allow(unused_variables)] + fn after_render_page_body(&self, page: &mut Page) { + 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), + )); } } - fn label(&self) -> L10n { - L10n::l(join!("region_", self.key())) - } -} - -/// Métodos predefinidos de renderizado para las páginas de un tema. -/// -/// Contiene las implementaciones base para renderizar 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. -/// -/// Si un tema **sobrescribe** uno o más de los siguientes métodos de [`Theme`]: -/// -/// - [`render_page_region()`](Theme::render_page_region), -/// - [`render_page_head()`](Theme::render_page_head), o -/// - [`render_page_body()`](Theme::render_page_body); -/// -/// puede volver al comportamiento por defecto con una llamada FQS (*Fully Qualified Syntax*) a: -/// -/// - `<Self as ThemePage>::render_region(self, page, region)`, -/// - `<Self as ThemePage>::render_body(self, page, self.page_regions())`, o -/// - `<Self as ThemePage>::render_head(self, page)`. -pub trait ThemePage { - /// Renderiza el **contenedor** de una región concreta del `<body>` de la página. + /// Renderiza el contenido del `<head>` de la página. /// - /// Obtiene los componentes asociados a `region.key()` desde el contexto de la página y, si hay - /// salida, envuelve el contenido en un contenedor `<div>` predefinido. + /// Aunque en una página el `<head>` se encuentra antes del `<body>`, internamente se renderiza + /// después para contar con los ajustes que hayan ido acumulando los componentes. Por ejemplo, + /// permitiría añadir un archivo de iconos sólo si se ha incluido un icono en la página. /// - /// Si la región **no produce contenido**, devuelve un `Markup` vacío. + /// Por defecto incluye: + /// + /// - La codificación (`charset="utf-8"`). + /// - El título, usando el título de la página si existe y, en caso contrario, sólo el nombre de + /// la aplicación. + /// - La descripción (`<meta name="description">`), si está definida. + /// - La etiqueta `viewport` básica para diseño adaptable. + /// - Los metadatos (`name`/`content`) y propiedades (`property`/`content`) declarados en la + /// página. + /// - Todos los *assets* registrados en el contexto de la página. + /// + /// Los temas pueden sobrescribir este método para añadir etiquetas adicionales (por ejemplo, + /// *favicons* personalizados, manifest, etiquetas de analítica, etc.). #[inline] - fn render_region(&self, page: &mut Page, region: RegionRef) -> Markup { - html! { - @let key = region.key(); - @let output = page.context().render_components_of(key); - @if !output.is_empty() { - div - id=(key) - class={ "region region--" (key) } - role="region" - aria-label=[region.label().lookup(page)] - { - (output) - } - } - } - } - - /// Renderiza el **contenido interior** del `<body>` de la página. - /// - /// Recorre `regions` en el **orden declarado** y, para cada región con contenido, delega en - /// [`render_region()`](Self::render_region) la generación del contenedor. Las regiones sin - /// contenido **no** producen salida. Se asume que cada identificador de región es **único** - /// dentro de la página. - /// - /// La etiqueta `<body>` no se incluye aquí; únicamente renderiza su contenido. - #[inline] - fn render_body(&self, page: &mut Page, regions: &[RegionRef]) -> Markup { - html! { - @for region in regions { - (self.render_region(page, *region)) - } - } - } - - /// Renderiza el **contenido interior** del `<head>` de la página. - /// - /// Incluye por defecto 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. - /// - /// La etiqueta `<head>` no se incluye aquí; únicamente se renderiza su contenido. - #[inline] - fn render_head(&self, page: &mut Page) -> Markup { + fn render_page_head(&self, page: &mut Page) -> Markup { let viewport = "width=device-width, initial-scale=1, shrink-to-fit=no"; html! { meta charset="utf-8"; @@ -151,155 +158,20 @@ pub trait ThemePage { (page.context().render_assets()) } } -} - -/// 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. - /// - /// Retorna una **lista estática** de referencias ([`RegionRef`](crate::core::theme::RegionRef)) - /// que representan las regiones que el tema admite dentro del `<body>`. - /// - /// Cada referencia apunta a una instancia que implementa [`Region`](crate::core::theme::Region) - /// para definir cada región de forma segura y estable. Y si un tema necesita un conjunto - /// distinto de regiones, puede **sobrescribir** este método siguiendo estas recomendaciones: - /// - /// - Los identificadores devueltos por [`Region::key()`](crate::core::theme::Region::key) - /// deben ser **estables** (p. ej. `"sidebar-left"`, `"content"`). - /// - La región `"content"` es **obligatoria**, ya que se usa como destino por defecto para - /// insertar componentes y renderizarlos. - /// - El orden de la lista podría tener relevancia como **orden de renderizado** dentro del - /// `<body>` segun la implementación de [`render_page_body()`](Self::render_page_body). - /// - Las etiquetas (`L10n`) de cada región se evaluarán con el idioma activo de la página. - /// - /// # Ejemplo - /// - /// ```rust,ignore - /// fn page_regions(&self) -> &'static [RegionRef] { - /// static REGIONS: LazyLock<[RegionRef; 4]> = LazyLock::new(|| { - /// [ - /// &DefaultRegions::Header, - /// &DefaultRegions::Content, - /// &DefaultRegions::Footer, - /// ] - /// }); - /// &*REGIONS - /// } - /// ``` - fn page_regions(&self) -> &'static [RegionRef] { - static REGIONS: LazyLock<[RegionRef; 3]> = LazyLock::new(|| { - [ - &DefaultRegions::Header, - &DefaultRegions::Content, - &DefaultRegions::Footer, - ] - }); - &*REGIONS - } - - /// Renderiza una región de la página. - /// - /// Si se sobrescribe este método, se puede volver al comportamiento base con: - /// `<Self as ThemePage>::render_region(self, page, region)`. - #[inline] - fn render_page_region(&self, page: &mut Page, region: RegionRef) -> Markup { - <Self as ThemePage>::render_region(self, page, region) - } - - /// 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 renderizado 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 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) - } /// Contenido predeterminado para la página de error "*403 - Forbidden*". /// - /// Se puede sobrescribir este método para personalizar y adaptar este contenido al tema. + /// Los temas pueden sobrescribir este método para personalizar el diseño y el contenido de la + /// página de error, manteniendo o no el mensaje de los textos localizados. fn error403(&self, page: &mut Page) -> Markup { html! { div { h1 { (L10n::l("error403_notice").using(page)) } } } } /// 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. + /// Los temas pueden sobrescribir este método para personalizar el diseño y el contenido de la + /// página de error, manteniendo o no el mensaje de los textos localizados. fn error404(&self, page: &mut Page) -> Markup { html! { div { h1 { (L10n::l("error404_notice").using(page)) } } } } } - -/// Se implementa automáticamente `ThemePage` para cualquier tema. -impl<T: Theme> ThemePage for T {} diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index 17e15436..259417eb 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -1,6 +1,6 @@ +use crate::base::component::Region; use crate::core::component::{Child, ChildOp, Children}; use crate::core::theme::ThemeRef; -use crate::locale::L10n; use crate::{builder_fn, AutoDefault, UniqueId}; use parking_lot::RwLock; @@ -16,97 +16,36 @@ static THEME_REGIONS: LazyLock<RwLock<HashMap<UniqueId, ChildrenInRegions>>> = static COMMON_REGIONS: LazyLock<RwLock<ChildrenInRegions>> = LazyLock::new(|| RwLock::new(ChildrenInRegions::default())); -/// Nombre de la región de contenido por defecto (`"content"`). -pub const REGION_CONTENT: &str = "content"; - -/// Define la interfaz mínima que describe una **región de renderizado** dentro de una página. -/// -/// Una *región* representa una zona del documento HTML (por ejemplo: `"header"`, `"content"` o -/// `"sidebar-left"`), en la que se pueden incluir y renderizar componentes dinámicamente. -/// -/// Este `trait` abstrae los metadatos básicos de cada región, esencialmente: -/// -/// - su **clave interna** (`key()`), que la identifica de forma única dentro de la página, y -/// - su **etiqueta localizada** (`label()`), que se usa como texto accesible (por ejemplo en -/// `aria-label` o en descripciones semánticas del contenedor). -/// -/// Las implementaciones típicas son *enumeraciones estáticas* declaradas por cada tema (ver como -/// ejemplo [`DefaultRegions`](crate::core::theme::DefaultRegions)), de modo que las claves y -/// etiquetas permanecen inmutables y fácilmente referenciables. -/// -/// # Ejemplo -/// -/// ```rust -/// # use pagetop::prelude::*; -/// pub enum MyThemeRegions { -/// Header, -/// Content, -/// Footer, -/// } -/// -/// impl Region for MyThemeRegions { -/// fn key(&self) -> &str { -/// match self { -/// Self::Header => "header", -/// Self::Content => "content", -/// Self::Footer => "footer", -/// } -/// } -/// -/// fn label(&self) -> L10n { -/// L10n::l(join!("region__", self.key())) -/// } -/// } -/// ``` -pub trait Region: Send + Sync { - /// Devuelve la **clave interna** que identifica de forma única una región. - /// - /// La clave se utiliza para asociar los componentes de la región con su contenedor HTML - /// correspondiente. Por convención, se emplean nombres en minúsculas y con guiones (`"header"`, - /// `"main"`, `"sidebar-right"`, etc.), y la región `"content"` es **obligatoria** en todos los - /// temas. - fn key(&self) -> &str; - - /// Devuelve la **etiqueta localizada** (`L10n`) asociada a la región. - /// - /// Esta etiqueta se evalúa en el idioma activo de la página y se utiliza principalmente para - /// accesibilidad, como el valor de `aria-label` en el contenedor generado por - /// [`ThemePage::render_region()`](crate::core::theme::ThemePage::render_region). - fn label(&self) -> L10n; -} - -/// Referencia estática a una región. -pub type RegionRef = &'static dyn Region; - // Contenedor interno de componentes agrupados por región. #[derive(AutoDefault)] -pub struct ChildrenInRegions(HashMap<&'static str, Children>); +pub(crate) struct ChildrenInRegions(HashMap<String, Children>); impl ChildrenInRegions { - pub fn with(region_key: &'static str, child: Child) -> Self { - ChildrenInRegions::default().with_child_in(region_key, ChildOp::Add(child)) + pub fn with(region_name: impl AsRef<str>, child: Child) -> Self { + Self::default().with_child_in(region_name, ChildOp::Add(child)) } #[builder_fn] - pub fn with_child_in(mut self, region_key: &'static str, op: ChildOp) -> Self { - if let Some(region) = self.0.get_mut(region_key) { + pub fn with_child_in(mut self, region_name: impl AsRef<str>, op: ChildOp) -> Self { + let name = region_name.as_ref(); + if let Some(region) = self.0.get_mut(name) { region.alter_child(op); } else { - self.0.insert(region_key, Children::new().with_child(op)); + self.0 + .insert(name.to_owned(), Children::new().with_child(op)); } self } - pub fn merge_all_components(&self, theme_ref: ThemeRef, region_key: &'static str) -> Children { + pub fn children_for(&self, theme_ref: ThemeRef, region_name: impl AsRef<str>) -> Children { + let name = region_name.as_ref(); let common = COMMON_REGIONS.read(); - if let Some(r) = THEME_REGIONS.read().get(&theme_ref.type_id()) { - Children::merge(&[ - common.0.get(region_key), - self.0.get(region_key), - r.0.get(region_key), - ]) + let themed = THEME_REGIONS.read(); + + if let Some(r) = themed.get(&theme_ref.type_id()) { + Children::merge(&[common.0.get(name), self.0.get(name), r.0.get(name)]) } else { - Children::merge(&[common.0.get(region_key), self.0.get(region_key)]) + Children::merge(&[common.0.get(name), self.0.get(name)]) } } } @@ -120,10 +59,10 @@ impl ChildrenInRegions { /// estas regiones, como las páginas de contenido ([`Page`](crate::response::page::Page)). pub enum InRegion { /// Región de contenido por defecto. - Content, - /// Región identificada por la clave proporcionado. - Key(&'static str), - /// Región identificada por una clave para un tema concreto. + Default, + /// Región identificada por el nombre proporcionado. + Named(&'static str), + /// Región identificada por su nombre para un tema concreto. OfTheme(&'static str, ThemeRef), } @@ -135,39 +74,38 @@ impl InRegion { /// ```rust /// # use pagetop::prelude::*; /// // Banner global, en la región por defecto de cualquier página. - /// InRegion::Content.add(Child::with(Html::with(|_| + /// InRegion::Default.add(Child::with(Html::with(|_| /// html! { ("🎉 ¡Bienvenido!") } /// ))); /// /// // Texto en la región "sidebar". - /// InRegion::Key("sidebar").add(Child::with(Html::with(|_| + /// InRegion::Named("sidebar").add(Child::with(Html::with(|_| /// html! { ("Publicidad") } /// ))); /// ``` pub fn add(&self, child: Child) -> &Self { match self { - InRegion::Content => { - COMMON_REGIONS - .write() - .alter_child_in(REGION_CONTENT, ChildOp::Add(child)); - } - InRegion::Key(region_key) => { - COMMON_REGIONS - .write() - .alter_child_in(region_key, ChildOp::Add(child)); - } - InRegion::OfTheme(region_key, theme_ref) => { + InRegion::Default => Self::add_to_common(Region::DEFAULT, child), + InRegion::Named(region_name) => Self::add_to_common(region_name, child), + InRegion::OfTheme(region_name, theme_ref) => { let mut regions = THEME_REGIONS.write(); if let Some(r) = regions.get_mut(&theme_ref.type_id()) { - r.alter_child_in(region_key, ChildOp::Add(child)); + r.alter_child_in(region_name, ChildOp::Add(child)); } else { regions.insert( theme_ref.type_id(), - ChildrenInRegions::with(region_key, child), + ChildrenInRegions::with(region_name, child), ); } } } self } + + #[inline] + fn add_to_common(region_name: &str, child: Child) { + COMMON_REGIONS + .write() + .alter_child_in(region_name, ChildOp::Add(child)); + } } diff --git a/src/response/page.rs b/src/response/page.rs index 036c999c..7d7789d4 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -4,8 +4,10 @@ pub use error::ErrorPage; pub use actix_web::Result as ResultPage; use crate::base::action; -use crate::core::component::{Child, ChildOp, Component, Context, ContextOp, Contextual}; -use crate::core::theme::{ThemeRef, REGION_CONTENT}; +use crate::base::component::Region; +use crate::core::component::{Child, ChildOp, Component, ComponentRender}; +use crate::core::component::{Context, ContextOp, Contextual}; +use crate::core::theme::ThemeRef; use crate::html::{html, Markup, DOCTYPE}; use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; use crate::html::{AttrClasses, ClassesOp}; @@ -109,14 +111,14 @@ impl Page { /// Añade un componente hijo a la región de contenido por defecto. pub fn add_child(mut self, component: impl Component) -> Self { self.context - .alter_child_in(REGION_CONTENT, ChildOp::Add(Child::with(component))); + .alter_child_in(Region::DEFAULT, ChildOp::Add(Child::with(component))); self } - /// Añade un componente hijo en una región (`region_key`) de la página. - pub fn add_child_in(mut self, region_key: &'static str, component: impl Component) -> Self { + /// Añade un componente hijo en la región `region_name` de la página. + pub fn add_child_in(mut self, region_name: &'static str, component: impl Component) -> Self { self.context - .alter_child_in(region_key, ChildOp::Add(Child::with(component))); + .alter_child_in(region_name, ChildOp::Add(Child::with(component))); self } @@ -191,7 +193,11 @@ impl Page { action::page::BeforeRenderBody::dispatch(self); // Renderiza el <body>. - let body = self.context.theme().render_page_body(self); + let body = html! { + (Region::named(Region::PAGETOP).render(&mut self.context)) + (self.context.theme().render_page_body(self)) + (Region::named(Region::PAGEBOTTOM).render(&mut self.context)) + }; // Acciones específicas del tema después de renderizar el <body>. self.context.theme().after_render_page_body(self); @@ -216,9 +222,7 @@ impl Page { (head) } body id=[self.body_id().get()] class=[self.body_classes().get()] { - (self.context.render_components_of("page-top")) (body) - (self.context.render_components_of("page-bottom")) } } }) @@ -247,14 +251,14 @@ impl Contextual for Page { } #[builder_fn] - fn with_theme(mut self, theme_name: &'static str) -> Self { - self.context.alter_theme(theme_name); + fn with_theme(mut self, theme: ThemeRef) -> Self { + self.context.alter_theme(theme); self } #[builder_fn] - fn with_layout(mut self, layout_name: &'static str) -> Self { - self.context.alter_layout(layout_name); + fn with_template(mut self, template_name: &'static str) -> Self { + self.context.alter_template(template_name); self } @@ -271,8 +275,8 @@ impl Contextual for Page { } #[builder_fn] - fn with_child_in(mut self, region_key: &'static str, op: ChildOp) -> Self { - self.context.alter_child_in(region_key, op); + fn with_child_in(mut self, region_name: impl AsRef<str>, op: ChildOp) -> Self { + self.context.alter_child_in(region_name, op); self } @@ -286,8 +290,8 @@ impl Contextual for Page { self.context.theme() } - fn layout(&self) -> &str { - self.context.layout() + fn template(&self) -> &str { + self.context.template() } fn param<T: 'static>(&self, key: &'static str) -> Option<&T> { diff --git a/src/response/page/error.rs b/src/response/page/error.rs index 9945a948..7a590e6e 100644 --- a/src/response/page/error.rs +++ b/src/response/page/error.rs @@ -1,4 +1,4 @@ -use crate::base::component::Html; +use crate::base::component::{Html, Template}; use crate::core::component::Contextual; use crate::locale::L10n; use crate::response::ResponseError; @@ -33,7 +33,7 @@ impl Display for ErrorPage { let error403 = error_page.theme().error403(&mut error_page); if let Ok(page) = error_page .with_title(L10n::n("Error FORBIDDEN")) - .with_layout("error") + .with_template(Template::ERROR) .add_child(Html::with(move |_| error403.clone())) .render() { @@ -48,7 +48,7 @@ impl Display for ErrorPage { let error404 = error_page.theme().error404(&mut error_page); if let Ok(page) = error_page .with_title(L10n::n("Error RESOURCE NOT FOUND")) - .with_layout("error") + .with_template(Template::ERROR) .add_child(Html::with(move |_| error404.clone())) .render() {