pagetop/extensions/pagetop-bootsier/src/theme/image/component.rs

123 lines
4 KiB
Rust

use pagetop::prelude::*;
use crate::prelude::*;
/// Componente para renderizar una **imagen**.
///
/// - Ajusta su disposición según el origen definido en [`image::Source`].
/// - Permite configurar **dimensiones** ([`with_size()`](Self::with_size)), **borde**
/// ([`classes::Border`](crate::theme::classes::Border)) y **redondeo de esquinas**
/// ([`classes::Rounded`](crate::theme::classes::Rounded)).
/// - Resuelve el texto alternativo `alt` con **localización** mediante [`L10n`].
#[derive(AutoDefault, Getters)]
pub struct Image {
#[getters(skip)]
id: AttrId,
/// Devuelve las clases CSS asociadas a la imagen.
classes: AttrClasses,
/// Devuelve las dimensiones de la imagen.
size: image::Size,
/// Devuelve el origen de la imagen.
source: image::Source,
/// Devuelve el texto alternativo localizado.
alternative: AttrL10n,
}
impl Component for Image {
fn new() -> Self {
Image::default()
}
fn id(&self) -> Option<String> {
self.id.get()
}
fn setup_before_prepare(&mut self, _cx: &mut Context) {
self.alter_classes(ClassesOp::Prepend, self.source().to_class());
}
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {
let dimensions = self.size().to_style();
let alt_text = self.alternative().lookup(cx).unwrap_or_default();
let is_decorative = alt_text.is_empty();
let source = match self.source() {
image::Source::Logo(logo) => {
return PrepareMarkup::With(html! {
span
id=[self.id()]
class=[self.classes().get()]
style=[dimensions]
role=[(!is_decorative).then_some("img")]
aria-label=[(!is_decorative).then_some(alt_text)]
aria-hidden=[is_decorative.then_some("true")]
{
(logo.render(cx))
}
})
}
image::Source::Responsive(source) => Some(source),
image::Source::Thumbnail(source) => Some(source),
image::Source::Plain(source) => Some(source),
};
PrepareMarkup::With(html! {
img
src=[source]
alt=(alt_text)
id=[self.id()]
class=[self.classes().get()]
style=[dimensions] {}
})
}
}
impl Image {
/// Crea rápidamente una imagen especificando su origen.
pub fn with(source: image::Source) -> Self {
Image::default().with_source(source)
}
// **< Image BUILDER >**************************************************************************
/// Establece el identificador único (`id`) de la imagen.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self
}
/// Modifica la lista de clases CSS aplicadas a la imagen.
///
/// También acepta clases predefinidas para:
///
/// - Establecer bordes ([`classes::Border`]).
/// - Redondear las esquinas ([`classes::Rounded`]).
#[builder_fn]
pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
self.classes.alter_value(op, classes);
self
}
/// Define las dimensiones de la imagen (auto, ancho/alto, ambos).
#[builder_fn]
pub fn with_size(mut self, size: image::Size) -> Self {
self.size = size;
self
}
/// Establece el origen de la imagen, influyendo en su disposición en el contenido.
#[builder_fn]
pub fn with_source(mut self, source: image::Source) -> Self {
self.source = source;
self
}
/// Define un *texto localizado* ([`L10n`]) alternativo para la imagen.
///
/// Se recomienda siempre aportar un texto alternativo salvo que la imagen sea puramente
/// decorativa.
#[builder_fn]
pub fn with_alternative(mut self, alt: L10n) -> Self {
self.alternative.alter_value(alt);
self
}
}