♻️ (bootsier): Mueve Image al core de PageTop
`Image`, `Size` y `Source` pasan a `pagetop::base::component` como componente genérico reutilizable por cualquier tema. Bootsier sustituye las clases semánticas por las de Bootstrap (`img-fluid`, `img-thumbnail`) interceptando `setup()`.
This commit is contained in:
parent
745d492d5b
commit
c3ff8a6ff8
6 changed files with 97 additions and 88 deletions
|
|
@ -145,6 +145,7 @@ impl Theme for Bootsier {
|
||||||
setup_component!(component, {
|
setup_component!(component, {
|
||||||
Button => |c| theme::bs::button::setup(c),
|
Button => |c| theme::bs::button::setup(c),
|
||||||
Container => |c| theme::bs::container::setup(c),
|
Container => |c| theme::bs::container::setup(c),
|
||||||
|
Image => |c| theme::bs::image::setup(c),
|
||||||
form::input::Field => |c| theme::bs::form::input::setup(c),
|
form::input::Field => |c| theme::bs::form::input::setup(c),
|
||||||
form::select::Field => |c| theme::bs::form::select::setup(c),
|
form::select::Field => |c| theme::bs::form::select::setup(c),
|
||||||
form::Textarea => |c| theme::bs::form::textarea::setup(c),
|
form::Textarea => |c| theme::bs::form::textarea::setup(c),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,24 @@
|
||||||
//! Definiciones para renderizar imágenes ([`Image`]).
|
//! Definiciones para renderizar imágenes ([`Image`]).
|
||||||
|
|
||||||
mod props;
|
use pagetop::prelude::*;
|
||||||
pub use props::{Size, Source};
|
|
||||||
|
|
||||||
mod component;
|
pub use pagetop::base::component::image::{Image, Size, Source};
|
||||||
pub use component::Image;
|
|
||||||
|
// **< Image SETUP >********************************************************************************
|
||||||
|
|
||||||
|
pub(crate) fn setup(image: &mut Image) {
|
||||||
|
match image.source() {
|
||||||
|
Source::Logo(_) | Source::Responsive(_) => {
|
||||||
|
image.alter_prop(PropsOp::replace_classes("image image-fluid", "img-fluid"));
|
||||||
|
}
|
||||||
|
Source::Thumbnail(_) => {
|
||||||
|
image.alter_prop(PropsOp::replace_classes(
|
||||||
|
"image image-thumbnail",
|
||||||
|
"img-thumbnail",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Source::Plain(_) => {
|
||||||
|
image.alter_prop(PropsOp::remove_classes("image"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,10 @@ pub use form::Form;
|
||||||
mod html;
|
mod html;
|
||||||
pub use html::Html;
|
pub use html::Html;
|
||||||
|
|
||||||
|
pub mod image;
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use image::Image;
|
||||||
|
|
||||||
mod intro;
|
mod intro;
|
||||||
pub use intro::{Intro, IntroOpening};
|
pub use intro::{Intro, IntroOpening};
|
||||||
|
|
||||||
|
|
|
||||||
7
src/base/component/image.rs
Normal file
7
src/base/component/image.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
//! Definiciones para renderizar imágenes ([`Image`]).
|
||||||
|
|
||||||
|
mod props;
|
||||||
|
pub use props::{Size, Source};
|
||||||
|
|
||||||
|
mod component;
|
||||||
|
pub use component::Image;
|
||||||
|
|
@ -1,25 +1,33 @@
|
||||||
use pagetop::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::theme::*;
|
|
||||||
|
|
||||||
/// Componente para renderizar una **imagen**.
|
/// Componente para renderizar una **imagen**.
|
||||||
///
|
///
|
||||||
/// A una imagen se le puede:
|
/// A una imagen se le puede:
|
||||||
///
|
///
|
||||||
/// - Establecer su contenido a partir del origen definido en
|
/// - Establecer su contenido a partir del origen definido en [`image::Source`].
|
||||||
/// [`image::Source`](crate::theme::bs::image::Source).
|
/// - Configurar sus **dimensiones** ([`with_size()`](Self::with_size)).
|
||||||
/// - Configurar sus **dimensiones** ([`with_size()`](Self::with_size)), **borde**
|
|
||||||
/// ([`Border`](crate::theme::class::Border)) y **redondeo de esquinas**
|
|
||||||
/// ([`Rounded`](crate::theme::class::Rounded)).
|
|
||||||
/// - Aplicar el texto alternativo `alt` con **localización** mediante [`Lc`].
|
/// - Aplicar el texto alternativo `alt` con **localización** mediante [`Lc`].
|
||||||
|
///
|
||||||
|
/// # Ejemplo
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// use pagetop::prelude::*;
|
||||||
|
///
|
||||||
|
/// let logo = Image::with(image::Source::logo(PageTopSvg::Color))
|
||||||
|
/// .with_alternative(Lc::n("PageTop"));
|
||||||
|
///
|
||||||
|
/// let photo = Image::with(image::Source::responsive("/files/photo.jpg"))
|
||||||
|
/// .with_size(image::Size::Width(UnitValue::Px(320)))
|
||||||
|
/// .with_alternative(Lc::n("Team photo"));
|
||||||
|
/// ```
|
||||||
#[derive(AutoDefault, Clone, Debug, Getters)]
|
#[derive(AutoDefault, Clone, Debug, Getters)]
|
||||||
pub struct Image {
|
pub struct Image {
|
||||||
/// Devuelve identificador, clases CSS, atributos HTML y valores extra del componente.
|
/// Devuelve identificador, clases CSS, atributos HTML y valores extra del componente.
|
||||||
props: Props,
|
props: Props,
|
||||||
/// Devuelve las dimensiones de la imagen.
|
/// Devuelve las dimensiones de la imagen.
|
||||||
size: bs::image::Size,
|
size: image::Size,
|
||||||
/// Devuelve el origen de la imagen.
|
/// Devuelve el origen de la imagen.
|
||||||
source: bs::image::Source,
|
source: image::Source,
|
||||||
/// Devuelve el texto alternativo localizado.
|
/// Devuelve el texto alternativo localizado.
|
||||||
alternative: Attr<Lc>,
|
alternative: Attr<Lc>,
|
||||||
}
|
}
|
||||||
|
|
@ -35,20 +43,40 @@ impl Component for Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(&mut self, _cx: &Context) {
|
fn setup(&mut self, _cx: &Context) {
|
||||||
// Clases CSS por defecto para la imagen, según el origen seleccionado.
|
self.alter_prop(PropsOp::prepend_classes(match self.source() {
|
||||||
self.alter_prop(PropsOp::prepend_classes(self.source().to_class()));
|
image::Source::Logo(_) => "image image-fluid",
|
||||||
|
image::Source::Responsive(_) => "image image-fluid",
|
||||||
|
image::Source::Thumbnail(_) => "image image-thumbnail",
|
||||||
|
image::Source::Plain(_) => "image",
|
||||||
|
}));
|
||||||
|
// El tamaño se aplica como declaraciones `style` individuales sobre `Props`.
|
||||||
|
match *self.size() {
|
||||||
|
image::Size::Auto => {}
|
||||||
|
image::Size::Dimensions(w, h) => {
|
||||||
|
self.alter_prop(PropsOp::add_style("width", w.to_string()));
|
||||||
|
self.alter_prop(PropsOp::add_style("height", h.to_string()));
|
||||||
|
}
|
||||||
|
image::Size::Width(w) => {
|
||||||
|
self.alter_prop(PropsOp::add_style("width", w.to_string()));
|
||||||
|
}
|
||||||
|
image::Size::Height(h) => {
|
||||||
|
self.alter_prop(PropsOp::add_style("height", h.to_string()));
|
||||||
|
}
|
||||||
|
image::Size::Both(v) => {
|
||||||
|
self.alter_prop(PropsOp::add_style("width", v.to_string()));
|
||||||
|
self.alter_prop(PropsOp::add_style("height", v.to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn prepare(&self, cx: &mut Context) -> Result<Markup, ComponentError> {
|
async fn prepare(&self, cx: &mut Context) -> Result<Markup, ComponentError> {
|
||||||
let dimensions = self.size().to_style();
|
|
||||||
let alt_text = self.alternative().lookup(cx).unwrap_or_default();
|
let alt_text = self.alternative().lookup(cx).unwrap_or_default();
|
||||||
let is_decorative = alt_text.is_empty();
|
|
||||||
let source = match self.source() {
|
let source = match self.source() {
|
||||||
bs::image::Source::Logo(logo) => {
|
image::Source::Logo(logo) => {
|
||||||
|
let is_decorative = alt_text.is_empty();
|
||||||
return Ok(html! {
|
return Ok(html! {
|
||||||
span
|
span
|
||||||
(self.props())
|
(self.props())
|
||||||
style=[dimensions]
|
|
||||||
role=[(!is_decorative).then_some("img")]
|
role=[(!is_decorative).then_some("img")]
|
||||||
aria-label=[(!is_decorative).then_some(alt_text)]
|
aria-label=[(!is_decorative).then_some(alt_text)]
|
||||||
aria-hidden=[is_decorative.then_some("true")]
|
aria-hidden=[is_decorative.then_some("true")]
|
||||||
|
|
@ -57,23 +85,22 @@ impl Component for Image {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
bs::image::Source::Responsive(source) => Some(source),
|
image::Source::Responsive(source) => Some(source),
|
||||||
bs::image::Source::Thumbnail(source) => Some(source),
|
image::Source::Thumbnail(source) => Some(source),
|
||||||
bs::image::Source::Plain(source) => Some(source),
|
image::Source::Plain(source) => Some(source),
|
||||||
};
|
};
|
||||||
Ok(html! {
|
Ok(html! {
|
||||||
img
|
img
|
||||||
src=[source]
|
src=[source]
|
||||||
alt=(alt_text)
|
alt=(alt_text)
|
||||||
(self.props())
|
(self.props()) {}
|
||||||
style=[dimensions] {}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Image {
|
impl Image {
|
||||||
/// Crea rápidamente una imagen especificando su origen.
|
/// Crea rápidamente una imagen especificando su origen.
|
||||||
pub fn with(source: bs::image::Source) -> Self {
|
pub fn with(source: image::Source) -> Self {
|
||||||
Self::default().with_source(source)
|
Self::default().with_source(source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,11 +114,6 @@ impl Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modifica identificador, clases CSS, atributos HTML o valores extra del componente.
|
/// Modifica identificador, clases CSS, atributos HTML o valores extra del componente.
|
||||||
///
|
|
||||||
/// También acepta clases predefinidas para:
|
|
||||||
///
|
|
||||||
/// - Establecer bordes ([`Border`]).
|
|
||||||
/// - Redondear las esquinas ([`Rounded`]).
|
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_prop(mut self, op: PropsOp) -> Self {
|
pub fn with_prop(mut self, op: PropsOp) -> Self {
|
||||||
self.props.alter_prop(op);
|
self.props.alter_prop(op);
|
||||||
|
|
@ -100,14 +122,14 @@ impl Image {
|
||||||
|
|
||||||
/// Define las dimensiones de la imagen (auto, ancho/alto, ambos).
|
/// Define las dimensiones de la imagen (auto, ancho/alto, ambos).
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_size(mut self, size: bs::image::Size) -> Self {
|
pub fn with_size(mut self, size: image::Size) -> Self {
|
||||||
self.size = size;
|
self.size = size;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Establece el origen de la imagen, influyendo en su disposición en el contenido.
|
/// Establece el origen de la imagen, influyendo en su disposición en el contenido.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_source(mut self, source: bs::image::Source) -> Self {
|
pub fn with_source(mut self, source: image::Source) -> Self {
|
||||||
self.source = source;
|
self.source = source;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use pagetop::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
// **< Size >***************************************************************************************
|
// **< Size >***************************************************************************************
|
||||||
|
|
||||||
/// Define las **dimensiones** de una imagen ([`Image`](crate::theme::bs::Image)).
|
/// Define las **dimensiones** de una imagen ([`Image`](super::Image)).
|
||||||
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
|
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
|
||||||
pub enum Size {
|
pub enum Size {
|
||||||
/// Ajuste automático por defecto.
|
/// Ajuste automático por defecto.
|
||||||
|
|
@ -30,23 +30,13 @@ pub enum Size {
|
||||||
Both(UnitValue),
|
Both(UnitValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Size {
|
|
||||||
/// Devuelve el valor del atributo `style` en función del tamaño, o `None` si no aplica.
|
|
||||||
#[inline]
|
|
||||||
pub fn to_style(self) -> Option<String> {
|
|
||||||
match self {
|
|
||||||
Self::Auto => None,
|
|
||||||
Self::Dimensions(w, h) => Some(format!("width: {w}; height: {h};")),
|
|
||||||
Self::Width(w) => Some(format!("width: {w};")),
|
|
||||||
Self::Height(h) => Some(format!("height: {h};")),
|
|
||||||
Self::Both(v) => Some(format!("width: {v}; height: {v};")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// **< Source >*************************************************************************************
|
// **< Source >*************************************************************************************
|
||||||
|
|
||||||
/// Especifica la **fuente** para publicar una imagen ([`Image`](crate::theme::bs::Image)).
|
/// Especifica la **fuente** para publicar una imagen ([`Image`](super::Image)).
|
||||||
|
///
|
||||||
|
/// Las variantes son puramente semánticas. El componente aplica una clase CSS base según la
|
||||||
|
/// variante en su propio `setup()`; los temas pueden sobrescribirla interceptando el renderizado
|
||||||
|
/// del componente.
|
||||||
#[derive(AutoDefault, Clone, Debug, PartialEq)]
|
#[derive(AutoDefault, Clone, Debug, PartialEq)]
|
||||||
pub enum Source {
|
pub enum Source {
|
||||||
/// Imagen con el logotipo de PageTop.
|
/// Imagen con el logotipo de PageTop.
|
||||||
|
|
@ -56,71 +46,39 @@ pub enum Source {
|
||||||
///
|
///
|
||||||
/// Lleva asociada la URL (o ruta) de la imagen.
|
/// Lleva asociada la URL (o ruta) de la imagen.
|
||||||
Responsive(CowStr),
|
Responsive(CowStr),
|
||||||
/// Imagen que aplica el estilo **miniatura** de Bootstrap.
|
/// Imagen que aplica un estilo de miniatura.
|
||||||
///
|
///
|
||||||
/// Lleva asociada la URL (o ruta) de la imagen.
|
/// Lleva asociada la URL (o ruta) de la imagen.
|
||||||
Thumbnail(CowStr),
|
Thumbnail(CowStr),
|
||||||
/// Imagen sin clases específicas de Bootstrap, útil para controlar con CSS propio.
|
/// Imagen sin modificadores adicionales de estilo, útil para controlar la apariencia con CSS
|
||||||
|
/// propio.
|
||||||
///
|
///
|
||||||
/// Lleva asociada la URL (o ruta) de la imagen.
|
/// Lleva asociada la URL (o ruta) de la imagen.
|
||||||
Plain(CowStr),
|
Plain(CowStr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Source {
|
impl Source {
|
||||||
const IMG_FLUID: &str = "img-fluid";
|
|
||||||
const IMG_THUMBNAIL: &str = "img-thumbnail";
|
|
||||||
|
|
||||||
/// Imagen con el logotipo de PageTop.
|
/// Imagen con el logotipo de PageTop.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn logo(svg: PageTopSvg) -> Self {
|
pub fn logo(svg: PageTopSvg) -> Self {
|
||||||
Self::Logo(svg)
|
Self::Logo(svg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Imagen responsive (`img-fluid`).
|
/// Imagen responsive.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn responsive(url: impl Into<CowStr>) -> Self {
|
pub fn responsive(url: impl Into<CowStr>) -> Self {
|
||||||
Self::Responsive(url.into())
|
Self::Responsive(url.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Imagen miniatura (`img-thumbnail`).
|
/// Imagen miniatura.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn thumbnail(url: impl Into<CowStr>) -> Self {
|
pub fn thumbnail(url: impl Into<CowStr>) -> Self {
|
||||||
Self::Thumbnail(url.into())
|
Self::Thumbnail(url.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Imagen sin clases adicionales.
|
/// Imagen sin modificadores adicionales de estilo.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn plain(url: impl Into<CowStr>) -> Self {
|
pub fn plain(url: impl Into<CowStr>) -> Self {
|
||||||
Self::Plain(url.into())
|
Self::Plain(url.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Devuelve la clase base asociada a la imagen según la fuente.
|
|
||||||
#[inline]
|
|
||||||
pub const fn as_str(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Source::Logo(_) | Source::Responsive(_) => Self::IMG_FLUID,
|
|
||||||
Source::Thumbnail(_) => Self::IMG_THUMBNAIL,
|
|
||||||
Source::Plain(_) => "",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Añade la clase asociada al tipo de imagen a la cadena de clases.
|
|
||||||
#[inline]
|
|
||||||
pub fn push_to(&self, classes: &mut String) {
|
|
||||||
let s = self.as_str();
|
|
||||||
if s.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if !classes.is_empty() {
|
|
||||||
classes.push(' ');
|
|
||||||
}
|
|
||||||
classes.push_str(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Devuelve la clase asociada al tipo de imagen.
|
|
||||||
pub fn to_class(&self) -> String {
|
|
||||||
let mut class = String::new();
|
|
||||||
self.push_to(&mut class);
|
|
||||||
class
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue