diff --git a/.cargo/cliff.toml b/.cargo/cliff.toml deleted file mode 100644 index f6f14106..00000000 --- a/.cargo/cliff.toml +++ /dev/null @@ -1,79 +0,0 @@ -# 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 %}\ -{% 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="") - | 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="") --%} - -- {{ msg | trim }}{% 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 = "^🔖", skip = true }, - { message = "^✨", group = "Añadido" }, - { message = "^🐛", group = "Corregido" }, - { 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/config.toml b/.cargo/config.toml deleted file mode 100644 index d29b0de3..00000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,3 +0,0 @@ -[alias] -ts = ["test", "--features", "testing"] # cargo ts -tw = ["test", "--workspace", "--features", "testing"] # cargo tw diff --git a/.cargo/release.toml b/.cargo/release.toml deleted file mode 100644 index 68f7a9cc..00000000 --- a/.cargo/release.toml +++ /dev/null @@ -1,25 +0,0 @@ -# release.toml - -# Etiqueta por crate: `pagetop-macros-v0.2.0` -tag-prefix = "{{crate_name}}-" - -# 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 - -# Solo permite publicar estos crates (los que forman parte del workspace) -allow-branch = ["main"] -consolidate-commits = false - -# Mensaje personalizado para el commit de versión -pre-release-commit-message = "🔖 Prepara publicación de {{crate_name}} {{version}}" - -pre-release-hook = [ - "sh", "-c", "ROOT=$(git rev-parse --show-toplevel) && \"$ROOT/tools/changelog.sh\" {{crate_name}} {{version}} --stage" -] diff --git a/.gitignore b/.gitignore index ed088133..4ebc5a92 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,4 @@ -# Ignora directorios de compilación **/target - -# Archivos de log **/log/*.log* - -# Archivos de configuración locales -**/local.*.toml -**/local.toml -.env -.vscode +Cargo.lock +workdir diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index cbec9ab9..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,115 +0,0 @@ -# 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.5.0 (2026-05-03) - -PageTop 0.5.0 es la versión más ambiciosa hasta la fecha; concentra un largo periodo de trabajo en -refactorizaciones, nuevas abstracciones y mejoras que sientan las bases para una API estable y -robusta. - -Algunos cambios pueden romper la compatibilidad con versiones anteriores. Se recomienda consultar la -[documentación de PageTop](https://docs.rs/pagetop) para actualizar el código a un entorno más -expresivo y mejor preparado para crecer hacia la versión 1.0. Entre estos cambios destacan: - -- **Respuestas web completas**: soporte para páginas HTML, redirecciones HTTP, respuestas JSON, - cookies, y página de bienvenida integrada. -- **API de componentes consolidada**: ciclo de renderizado definitivo con `is_renderable`, manejo de - errores con `ComponentError` o mensajes de estado con `StatusMessage`/`MessageLevel`. -- **Temas hijo y macros de renderizado**: los temas pueden extenderse entre sí para sobrescribir el - renderizado de cualquier componente con `render_component!` y `setup_component!`. -- **Nueva acción `AlterMarkup`**: permite a extensiones y temas interceptar y transformar el HTML - final de cualquier componente antes de entregarlo. -- **Regiones y plantillas en temas**: los componentes `Region` y `Template` formalizan la gestión de - regiones, respaldados por una API de `Children` e `InRegion` completamente revisada. -- **Sistema de localización refactorizado**: nueva arquitectura interna con API más clara, mejor - integración en el contexto y soporte robusto para múltiples idiomas. -- **Tipos HTML consolidados**: unidades CSS, clase `Classes`, atributos HTML refactorizados y - cadenas internas optimizadas con `CowStr`. -- **Nuevas macros y utilidades de API pública**: macro `Getters` para exponer campos de componentes. -- **Configuración tipada**: nuevas opciones de configuración enumeradas para el log y otros - parámetros del sistema, con una gestión más expresiva y segura. -- **Recursos estáticos y trazabilidad**: gestión de recursos estáticos integrada en el núcleo de - PageTop y soporte para trazas y registro de eventos desde la propia librería. - -## 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_child` - -### 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 -- Unifica conversiones a String con `to_string()` -- Elimina `Render` para usar siempre el contexto - -## 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 - -## 0.2.0 (2025-08-09) - -### Añadido - -- Añade librería para gestionar recursos estáticos -- Añade soporte a changelog de `pagetop-statics` - -### Documentado - -- Corrige enlace del botón 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/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 48fe96bf..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,130 +0,0 @@ -# Guía de contribución a PageTop - -Gracias por tu interés en contribuir a **PageTop** 🎉 - -Este documento describe **cómo participar en el desarrollo del proyecto**, el flujo de trabajo y las -normas que permitan garantizar un historial limpio, trazable y sostenible a largo plazo. - -Por favor, léelo completo antes de abrir una *issue* o una *pull request*. - - -## 1. Repositorios - -PageTop mantiene **un único repositorio oficial**: - - * **Repositorio oficial:** https://git.cillero.es/manuelcillero/pagetop - * **Repositorio espejo:** https://github.com/manuelcillero/pagetop - -> ⚠️ **Importante** -> Aunque GitHub permite abrir *issues* y *pull requests*, **la integración del código se realiza -> únicamente en el repositorio oficial**. GitHub actúa como repositorio espejo que se sincroniza -> automáticamente para reflejar el mismo estado. - - -## 2. Issues (incidencias, propuestas, preguntas) - -Antes de abrir una *issue* **en GitHub**: - - * comprueba que no exista ya una similar, - * describe claramente el problema o propuesta, - * incluye pasos de reproducción si se trata de un *bug*, - * indica versión, entorno y contexto cuando sea relevante. - -Las *issues* se usan para: - - * informar de errores, - * propuestas de mejora, - * discusión técnica previa a cambios relevantes. - - -## 3. Pull Requests (PRs) - -### 3.1 Dónde abrirlas - -Las *pull requests* se abren **en GitHub**, normalmente contra la rama `main`. GitHub es el punto de -entrada recomendado para contribuciones externas. - -### 3.2 Reglas generales para PRs - - * Cada PR debe abordar **un único objetivo claro**. - * Mantén el alcance lo más acotado posible. - * Incluye descripción clara del cambio. - * Si el PR corrige una *issue*, enlázala explícitamente. - * Asegúrate de que el código compila y pasa las pruebas. - -### 3.3 Revisión y aceptación - -Todas las PRs son **revisadas manualmente** y pueden recibir comentarios o solicitudes de cambios. - -Las PRs aceptadas se integran en el repositorio oficial, nunca directamente en GitHub, preservando -siempre la **autoría original** del contribuidor. - - -### 3.4. Cierre de Pull Requests y sincronización - -Una vez que el cambio ha sido integrado en el repositorio oficial: - - * La PR en GitHub se **cierra manualmente**. - * Se añade un **mensaje estándar de cierre** indicando que el cambio ha sido integrado. - * El repositorio de GitHub **se sincroniza automáticamente** como espejo. - - -## 4. Estilo de código y calidad - - * Sigue el estilo existente del proyecto. - * Mantén los comentarios claros y precisos. - * La documentación es parte del código: actualízala cuando sea necesario. - * Cambios públicos o estructurales deben ir acompañados de documentación. - - -## 5. Commits - -PageTop usa la especificación **gitmoji** para los mensajes de *commit*. El formato recomendado es: - - ```text - [(ámbito opcional):] - «LÍNEA EN BLANCO» - Cuerpo opcional - «LÍNEA EN BLANCO» - Nota(s) al pie opcional(es) para referencias, incidencias o cambios incompatibles - ``` - -Ejemplos (no más de 50 caracteres en la primera línea, y no más de 80 en el resto): - - * `📝 Actualiza la guía de contribución` - * `♻️ (locale): Refactoriza sistema de localización` - * Un mensaje completo: - ``` - 🎨 (bootsier): Mejora la asignación de clases - - - Simplifica la generación de clases CSS para componentes Bootstrap. - - Elimina duplicidades en enums de estilos y centraliza la lógica de composición - para reducir errores y facilitar mantenimiento. - - Alinea los nombres de variantes con la documentación pública. - - Refs: PR #123 - ``` - -El emoji puede usarse en formato Unicode o como *shortcode*, por ejemplo `:sparkles:` en vez de ✨. - -Consulta la especificación oficial en https://gitmoji.dev/specification - -Durante la integración, los *commits* pueden ajustarse para adaptarse al historial del proyecto. - -Un *commit* debe representar una unidad lógica de cambio. Usa mensajes claros y descriptivos. - - -## 6. Comunicación y respeto - -PageTop sigue un enfoque profesional y colaborativo: - - * Sé respetuoso en revisiones y discusiones. - * Acepta sugerencias técnicas como parte del proceso. - * Recuerda que todas las contribuciones son revisadas con el objetivo de mejorar el proyecto. - -Si tienes dudas sobre el proceso, abre una *issue* de tipo pregunta para tratar la cuestión en -comunidad. - ---- - -Gracias por contribuir a **PageTop** 🚀 Cada aportación contribuye a mejorar el proyecto. diff --git a/CREDITS.md b/CREDITS.md index eaf97333..298295dc 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -1,40 +1,46 @@ -# 🔃 Dependencias +# ⌨️ Código -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 incluye código de la versión [0.11.0](https://github.com/mehcode/config-rs/tree/0.11.0) de + [config](https://crates.io/crates/config), de [Ryan Leckey](https://crates.io/users/mehcode), por + las facilidades que ofrece frente a sus versiones más modernas para leer los ajustes de + configuración y delegar su asignación a tipos seguros según los requerimientos de cada módulo, + tema o aplicación. - * [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. +* PageTop incorpora una versión adaptada del excelente *crate* [maud](https://crates.io/crates/maud) + de [Chris Wong](https://crates.io/users/lambda-fairy) (versión + [0.25.0](https://github.com/lambda-fairy/maud/tree/v0.25.0/maud)), para añadir sus funcionalidades + sin requerir la referencia a `maud` en el archivo `Cargo.toml` de cada proyecto. + +* PageTop usa los reconocidos *crates* [SQLx](https://github.com/launchbadge/sqlx) y + [SeaQuery](https://github.com/SeaQL/sea-query) para interactuar con bases de datos. Sin embargo, + para restringir las migraciones a módulos, se ha integrado en el código una versión modificada de + [SeaORM Migration](https://github.com/SeaQL/sea-orm/tree/master/sea-orm-migration) (versión + [0.11.3](https://github.com/SeaQL/sea-orm/tree/0.11.3/sea-orm-migration/src)). # 🗚 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 utiliza el paquete [figlet-rs](https://crates.io/crates/figlet-rs) de *yuanbohan* para +mostrar 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 `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* +* [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* + (predeterminado). +* [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*. -# 🎨 CSS +# 📰 Plantillas -La extensión `pagetop-bootsier` es un tema que integra [Bootstrap 5.3.8](https://getbootstrap.com/) -para los estilos y componentes de la interfaz. Bootstrap está distribuido bajo licencia -[MIT](https://github.com/twbs/bootstrap/blob/main/LICENSE). +* El diseño de la página predeterminada de inicio está basado en la plantilla + [Zinc](https://themewagon.com/themes/free-bootstrap-5-html5-business-website-template-zinc) creada + por [inovatik](https://inovatik.com/) y distribuida por [ThemeWagon](https://themewagon.com). -# 👾 Icono +# 🎨 Icono -"La Mascota" 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). +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/Cargo.lock b/Cargo.lock deleted file mode 100644 index bf8d11ed..00000000 --- a/Cargo.lock +++ /dev/null @@ -1,3276 +0,0 @@ -# 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-files" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8c4f30e3272d7c345f88ae0aac3848507ef5ba871f9cc2a41c8085a0f0523b" -dependencies = [ - "actix-http", - "actix-service", - "actix-utils", - "actix-web", - "bitflags", - "bytes", - "derive_more 2.1.1", - "futures-core", - "http-range", - "log", - "mime", - "mime_guess", - "percent-encoding", - "pin-project-lite", - "v_htmlescape", -] - -[[package]] -name = "actix-http" -version = "3.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93acb4a42f64936f9b8cae4a433b237599dd6eb6ed06124eb67132ef8cc90662" -dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", - "base64 0.22.1", - "bitflags", - "brotli", - "bytes", - "bytestring", - "derive_more 2.1.1", - "encoding_rs", - "flate2", - "foldhash", - "futures-core", - "h2", - "http", - "httparse", - "httpdate", - "itoa", - "language-tags", - "local-channel", - "mime", - "percent-encoding", - "pin-project-lite", - "rand 0.10.1", - "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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f8c75c51892f18d9c46150c5ac7beb81c95f78c8b83a634d49f4ca32551fe7" -dependencies = [ - "bytestring", - "cfg-if", - "http", - "regex", - "regex-lite", - "serde", - "tracing", -] - -[[package]] -name = "actix-rt" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92589714878ca59a7626ea19734f0e07a6a875197eec751bb5d3f99e64998c63" -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 0.5.10", - "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-session" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "400c27fd4cdbe0082b7bbd29ac44a3070cbda1b2114138dc106ba39fe2f90dff" -dependencies = [ - "actix-service", - "actix-utils", - "actix-web", - "anyhow", - "derive_more 2.1.1", - "rand 0.9.4", - "serde", - "serde_json", - "tracing", -] - -[[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.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff87453bc3b56e9b2b23c1cc0b1be8797184accf51d2abe0f8a33ec275d316bf" -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 2.1.1", - "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 0.6.3", - "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 = "adler2" -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 0.1.7", - "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 0.2.17", -] - -[[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" -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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -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 = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[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 = "anstream" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" - -[[package]] -name = "anstyle-parse" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.61.2", -] - -[[package]] -name = "anyhow" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bitflags" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" - -[[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 = "block-buffer" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" -dependencies = [ - "hybrid-array", -] - -[[package]] -name = "brotli" -version = "8.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" -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 = "bstr" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" - -[[package]] -name = "bytestring" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86566c496f2f47d9b8147a4c8b02ffdb69c919fe0c2b2e7195d22cbba0e635c9" -dependencies = [ - "bytes", -] - -[[package]] -name = "cc" -version = "1.2.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" -dependencies = [ - "find-msvc-tools", - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "chacha20" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "rand_core 0.10.1", -] - -[[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 0.1.5", -] - -[[package]] -name = "chrono" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-link", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common 0.1.7", - "inout", -] - -[[package]] -name = "clap" -version = "4.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" -dependencies = [ - "clap_builder", -] - -[[package]] -name = "clap_builder" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_lex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" - -[[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.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" - -[[package]] -name = "colored" -version = "3.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" -dependencies = [ - "windows-sys 0.61.2", -] - -[[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.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e68cfe19cd7d23ffde002c24ffa5cda73931913ef394d5eaaa32037dc940c0c" -dependencies = [ - "pathdiff", - "serde_core", - "toml", - "winnow", -] - -[[package]] -name = "const-oid" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "convert_case" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "cookie" -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.6", - "sha2", - "subtle", - "time", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -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-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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "typenum", -] - -[[package]] -name = "crypto-common" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" -dependencies = [ - "hybrid-array", -] - -[[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.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" -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 0.4.0", - "proc-macro2", - "quote", - "rustc_version", - "syn", -] - -[[package]] -name = "derive_more" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" -dependencies = [ - "convert_case 0.10.0", - "proc-macro2", - "quote", - "rustc_version", - "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 0.10.4", - "crypto-common 0.1.7", - "subtle", -] - -[[package]] -name = "digest" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" -dependencies = [ - "block-buffer 0.12.0", - "const-oid", - "crypto-common 0.2.1", -] - -[[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 = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "fastrand" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" - -[[package]] -name = "figlet-rs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aad4cf7e378685c1af30f41b4832c29700325524c648d47752cabd5b97e7b09b" -dependencies = [ - "zip", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "flate2" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fluent-bundle" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01203cb8918f5711e73891b347816d932046f95f54207710bda99beaeb423bf4" -dependencies = [ - "fluent-langneg", - "fluent-syntax", - "intl-memoizer", - "intl_pluralrules", - "rustc-hash", - "self_cell", - "smallvec", - "unic-langid", -] - -[[package]] -name = "fluent-langneg" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eebbe59450baee8282d71676f3bfed5689aeab00b27545e83e5f14b1195e8b0" -dependencies = [ - "unic-langid", -] - -[[package]] -name = "fluent-syntax" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198" -dependencies = [ - "memchr", - "thiserror", -] - -[[package]] -name = "fluent-template-macros" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b1dac7e7f07f8a60aa844f616bede13deeffaf24e9e35ae9e4979a7dac4a5c" -dependencies = [ - "flume", - "ignore", - "proc-macro2", - "quote", - "syn", - "unic-langid", -] - -[[package]] -name = "fluent-templates" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d48ac2b8e7c3a2198fc584af78e674d15dacdede8a6cebb686c844713f7d0ba" -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" -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.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures-core" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" - -[[package]] -name = "futures-sink" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" - -[[package]] -name = "futures-task" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" - -[[package]] -name = "futures-util" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "slab", -] - -[[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.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "libc", - "r-efi 5.3.0", - "wasip2", -] - -[[package]] -name = "getrandom" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" -dependencies = [ - "cfg-if", - "libc", - "r-efi 6.0.0", - "rand_core 0.10.1", - "wasip2", - "wasip3", -] - -[[package]] -name = "getter-methods" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43d815f896a3c730f0d76b8348a1700dc8d8fd6c377e4590d531bdd646574d8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[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 = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - -[[package]] -name = "globset" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "grass" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7a68216437ef68f0738e48d6c7bb9e6e6a92237e001b03d838314b068f33c94" -dependencies = [ - "clap", - "getrandom 0.2.17", - "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.6", -] - -[[package]] -name = "h2" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "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.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash", -] - -[[package]] -name = "hashbrown" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[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 0.10.7", -] - -[[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 = "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" -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 = "hybrid-array" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d46837a0ed51fe95bd3b05de33cd64a1ee88fc797477ca48446872504507c5" -dependencies = [ - "typenum", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" -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.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" - -[[package]] -name = "icu_properties" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" - -[[package]] -name = "icu_provider" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "ignore" -version = "0.4.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata", - "same-file", - "walkdir", - "winapi-util", -] - -[[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.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" -dependencies = [ - "equivalent", - "hashbrown 0.17.0", - "serde", - "serde_core", -] - -[[package]] -name = "indoc" -version = "2.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" -dependencies = [ - "rustversion", -] - -[[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" -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 = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.4", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf" -dependencies = [ - "cfg-if", - "futures-util", - "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 = "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "libc" -version = "0.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "linux-raw-sys" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" - -[[package]] -name = "litemap" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" - -[[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.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - -[[package]] -name = "matchers" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "mime" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "mio" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.61.2", -] - -[[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.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "num-conv" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "pagetop" -version = "0.5.0" -dependencies = [ - "actix-files", - "actix-session", - "actix-web", - "chrono", - "colored", - "config", - "figlet-rs", - "fluent-templates", - "getter-methods", - "indexmap", - "itoa", - "pagetop-aliner", - "pagetop-bootsier", - "pagetop-build", - "pagetop-macros", - "pagetop-minimal", - "pagetop-statics", - "parking_lot", - "serde", - "serde_json", - "substring", - "tempfile", - "terminal_size", - "tracing", - "tracing-actix-web", - "tracing-appender", - "tracing-subscriber", - "unic-langid", -] - -[[package]] -name = "pagetop-aliner" -version = "0.1.0" -dependencies = [ - "pagetop", - "pagetop-build", -] - -[[package]] -name = "pagetop-bootsier" -version = "0.1.1" -dependencies = [ - "pagetop", - "pagetop-build", - "serde", -] - -[[package]] -name = "pagetop-build" -version = "0.3.2" -dependencies = [ - "grass", - "pagetop-statics", -] - -[[package]] -name = "pagetop-macros" -version = "0.3.0" -dependencies = [ - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn", -] - -[[package]] -name = "pagetop-minimal" -version = "0.1.0" -dependencies = [ - "concat-string", - "indoc", - "pastey", -] - -[[package]] -name = "pagetop-statics" -version = "0.1.3" -dependencies = [ - "actix-web", - "change-detection", - "derive_more 0.99.20", - "futures-util", - "mime_guess", - "path-slash 0.2.1", -] - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - -[[package]] -name = "pastey" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a797f0e07bdf071d15742978fc3128ec6c22891c31a3a931513263904c982a" - -[[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 = "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[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.6", -] - -[[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.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "pkg-config" -version = "0.3.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" - -[[package]] -name = "polyval" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" -dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "potential_utf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" -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 = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn", -] - -[[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.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -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.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -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 = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - -[[package]] -name = "rand" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", -] - -[[package]] -name = "rand" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" -dependencies = [ - "chacha20", - "getrandom 0.4.2", - "rand_core 0.10.1", -] - -[[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]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.17", -] - -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.4", -] - -[[package]] -name = "rand_core" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-lite" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" - -[[package]] -name = "regex-syntax" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - -[[package]] -name = "rustc-hash" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" - -[[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.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "ryu" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" - -[[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 = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" - -[[package]] -name = "semver" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "serde_spanned" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" -dependencies = [ - "serde_core", -] - -[[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.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "digest 0.11.2", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - -[[package]] -name = "simd-adler32" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" - -[[package]] -name = "siphasher" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" - -[[package]] -name = "slab" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" - -[[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 = "socket2" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ee6433ecef213b2e72f587ef64a2f5943e7cd16fbd82dbe8bc07486c534c86" -dependencies = [ - "autocfg", -] - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "symlink" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -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 = "tempfile" -version = "3.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" -dependencies = [ - "fastrand", - "getrandom 0.4.2", - "once_cell", - "rustix", - "windows-sys 0.61.2", -] - -[[package]] -name = "terminal_size" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" -dependencies = [ - "rustix", - "windows-sys 0.61.2", -] - -[[package]] -name = "thiserror" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -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.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde_core", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" - -[[package]] -name = "time-macros" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" -dependencies = [ - "displaydoc", - "serde_core", - "zerovec", -] - -[[package]] -name = "tokio" -version = "1.52.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" -dependencies = [ - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2 0.6.3", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-util" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "1.1.2+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" -dependencies = [ - "serde_core", - "serde_spanned", - "toml_datetime", - "toml_parser", - "winnow", -] - -[[package]] -name = "toml_datetime" -version = "1.1.1+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_parser" -version = "1.1.2+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" -dependencies = [ - "winnow", -] - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-actix-web" -version = "0.7.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca6b15407f9bfcb35f82d0e79e603e1629ece4e91cc6d9e58f890c184dd20af" -dependencies = [ - "actix-web", - "mutually_exclusive_features", - "pin-project", - "tracing", - "uuid", -] - -[[package]] -name = "tracing-appender" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" -dependencies = [ - "crossbeam-channel", - "symlink", - "thiserror", - "time", - "tracing-subscriber", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -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.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex-automata", - "serde", - "serde_json", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", - "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", -] - -[[package]] -name = "typenum" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" - -[[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 = "unicase" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "unicode-segmentation" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" - -[[package]] -name = "unicode-xid" -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 0.1.7", - "subtle", -] - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf8_iter" -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.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" -dependencies = [ - "getrandom 0.4.2", - "js-sys", - "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "version_check" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasip2" -version = "1.0.3+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" -dependencies = [ - "wit-bindgen 0.57.1", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen 0.51.0", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.120" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.120" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.120" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.120" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap", - "semver", -] - -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link", -] - -[[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.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - -[[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 = "winnow" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" -dependencies = [ - "memchr", -] - -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen" -version = "0.57.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - -[[package]] -name = "writeable" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" - -[[package]] -name = "yoke" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zerofrom" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerotrie" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" -dependencies = [ - "serde", - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "byteorder", - "crc32fast", - "crossbeam-utils", - "flate2", -] - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" - -[[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.16+zstd.1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/Cargo.toml b/Cargo.toml index d809c122..2029180c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,92 +1,27 @@ -[package] -name = "pagetop" -version = "0.5.0" -edition = "2021" - -description = """ - Un entorno de desarrollo para crear soluciones web modulares, extensibles y configurables. -""" -categories = ["web-programming::http-server"] -keywords = ["pagetop", "web", "framework", "frontend", "ssr"] - -repository.workspace = true -homepage.workspace = true -license.workspace = true -authors.workspace = true - -[dependencies] -chrono = "0.4" -colored = "3.1" -config = { version = "0.15", default-features = false, features = ["toml"] } -figlet-rs = "1.0" -getter-methods = "2.0" -itoa = "1.0" -indexmap = "2.14" -parking_lot = "0.12" -substring = "1.4" -terminal_size = "0.4" - -tracing = "0.1" -tracing-appender = "0.2" -tracing-subscriber = { version = "0.3", features = ["json", "env-filter"] } -tracing-actix-web = "0.7" - -fluent-templates = "0.14" -unic-langid = { version = "0.9", features = ["macros"] } - -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.workspace = true - -pagetop-macros.workspace = true -pagetop-minimal.workspace = true -pagetop-statics.workspace = true - -[features] -default = [] -testing = [] - -[dev-dependencies] -tempfile = "3.27" -serde_json = "1.0" -pagetop-aliner.workspace = true -pagetop-bootsier.workspace = true - -[build-dependencies] -pagetop-build.workspace = true - - [workspace] -resolver = "2" + members = [ - # Helpers - "helpers/pagetop-build", - "helpers/pagetop-macros", - "helpers/pagetop-minimal", - "helpers/pagetop-statics", - # Extensions - "extensions/pagetop-aliner", - "extensions/pagetop-bootsier", + "pagetop", + # Utilities. + "pagetop-macros", + "pagetop-build", + "pagetop-jquery", + "pagetop-homedemo", + # Components. + "pagetop-minimal", + "pagetop-megamenu", + # Modules. + "pagetop-admin", + "pagetop-user", + "pagetop-node", + # Themes. + "pagetop-aliner", + "pagetop-bootsier", + "pagetop-bulmix", ] -[workspace.package] -repository = "https://git.cillero.es/manuelcillero/pagetop" -homepage = "https://pagetop.cillero.es" -license = "MIT OR Apache-2.0" -authors = ["Manuel Cillero "] - -[workspace.dependencies] -actix-web = { version = "4.13", default-features = false } -serde = { version = "1.0", features = ["derive"] } -# Helpers -pagetop-build = { version = "0.3", path = "helpers/pagetop-build" } -pagetop-macros = { version = "0.3", path = "helpers/pagetop-macros" } -pagetop-minimal = { version = "0.1", path = "helpers/pagetop-minimal" } -pagetop-statics = { version = "0.1", path = "helpers/pagetop-statics" } -# Extensions -pagetop-aliner = { version = "0.1", path = "extensions/pagetop-aliner" } -pagetop-bootsier = { version = "0.1", path = "extensions/pagetop-bootsier" } -# PageTop -pagetop = { version = "0.5", path = "." } +exclude = [ + "drust", + "examples", + "tests", +] diff --git a/MAINTAINERS.md b/MAINTAINERS.md deleted file mode 100644 index 25559841..00000000 --- a/MAINTAINERS.md +++ /dev/null @@ -1,156 +0,0 @@ -# MAINTAINERS.md - -## Guía para mantenedores de PageTop - -Este documento describe **el flujo técnico interno de revisión e integración de contribuciones** en -**PageTop**. - -Está dirigido a **mantenedores del proyecto** y **no forma parte de la guía de contribución para -usuarios externos**. Su objetivo es servir como **referencia operativa**, garantizando coherencia, -trazabilidad y preservación de la autoría en un entorno con repositorios espejo. - - -## 1. Repositorios y principios - -PageTop mantiene **un único repositorio oficial**: - - * **Repositorio oficial:** https://git.cillero.es/manuelcillero/pagetop - * **Repositorio espejo:** https://github.com/manuelcillero/pagetop - -### Principios clave - - * El repositorio oficial **es la única fuente de verdad** del historial. - * **Nunca se realizan *merges* en GitHub**. - * Toda integración definitiva se realiza en el repositorio oficial. - * La autoría original debe preservarse siempre. - - -## 2. Configuración local recomendada - -El remoto `github` debe configurarse únicamente para operaciones de lectura (*fetch*), con la URL de -*push* deshabilitada para evitar publicaciones accidentales en el repositorio espejo. - -Estado esperado de `git remote -v`: - -```text -origin git@git.cillero.es:manuelcillero/pagetop.git (fetch) -origin git@git.cillero.es:manuelcillero/pagetop.git (push) -github git@github.com:manuelcillero/pagetop.git (fetch) -github DISABLED (push) -``` - -Convenciones usadas en este documento: - - * `origin` -> Repositorio oficial - * `github` -> Repositorio espejo - - -## 3. Recepción y revisión de Pull Requests - -Las PRs externas llegan por GitHub, normalmente contra la rama `main`. - -Se asume que el repositorio local está configurado para recuperar PRs de GitHub como referencias -remotas (`refs/pull//head`): - -```bash -git fetch github --prune -git checkout -b pr-123 github/pr/123 -``` - -Antes de integrar: - - * Revisar el código manualmente. - * Verificar formato, análisis y pruebas: - - ```bash - cargo fmt - cargo clippy - cargo test - ``` - - * Comprobar impacto en documentación. - * Evaluar coherencia con la arquitectura y el estilo del proyecto. - -Los cambios adicionales se solicitan o se aplican explicando claramente el motivo. - - -## 4. Estrategia de integración - -La integración **se realiza siempre en el repositorio oficial** (`origin`). - -### 4.1 Estrategia por defecto: *rebase* + *fast-forward* - -Esta es la **estrategia estándar y recomendada** en PageTop. Ventajas: - - * conserva los commits originales, - * preserva la autoría real de cada cambio, - * mantiene un historial lineal y trazable, - * facilita auditoría y depuración. - -Procedimiento típico: - -```bash -git checkout pr-123 -git rebase main - -# Resolver conflictos si los hay - -git checkout main -git merge --ff-only pr-123 -``` - -Si `merge --ff-only` falla, **no se debe continuar**, indica divergencias que deben resolverse antes -de integrar la PR. - -### 4.2 Estrategia excepcional: *Squash* - -Sólo debe usarse cuando esté justificado: - - * la PR contiene múltiples commits de prueba o ruido, - * el historial aportado no es significativo, - * el cambio es pequeño y autocontenido. - -En este caso, se debe **preservar explícitamente la autoría**: - -```bash -git checkout main -git merge --squash pr-123 -git commit --author="Nombre Apellido " -``` - - -### 4.3. Publicación en el repositorio oficial - -```bash -git push origin main -``` - -Este *push* representa la **integración definitiva** del cambio en la rama `main`. - - -## 5. Cierre de la PR y sincronización - -Tras integrar el cambio en el repositorio oficial, se cierra manualmente la PR en GitHub con un -mensaje estándar: - -```text -Gracias por tu contribución. - -Este cambio ha sido integrado en el repositorio oficial en `main` (``). -GitHub actúa como repositorio espejo sincronizado. -``` - - -## 6. Principios de mantenimiento - - * Priorizar **claridad y trazabilidad** frente a rapidez. - * Mantener un historial legible y significativo. - * Documentar cambios estructurales o públicos. - * Tratar las contribuciones externas con respeto y transparencia. - ---- - -Este documento puede evolucionar con el proyecto. - -No se trata de imponer rigidez, sino de **capturar el conocimiento operativo real** de PageTop como -guía práctica para el mantenimiento. diff --git a/README.md b/README.md index 463855f2..cfc3abcd 100644 --- a/README.md +++ b/README.md @@ -1,176 +1,105 @@
- + -

PageTop

+

PageTop

-

Un entorno para el desarrollo de soluciones web modulares, extensibles y configurables.

+ [![crate](https://img.shields.io/crates/v/pagetop.svg)](https://crates.io/crates/pagetop) + [![docs](https://docs.rs/pagetop/badge.svg)](https://docs.rs/pagetop) -[![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)](https://git.cillero.es/manuelcillero/pagetop#licencia) - -
-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: +**PageTop** es un entorno de desarrollo basado en [Rust](https://www.rust-lang.org/es/) que reúne +algunos de los crates más estables y populares para crear soluciones web modulares, extensibles y +configurables. - * **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. +Incluye **Drust**, un sistema de gestión de contenidos basado en PageTop que permite crear, editar y +mantener sitios web dinámicos, rápidos y seguros. -## ⚡️ Guía rápida +# 🚧 Advertencia -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 { - Page::new(request) - .add_child(Html::with(|_| 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 `

`. +**PageTop** es un proyecto personal para aprender Rust y conocer su ecosistema. Sólo se liberan +versiones de desarrollo. En este contexto la API no es estable y los cambios son constantes. No +puede considerarse preparado hasta que se libere la versión **0.1.0**. -## 📂 Proyecto +# 📂 Estructura del código -El código se organiza en un *workspace* donde actualmente se incluyen los siguientes subproyectos: +El repositorio se organiza en un *workspace* con 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. +* **[pagetop](https://github.com/manuelcillero/pagetop/tree/main/pagetop)**, es la librería esencial + construida con *crates* estables y muy conocidos del ecosistema Rust para proporcionar APIs, + patrones de desarrollo y buenas prácticas para la creación avanzada de soluciones web SSR + (*Server-Side Rendering*). -### Auxiliares +## Auxiliares - * **[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. +* **[pagetop-macros](https://github.com/manuelcillero/pagetop/tree/main/pagetop-macros)**, agrupa + las principales macros procedurales para usar desde **PageTop**. - * **[pagetop-macros](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-macros)**, - proporciona una colección de macros procedurales que mejoran la experiencia de desarrollo con - PageTop. +* **[pagetop-build](https://github.com/manuelcillero/pagetop/tree/main/pagetop-build)**, permite + incluir fácilmente recursos en los archivos binarios al compilar aplicaciones creadas con + **PageTop**. - * **[pagetop-minimal](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-minimal)**, - ofrece macros declarativas esenciales para optimizar tareas comunes como la composición de - texto, la concatenación de cadenas y el manejo de colecciones clave-valor. +## Componentes - * **[pagetop-statics](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-statics)**, - 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-minimal](https://github.com/manuelcillero/pagetop/tree/main/pagetop-minimal)**, módulo + que proporciona un conjunto básico de componentes para la composición de páginas. -### Extensiones +* **[pagetop-jquery](https://github.com/manuelcillero/pagetop/tree/main/pagetop-jquery)**, módulo + que permite añadir jQuery en las páginas que incluyen componentes o temas que usen esta librería + JavaScript para interactuar con el documento HTML.​ - * **[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-megamenu](https://github.com/manuelcillero/pagetop/tree/main/pagetop-megamenu)**, + módulo que proporciona un nuevo componente para incluir menús avanzados en las aplicaciones web + creadas con **PageTop**. - * **[pagetop-bootsier](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-bootsier)**, - tema basado en [Bootstrap](https://getbootstrap.com) para integrar su catálogo de estilos y - componentes flexibles. +## Módulos + +* **[pagetop-homedemo](https://github.com/manuelcillero/pagetop/tree/main/pagetop-homedemo)**, + módulo que muestra una página de inicio de demostración para presentar **PageTop**. + +* **[pagetop-admin](https://github.com/manuelcillero/pagetop/tree/main/pagetop-admin)**, módulo que + proporciona a otros módulos un lugar común donde presentar a los administradores sus opciones de + configuración. + +* **[pagetop-user](https://github.com/manuelcillero/pagetop/tree/main/pagetop-user)**, módulo para + añadir gestión de usuarios, roles, permisos y sesiones en aplicaciones desarrolladas con PageTop. + +* **[pagetop-node](https://github.com/manuelcillero/pagetop/tree/main/pagetop-node)**, módulo para + crear, extender o personalizar los tipos de contenido que puede administrar un sitio web. + +## Temas + +* **[pagetop-aliner](https://github.com/manuelcillero/pagetop/tree/main/pagetop-aliner)**, tema que + delimita con cajas los elementos HTML para mostrar esquemáticamente la composición de las páginas. + +* **[pagetop-bootsier](https://github.com/manuelcillero/pagetop/tree/main/pagetop-bootsier)**, tema + que utiliza el *framework* [Bootstrap](https://getbootstrap.com/) para la composición de páginas y + visualización de componentes. + +* **[pagetop-bulmix](https://github.com/manuelcillero/pagetop/tree/main/pagetop-bulmix)**, tema que + utiliza el *framework* [Bulma](https://bulma.io/) para la composición de páginas y visualización + de componentes. + +## Aplicación + +* **[drust](https://github.com/manuelcillero/pagetop/tree/main/drust)**, es una aplicación + inspirada modestamente en [Drupal](https://www.drupal.org) que utiliza PageTop para crear un CMS + (*Content Management System* o sistema de gestión de contenidos) para construir sitios web + dinámicos, administrados y configurables. -## 🧪 Pruebas +# 📜 Licencia -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: +Este proyecto tiene licencia, de hecho tiene dos, puedes aplicar cualquiera de las siguientes a tu +elección: -| 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 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*. | +* Licencia Apache versión 2.0 + ([LICENSE-APACHE](https://github.com/manuelcillero/pagetop/blob/main/LICENSE-APACHE) o + [http://www.apache.org/licenses/LICENSE-2.0]). -> **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 -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. - - -## ✨ Contribuir - -PageTop mantiene **un único repositorio oficial**: - - * **Repositorio oficial:** https://git.cillero.es/manuelcillero/pagetop - * **Repositorio espejo:** https://github.com/manuelcillero/pagetop - -El repositorio de GitHub actúa como espejo y punto de entrada para: - - * dar mayor visibilidad al proyecto, - * facilitar la participación de la comunidad, - * centralizar *issues* y *pull requests* externas. - -Aunque GitHub permite abrir *pull requests*, **la integración del código se realiza únicamente en el -repositorio oficial**. El repositorio de GitHub se sincroniza posteriormente para reflejar el mismo -estado. - -En todos los casos, se respeta la **autoría original** de las contribuciones integradas, tanto en el -historial como en la documentación asociada al cambio. - -Para conocer el proceso completo de participación, revisión e integración de cambios, consulta el -archivo [`CONTRIBUTING.md`](CONTRIBUTING.md). - -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*. +* Licencia MIT + ([LICENSE-MIT](https://github.com/manuelcillero/pagetop/blob/main/LICENSE-MIT) o + [http://opensource.org/licenses/MIT]). diff --git a/banner-pagetop.png b/banner-pagetop.png new file mode 100644 index 00000000..3ad51741 Binary files /dev/null and b/banner-pagetop.png differ diff --git a/config/default.toml b/config/default.toml deleted file mode 100644 index 3e254586..00000000 --- a/config/default.toml +++ /dev/null @@ -1,2 +0,0 @@ -[log] -tracing = "Info,pagetop=Debug" diff --git a/drust/Cargo.toml b/drust/Cargo.toml new file mode 100644 index 00000000..c0de9ab6 --- /dev/null +++ b/drust/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "drust" +version = "0.0.3" +edition = "2021" + +authors = [ + "Manuel Cillero " +] +description = """\ + A modern web Content Management System to share your world.\ +""" +homepage = "https://pagetop.cillero.es" +repository = "https://github.com/manuelcillero/pagetop" +license = "Apache-2.0 OR MIT" + +[dependencies] +pagetop = { version = "0.0", path = "../pagetop", features = ["mysql"], default-features = false } +# Themes. +pagetop-aliner = { version = "0.0", path = "../pagetop-aliner" } +pagetop-bootsier = { version = "0.0", path = "../pagetop-bootsier" } +pagetop-bulmix = { version = "0.0", path = "../pagetop-bulmix" } +# Modules. +pagetop-homedemo = { version = "0.0", path = "../pagetop-homedemo" } +pagetop-admin = { version = "0.0", path = "../pagetop-admin" } +pagetop-user = { version = "0.0", path = "../pagetop-user" } +pagetop-node = { version = "0.0", path = "../pagetop-node" } diff --git a/drust/README.md b/drust/README.md new file mode 100644 index 00000000..25431d18 --- /dev/null +++ b/drust/README.md @@ -0,0 +1,28 @@ +**Drust** es una aplicación inspirada modestamente en [Drupal](https://www.drupal.org) que utiliza +**PageTop** para crear un CMS (*Content Management System* o sistema de gestión de contenidos) para +construir sitios web dinámicos, administrados y configurables. + +[PageTop](https://github.com/manuelcillero/pagetop/tree/main/pagetop), es un entorno de desarrollo +basado en algunos de los *crates* más estables y populares del ecosistema Rust para proporcionar +APIs, patrones de desarrollo y buenas prácticas para la creación de soluciones web SSR (*Server-Side +Rendering*). + + +# 🚧 Advertencia + +**PageTop** sólo libera actualmente versiones de desarrollo. La API no es estable y los cambios son +constantes. No puede considerarse preparado hasta que se libere la versión **0.1.0**. + + +# 📜 Licencia + +Este proyecto tiene licencia, de hecho tiene dos, puedes aplicar cualquiera de las siguientes a tu +elección: + +* Licencia Apache versión 2.0 + ([LICENSE-APACHE](https://github.com/manuelcillero/pagetop/blob/main/LICENSE-APACHE) o + [http://www.apache.org/licenses/LICENSE-2.0]). + +* Licencia MIT + ([LICENSE-MIT](https://github.com/manuelcillero/pagetop/blob/main/LICENSE-MIT) o + [http://opensource.org/licenses/MIT]). diff --git a/drust/config/common.toml b/drust/config/common.toml new file mode 100644 index 00000000..1562e469 --- /dev/null +++ b/drust/config/common.toml @@ -0,0 +1,8 @@ +[app] +name = "Drust" +description = """\ + A modern web Content Management System to share your world.\ +""" + +[database] +db_type = "mysql" diff --git a/drust/config/default.toml b/drust/config/default.toml new file mode 100644 index 00000000..1cbcbfea --- /dev/null +++ b/drust/config/default.toml @@ -0,0 +1,4 @@ +[database] +db_name = "drust" +db_user = "drust" +db_pass = "DrU__#3T" diff --git a/drust/config/local.toml b/drust/config/local.toml new file mode 100644 index 00000000..410a913d --- /dev/null +++ b/drust/config/local.toml @@ -0,0 +1,12 @@ +[app] +#theme = "Default" +#theme = "Aliner" +theme = "Bootsier" +#theme = "Bulmix" +language = "es-ES" + +[log] +tracing = "Info,pagetop=Debug,sqlx::query=Warn" + +[dev] +#static_files = "../pagetop/static" diff --git a/drust/src/main.rs b/drust/src/main.rs new file mode 100644 index 00000000..306b3c02 --- /dev/null +++ b/drust/src/main.rs @@ -0,0 +1,36 @@ +use pagetop::prelude::*; + +new_handle!(APP_DRUST); + +struct Drust; + +impl ModuleTrait for Drust { + fn handle(&self) -> Handle { + APP_DRUST + } + + fn dependencies(&self) -> Vec { + vec![ + // Themes. + &pagetop_aliner::Aliner, + &pagetop_bootsier::Bootsier, + &pagetop_bulmix::Bulmix, + // Modules. + &pagetop_homedemo::HomeDemo, + &pagetop_admin::Admin, + &pagetop_user::User, + &pagetop_node::Node, + ] + } + + fn drop_modules(&self) -> Vec { + vec![ + // &pagetop_node::Node + ] + } +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&Drust).unwrap().run()?.await +} diff --git a/examples/Cargo.toml b/examples/Cargo.toml new file mode 100644 index 00000000..167bbef8 --- /dev/null +++ b/examples/Cargo.toml @@ -0,0 +1,4 @@ +[workspace] +members = [ + "basics/*", +] diff --git a/examples/app-basic.rs b/examples/app-basic.rs deleted file mode 100644 index 53743870..00000000 --- a/examples/app-basic.rs +++ /dev/null @@ -1,6 +0,0 @@ -use pagetop::prelude::*; - -#[pagetop::main] -async fn main() -> std::io::Result<()> { - Application::new().run()?.await -} diff --git a/examples/basics/hello-name/Cargo.toml b/examples/basics/hello-name/Cargo.toml new file mode 100644 index 00000000..6b41c11b --- /dev/null +++ b/examples/basics/hello-name/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "hello_name" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +actix-web = "4" +pagetop = { version = "0.0", path = "../../../pagetop" } diff --git a/examples/basics/hello-name/src/main.rs b/examples/basics/hello-name/src/main.rs new file mode 100644 index 00000000..0af7c2d0 --- /dev/null +++ b/examples/basics/hello-name/src/main.rs @@ -0,0 +1,31 @@ +use pagetop::prelude::*; + +new_handle!(APP_HELLO_NAME); + +struct HelloName; + +impl ModuleTrait for HelloName { + fn handle(&self) -> Handle { + APP_HELLO_NAME + } + + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + scfg.service(hello_name); + } +} + +#[service::get("/hello/{name}")] +async fn hello_name( + request: service::HttpRequest, + path: service::web::Path, +) -> ResultPage { + let name = path.into_inner(); + Page::new(request) + .with_in("content", Html::with(html! { h1 { "Hello " (name) "!" } })) + .render() +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&HelloName).unwrap().run()?.await +} diff --git a/examples/basics/hello-world/Cargo.toml b/examples/basics/hello-world/Cargo.toml new file mode 100644 index 00000000..517f6a10 --- /dev/null +++ b/examples/basics/hello-world/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "hello_world" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +pagetop = { version = "0.0", path = "../../../pagetop" } diff --git a/examples/basics/hello-world/src/main.rs b/examples/basics/hello-world/src/main.rs new file mode 100644 index 00000000..176c7304 --- /dev/null +++ b/examples/basics/hello-world/src/main.rs @@ -0,0 +1,26 @@ +use pagetop::prelude::*; + +new_handle!(APP_HELLO_WORLD); + +struct HelloWorld; + +impl ModuleTrait for HelloWorld { + fn handle(&self) -> Handle { + APP_HELLO_WORLD + } + + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + scfg.route("/", service::web::get().to(hello_world)); + } +} + +async fn hello_world(request: service::HttpRequest) -> ResultPage { + Page::new(request) + .with_in("content", Html::with(html! { h1 { "Hello World!" } })) + .render() +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&HelloWorld).unwrap().run()?.await +} diff --git a/examples/form-controls.rs b/examples/form-controls.rs deleted file mode 100644 index e49844e8..00000000 --- a/examples/form-controls.rs +++ /dev/null @@ -1,456 +0,0 @@ -use pagetop::prelude::*; - -use pagetop_bootsier::prelude::*; - -include_locales!(LOC from "examples/locale"); - -struct FormControls; - -impl Extension for FormControls { - fn dependencies(&self) -> Vec { - vec![&pagetop_aliner::Aliner, &pagetop_bootsier::Bootsier] - } - - fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { - scfg.route("/", service::web::get().to(form_controls)); - } -} - -async fn form_controls(request: HttpRequest) -> ResultPage { - Page::new(request) - .with_child( - Intro::default() - .with_opening(IntroOpening::Custom) - .with_title(L10n::t("title", &LOC)) - .with_slogan(L10n::t("slogan", &LOC)) - .with_button(None::<(L10n, FnPathByContext)>) - // Bloque 1: casillas, interruptores y botones de opción. - .with_child( - Block::new() - .with_title(L10n::t("block_selections", &LOC)) - .with_child( - Form::new() - .with_id("form-selections") - .with_action("/") - .with_method(form::Method::Post) - // Casillas e interruptores (form::Checkbox). - .with_child( - form::Fieldset::new() - .with_legend(L10n::t("fieldset_checkbox", &LOC)) - .with_description(L10n::t("desc_checkbox", &LOC)) - .with_child( - form::Checkbox::new() - .with_name("accept_terms") - .with_label(L10n::t("label_terms", &LOC)) - .with_required(true), - ) - .with_child( - form::Checkbox::new() - .with_name("accept_marketing") - .with_label(L10n::t("label_marketing", &LOC)) - .with_checked(true) - .with_inline(true), - ) - .with_child( - form::Checkbox::new() - .with_name("newsletter") - .with_label(L10n::t("label_newsletter", &LOC)) - .with_inline(true), - ) - .with_child( - form::Checkbox::switch() - .with_name("notifications") - .with_label(L10n::t("label_notifications", &LOC)) - .with_checked(true) - .with_reverse(true), - ) - .with_child( - form::Checkbox::switch() - .with_name("dark_mode") - .with_label(L10n::t("label_dark_mode", &LOC)) - .with_disabled(true), - ), - ) - // Grupo de casillas de verificación (form::check::Field). - .with_child( - form::Fieldset::new() - .with_legend(L10n::t("fieldset_checkgroup", &LOC)) - .with_child( - form::check::Field::new() - .with_name("interests") - .with_label(L10n::t("label_interests", &LOC)) - .with_help_text(L10n::t("help_interests", &LOC)) - .with_item( - form::check::Item::new( - "rust", - L10n::t("check_rust", &LOC), - ) - .with_checked(true), - ) - .with_item(form::check::Item::new( - "web", - L10n::t("check_web", &LOC), - )) - .with_item(form::check::Item::new( - "ai", - L10n::t("check_ai", &LOC), - )) - .with_item( - form::check::Item::new( - "games", - L10n::t("check_games", &LOC), - ) - .with_disabled(true), - ), - ), - ) - // Botones de opción (form::radio::Field). - .with_child( - form::Fieldset::new() - .with_legend(L10n::t("fieldset_radio", &LOC)) - .with_child( - form::radio::Field::new() - .with_name("frequency") - .with_label(L10n::t("label_frequency", &LOC)) - .with_item(form::radio::Item::new( - "daily", - L10n::t("radio_daily", &LOC), - )) - .with_item( - form::radio::Item::new( - "weekly", - L10n::t("radio_weekly", &LOC), - ) - .with_checked(true), - ) - .with_item(form::radio::Item::new( - "monthly", - L10n::t("radio_monthly", &LOC), - )) - .with_item( - form::radio::Item::new( - "never", - L10n::t("radio_never", &LOC), - ) - .with_disabled(true), - ), - ), - ) - // Campo oculto (form::Hidden). - .with_child( - form::Hidden::new() - .with_name("origin") - .with_value("form-selections"), - ) - // Botones de acción. - .with_child( - Button::submit(L10n::t("btn_submit", &LOC)) - .with_color(ButtonColor::Background(Color::Primary)), - ) - .with_child( - Button::reset(L10n::t("btn_reset", &LOC)) - .with_color(ButtonColor::Outline(Color::Secondary)), - ) - .with_child( - Button::plain(L10n::t("btn_cancel", &LOC)) - .with_color(ButtonColor::Link), - ), - ), - ) - // Bloque 2: campos de texto, multilínea y rango. - .with_child( - Block::new() - .with_title(L10n::t("block_text", &LOC)) - .with_child( - Form::new() - .with_id("form-text") - .with_action("/") - .with_method(form::Method::Post) - // Campos de texto (form::input::Field). - .with_child( - form::Fieldset::new() - .with_legend(L10n::t("fieldset_text", &LOC)) - .with_child( - form::input::Field::text() - .with_name("name") - .with_label(L10n::t("label_name", &LOC)) - .with_placeholder(L10n::t("placeholder_name", &LOC)) - .with_required(true), - ) - .with_child( - form::input::Field::email() - .with_name("email") - .with_label(L10n::t("label_email", &LOC)) - .with_placeholder(L10n::t( - "placeholder_email", - &LOC, - )) - .with_autocomplete( - Some(form::Autocomplete::email()), - ) - .with_required(true), - ) - .with_child( - form::input::Field::password() - .with_name("password") - .with_label(L10n::t("label_password", &LOC)) - .with_autocomplete(Some( - form::Autocomplete::new_password(), - )) - .with_required(true), - ) - .with_child( - form::input::Field::telephone() - .with_name("phone") - .with_label(L10n::t("label_phone", &LOC)) - .with_placeholder(L10n::t( - "placeholder_phone", - &LOC, - )), - ) - .with_child( - form::input::Field::url() - .with_name("website") - .with_label(L10n::t("label_url", &LOC)) - .with_placeholder(L10n::t("placeholder_url", &LOC)), - ) - .with_child( - form::input::Field::search() - .with_name("search") - .with_label(L10n::t("label_search", &LOC)) - .with_placeholder(L10n::t( - "placeholder_search", - &LOC, - )), - ), - ) - // Área de texto (form::Textarea). - .with_child( - form::Fieldset::new() - .with_legend(L10n::t("fieldset_textarea", &LOC)) - .with_child( - form::Textarea::new() - .with_name("comment") - .with_label(L10n::t("label_comment", &LOC)) - .with_placeholder(L10n::t( - "placeholder_comment", - &LOC, - )) - .with_rows(Some(4)) - .with_help_text(L10n::t("help_comment", &LOC)), - ), - ) - // Control deslizante (form::Range). - .with_child( - form::Fieldset::new() - .with_legend(L10n::t("fieldset_range", &LOC)) - .with_child( - form::Range::new() - .with_name("rating") - .with_label(L10n::t("label_rating", &LOC)) - .with_min(Some(1.0)) - .with_max(Some(10.0)) - .with_step(Some(1.0)) - .with_value(Some(5.0)) - .with_help_text(L10n::t("help_rating", &LOC)), - ), - ) - // Campo oculto (form::Hidden). - .with_child( - form::Hidden::new() - .with_name("origin") - .with_value("form-text"), - ) - // Botones de acción. - .with_child( - Button::submit(L10n::t("btn_submit", &LOC)) - .with_color(ButtonColor::Background(Color::Primary)), - ) - .with_child( - Button::reset(L10n::t("btn_reset", &LOC)) - .with_color(ButtonColor::Outline(Color::Secondary)), - ) - .with_child( - Button::plain(L10n::t("btn_cancel", &LOC)) - .with_color(ButtonColor::Link), - ), - ), - ) - // Bloque 3: listas de selección y etiquetas flotantes. - .with_child( - Block::new() - .with_title(L10n::t("block_lists", &LOC)) - .with_child( - Form::new() - .with_id("form-lists") - .with_action("/") - .with_method(form::Method::Post) - // Listas de selección (form::select::Field). - .with_child( - form::Fieldset::new() - .with_legend(L10n::t("fieldset_select", &LOC)) - .with_child( - form::select::Field::new() - .with_name("language") - .with_label(L10n::t("label_language", &LOC)) - .with_item( - form::select::Item::new( - "", - L10n::t("select_choose", &LOC), - ) - .with_selected(true), - ) - .with_group( - form::select::Group::new(L10n::t( - "select_group_europe", - &LOC, - )) - .with_item(form::select::Item::new( - "es", - L10n::t("select_spanish", &LOC), - )) - .with_item(form::select::Item::new( - "fr", - L10n::t("select_french", &LOC), - )), - ) - .with_group( - form::select::Group::new(L10n::t( - "select_group_americas", - &LOC, - )) - .with_item(form::select::Item::new( - "en", - L10n::t("select_english", &LOC), - )) - .with_item(form::select::Item::new( - "pt", - L10n::t("select_portuguese", &LOC), - )), - ) - .with_item( - form::select::Item::new( - "xx", - L10n::t("select_disabled", &LOC), - ) - .with_disabled(true), - ) - .with_required(true), - ) - .with_child( - form::select::Field::new() - .with_name("technologies") - .with_label(L10n::t("label_technologies", &LOC)) - .with_item( - form::select::Item::new( - "rust", - L10n::n("Rust"), - ) - .with_selected(true), - ) - .with_item( - form::select::Item::new( - "python", - L10n::n("Python"), - ) - .with_selected(true), - ) - .with_item(form::select::Item::new( - "javascript", - L10n::n("JavaScript"), - )) - .with_item(form::select::Item::new( - "go", - L10n::n("Go"), - )) - .with_item(form::select::Item::new( - "typescript", - L10n::n("TypeScript"), - )) - .with_multiple(true) - .with_rows(Some(4)) - .with_help_text(L10n::t("help_technologies", &LOC)), - ), - ) - // Etiquetas flotantes. - .with_child( - form::Fieldset::new() - .with_legend(L10n::t("fieldset_floating", &LOC)) - .with_child( - form::input::Field::text() - .with_name("fl_name") - .with_label(L10n::t("label_name", &LOC)) - .with_placeholder(L10n::t("placeholder_name", &LOC)) - .with_floating_label(true) - .with_required(true), - ) - .with_child( - form::Textarea::new() - .with_name("fl_comment") - .with_label(L10n::t("label_comment", &LOC)) - .with_placeholder(L10n::t( - "placeholder_comment", - &LOC, - )) - .with_floating_label(true), - ) - .with_child( - form::select::Field::new() - .with_name("fl_country") - .with_label(L10n::t("label_country", &LOC)) - .with_item( - form::select::Item::new( - "", - L10n::t("select_choose", &LOC), - ) - .with_selected(true), - ) - .with_item(form::select::Item::new( - "de", - L10n::t("select_germany", &LOC), - )) - .with_item(form::select::Item::new( - "es", - L10n::t("select_spain", &LOC), - )) - .with_item(form::select::Item::new( - "fr", - L10n::t("select_france", &LOC), - )) - .with_item(form::select::Item::new( - "pt", - L10n::t("select_portugal", &LOC), - )) - .with_floating_label(true) - .with_required(true), - ), - ) - // Campo oculto (form::Hidden). - .with_child( - form::Hidden::new() - .with_name("origin") - .with_value("form-lists"), - ) - // Botones de acción. - .with_child( - Button::submit(L10n::t("btn_submit", &LOC)) - .with_color(ButtonColor::Background(Color::Primary)), - ) - .with_child( - Button::reset(L10n::t("btn_reset", &LOC)) - .with_color(ButtonColor::Outline(Color::Secondary)), - ) - .with_child( - Button::plain(L10n::t("btn_cancel", &LOC)) - .with_color(ButtonColor::Link), - ), - ), - ), - ) - .render() -} - -#[pagetop::main] -async fn main() -> std::io::Result<()> { - Application::prepare(&FormControls).run()?.await -} diff --git a/examples/hello-name.rs b/examples/hello-name.rs deleted file mode 100644 index e2904c6f..00000000 --- a/examples/hello-name.rs +++ /dev/null @@ -1,28 +0,0 @@ -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, -) -> ResultPage { - let name = path.into_inner(); - Page::new(request) - .with_child(Html::with(move |_| { - html! { - h1 style="text-align: center;" { "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 deleted file mode 100644 index e6127af9..00000000 --- a/examples/hello-world.rs +++ /dev/null @@ -1,24 +0,0 @@ -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 { - Page::new(request) - .with_child(Html::with(|_| { - html! { - h1 style="text-align: center;" { "Hello World!" } - } - })) - .render() -} - -#[pagetop::main] -async fn main() -> std::io::Result<()> { - Application::prepare(&HelloWorld).run()?.await -} diff --git a/examples/intro-colors.rs b/examples/intro-colors.rs deleted file mode 100644 index 57ddeed4..00000000 --- a/examples/intro-colors.rs +++ /dev/null @@ -1,82 +0,0 @@ -use pagetop::prelude::*; - -include_locales!(LOC from "examples/locale"); - -struct IntroColors; - -impl Extension for IntroColors { - fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { - scfg.route("/", service::web::get().to(intro_colors)); - } -} - -async fn intro_colors(request: HttpRequest) -> ResultPage { - Page::new(request) - .with_child( - Intro::default() - .with_opening(IntroOpening::Custom) - .with_title(L10n::n("PageTop")) - .with_slogan(L10n::t("colors_slogan", &LOC)) - .with_button(None::<(L10n, FnPathByContext)>) - .with_child( - Block::new() - .with_title(L10n::t("colors_block", &LOC).with_arg("n", "1")) - .with_child(Html::with(|cx| { - html! { - p { (L10n::t("colors_val_1", &LOC).using(cx)) } - } - })), - ) - .with_child( - Block::new() - .with_title(L10n::t("colors_block", &LOC).with_arg("n", "2")) - .with_child(Html::with(|cx| { - html! { - p { (L10n::t("colors_val_2", &LOC).using(cx)) } - } - })), - ) - .with_child( - Block::new() - .with_title(L10n::t("colors_block", &LOC).with_arg("n", "3")) - .with_child(Html::with(|cx| { - html! { - p { (L10n::t("colors_val_3", &LOC).using(cx)) } - } - })), - ) - .with_child( - Block::new() - .with_title(L10n::t("colors_block", &LOC).with_arg("n", "4")) - .with_child(Html::with(|cx| { - html! { - p { (L10n::t("colors_val_4", &LOC).using(cx)) } - } - })), - ) - .with_child( - Block::new() - .with_title(L10n::t("colors_block", &LOC).with_arg("n", "5")) - .with_child(Html::with(|cx| { - html! { - p { (L10n::t("colors_val_5", &LOC).using(cx)) } - } - })), - ) - .with_child( - Block::new() - .with_title(L10n::t("colors_block", &LOC).with_arg("n", "6")) - .with_child(Html::with(|cx| { - html! { - p { (L10n::t("colors_val_6", &LOC).using(cx)) } - } - })), - ), - ) - .render() -} - -#[pagetop::main] -async fn main() -> std::io::Result<()> { - Application::prepare(&IntroColors).run()?.await -} diff --git a/examples/locale/en-US/form-controls.ftl b/examples/locale/en-US/form-controls.ftl deleted file mode 100644 index 7c2b3c96..00000000 --- a/examples/locale/en-US/form-controls.ftl +++ /dev/null @@ -1,74 +0,0 @@ -title = Form controls -slogan = Bootsier form components showcase -block_selections = Checkboxes, switches and radio buttons -block_text = Text fields, multiline and range -block_lists = Select lists and floating labels - -fieldset_text = Text fields -label_name = Full name -placeholder_name = e.g.: Jane Smith -label_email = Email address -placeholder_email = user@example.com -label_password = Password -label_phone = Phone number -placeholder_phone = +1 555 000 0000 -label_url = Website -placeholder_url = https://example.com -label_search = Search -placeholder_search = Search term... - -fieldset_textarea = Multiline text -label_comment = Comment -placeholder_comment = Write your comment here... -help_comment = Maximum 500 characters. - -fieldset_select = Selection lists -label_language = Language -label_country = Country -label_technologies = Preferred technologies -help_technologies = Hold Ctrl (or Cmd on Mac) to select multiple options. -select_choose = — Choose an option — -select_group_europe = Europe -select_spanish = Spanish -select_french = French -select_group_americas = Americas -select_english = English -select_portuguese = Portuguese -select_disabled = Not available -select_germany = Germany -select_spain = Spain -select_france = France -select_portugal = Portugal - -fieldset_checkbox = Checkboxes and switches -desc_checkbox = This group shows standard checkboxes, inline checkboxes, reverse-aligned options, and toggle switches for binary choices. -label_terms = I accept the terms and conditions -label_marketing = Commercial emails (inline) -label_newsletter = Newsletter (inline) -label_notifications = Enable notifications (reverse) -label_dark_mode = Dark mode (unavailable) - -fieldset_radio = Radio buttons -label_frequency = Newsletter frequency -radio_daily = Daily -radio_weekly = Weekly -radio_monthly = Monthly -radio_never = Never (disabled) - -fieldset_checkgroup = Checkbox group -label_interests = Areas of interest -help_interests = Select all options that apply. -check_rust = Rust programming -check_web = Web development -check_ai = Artificial intelligence -check_games = Game development (disabled) - -fieldset_floating = Floating labels - -fieldset_range = Slider -label_rating = Overall rating -help_rating = From 1 (very poor) to 10 (excellent). - -btn_submit = Submit -btn_reset = Reset -btn_cancel = Cancel diff --git a/examples/locale/en-US/intro-colors.ftl b/examples/locale/en-US/intro-colors.ftl deleted file mode 100644 index 8b33f218..00000000 --- a/examples/locale/en-US/intro-colors.ftl +++ /dev/null @@ -1,8 +0,0 @@ -colors_slogan = Chromatic intro test -colors_block = Block { $n } — intro-bg-block-{ $n } -colors_val_1 = Background color: #FFB84B — Amber gold. -colors_val_2 = Background color: #FFC66F — Light golden. -colors_val_3 = Background color: #FFD493 — Pale golden. -colors_val_4 = Background color: #FFE3B7 — Light peach. -colors_val_5 = Background color: #FFF1DB — Cream. -colors_val_6 = Background color: #FFFFFF — White. diff --git a/examples/locale/en-US/navbar-menus.ftl b/examples/locale/en-US/navbar-menus.ftl deleted file mode 100644 index 98de2401..00000000 --- a/examples/locale/en-US/navbar-menus.ftl +++ /dev/null @@ -1,23 +0,0 @@ -menus_item_label = Label -menus_item_link = Link -menus_item_blank = External link -menus_item_disabled = Disabled link - -menus_test_title = Dropdown - -menus_dev_header = Intro -menus_dev_getting_started = Getting started -menus_dev_guides = Development guides -menus_dev_forum = Developers forum - -menus_sdk_header = Software Development Kits -menus_sdk_rust = SDKs Rust -menus_sdk_js = SDKs JavaScript -menus_sdk_python = SDKs Python - -menus_plugin_header = Plugins -menus_plugin_auth = Rust Plugin Auth -menus_plugin_cache = Rust Plugin Cache - -menus_item_sign_up = Sign up -menus_item_login = Login diff --git a/examples/locale/es-ES/form-controls.ftl b/examples/locale/es-ES/form-controls.ftl deleted file mode 100644 index 67a0fd2c..00000000 --- a/examples/locale/es-ES/form-controls.ftl +++ /dev/null @@ -1,74 +0,0 @@ -title = Controles de formulario -slogan = Componentes Bootsier para formularios -block_selections = Casillas, interruptores y botones de opción -block_text = Campos de texto, multilínea y rango -block_lists = Listas de selección y etiquetas flotantes - -fieldset_text = Campos de texto -label_name = Nombre completo -placeholder_name = Ej.: Ana García -label_email = Correo electrónico -placeholder_email = usuario@ejemplo.com -label_password = Contraseña -label_phone = Teléfono -placeholder_phone = +34 600 000 -label_url = Sitio web -placeholder_url = https://ejemplo.com -label_search = Búsqueda -placeholder_search = Término de búsqueda... - -fieldset_textarea = Texto multilínea -label_comment = Comentario -placeholder_comment = Escribe tu comentario aquí... -help_comment = Máximo 500 caracteres. - -fieldset_select = Listas de selección -label_language = Idioma -label_country = País -label_technologies = Tecnologías preferidas -help_technologies = Mantén Ctrl (o Cmd en Mac) para seleccionar varias opciones. -select_choose = — Elige una opción — -select_group_europe = Europa -select_spanish = Español -select_french = Francés -select_group_americas = América -select_english = Inglés -select_portuguese = Portugués -select_disabled = No disponible -select_germany = Alemania -select_spain = España -select_france = Francia -select_portugal = Portugal - -fieldset_checkbox = Casillas e interruptores -desc_checkbox = Este grupo muestra casillas de verificación estándar, casillas en línea, opciones alineadas a la derecha e interruptores para elecciones binarias. -label_terms = Acepto los términos y condiciones -label_marketing = Emails comerciales (en línea) -label_newsletter = Boletín (en línea) -label_notifications = Activar notificaciones (invertida) -label_dark_mode = Modo oscuro (no disponible) - -fieldset_radio = Botones de opción -label_frequency = Frecuencia del boletín -radio_daily = Diario -radio_weekly = Semanal -radio_monthly = Mensual -radio_never = Nunca (deshabilitado) - -fieldset_checkgroup = Grupo de casillas -label_interests = Áreas de interés -help_interests = Selecciona todas las opciones que correspondan. -check_rust = Programación en Rust -check_web = Desarrollo web -check_ai = Inteligencia artificial -check_games = Desarrollo de videojuegos (deshabilitado) - -fieldset_floating = Etiquetas flotantes - -fieldset_range = Control deslizante -label_rating = Valoración general -help_rating = De 1 (muy malo) a 10 (excelente). - -btn_submit = Enviar -btn_reset = Restablecer -btn_cancel = Cancelar diff --git a/examples/locale/es-ES/intro-colors.ftl b/examples/locale/es-ES/intro-colors.ftl deleted file mode 100644 index 280ecb11..00000000 --- a/examples/locale/es-ES/intro-colors.ftl +++ /dev/null @@ -1,8 +0,0 @@ -colors_slogan = Prueba de intro cromática -colors_block = Bloque { $n } — intro-bg-block-{ $n } -colors_val_1 = Color de fondo: #FFB84B — Ámbar dorado. -colors_val_2 = Color de fondo: #FFC66F — Dorado claro. -colors_val_3 = Color de fondo: #FFD493 — Dorado pálido. -colors_val_4 = Color de fondo: #FFE3B7 — Melocotón claro. -colors_val_5 = Color de fondo: #FFF1DB — Crema. -colors_val_6 = Color de fondo: #FFFFFF — Blanco. diff --git a/examples/locale/es-ES/navbar-menus.ftl b/examples/locale/es-ES/navbar-menus.ftl deleted file mode 100644 index af0b1ec3..00000000 --- a/examples/locale/es-ES/navbar-menus.ftl +++ /dev/null @@ -1,23 +0,0 @@ -menus_item_label = Etiqueta -menus_item_link = Enlace -menus_item_blank = Enlace externo -menus_item_disabled = Enlace deshabilitado - -menus_test_title = Desplegable - -menus_dev_header = Introducción -menus_dev_getting_started = Primeros pasos -menus_dev_guides = Guías de desarrollo -menus_dev_forum = Foro de desarrolladores - -menus_sdk_header = Kits de Desarrollo Software -menus_sdk_rust = SDKs de Rust -menus_sdk_js = SDKs de JavaScript -menus_sdk_python = SDKs de Python - -menus_plugin_header = Plugins -menus_plugin_auth = Plugin Rust de autenticación -menus_plugin_cache = Plugin Rust de caché - -menus_item_sign_up = Registrarse -menus_item_login = Iniciar sesión diff --git a/examples/navbar-menus.rs b/examples/navbar-menus.rs deleted file mode 100644 index a0d85f3b..00000000 --- a/examples/navbar-menus.rs +++ /dev/null @@ -1,102 +0,0 @@ -use pagetop::prelude::*; - -use pagetop_bootsier::prelude::*; - -include_locales!(LOC from "examples/locale"); - -struct SuperMenu; - -impl Extension for SuperMenu { - fn dependencies(&self) -> Vec { - vec![&pagetop_aliner::Aliner, &pagetop_bootsier::Bootsier] - } - - fn initialize(&self) { - let navbar_menu = Navbar::brand_left(navbar::Brand::new()) - .with_expand(BreakPoint::LG) - .with_item(navbar::Item::nav( - Nav::new() - .with_item(nav::Item::link(L10n::t("menus_item_link", &LOC), |cx| { - cx.route("/") - })) - .with_item(nav::Item::link_blank( - L10n::t("menus_item_blank", &LOC), - |_| "https://docs.rs/pagetop".into(), - )) - .with_item(nav::Item::dropdown( - Dropdown::new() - .with_title(L10n::t("menus_test_title", &LOC)) - .with_item(dropdown::Item::header(L10n::t("menus_dev_header", &LOC))) - .with_item(dropdown::Item::link( - L10n::t("menus_dev_getting_started", &LOC), - |cx| cx.route("/dev/getting-started"), - )) - .with_item(dropdown::Item::link( - L10n::t("menus_dev_guides", &LOC), - |cx| cx.route("/dev/guides"), - )) - .with_item(dropdown::Item::link_blank( - L10n::t("menus_dev_forum", &LOC), - |_| "https://forum.example.dev".into(), - )) - .with_item(dropdown::Item::divider()) - .with_item(dropdown::Item::header(L10n::t("menus_sdk_header", &LOC))) - .with_item(dropdown::Item::link( - L10n::t("menus_sdk_rust", &LOC), - |cx| cx.route("/dev/sdks/rust"), - )) - .with_item(dropdown::Item::link(L10n::t("menus_sdk_js", &LOC), |cx| { - cx.route("/dev/sdks/js") - })) - .with_item(dropdown::Item::link( - L10n::t("menus_sdk_python", &LOC), - |cx| cx.route("/dev/sdks/python"), - )) - .with_item(dropdown::Item::divider()) - .with_item(dropdown::Item::header(L10n::t("menus_plugin_header", &LOC))) - .with_item(dropdown::Item::link( - L10n::t("menus_plugin_auth", &LOC), - |cx| cx.route("/dev/sdks/rust/plugins/auth"), - )) - .with_item(dropdown::Item::link( - L10n::t("menus_plugin_cache", &LOC), - |cx| cx.route("/dev/sdks/rust/plugins/cache"), - )) - .with_item(dropdown::Item::divider()) - .with_item(dropdown::Item::label(L10n::t("menus_item_label", &LOC))) - .with_item(dropdown::Item::link_disabled( - L10n::t("menus_item_disabled", &LOC), - |cx| cx.route("#"), - )), - )) - .with_item(nav::Item::link_disabled( - L10n::t("menus_item_disabled", &LOC), - |cx| cx.route("#"), - )), - )) - .with_item(navbar::Item::nav( - Nav::new() - .with_classes( - ClassesOp::Add, - classes::Margin::with(Side::Start, ScaleSize::Auto).to_class(), - ) - .with_item(nav::Item::link(L10n::t("menus_item_sign_up", &LOC), |cx| { - cx.route("/auth/sign-up") - })) - .with_item(nav::Item::link(L10n::t("menus_item_login", &LOC), |cx| { - cx.route("/auth/login") - })), - )); - - InRegion::Global(&DefaultRegion::Header).add( - Container::new() - .with_width(container::Width::FluidMax(UnitValue::RelRem(75.0))) - .with_child(navbar_menu), - ); - } -} - -#[pagetop::main] -async fn main() -> std::io::Result<()> { - Application::prepare(&SuperMenu).run()?.await -} diff --git a/extensions/pagetop-aliner/CHANGELOG.md b/extensions/pagetop-aliner/CHANGELOG.md deleted file mode 100644 index e8afc73d..00000000 --- a/extensions/pagetop-aliner/CHANGELOG.md +++ /dev/null @@ -1,15 +0,0 @@ -# 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 (2026-05-03) - -### Añadido - -- Versión inicial diff --git a/extensions/pagetop-aliner/Cargo.toml b/extensions/pagetop-aliner/Cargo.toml deleted file mode 100644 index 00deda3e..00000000 --- a/extensions/pagetop-aliner/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "pagetop-aliner" -version = "0.1.0" -edition = "2021" - -description = """ - Tema de 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/LICENSE-APACHE b/extensions/pagetop-aliner/LICENSE-APACHE deleted file mode 100644 index 263ddac1..00000000 --- a/extensions/pagetop-aliner/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - 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 deleted file mode 100644 index cd8af3d6..00000000 --- a/extensions/pagetop-aliner/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 09a337eb..00000000 --- a/extensions/pagetop-aliner/README.md +++ /dev/null @@ -1,101 +0,0 @@ -
- -

PageTop Aliner

- -

Tema de PageTop que muestra esquemáticamente la composición de las páginas HTML.

- -[![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)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-aliner#licencia) - -
-
- -## 🧭 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 { - 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::*; -use pagetop_aliner::Aliner; - -async fn homepage(request: HttpRequest) -> ResultPage { - Page::new(request) - .with_theme(&Aliner) - .add_child( - Block::new() - .with_title(L10n::l("sample_title")) - .add_child(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/src/lib.rs b/extensions/pagetop-aliner/src/lib.rs deleted file mode 100644 index 95f22196..00000000 --- a/extensions/pagetop-aliner/src/lib.rs +++ /dev/null @@ -1,128 +0,0 @@ -/*! -
- -

PageTop Aliner

- -

Tema para PageTop que muestra esquemáticamente la composición de las páginas HTML.

- -[![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)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-aliner#licencia) - -
-
- -## 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 { - 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::*; -use pagetop_aliner::Aliner; - -async fn homepage(request: HttpRequest) -> ResultPage { - Page::new(request) - .with_theme(&Aliner) - .with_child( - Block::new() - .with_title(L10n::l("sample_title")) - .with_child(Html::with(|cx| html! { - p { (L10n::l("sample_content").using(cx)) } - })), - ) - .render() -} -``` -*/ - -use pagetop::prelude::*; - -/// Implementa el tema para usar en pruebas que muestran el esquema de páginas HTML. -/// -/// 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. -pub struct Aliner; - -impl Extension for Aliner { - fn theme(&self) -> Option { - 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_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") - .with_version(PAGETOP_VERSION) - .with_weight(-99), - )) - .alter_assets(AssetsOp::AddStyleSheet( - StyleSheet::from("/aliner/css/styles.css") - .with_version(env!("CARGO_PKG_VERSION")) - .with_weight(-99), - )) - .alter_child_in( - &DefaultRegion::Footer, - ChildOp::AddIfEmpty(PoweredBy::new().into()), - ); - } -} diff --git a/extensions/pagetop-bootsier/.gitattributes b/extensions/pagetop-bootsier/.gitattributes deleted file mode 100644 index 940d6a84..00000000 --- a/extensions/pagetop-bootsier/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -static/** linguist-vendored diff --git a/extensions/pagetop-bootsier/CHANGELOG.md b/extensions/pagetop-bootsier/CHANGELOG.md deleted file mode 100644 index 649733b9..00000000 --- a/extensions/pagetop-bootsier/CHANGELOG.md +++ /dev/null @@ -1,21 +0,0 @@ -# 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 (2026-05-07) - -### Cambiado - -- Renombra módulo `aux` por `attrs` para evitar posibles conflictos en Windows (#11) - -## 0.1.0 (2026-05-03) - -### Añadido - -- Versión inicial diff --git a/extensions/pagetop-bootsier/Cargo.toml b/extensions/pagetop-bootsier/Cargo.toml deleted file mode 100644 index 6e6fc66b..00000000 --- a/extensions/pagetop-bootsier/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "pagetop-bootsier" -version = "0.1.1" -edition = "2021" - -description = """ - 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"] - -repository.workspace = true -homepage.workspace = true -license.workspace = true -authors.workspace = true - -[dependencies] -pagetop.workspace = true -serde.workspace = true - -[build-dependencies] -pagetop-build.workspace = true diff --git a/extensions/pagetop-bootsier/LICENSE-APACHE b/extensions/pagetop-bootsier/LICENSE-APACHE deleted file mode 100644 index 263ddac1..00000000 --- a/extensions/pagetop-bootsier/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - 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 deleted file mode 100644 index cd8af3d6..00000000 --- a/extensions/pagetop-bootsier/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index b34eeb51..00000000 --- a/extensions/pagetop-bootsier/README.md +++ /dev/null @@ -1,101 +0,0 @@ -
- -

PageTop Bootsier

- -

Tema de PageTop basado en Bootstrap para aplicar su catálogo de estilos y componentes flexibles.

- -[![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)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-bootsier#licencia) - -
-
- -## 🧭 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 { - 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::*; -use pagetop_bootsier::Bootsier; - -async fn homepage(request: HttpRequest) -> ResultPage { - Page::new(request) - .with_theme(&Bootsier) - .add_child( - Block::new() - .with_title(L10n::l("sample_title")) - .add_child(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 deleted file mode 100644 index df7a2750..00000000 --- a/extensions/pagetop-bootsier/build.rs +++ /dev/null @@ -1,20 +0,0 @@ -use pagetop_build::StaticFilesBundle; - -use std::env; -use std::path::Path; - -fn main() -> std::io::Result<()> { - 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") - .build() -} - -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(|f| f == bootstrap_js) -} diff --git a/extensions/pagetop-bootsier/src/config.rs b/extensions/pagetop-bootsier/src/config.rs deleted file mode 100644 index 6c2365ba..00000000 --- a/extensions/pagetop-bootsier/src/config.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! 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 deleted file mode 100644 index d562ec09..00000000 --- a/extensions/pagetop-bootsier/src/lib.rs +++ /dev/null @@ -1,169 +0,0 @@ -/*! -
- -

PageTop Bootsier

- -

Tema de PageTop basado en Bootstrap para aplicar su catálogo de estilos y componentes flexibles.

- -[![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)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-bootsier#licencia) - -
-
- -## 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 { - 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::*; -use pagetop_bootsier::Bootsier; - -async fn homepage(request: HttpRequest) -> ResultPage { - Page::new(request) - .with_theme(&Bootsier) - .with_child( - Block::new() - .with_title(L10n::l("sample_title")) - .with_child(Html::with(|cx| html! { - p { (L10n::l("sample_content").using(cx)) } - })), - ) - .render() -} -``` -*/ - -#![doc( - html_favicon_url = "https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/favicon.ico" -)] - -use pagetop::prelude::*; - -include_locales!(LOCALES_BOOTSIER); - -// Versión de la librería Bootstrap. -const BOOTSTRAP_VERSION: &str = "5.3.8"; - -pub mod config; - -pub mod theme; - -/// *Prelude* del tema. -pub mod prelude { - pub use crate::config::*; - pub use crate::theme::*; -} - -/// Plantillas que Bootsier añade. -#[derive(AutoDefault)] -pub enum BootsierTemplate { - /// Plantilla predeterminada de Bootsier. - #[default] - Standard, -} - -impl Template for BootsierTemplate { - fn render(&'static self, cx: &mut Context) -> Markup { - match self { - Self::Standard => theme::Container::new() - .with_classes(ClassesOp::Add, "container-wrapper") - .with_width(theme::container::Width::FluidMax( - config::SETTINGS.bootsier.max_width, - )) - .with_child(Html::with(|cx| { - html! { - (DefaultRegion::Header.render(cx)) - (DefaultRegion::Content.render(cx)) - (DefaultRegion::Footer.render(cx)) - } - })), - } - .render(cx) - } -} - -/// Implementa el tema. -pub struct Bootsier; - -impl Extension for Bootsier { - fn theme(&self) -> Option { - Some(&Self) - } - - fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { - static_files_service!(scfg, [bootsier_bs] => "/bootsier/bs"); - static_files_service!(scfg, [bootsier_js] => "/bootsier/js"); - } -} - -impl Theme for Bootsier { - #[inline] - fn default_template(&self) -> TemplateRef { - &BootsierTemplate::Standard - } - - fn before_render_page_body(&self, page: &mut Page) { - page.alter_assets(AssetsOp::AddStyleSheet( - StyleSheet::from("/bootsier/bs/bootstrap.min.css") - .with_version(BOOTSTRAP_VERSION) - .with_weight(-90), - )) - .alter_assets(AssetsOp::AddJavaScript( - JavaScript::defer("/bootsier/js/bootstrap.bundle.min.js") - .with_version(BOOTSTRAP_VERSION) - .with_weight(-90), - )) - .alter_child_in( - &DefaultRegion::Footer, - ChildOp::AddIfEmpty(PoweredBy::new().into()), - ); - } -} diff --git a/extensions/pagetop-bootsier/src/locale/en-US/bootsier.ftl b/extensions/pagetop-bootsier/src/locale/en-US/bootsier.ftl deleted file mode 100644 index 2454c84e..00000000 --- a/extensions/pagetop-bootsier/src/locale/en-US/bootsier.ftl +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index c73478bf..00000000 --- a/extensions/pagetop-bootsier/src/locale/en-US/components.ftl +++ /dev/null @@ -1,11 +0,0 @@ -# Dropdown -dropdown_toggle = Toggle Dropdown - -# form::Input -input_required = This field is required - -# Navbar -toggle = Toggle navigation - -# Offcanvas -offcanvas_close = Close diff --git a/extensions/pagetop-bootsier/src/locale/en-US/regions.ftl b/extensions/pagetop-bootsier/src/locale/en-US/regions.ftl deleted file mode 100644 index af830a4e..00000000 --- a/extensions/pagetop-bootsier/src/locale/en-US/regions.ftl +++ /dev/null @@ -1,9 +0,0 @@ -region_header = Header -region_nav_branding = Navigation branding region -region_nav_main = Main navigation region -region_nav_additional = Additional navigation region (eg search form, social icons, etc) -region_breadcrumb = Breadcrumb -region_content = Main content -region_sidebar_first = Sidebar first -region_sidebar_second = Sidebar second -region_footer = Footer diff --git a/extensions/pagetop-bootsier/src/locale/es-ES/bootsier.ftl b/extensions/pagetop-bootsier/src/locale/es-ES/bootsier.ftl deleted file mode 100644 index bd97c2ed..00000000 --- a/extensions/pagetop-bootsier/src/locale/es-ES/bootsier.ftl +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 21b52c91..00000000 --- a/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl +++ /dev/null @@ -1,11 +0,0 @@ -# Dropdown -dropdown_toggle = Mostrar/ocultar menú - -# form::Input -input_required = Este campo es obligatorio - -# Navbar -toggle = Mostrar/ocultar navegación - -# Offcanvas -offcanvas_close = Cerrar diff --git a/extensions/pagetop-bootsier/src/locale/es-ES/regions.ftl b/extensions/pagetop-bootsier/src/locale/es-ES/regions.ftl deleted file mode 100644 index e4665add..00000000 --- a/extensions/pagetop-bootsier/src/locale/es-ES/regions.ftl +++ /dev/null @@ -1,9 +0,0 @@ -region_header = Cabecera -region_nav_branding = Navegación y marca -region_nav_main = Navegación principal -region_nav_additional = Navegación adicional (p.e. formulario de búsqueda, iconos sociales, etc.) -region_breadcrumb = Ruta de posicionamiento -region_content = Contenido principal -region_sidebar_first = Barra lateral primera -region_sidebar_second = Barra lateral segunda -region_footer = Pie diff --git a/extensions/pagetop-bootsier/src/theme.rs b/extensions/pagetop-bootsier/src/theme.rs deleted file mode 100644 index fb7dd0ed..00000000 --- a/extensions/pagetop-bootsier/src/theme.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! 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. - -mod attrs; -pub use attrs::*; - -pub mod classes; - -// Button. -mod button; -pub use button::Button; - -// Container. -pub mod container; -#[doc(inline)] -pub use container::Container; - -// Dropdown. -pub mod dropdown; -#[doc(inline)] -pub use dropdown::Dropdown; - -// Form. -pub mod form; -#[doc(inline)] -pub use form::Form; - -// Image. -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)] -pub use navbar::Navbar; - -// Offcanvas. -pub mod offcanvas; -#[doc(inline)] -pub use offcanvas::Offcanvas; diff --git a/extensions/pagetop-bootsier/src/theme/attrs.rs b/extensions/pagetop-bootsier/src/theme/attrs.rs deleted file mode 100644 index e5f0a82f..00000000 --- a/extensions/pagetop-bootsier/src/theme/attrs.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Colección de elementos auxiliares de Bootstrap para Bootsier. - -mod breakpoint; -pub use breakpoint::BreakPoint; - -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; - -mod rounded; -pub use rounded::RoundedRadius; - -mod button; -pub use button::{ButtonAction, ButtonColor, ButtonSize}; diff --git a/extensions/pagetop-bootsier/src/theme/attrs/border.rs b/extensions/pagetop-bootsier/src/theme/attrs/border.rs deleted file mode 100644 index b46a5c6b..00000000 --- a/extensions/pagetop-bootsier/src/theme/attrs/border.rs +++ /dev/null @@ -1,86 +0,0 @@ -use pagetop::prelude::*; - -use crate::theme::attrs::Color; - -/// Esquema de color para los bordes ([`classes::Border`](crate::theme::classes::Border)). -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -pub enum BorderColor { - /// No define ninguna clase. - #[default] - Default, - /// Genera la clase `border-{color}`. - Theme(Color), - /// Genera la clase `border-{color}-subtle` (un tono suavizado del color). - Subtle(Color), - /// Color negro. - Black, - /// Color blanco. - White, -} - -impl BorderColor { - const BORDER: &str = "border"; - const BORDER_PREFIX: &str = "border-"; - - /// Devuelve el sufijo de la clase `border-*`, o `None` si no define ninguna clase. - #[rustfmt::skip] - #[inline] - const fn suffix(self) -> Option<&'static str> { - match self { - Self::Default => None, - Self::Theme(_) => Some(""), - Self::Subtle(_) => Some("-subtle"), - Self::Black => Some("-black"), - Self::White => Some("-white"), - } - } - - /// 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(), ""); - /// ``` - 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/attrs/breakpoint.rs b/extensions/pagetop-bootsier/src/theme/attrs/breakpoint.rs deleted file mode 100644 index 992f8525..00000000 --- a/extensions/pagetop-bootsier/src/theme/attrs/breakpoint.rs +++ /dev/null @@ -1,114 +0,0 @@ -use pagetop::prelude::*; - -/// Define los puntos de ruptura (*breakpoints*) para aplicar diseño *responsive*. -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -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, -} - -impl BreakPoint { - /// Devuelve la identificación del punto de ruptura. - #[rustfmt::skip] - #[inline] - pub(crate) const fn as_str(self) -> &'static str { - match self { - Self::None => "", - Self::SM => "sm", - Self::MD => "md", - Self::LG => "lg", - Self::XL => "xl", - Self::XXL => "xxl", - } - } - - /// 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(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"), ""); - /// ``` - #[doc(hidden)] - pub 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/attrs/button.rs b/extensions/pagetop-bootsier/src/theme/attrs/button.rs deleted file mode 100644 index dc74fbea..00000000 --- a/extensions/pagetop-bootsier/src/theme/attrs/button.rs +++ /dev/null @@ -1,145 +0,0 @@ -use pagetop::prelude::*; - -use crate::theme::attrs::Color; - -// **< ButtonAction >********************************************************************************* - -/// Comportamiento de un [`Button`](crate::theme::Button) al activarse. -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -pub enum ButtonAction { - /// Envía un formulario al servidor. Es el **tipo por defecto**. - #[default] - Submit, - /// Restablece todos los campos de un formulario a sus valores iniciales. - Reset, - /// Botón de propósito general, sin efecto predeterminado. Su comportamiento podría definirse - /// mediante JavaScript. - Plain, -} - -impl std::fmt::Display for ButtonAction { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - ButtonAction::Submit => "submit", - ButtonAction::Reset => "reset", - ButtonAction::Plain => "button", - }) - } -} - -// **< ButtonColor >******************************************************************************** - -/// Esquema de color para [`Button`](crate::theme::Button). -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -pub enum ButtonColor { - /// No define ninguna clase. - #[default] - Default, - /// Genera la clase `btn-{color}` (botón sólido). - Background(Color), - /// Genera la clase `btn-outline-{color}` (fondo transparente con contorno coloreado). - Outline(Color), - /// Aplica estilo de los enlaces (`btn-link`), sin caja ni fondo, heredando el color de texto. - Link, -} - -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::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), - Self::Default => unreachable!(), - } - } - - /// 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(), ""); - /// ``` - pub fn to_class(self) -> String { - let mut class = String::new(); - self.push_class(&mut class); - class - } -} - -// **< ButtonSize >********************************************************************************* - -/// Tamaño visual de un botón. -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -pub enum ButtonSize { - /// Tamaño por defecto del tema (no añade clase). - #[default] - Default, - /// Botón compacto. - Small, - /// Botón grande. - Large, -} - -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) { - let class = match self { - Self::Default => return, - Self::Small => Self::BTN_SM, - Self::Large => Self::BTN_LG, - }; - if !classes.is_empty() { - classes.push(' '); - } - classes.push_str(class); - } - - /// 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(), ""); - /// ``` - pub fn to_class(self) -> String { - let mut class = String::new(); - self.push_class(&mut class); - class - } -} diff --git a/extensions/pagetop-bootsier/src/theme/attrs/color.rs b/extensions/pagetop-bootsier/src/theme/attrs/color.rs deleted file mode 100644 index c408aadc..00000000 --- a/extensions/pagetop-bootsier/src/theme/attrs/color.rs +++ /dev/null @@ -1,336 +0,0 @@ -use pagetop::prelude::*; - -// **< Color >************************************************************************************** - -/// Paleta de colores temáticos. -/// -/// Equivalen a los nombres estándar definidos por Bootstrap (`primary`, `secondary`, `success`, -/// etc.). Este tipo enumerado sirve de referencia para componer las clases de color para el fondo -/// ([`classes::Background`](crate::theme::classes::Background)), los bordes -/// ([`classes::Border`](crate::theme::classes::Border)) o para el texto -/// ([`classes::Text`](crate::theme::classes::Text)). -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -pub enum Color { - #[default] - Primary, - Secondary, - Success, - Info, - Warning, - Danger, - Light, - Dark, -} - -impl Color { - /// Devuelve el nombre del color. - #[rustfmt::skip] - #[inline] - pub(crate) const fn as_str(self) -> &'static str { - match self { - Self::Primary => "primary", - Self::Secondary => "secondary", - Self::Success => "success", - Self::Info => "info", - Self::Warning => "warning", - Self::Danger => "danger", - Self::Light => "light", - Self::Dark => "dark", - } - } - - /// 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 >************************************************************************************ - -/// 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, Clone, Copy, Debug, PartialEq)] -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 { - 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) -> Option<&'static str> { - match self { - 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 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); - } - } - - /// 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"), ""); - /// ``` - #[doc(hidden)] - pub 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 >************************************************************************************ - -/// Esquema de color para el fondo. -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -pub enum ColorBg { - /// No define ninguna clase. - #[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 la clase `bg-{color}` (p. ej., `bg-primary`). - Theme(Color), - /// Genera la clase `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, -} - -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 => 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(), ""); - /// ``` - pub fn to_class(self) -> String { - let mut class = String::new(); - self.push_class(&mut class); - class - } -} - -// **< ColorText >********************************************************************************** - -/// Esquema de color para el texto. -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -pub enum ColorText { - /// No define ninguna clase. - #[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 la clase `text-{color}`. - Theme(Color), - /// Genera la clase `text-{color}-emphasis` (mayor contraste acorde al tema). - Emphasis(Color), - /// Color negro. - Black, - /// Color blanco. - White, -} - -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 => 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(), ""); - /// ``` - pub fn to_class(self) -> String { - let mut class = String::new(); - self.push_class(&mut class); - class - } -} diff --git a/extensions/pagetop-bootsier/src/theme/attrs/layout.rs b/extensions/pagetop-bootsier/src/theme/attrs/layout.rs deleted file mode 100644 index a1255dc0..00000000 --- a/extensions/pagetop-bootsier/src/theme/attrs/layout.rs +++ /dev/null @@ -1,104 +0,0 @@ -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"), ""); - /// ``` - #[doc(hidden)] - pub 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/attrs/rounded.rs b/extensions/pagetop-bootsier/src/theme/attrs/rounded.rs deleted file mode 100644 index 69976142..00000000 --- a/extensions/pagetop-bootsier/src/theme/attrs/rounded.rs +++ /dev/null @@ -1,117 +0,0 @@ -use pagetop::prelude::*; - -/// Radio para el redondeo de esquinas ([`classes::Rounded`](crate::theme::classes::Rounded)). -#[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] - #[inline] - const fn suffix(self) -> Option<&'static str> { - match self { - 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"), - } - } - - /// 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"), ""); - /// ``` - #[doc(hidden)] - pub 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/button.rs b/extensions/pagetop-bootsier/src/theme/button.rs deleted file mode 100644 index 48eb7283..00000000 --- a/extensions/pagetop-bootsier/src/theme/button.rs +++ /dev/null @@ -1,213 +0,0 @@ -use pagetop::prelude::*; - -use crate::theme::{ButtonAction, ButtonColor, ButtonSize}; - -/// Componente para crear un **botón**. -/// -/// Renderiza un botón con soporte para las variantes disponibles en [`ButtonAction`] (`submit`, -/// `reset` y botón genérico) y con la variedad de estilos del tema a través de [`ButtonColor`] y -/// [`ButtonSize`]. -/// -/// El comportamiento del botón se establece al crearlo: -/// -/// - [`Button::submit()`]: botón de envío (por defecto). -/// - [`Button::reset()`]: botón de restablecimiento de valores. -/// - [`Button::plain()`]: botón genérico sin comportamiento predeterminado. -/// -/// El botón puede usarse dentro o fuera de un formulario. -/// -/// # Ejemplo -/// -/// ```rust -/// # use pagetop::prelude::*; -/// # use pagetop_bootsier::prelude::*; -/// let save = Button::submit(L10n::n("Save")) -/// .with_color(ButtonColor::Background(Color::Primary)); -/// -/// let cancel = Button::plain(L10n::n("Cancel")) -/// .with_color(ButtonColor::Outline(Color::Secondary)); -/// -/// let clear = Button::reset(L10n::n("Clear")) -/// .with_size(ButtonSize::Small); -/// ``` -/// -/// Cuando el botón activa el envío, el navegador incluye el par `name=value` en los datos del -/// formulario **sólo si** tiene el atributo `name` definido. Es la forma habitual de identificar -/// cuál de los botones de envío fue pulsado. En el servidor se deserializa como `Option`: -/// -/// ```rust,ignore -/// #[derive(serde::Deserialize)] -/// struct FormData { -/// #[serde(default)] -/// action: Option, // p. ej., "save" o "delete"; `None` si el botón no tenía `name`. -/// } -/// ``` -#[derive(AutoDefault, Clone, Debug, Getters)] -pub struct Button { - #[getters(skip)] - id: AttrId, - /// Devuelve las clases CSS del botón. - classes: Classes, - /// Devuelve el comportamiento del botón al activarse. - kind: ButtonAction, - /// Devuelve el esquema de color del botón. - color: ButtonColor, - /// Devuelve el tamaño visual del botón. - size: ButtonSize, - /// Devuelve el nombre del botón. - name: AttrName, - /// Devuelve el valor del botón. - value: AttrValue, - /// Devuelve la etiqueta del botón. - label: Attr, - /// Devuelve si el botón recibe el foco automáticamente al cargar la página. - autofocus: bool, - /// Devuelve si el botón está deshabilitado. - disabled: bool, -} - -impl Component for Button { - fn new() -> Self { - Self::default() - } - - fn id(&self) -> Option { - self.id.get() - } - - fn setup(&mut self, _cx: &Context) { - let mut classes = "btn".to_string(); - (*self.color()).push_class(&mut classes); - (*self.size()).push_class(&mut classes); - self.alter_classes(ClassesOp::Prepend, classes); - } - - fn prepare(&self, cx: &mut Context) -> Result { - Ok(html! { - button - id=[self.id()] - type=(self.kind()) - class=[self.classes().get()] - name=[self.name().get()] - value=[self.value().get()] - autofocus[*self.autofocus()] - disabled[*self.disabled()] - { - @if let Some(label) = self.label().lookup(cx) { - (label) - } - } - }) - } -} - -impl Button { - /// Crea un botón de **envío** (`type="submit"`). - /// - /// Es la acción predeterminada al pulsar un botón en la mayoría de los formularios: envía los - /// datos al servidor. - pub fn submit(label: L10n) -> Self { - Self { - kind: ButtonAction::Submit, - label: Attr::some(label), - ..Default::default() - } - } - - /// Crea un botón de **restablecimiento** (`type="reset"`). - /// - /// Al pulsarlo, devuelve todos los campos del formulario a sus valores iniciales. - pub fn reset(label: L10n) -> Self { - Self { - kind: ButtonAction::Reset, - label: Attr::some(label), - ..Default::default() - } - } - - /// Crea un **botón genérico** (`type="button"`). - /// - /// No tiene un comportamiento predeterminado sobre el formulario. Su comportamiento puede - /// definirse mediante JavaScript. - pub fn plain(label: L10n) -> Self { - Self { - kind: ButtonAction::Plain, - label: Attr::some(label), - ..Default::default() - } - } - - // **< Button BUILDER >************************************************************************* - - /// Establece el identificador único (`id`) del botón. - #[builder_fn] - pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_id(id); - self - } - - /// Modifica la lista de clases CSS aplicadas al botón. - #[builder_fn] - pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef) -> Self { - self.classes.alter_classes(op, classes); - self - } - - /// Establece el esquema de color del botón. - /// - /// Usa [`ButtonColor::Background`] para botones sólidos o [`ButtonColor::Outline`] para - /// variantes con contorno. - #[builder_fn] - pub fn with_color(mut self, color: ButtonColor) -> Self { - self.color = color; - self - } - - /// Establece el tamaño visual del botón. - #[builder_fn] - pub fn with_size(mut self, size: ButtonSize) -> Self { - self.size = size; - self - } - - /// Establece el nombre del botón (atributo `name`). - /// - /// Cuando el formulario tiene varios botones de envío, el navegador incluye en el envío el par - /// `name=value` sólo del botón que activó el formulario. Permite identificar cuál fue pulsado. - #[builder_fn] - pub fn with_name(mut self, name: impl AsRef) -> Self { - self.name.alter_name(name); - self - } - - /// Establece el valor del botón (atributo `value`). - /// - /// Es el dato que el navegador transmite al servidor junto con el `name` cuando este botón - /// activa el envío. Útil para distinguir entre varios botones de envío en un mismo formulario. - #[builder_fn] - pub fn with_value(mut self, value: impl AsRef) -> Self { - self.value.alter_str(value); - self - } - - /// Establece o elimina la etiqueta visible del botón (basta pasar `None` para quitarla). - #[builder_fn] - pub fn with_label(mut self, label: impl Into>) -> Self { - self.label.alter_opt(label.into()); - self - } - - /// Establece si el botón recibe el foco automáticamente al cargar la página. - #[builder_fn] - pub fn with_autofocus(mut self, autofocus: bool) -> Self { - self.autofocus = autofocus; - self - } - - /// Establece si el botón está deshabilitado. - #[builder_fn] - pub fn with_disabled(mut self, disabled: bool) -> Self { - self.disabled = disabled; - self - } -} diff --git a/extensions/pagetop-bootsier/src/theme/classes.rs b/extensions/pagetop-bootsier/src/theme/classes.rs deleted file mode 100644 index 9e6c234d..00000000 --- a/extensions/pagetop-bootsier/src/theme/classes.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! 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; - -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 deleted file mode 100644 index 8a6bd6c4..00000000 --- a/extensions/pagetop-bootsier/src/theme/classes/border.rs +++ /dev/null @@ -1,174 +0,0 @@ -use pagetop::prelude::*; - -use crate::theme::attrs::{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`). -/// - 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::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. usando -/// `classes::Border::new()` o `classes::Border::with(ScaleSize::Two)` y eliminar los lados -/// deseados con `ScaleSize::Zero`. -/// -/// - **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(ScaleSize::Two); -/// assert_eq!(b.to_class(), "border-2"); -/// ``` -/// -/// **Aditivo (solo borde superior):** -/// ```rust -/// # use pagetop_bootsier::prelude::*; -/// 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::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::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::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_class(), "border border-top-0 border-end-3 border-primary border-opacity-50"); -/// ``` -#[rustfmt::skip] -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -pub struct Border { - all : ScaleSize, - top : ScaleSize, - end : ScaleSize, - bottom : ScaleSize, - start : ScaleSize, - color : BorderColor, - opacity: Opacity, -} - -impl Border { - /// Prepara un borde del tamaño predefinido. Equivale a `border` (ancho por defecto del tema). - pub fn new() -> Self { - Self::with(ScaleSize::Auto) - } - - /// Crea un borde **con un tamaño global** (`size`). - pub fn with(size: ScaleSize) -> Self { - Self::default().with_side(Side::All, size) - } - - // **< Border BUILDER >************************************************************************* - - 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 - } - - /// 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 - } - - // **< 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 `""`. - 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 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 deleted file mode 100644 index 4776ca9f..00000000 --- a/extensions/pagetop-bootsier/src/theme/classes/color.rs +++ /dev/null @@ -1,228 +0,0 @@ -use pagetop::prelude::*; - -use crate::theme::attrs::{ColorBg, ColorText, Opacity}; - -// **< Background >********************************************************************************* - -/// Clases para establecer **color/opacidad del fondo**. -/// -/// # Ejemplos -/// -/// ``` -/// # use pagetop_bootsier::prelude::*; -/// // Sin clases. -/// let s = classes::Background::new(); -/// assert_eq!(s.to_class(), ""); -/// -/// // Sólo color de fondo. -/// let s = classes::Background::with(ColorBg::Theme(Color::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_class(), "bg-body-secondary bg-opacity-50"); -/// -/// // Usando `From`. -/// let s: classes::Background = ColorBg::Black.into(); -/// assert_eq!(s.to_class(), "bg-black"); -/// -/// // Usando `From<(ColorBg, Opacity)>`. -/// let s: classes::Background = (ColorBg::White, Opacity::SemiTransparent).into(); -/// assert_eq!(s.to_class(), "bg-white bg-opacity-25"); -/// ``` -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -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) - } - - // **< Background 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 - } - - // **< 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 `""`. - pub fn to_class(self) -> String { - let mut classes = String::new(); - self.push_class(&mut classes); - 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_class(), "bg-white bg-opacity-25"); - /// ``` - fn from((color, opacity): (ColorBg, Opacity)) -> Self { - Background::with(color).with_opacity(opacity) - } -} - -impl From 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_class(), "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_class(), ""); -/// -/// // Sólo color del texto. -/// let s = classes::Text::with(ColorText::Theme(Color::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_class(), "text-white text-opacity-25"); -/// -/// // Usando `From`. -/// let s: classes::Text = ColorText::Black.into(); -/// 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_class(), "text-danger text-opacity-100"); -/// ``` -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -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 - } - - // **< 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 `""`. - pub fn to_class(self) -> String { - let mut classes = String::new(); - self.push_class(&mut classes); - 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_class(), "text-danger text-opacity-100"); - /// ``` - fn from((color, opacity): (ColorText, Opacity)) -> Self { - Text::with(color).with_opacity(opacity) - } -} - -impl From 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_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 deleted file mode 100644 index 2a927acc..00000000 --- a/extensions/pagetop-bootsier/src/theme/classes/layout.rs +++ /dev/null @@ -1,180 +0,0 @@ -use pagetop::prelude::*; - -use crate::theme::attrs::{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"), - } - } - - /// Devuelve la clase de **margin** como cadena (`"mt-3"`, `"ms-lg-auto"`, etc.). - /// - /// Si `size` es `ScaleSize::None`, devuelve `""`. - 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"), - } - } - - /// Devuelve la clase de **padding** como cadena (`"px-2"`, `"pe-sm-4"`, etc.). - /// - /// Si `size` es `ScaleSize::None` o `ScaleSize::Auto`, devuelve `""`. - 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 deleted file mode 100644 index 16213e01..00000000 --- a/extensions/pagetop-bootsier/src/theme/classes/rounded.rs +++ /dev/null @@ -1,168 +0,0 @@ -use pagetop::prelude::*; - -use crate::theme::attrs::RoundedRadius; - -/// 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_class(), "rounded"); -/// ``` -/// -/// **Sin redondeo:** -/// ```rust -/// # use pagetop_bootsier::prelude::*; -/// let r = classes::Rounded::new(); -/// 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_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_class(), "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_class(), "rounded-top rounded-bottom-start-4 rounded-bottom-end-circle"); -/// ``` -#[rustfmt::skip] -#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] -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 - } - - // **< 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. - #[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 `""`. - 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.rs b/extensions/pagetop-bootsier/src/theme/container.rs deleted file mode 100644 index a860110f..00000000 --- a/extensions/pagetop-bootsier/src/theme/container.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! 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)); -//! ``` - -mod props; -pub use props::{Kind, Width}; - -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 deleted file mode 100644 index 0635ad18..00000000 --- a/extensions/pagetop-bootsier/src/theme/container/component.rs +++ /dev/null @@ -1,160 +0,0 @@ -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*). -#[derive(AutoDefault, Clone, Debug, Getters)] -pub struct Container { - #[getters(skip)] - id: AttrId, - /// Devuelve las clases CSS asociadas al contenedor. - classes: Classes, - /// Devuelve el tipo semántico del contenedor. - container_kind: container::Kind, - /// Devuelve el comportamiento para el ancho del contenedor. - container_width: container::Width, - /// Devuelve la lista de componentes (`children`) del contenedor. - children: Children, -} - -impl Component for Container { - fn new() -> Self { - Self::default() - } - - fn id(&self) -> Option { - self.id.get() - } - - fn setup(&mut self, _cx: &Context) { - self.alter_classes(ClassesOp::Prepend, self.container_width().to_class()); - } - - fn prepare(&self, cx: &mut Context) -> Result { - let output = self.children().render(cx); - if output.is_empty() { - return Ok(html! {}); - } - let style = match self.container_width() { - container::Width::FluidMax(w) if w.is_measurable() => { - Some(util::join!("max-width: ", w.to_string(), ";")) - } - _ => None, - }; - Ok(match self.container_kind() { - container::Kind::Default => html! { - div id=[self.id()] class=[self.classes().get()] style=[style] { - (output) - } - }, - container::Kind::Main => html! { - main id=[self.id()] class=[self.classes().get()] style=[style] { - (output) - } - }, - container::Kind::Header => html! { - header id=[self.id()] class=[self.classes().get()] style=[style] { - (output) - } - }, - container::Kind::Footer => html! { - footer id=[self.id()] class=[self.classes().get()] style=[style] { - (output) - } - }, - container::Kind::Section => html! { - section id=[self.id()] class=[self.classes().get()] style=[style] { - (output) - } - }, - container::Kind::Article => html! { - article id=[self.id()] class=[self.classes().get()] style=[style] { - (output) - } - }, - }) - } -} - -impl Container { - /// Crea un contenedor de tipo `Main` (`
`). - pub fn main() -> Self { - Self { - container_kind: container::Kind::Main, - ..Default::default() - } - } - - /// Crea un contenedor de tipo `Header` (`
`). - pub fn header() -> Self { - Self { - container_kind: container::Kind::Header, - ..Default::default() - } - } - - /// Crea un contenedor de tipo `Footer` (`