🎨 [theme] Mejora gestión de regiones en páginas

This commit is contained in:
Manuel Cillero 2025-08-22 08:29:11 +02:00
parent 512a406ede
commit 75eec8bebc
7 changed files with 174 additions and 49 deletions

View file

@ -1,5 +1,5 @@
use crate::core::component::{Child, ChildOp, Children};
use crate::core::theme::{ThemeRef, CONTENT_REGION_NAME};
use crate::core::theme::ThemeRef;
use crate::{builder_fn, AutoDefault, UniqueId};
use parking_lot::RwLock;
@ -7,15 +7,71 @@ use parking_lot::RwLock;
use std::collections::HashMap;
use std::sync::LazyLock;
// Regiones globales con componentes para un tema dado.
// Conjunto de regiones globales asociadas a un tema específico.
static THEME_REGIONS: LazyLock<RwLock<HashMap<UniqueId, ChildrenInRegions>>> =
LazyLock::new(|| RwLock::new(HashMap::new()));
// Regiones globales con componentes para cualquier tema.
// Conjunto de regiones globales comunes a todos los temas.
static COMMON_REGIONS: LazyLock<RwLock<ChildrenInRegions>> =
LazyLock::new(|| RwLock::new(ChildrenInRegions::default()));
// Estructura interna para mantener los componentes de una región.
/// Nombre de la región de contenido por defecto (`"content"`).
pub const REGION_CONTENT: &str = "content";
/// Identificador de una región de página.
///
/// Incluye una **clave estática** ([`key()`](Self::key)) que identifica la región en el tema, y un
/// **nombre normalizado** ([`name()`](Self::name)) en minúsculas para su uso en atributos HTML
/// (p.ej., clases `region__{name}`).
///
/// Se utiliza para declarar las regiones que componen una página en un tema (ver
/// [`declared_regions()`](crate::core::theme::Theme::declared_regions)).
pub struct Region {
key: &'static str,
name: String,
}
impl Default for Region {
#[inline]
fn default() -> Self {
Self {
key: REGION_CONTENT,
name: String::from(REGION_CONTENT),
}
}
}
impl Region {
/// Declara una región a partir de su clave estática.
///
/// Genera además un nombre normalizado de la clave, eliminando espacios iniciales y finales,
/// convirtiendo a minúsculas y sustituyendo los espacios intermedios por guiones (`-`).
///
/// Esta clave se usará para añadir componentes a la región; por ello se recomiendan nombres
/// sencillos, limitando los caracteres a `[a-z0-9-]` (p.ej., `"sidebar"` o `"main-menu"`), cuyo
/// nombre normalizado coincidirá con la clave.
#[inline]
pub fn declare(key: &'static str) -> Self {
Self {
key,
name: key.trim().to_ascii_lowercase().replace(' ', "-"),
}
}
/// Devuelve la clave estática asignada a la región.
#[inline]
pub fn key(&self) -> &'static str {
self.key
}
/// Devuelve el nombre normalizado de la región (para atributos y búsquedas).
#[inline]
pub fn name(&self) -> &str {
&self.name
}
}
// Contenedor interno de componentes agrupados por región.
#[derive(AutoDefault)]
pub struct ChildrenInRegions(HashMap<&'static str, Children>);
@ -48,25 +104,24 @@ impl ChildrenInRegions {
}
}
/// Permite añadir componentes a regiones globales o regiones de temas concretos.
/// Punto de acceso para añadir componentes a regiones globales o específicas de un tema.
///
/// Dada una región, según la variante seleccionada, se le podrán añadir ([`add()`](Self::add))
/// componentes que se mantendrán durante la ejecución de la aplicación.
/// Según la variante, se pueden añadir componentes ([`add()`](Self::add)) que permanecerán
/// disponibles durante toda la ejecución.
///
/// Estas estructuras de componentes se renderizarán automáticamente al procesar los documentos HTML
/// que las usan, como las páginas de contenido ([`Page`](crate::response::page::Page)), por
/// ejemplo.
/// Estos componentes se renderizarán automáticamente al procesar los documentos HTML que incluyen
/// estas regiones, como las páginas de contenido ([`Page`](crate::response::page::Page)).
pub enum InRegion {
/// Representa la región por defecto en la que se pueden añadir componentes.
/// Región de contenido por defecto.
Content,
/// Representa la región con el nombre del argumento.
/// Región identificada por el nombre proporcionado.
Named(&'static str),
/// Representa la región con el nombre y del tema especificado en los argumentos.
/// Región identificada por un nombre y asociada a un tema concreto.
OfTheme(&'static str, ThemeRef),
}
impl InRegion {
/// Permite añadir un componente en la región de la variante seleccionada.
/// Añade un componente a la región indicada por la variante.
///
/// # Ejemplo
///
@ -88,7 +143,7 @@ impl InRegion {
InRegion::Content => {
COMMON_REGIONS
.write()
.alter_child_in_region(CONTENT_REGION_NAME, ChildOp::Add(child));
.alter_child_in_region(REGION_CONTENT, ChildOp::Add(child));
}
InRegion::Named(name) => {
COMMON_REGIONS