From 4c8610af079a13117429af32d0d8ec4673b09632 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Sat, 4 Oct 2025 08:25:04 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Mejora=20`Region`=20para=20decla?= =?UTF-8?q?rar=20las=20regiones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/theme/definition.rs | 32 ++++++++++++++++---------------- src/core/theme/regions.rs | 12 +++++++++++- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 4478ad0..0322a31 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -28,14 +28,14 @@ pub type ThemeRef = &'static dyn Theme; pub trait ThemePage { /// Renderiza el **contenido interior** del `` de la página. /// - /// Recorre `regions` en el **orden declarado** y, para cada región con contenido, genera un - /// contenedor con `role="region"` y un `aria-label` localizado. + /// Esta implementación recorre `regions` en el **orden declarado** y, para cada región con + /// contenido, genera un contenedor con `role="region"` y un `aria-label` localizado. /// Se asume que cada identificador de región es **único** dentro de la página. /// /// La etiqueta `` no se incluye aquí; únicamente renderiza su contenido. - fn render_body(&self, page: &mut Page, regions: &[(Region, L10n)]) -> Markup { + fn render_body(&self, page: &mut Page, regions: &[Region]) -> Markup { html! { - @for (region, region_label) in regions { + @for region in regions { @let output = page.context().render_components_of(region.key()); @if !output.is_empty() { @let region_name = region.name(); @@ -43,7 +43,7 @@ pub trait ThemePage { id=(region_name) class={ "region region--" (region_name) } role="region" - aria-label=[region_label.lookup(page)] + aria-label=[region.label().lookup(page)] { (output) } @@ -125,31 +125,31 @@ pub trait Theme: Extension + ThemePage + Send + Sync { /// Declaración ordenada de las regiones disponibles en la página. /// - /// Devuelve una **lista estática** de pares `(Region, L10n)` que se usará para renderizar todas - /// las regiones que componen una página en el orden indicado . + /// Devuelve una **lista estática** de regiones ([`Region`](crate::core::theme::Region)) con la + /// información necesaria para renderizar el contenedor de cada región. /// /// Si un tema necesita un conjunto distinto de regiones, se puede **sobrescribir** este método /// con los siguientes requisitos y recomendaciones: /// /// - Los identificadores deben ser **estables** (p. ej. `"sidebar-left"`, `"content"`). - /// - La región `"content"` es **obligatoria**. Se puede usar [`Region::default()`] para - /// declararla. - /// - La etiqueta `L10n` se evalúa con el idioma activo de la página. + /// - La región `"content"` es **obligatoria** porque se usa por defecto para añadir componentes + /// para renderizar. Se puede utilizar [`Region::default()`] para declararla. + /// - La etiqueta `L10n` se evaluará con el idioma activo de la página. /// /// Por defecto devuelve: /// /// - `"header"`: cabecera. /// - `"content"`: contenido principal (**obligatoria**). /// - `"footer"`: pie. - fn page_regions(&self) -> &'static [(Region, L10n)] { - static REGIONS: LazyLock<[(Region, L10n); 3]> = LazyLock::new(|| { + fn page_regions(&self) -> &'static [Region] { + static REGIONS: LazyLock<[Region; 3]> = LazyLock::new(|| { [ - (Region::declare("header"), L10n::l("region_header")), - (Region::default(), L10n::l("region_content")), - (Region::declare("footer"), L10n::l("region_footer")), + Region::declare("header", L10n::l("region_header")), + Region::default(), + Region::declare("footer", L10n::l("region_footer")), ] }); - ®IONS[..] + &*REGIONS } /// Acciones específicas del tema antes de renderizar el `` de la página. diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index 3fdfe09..00ff60c 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -1,5 +1,6 @@ use crate::core::component::{Child, ChildOp, Children}; use crate::core::theme::ThemeRef; +use crate::locale::L10n; use crate::{builder_fn, AutoDefault, UniqueId}; use parking_lot::RwLock; @@ -29,6 +30,7 @@ pub const REGION_CONTENT: &str = "content"; pub struct Region { key: &'static str, name: String, + label: L10n, } impl Default for Region { @@ -37,6 +39,7 @@ impl Default for Region { Self { key: REGION_CONTENT, name: REGION_CONTENT.to_string(), + label: L10n::l("region_content"), } } } @@ -51,10 +54,11 @@ impl Region { /// sencillos, limitando los caracteres a `[a-z0-9-]` (p.ej., `"sidebar"` o `"main-menu"`), cuyo /// nombre normalizado coincidirá con la clave. #[inline] - pub fn declare(key: &'static str) -> Self { + pub fn declare(key: &'static str, label: L10n) -> Self { Self { key, name: key.trim().to_ascii_lowercase().replace(' ', "-"), + label, } } @@ -69,6 +73,12 @@ impl Region { pub fn name(&self) -> &str { &self.name } + + /// Devuelve la etiqueta localizada asociada a la región. + #[inline] + pub fn label(&self) -> &L10n { + &self.label + } } // Contenedor interno de componentes agrupados por región.