🚧 Depura la estructura y estilos del menú e intro

This commit is contained in:
Manuel Cillero 2025-10-06 04:09:26 +02:00
parent 4c8610af07
commit fef927906c
8 changed files with 302 additions and 163 deletions

View file

@ -49,7 +49,7 @@ impl Component for Item {
}),
ItemKind::Link(label, path) => PrepareMarkup::With(html! {
li class="menu__item menu__item--link" {
a href=(path(cx)) title=[description] {
a class="menu__link" href=(path(cx)) title=[description] {
(left_icon)
span class="menu__label" { (label.using(cx)) }
(right_icon)
@ -58,7 +58,7 @@ impl Component for Item {
}),
ItemKind::LinkBlank(label, path) => PrepareMarkup::With(html! {
li class="menu__item menu__item--link" {
a href=(path(cx)) title=[description] target="_blank" {
a class="menu__link" href=(path(cx)) title=[description] target="_blank" {
(left_icon)
span class="menu__label" { (label.using(cx)) }
(right_icon)
@ -72,7 +72,7 @@ impl Component for Item {
}),
ItemKind::Submenu(label, submenu) => PrepareMarkup::With(html! {
li class="menu__item menu__item--children" {
a href="#" title=[description] {
button type="button" class="menu__link" title=[description] {
(left_icon)
span class="menu__label" { (label.using(cx)) }
(Icon::svg(html! {
@ -86,7 +86,7 @@ impl Component for Item {
}),
ItemKind::Megamenu(label, megamenu) => PrepareMarkup::With(html! {
li class="menu__item menu__item--children" {
a href="#" title=[description] {
button type="button" class="menu__link" title=[description] {
(left_icon)
span class="menu__label" { (label.using(cx)) }
(Icon::svg(html! {

View file

@ -46,12 +46,8 @@ impl Theme for Basic {
}
fn after_render_page_body(&self, page: &mut Page) {
let styles = match page.layout() {
"Intro" => "/css/intro.css",
"PageTopIntro" => "/css/intro.css",
_ => "/css/basic.css",
};
let pkg_version = env!("CARGO_PKG_VERSION");
page.alter_assets(ContextOp::AddStyleSheet(
StyleSheet::from("/css/normalize.css")
.with_version("8.0.1")
@ -62,6 +58,11 @@ impl Theme for Basic {
.with_version(pkg_version)
.with_weight(-99),
))
.alter_assets(ContextOp::AddStyleSheet(
StyleSheet::from("/css/basic.css")
.with_version(pkg_version)
.with_weight(-99),
))
.alter_assets(ContextOp::AddStyleSheet(
StyleSheet::from("/css/components.css")
.with_version(pkg_version)
@ -72,11 +73,6 @@ impl Theme for Basic {
.with_version(pkg_version)
.with_weight(-99),
))
.alter_assets(ContextOp::AddStyleSheet(
StyleSheet::from(styles)
.with_version(pkg_version)
.with_weight(-99),
))
.alter_assets(ContextOp::AddJavaScript(
JavaScript::defer("/js/menu.js")
.with_version(pkg_version)
@ -86,9 +82,18 @@ impl Theme for Basic {
}
fn render_intro(page: &mut Page) -> Markup {
page.alter_assets(ContextOp::AddStyleSheet(
StyleSheet::from("/css/intro.css").with_version(env!("CARGO_PKG_VERSION")),
));
let title = page.title().unwrap_or_default();
let intro = page.description().unwrap_or_default();
let theme = page.context().theme();
let h = theme.render_page_region(page, "header");
let c = theme.render_page_region(page, "content");
let f = theme.render_page_region(page, "footer");
let intro_button_txt: L10n = page.param_or_default("intro_button_txt");
let intro_button_lnk: Option<&String> = page.param("intro_button_lnk");
@ -118,26 +123,27 @@ fn render_intro(page: &mut Page) -> Markup {
}
}
}
(h)
}
main class="intro-content" {
section class="intro-content__body" {
@if intro_button_lnk.is_some() {
div class="intro-button" {
a
class="intro-button__link"
href=[intro_button_lnk]
target="_blank"
rel="noreferrer"
{
span {} span {} span {}
div class="intro-button__text" {
(intro_button_txt.using(page))
div class="intro-text" {
@if intro_button_lnk.is_some() {
div class="intro-button" {
a
class="intro-button__link"
href=[intro_button_lnk]
target="_blank"
rel="noreferrer"
{
span {} span {} span {}
div class="intro-button__text" {
(intro_button_txt.using(page))
}
}
}
}
}
div class="intro-text" {
(page.context().render_components_of("content"))
(c)
}
}
}
@ -164,6 +170,7 @@ fn render_intro(page: &mut Page) -> Markup {
em { (L10n::l("intro_have_fun").using(page)) }
}
}
(f)
}
}
}

View file

@ -15,50 +15,70 @@ pub type ThemeRef = &'static dyn Theme;
/// Métodos predefinidos de renderizado para las páginas de un tema.
///
/// Contiene las implementaciones base de las **secciones** `<head>` y `<body>`. Se implementa
/// automáticamente para cualquier tipo que implemente [`Theme`], por lo que normalmente no requiere
/// implementación explícita.
/// Contiene las implementaciones base para renderizar las **secciones** `<head>` y `<body>`. Se
/// implementa automáticamente para cualquier tipo que implemente [`Theme`], por lo que normalmente
/// no requiere implementación explícita.
///
/// Si un tema **sobrescribe** [`render_page_head()`](Theme::render_page_head) o
/// [`render_page_body()`](Theme::render_page_body), se puede volver al comportamiento por defecto
/// cuando se necesite usando FQS (*Fully Qualified Syntax*):
/// Si un tema **sobrescribe** uno o más de estos métodos de [`Theme`]:
///
/// - [`render_page_region()`](Theme::render_page_region),
/// - [`render_page_head()`](Theme::render_page_head), o
/// - [`render_page_body()`](Theme::render_page_body);
///
/// es posible volver al comportamiento por defecto usando FQS (*Fully Qualified Syntax*):
///
/// - `<Self as ThemePage>::render_body(self, page, self.page_regions())`
/// - `<Self as ThemePage>::render_head(self, page)`
pub trait ThemePage {
/// Renderiza el **contenedor** de una región concreta del `<body>` de la página.
///
/// Obtiene los componentes asociados a `region.key()` desde el contexto de la página y, si hay
/// salida, envuelve el contenido en un contenedor `<div>` predefinido.
///
/// Si la región **no produce contenido**, devuelve un `Markup` vacío.
#[inline]
fn render_region(&self, page: &mut Page, region: &Region) -> Markup {
html! {
@let output = page.context().render_components_of(region.key());
@if !output.is_empty() {
@let region_name = region.name();
div
id=(region_name)
class={ "region region--" (region_name) }
role="region"
aria-label=[region.label().lookup(page)]
{
(output)
}
}
}
}
/// Renderiza el **contenido interior** del `<body>` de la página.
///
/// Esta implementación recorre `regions` en el **orden declarado** y, para cada región con
/// contenido, genera un contenedor con `role="region"` y un `aria-label` localizado.
/// Se asume que cada identificador de región es **único** dentro de la página.
/// Recorre `regions` en el **orden declarado** y, para cada región con contenido, delega en
/// [`render_region()`](Self::render_region) la generación del contenedor. Las regiones sin
/// contenido **no** producen salida. Se asume que cada identificador de región es **único**
/// dentro de la página.
///
/// La etiqueta `<body>` no se incluye aquí; únicamente renderiza su contenido.
#[inline]
fn render_body(&self, page: &mut Page, regions: &[Region]) -> Markup {
html! {
@for region in regions {
@let output = page.context().render_components_of(region.key());
@if !output.is_empty() {
@let region_name = region.name();
div
id=(region_name)
class={ "region region--" (region_name) }
role="region"
aria-label=[region.label().lookup(page)]
{
(output)
}
}
(self.render_region(page, region))
}
}
}
/// Renderiza el **contenido interior** del `<head>` de la página.
///
/// Recorre y genera por defecto las etiquetas básicas (`charset`, `title`, `description`,
/// `viewport`, `X-UA-Compatible`), los metadatos (`name/content`) y propiedades
/// (`property/content`), además de los recursos CSS/JS de la página.
/// Incluye por defecto las etiquetas básicas (`charset`, `title`, `description`, `viewport`,
/// `X-UA-Compatible`), los metadatos (`name/content`) y propiedades (`property/content`),
/// además de los recursos CSS/JS de la página.
///
/// La etiqueta `<head>` no se incluye aquí; únicamente renderiza su contenido.
/// La etiqueta `<head>` no se incluye aquí; únicamente se renderiza su contenido.
#[inline]
fn render_head(&self, page: &mut Page) -> Markup {
let viewport = "width=device-width, initial-scale=1, shrink-to-fit=no";
html! {
@ -152,6 +172,19 @@ pub trait Theme: Extension + ThemePage + Send + Sync {
&*REGIONS
}
/// Renderiza una región de la página **por clave**.
///
/// Busca en [`page_regions()`](Self::page_regions) la región asociada a una clave y, si existe,
/// delega en [`ThemePage::render_region()`] su renderizado. Si no se encuentra la clave o la
/// región no produce contenido, devuelve un `Markup` vacío.
fn render_page_region(&self, page: &mut Page, key: &str) -> Markup {
html! {
@if let Some(region) = self.page_regions().iter().find(|r| r.key() == key) {
(self.render_region(page, region))
}
}
}
/// Acciones específicas del tema antes de renderizar el `<body>` de la página.
///
/// Útil para preparar clases, inyectar recursos o ajustar metadatos.