pagetop/src/core/theme/layout.rs
Manuel Cillero bb6855e41f (theme): Añade ColorName y CoreColors
Nuevo trait `ColorName` para que cada tema aporte su propia paleta de
colores; `CoreColors` es la paleta por defecto.

Aprovecha para refactorizar `core/theme.rs` en submódulos por concepto.
2026-08-20 21:54:12 +02:00

172 lines
7.1 KiB
Rust

use crate::AutoDefault;
use crate::core::AnyInfo;
use crate::locale::Lc;
// **< RegionName >*********************************************************************************
/// Interfaz común para las regiones lógicas del `<body>`.
///
/// Una [`RegionName`] representa un contenedor lógico identificado por un nombre de región. Su
/// contenido se obtiene del [`Context`], donde los componentes suelen registrarse usando
/// implementaciones de métodos como [`Contextual::with_child_in()`].
///
/// El contenido de una región viene determinado únicamente por su nombre, no por su tipo. Distintas
/// implementaciones de [`RegionName`] que devuelvan el mismo nombre comparten el mismo conjunto de
/// componentes registrados en el [`Context`]. Un *enum* propio que implemente [`RegionName`] está
/// pensado para **añadir** regiones que PageTop no ofrece (con un nombre propio que no colisione
/// con los de [`CoreRegions`] o [`ReservedRegions`]).
///
/// El tema decide qué regiones mostrar en el `<body>`, normalmente usando una plantilla
/// ([`TemplateName`]) al renderizar la página ([`Page`]).
///
/// Requiere [`AnyInfo`] para que un [`RegionRef`] pueda recuperarse mediante
/// [`AnyCast::downcast_ref()`] hacia su tipo concreto (por ejemplo, para que un tema distinga en
/// [`Theme::handle_component()`] qué variante concreta está renderizando el componente [`Region`]).
///
/// [`Context`]: crate::core::component::Context
/// [`Contextual::with_child_in()`]: crate::core::component::Contextual::with_child_in
/// [`ReservedRegions`]: crate::response::ReservedRegions
/// [`Page`]: crate::response::Page
/// [`AnyCast::downcast_ref()`]: crate::core::AnyCast::downcast_ref
/// [`Theme::handle_component()`]: crate::core::theme::Theme::handle_component
/// [`Region`]: crate::base::component::layout::Region
pub trait RegionName: Send + Sync + AnyInfo {
/// Devuelve el nombre de la región.
///
/// Este nombre es el identificador lógico de la región y se usa como clave en el
/// [`Context`](crate::core::component::Context) para recuperar y renderizar el contenido
/// registrado bajo ese nombre. Cualquier implementación de [`RegionName`] que devuelva el mismo
/// nombre compartirá el mismo conjunto de componentes.
fn name(&self) -> &'static str;
/// Devuelve un *texto localizado* como etiqueta de accesibilidad asociada a la región.
///
/// En la implementación predeterminada de [`Region`](crate::base::component::layout::Region),
/// este valor se usa como `aria-label` del contenedor de la región.
fn label(&self) -> Lc;
}
/// Referencia estática a una región.
pub type RegionRef = &'static dyn RegionName;
// **< CoreRegions >********************************************************************************
/// Regiones básicas que PageTop proporciona por defecto.
///
/// Comparten sus nombres (`"header"`, `"aside"`, `"content"`, `"footer"`) con otras regiones que
/// implementen [`RegionName`], por lo que comparten también el contenido registrado bajo esos
/// nombres. Por defecto, son las regiones usadas por [`Template`].
///
/// A estas regiones hay que sumar también las regiones internas reservadas por [`ReservedRegions`]
/// (`"page-top"` y `"page-bottom"`), que [`Page::render()`] renderiza en cualquier caso.
///
/// [`Template`]: crate::base::component::layout::Template
/// [`ReservedRegions`]: crate::response::ReservedRegions
/// [`Page::render()`]: crate::response::Page::render
#[derive(AutoDefault)]
pub enum CoreRegions {
/// Región estándar para la **cabecera** del documento, de nombre `"header"`.
///
/// Suele emplearse para mostrar un logotipo, navegación principal, barras superiores, etc.
Header,
/// Región de **contenido secundario**, de nombre `"aside"`.
///
/// Se renderiza por defecto entre `Header` y `Content`. Un tema podría maquetarla, por ejemplo,
/// como columna lateral junto a `Content` y emplearla para menús secundarios o cualquier otro
/// contenido complementario al principal.
Aside,
/// Región principal de **contenido**, de nombre `"content"`.
///
/// Es la región donde se renderiza el contenido principal del documento. En general será la
/// región mínima imprescindible para que una página tenga sentido.
#[default]
Content,
/// Región estándar para el **pie de página**, de nombre `"footer"`.
///
/// Suele contener información legal, enlaces secundarios, créditos, etc.
Footer,
}
impl RegionName for CoreRegions {
#[inline]
fn name(&self) -> &'static str {
match self {
Self::Header => "header",
Self::Aside => "aside",
Self::Content => "content",
Self::Footer => "footer",
}
}
#[inline]
fn label(&self) -> Lc {
match self {
Self::Header => Lc::l("region_header"),
Self::Aside => Lc::l("region_aside"),
Self::Content => Lc::l("region_content"),
Self::Footer => Lc::l("region_footer"),
}
}
}
// **< TemplateName >*******************************************************************************
/// Interfaz común para las plantillas lógicas de una página.
///
/// Representa una variante identificada por un nombre. Un tema puede usar este nombre para decidir
/// la composición del cuerpo de una página ([`Page`](crate::response::Page)), es decir, qué
/// regiones ([`RegionName`]) renderizar y en qué orden.
///
/// Requiere [`AnyInfo`] por el mismo motivo que [`RegionName`], para que un [`TemplateRef`] pueda
/// recuperarse mediante [`AnyCast::downcast_ref()`](crate::core::AnyCast::downcast_ref) hacia su
/// tipo concreto (por ejemplo, para que un tema distinga en
/// [`Theme::handle_component()`](crate::core::theme::Theme::handle_component) qué variante concreta
/// está renderizando el componente [`Template`](crate::base::component::layout::Template)).
pub trait TemplateName: Send + Sync + AnyInfo {
/// Devuelve el nombre de la plantilla.
fn name(&self) -> &'static str;
/// Devuelve un *texto localizado* como etiqueta descriptiva de la plantilla.
fn label(&self) -> Lc;
}
/// Referencia estática a una plantilla.
pub type TemplateRef = &'static dyn TemplateName;
// **< CoreTemplates >******************************************************************************
/// Plantillas que PageTop proporciona por defecto.
#[derive(AutoDefault)]
pub enum CoreTemplates {
/// Plantilla predeterminada, de nombre `"standard"`.
///
/// Se emplea cuando no se selecciona ninguna otra plantilla explícitamente.
#[default]
Standard,
/// Plantilla para la **interfaz de administración**, de nombre `"admin"`.
///
/// Se utiliza para páginas de administración o paneles de control.
Admin,
}
impl TemplateName for CoreTemplates {
#[inline]
fn name(&self) -> &'static str {
match self {
Self::Standard => "standard",
Self::Admin => "admin",
}
}
#[inline]
fn label(&self) -> Lc {
match self {
Self::Standard => Lc::l("template-standard"),
Self::Admin => Lc::l("template-admin"),
}
}
}