Compare commits

...

3 commits

30 changed files with 467 additions and 394 deletions

View file

@ -11,7 +11,7 @@ pub struct Container {
#[getters(skip)]
id: AttrId,
/// Devuelve las clases CSS asociadas al contenedor.
classes: AttrClasses,
classes: Classes,
/// Devuelve el tipo semántico del contenedor.
container_kind: container::Kind,
/// Devuelve el comportamiento para el ancho del contenedor.
@ -22,7 +22,7 @@ pub struct Container {
impl Component for Container {
fn new() -> Self {
Container::default()
Self::default()
}
fn id(&self) -> Option<String> {
@ -82,7 +82,7 @@ impl Component for Container {
impl Container {
/// Crea un contenedor de tipo `Main` (`<main>`).
pub fn main() -> Self {
Container {
Self {
container_kind: container::Kind::Main,
..Default::default()
}
@ -90,7 +90,7 @@ impl Container {
/// Crea un contenedor de tipo `Header` (`<header>`).
pub fn header() -> Self {
Container {
Self {
container_kind: container::Kind::Header,
..Default::default()
}
@ -98,7 +98,7 @@ impl Container {
/// Crea un contenedor de tipo `Footer` (`<footer>`).
pub fn footer() -> Self {
Container {
Self {
container_kind: container::Kind::Footer,
..Default::default()
}
@ -106,7 +106,7 @@ impl Container {
/// Crea un contenedor de tipo `Section` (`<section>`).
pub fn section() -> Self {
Container {
Self {
container_kind: container::Kind::Section,
..Default::default()
}
@ -114,7 +114,7 @@ impl Container {
/// Crea un contenedor de tipo `Article` (`<article>`).
pub fn article() -> Self {
Container {
Self {
container_kind: container::Kind::Article,
..Default::default()
}
@ -125,7 +125,7 @@ impl Container {
/// Establece el identificador único (`id`) del contenedor.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self.id.alter_id(id);
self
}
@ -139,7 +139,7 @@ impl Container {
/// - 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.classes.alter_classes(op, classes);
self
}

View file

@ -24,7 +24,7 @@ pub struct Dropdown {
#[getters(skip)]
id: AttrId,
/// Devuelve las clases CSS asociadas al menú desplegable.
classes: AttrClasses,
classes: Classes,
/// Devuelve el título del menú desplegable.
title: L10n,
/// Devuelve el tamaño configurado del botón.
@ -49,7 +49,7 @@ pub struct Dropdown {
impl Component for Dropdown {
fn new() -> Self {
Dropdown::default()
Self::default()
}
fn id(&self) -> Option<String> {
@ -76,7 +76,7 @@ impl Component for Dropdown {
PrepareMarkup::With(html! {
div id=[self.id()] class=[self.classes().get()] {
@if !title.is_empty() {
@let mut btn_classes = AttrClasses::new({
@let mut btn_classes = Classes::new({
let mut classes = "btn".to_string();
self.button_size().push_class(&mut classes);
self.button_color().push_class(&mut classes);
@ -86,7 +86,7 @@ impl Component for Dropdown {
@let offset = pos.data_offset();
@let reference = pos.data_reference();
@let auto_close = self.auto_close.as_str();
@let menu_classes = AttrClasses::new({
@let menu_classes = Classes::new({
let mut classes = "dropdown-menu".to_string();
self.menu_align().push_class(&mut classes);
classes
@ -107,7 +107,7 @@ impl Component for Dropdown {
@let btn_toggle = html! {
button
type="button"
class=[btn_classes.alter_value(
class=[btn_classes.alter_classes(
ClassesOp::Add, "dropdown-toggle dropdown-toggle-split"
).get()]
data-bs-toggle="dropdown"
@ -138,7 +138,7 @@ impl Component for Dropdown {
// Botón único con funcionalidad de *toggle*.
button
type="button"
class=[btn_classes.alter_value(
class=[btn_classes.alter_classes(
ClassesOp::Add, "dropdown-toggle"
).get()]
data-bs-toggle="dropdown"
@ -166,14 +166,14 @@ impl Dropdown {
/// Establece el identificador único (`id`) del menú desplegable.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self.id.alter_id(id);
self
}
/// Modifica la lista de clases CSS aplicadas al menú desplegable.
#[builder_fn]
pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
self.classes.alter_value(op, classes);
self.classes.alter_classes(op, classes);
self
}

View file

@ -48,14 +48,14 @@ pub struct Item {
#[getters(skip)]
id: AttrId,
/// Devuelve las clases CSS asociadas al elemento.
classes: AttrClasses,
classes: Classes,
/// Devuelve el tipo de elemento representado.
item_kind: ItemKind,
}
impl Component for Item {
fn new() -> Self {
Item::default()
Self::default()
}
fn id(&self) -> Option<String> {
@ -158,7 +158,7 @@ impl Component for Item {
impl Item {
/// Crea un elemento de tipo texto, mostrado sin interacción.
pub fn label(label: L10n) -> Self {
Item {
Self {
item_kind: ItemKind::Label(label),
..Default::default()
}
@ -170,7 +170,7 @@ impl Item {
/// [`RoutePath`] en función del [`Context`]. El enlace se marca como `active` si la ruta actual
/// del *request* coincide con la ruta de destino (devuelta por `RoutePath::path`).
pub fn link(label: L10n, route: FnPathByContext) -> Self {
Item {
Self {
item_kind: ItemKind::Link {
label,
route,
@ -183,7 +183,7 @@ impl Item {
/// Crea un enlace deshabilitado que no permite la interacción.
pub fn link_disabled(label: L10n, route: FnPathByContext) -> Self {
Item {
Self {
item_kind: ItemKind::Link {
label,
route,
@ -196,7 +196,7 @@ impl Item {
/// Crea un enlace que se abre en una nueva ventana o pestaña.
pub fn link_blank(label: L10n, route: FnPathByContext) -> Self {
Item {
Self {
item_kind: ItemKind::Link {
label,
route,
@ -209,7 +209,7 @@ impl Item {
/// Crea un enlace inicialmente deshabilitado que se abriría en una nueva ventana.
pub fn link_blank_disabled(label: L10n, route: FnPathByContext) -> Self {
Item {
Self {
item_kind: ItemKind::Link {
label,
route,
@ -222,7 +222,7 @@ impl Item {
/// Crea un botón de acción local, sin navegación asociada.
pub fn button(label: L10n) -> Self {
Item {
Self {
item_kind: ItemKind::Button {
label,
disabled: false,
@ -233,7 +233,7 @@ impl Item {
/// Crea un botón deshabilitado.
pub fn button_disabled(label: L10n) -> Self {
Item {
Self {
item_kind: ItemKind::Button {
label,
disabled: true,
@ -244,7 +244,7 @@ impl Item {
/// Crea un encabezado para un grupo de elementos dentro del menú.
pub fn header(label: L10n) -> Self {
Item {
Self {
item_kind: ItemKind::Header(label),
..Default::default()
}
@ -252,7 +252,7 @@ impl Item {
/// Crea un separador visual entre bloques de elementos.
pub fn divider() -> Self {
Item {
Self {
item_kind: ItemKind::Divider,
..Default::default()
}
@ -263,14 +263,14 @@ impl Item {
/// Establece el identificador único (`id`) del elemento.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self.id.alter_id(id);
self
}
/// Modifica la lista de clases CSS aplicadas al elemento.
#[builder_fn]
pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
self.classes.alter_value(op, classes);
self.classes.alter_classes(op, classes);
self
}
}

View file

@ -16,14 +16,14 @@ pub enum IconKind {
#[derive(AutoDefault, Getters)]
pub struct Icon {
/// Devuelve las clases CSS asociadas al icono.
classes: AttrClasses,
classes: Classes,
icon_kind: IconKind,
aria_label: AttrL10n,
}
impl Component for Icon {
fn new() -> Self {
Icon::default()
Self::default()
}
fn setup_before_prepare(&mut self, _cx: &mut Context) {
@ -75,22 +75,22 @@ impl Component for Icon {
impl Icon {
pub fn font() -> Self {
Icon::default().with_icon_kind(IconKind::Font(FontSize::default()))
Self::default().with_icon_kind(IconKind::Font(FontSize::default()))
}
pub fn font_sized(font_size: FontSize) -> Self {
Icon::default().with_icon_kind(IconKind::Font(font_size))
Self::default().with_icon_kind(IconKind::Font(font_size))
}
pub fn svg(shapes: Markup) -> Self {
Icon::default().with_icon_kind(IconKind::Svg {
Self::default().with_icon_kind(IconKind::Svg {
shapes,
viewbox: AttrValue::default(),
})
}
pub fn svg_with_viewbox(shapes: Markup, viewbox: impl AsRef<str>) -> Self {
Icon::default().with_icon_kind(IconKind::Svg {
Self::default().with_icon_kind(IconKind::Svg {
shapes,
viewbox: AttrValue::new(viewbox),
})

View file

@ -14,18 +14,18 @@ pub struct Image {
#[getters(skip)]
id: AttrId,
/// Devuelve las clases CSS asociadas a la imagen.
classes: AttrClasses,
classes: Classes,
/// 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,
alternative: Attr<L10n>,
}
impl Component for Image {
fn new() -> Self {
Image::default()
Self::default()
}
fn id(&self) -> Option<String> {
@ -73,7 +73,7 @@ impl Component for Image {
impl Image {
/// Crea rápidamente una imagen especificando su origen.
pub fn with(source: image::Source) -> Self {
Image::default().with_source(source)
Self::default().with_source(source)
}
// **< Image BUILDER >**************************************************************************
@ -81,7 +81,7 @@ impl Image {
/// 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.id.alter_id(id);
self
}
@ -93,7 +93,7 @@ impl Image {
/// - 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.classes.alter_classes(op, classes);
self
}

View file

@ -15,7 +15,7 @@ pub struct Nav {
#[getters(skip)]
id: AttrId,
/// Devuelve las clases CSS asociadas al menú.
classes: AttrClasses,
classes: Classes,
/// Devuelve el estilo visual seleccionado.
nav_kind: nav::Kind,
/// Devuelve la distribución y orientación seleccionada.
@ -26,7 +26,7 @@ pub struct Nav {
impl Component for Nav {
fn new() -> Self {
Nav::default()
Self::default()
}
fn id(&self) -> Option<String> {
@ -59,17 +59,17 @@ impl Component for Nav {
impl Nav {
/// Crea un `Nav` usando pestañas para los elementos (*Tabs*).
pub fn tabs() -> Self {
Nav::default().with_kind(nav::Kind::Tabs)
Self::default().with_kind(nav::Kind::Tabs)
}
/// Crea un `Nav` usando botones para los elementos (*Pills*).
pub fn pills() -> Self {
Nav::default().with_kind(nav::Kind::Pills)
Self::default().with_kind(nav::Kind::Pills)
}
/// Crea un `Nav` usando elementos subrayados (*Underline*).
pub fn underline() -> Self {
Nav::default().with_kind(nav::Kind::Underline)
Self::default().with_kind(nav::Kind::Underline)
}
// **< Nav BUILDER >****************************************************************************
@ -77,14 +77,14 @@ impl Nav {
/// Establece el identificador único (`id`) del menú.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self.id.alter_id(id);
self
}
/// Modifica la lista de clases CSS aplicadas al menú.
#[builder_fn]
pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
self.classes.alter_value(op, classes);
self.classes.alter_classes(op, classes);
self
}

View file

@ -81,14 +81,14 @@ pub struct Item {
#[getters(skip)]
id: AttrId,
/// Devuelve las clases CSS asociadas al elemento.
classes: AttrClasses,
classes: Classes,
/// Devuelve el tipo de elemento representado.
item_kind: ItemKind,
}
impl Component for Item {
fn new() -> Self {
Item::default()
Self::default()
}
fn id(&self) -> Option<String> {
@ -196,7 +196,7 @@ impl Component for Item {
impl Item {
/// Crea un elemento de tipo texto, mostrado sin interacción.
pub fn label(label: L10n) -> Self {
Item {
Self {
item_kind: ItemKind::Label(label),
..Default::default()
}
@ -208,7 +208,7 @@ impl Item {
/// [`RoutePath`] en función del [`Context`]. El enlace se marca como `active` si la ruta actual
/// del *request* coincide con la ruta de destino (devuelta por `RoutePath::path`).
pub fn link(label: L10n, route: FnPathByContext) -> Self {
Item {
Self {
item_kind: ItemKind::Link {
label,
route,
@ -221,7 +221,7 @@ impl Item {
/// Crea un enlace deshabilitado que no permite la interacción.
pub fn link_disabled(label: L10n, route: FnPathByContext) -> Self {
Item {
Self {
item_kind: ItemKind::Link {
label,
route,
@ -234,7 +234,7 @@ impl Item {
/// Crea un enlace que se abre en una nueva ventana o pestaña.
pub fn link_blank(label: L10n, route: FnPathByContext) -> Self {
Item {
Self {
item_kind: ItemKind::Link {
label,
route,
@ -247,7 +247,7 @@ impl Item {
/// Crea un enlace inicialmente deshabilitado que se abriría en una nueva ventana.
pub fn link_blank_disabled(label: L10n, route: FnPathByContext) -> Self {
Item {
Self {
item_kind: ItemKind::Link {
label,
route,
@ -263,7 +263,7 @@ impl Item {
/// El contenido se renderiza tal cual lo devuelve el componente [`Html`], dentro de un `<li>`
/// con las clases de navegación asociadas a [`Item`].
pub fn html(html: Html) -> Self {
Item {
Self {
item_kind: ItemKind::Html(Typed::with(html)),
..Default::default()
}
@ -275,7 +275,7 @@ impl Item {
/// lista de elementos** del [`Dropdown`]; el resto de propiedades del componente no afectarán
/// a su representación en [`Nav`].
pub fn dropdown(menu: Dropdown) -> Self {
Item {
Self {
item_kind: ItemKind::Dropdown(Typed::with(menu)),
..Default::default()
}
@ -286,14 +286,14 @@ impl Item {
/// Establece el identificador único (`id`) del elemento.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self.id.alter_id(id);
self
}
/// Modifica la lista de clases CSS aplicadas al elemento.
#[builder_fn]
pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
self.classes.alter_value(op, classes);
self.classes.alter_classes(op, classes);
self
}
}

View file

@ -29,7 +29,7 @@ pub struct Brand {
impl Component for Brand {
fn new() -> Self {
Brand::default()
Self::default()
}
fn id(&self) -> Option<String> {
@ -59,7 +59,7 @@ impl Brand {
/// Establece el identificador único (`id`) de la marca.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self.id.alter_id(id);
self
}

View file

@ -19,7 +19,7 @@ pub struct Navbar {
#[getters(skip)]
id: AttrId,
/// Devuelve las clases CSS asociadas a la barra de navegación.
classes: AttrClasses,
classes: Classes,
/// Devuelve el punto de ruptura configurado.
expand: BreakPoint,
/// Devuelve la disposición configurada para la barra de navegación.
@ -32,7 +32,7 @@ pub struct Navbar {
impl Component for Navbar {
fn new() -> Self {
Navbar::default()
Self::default()
}
fn id(&self) -> Option<String> {
@ -169,37 +169,37 @@ impl Component for Navbar {
impl Navbar {
/// Crea una barra de navegación **simple**, sin marca y sin botón.
pub fn simple() -> Self {
Navbar::default().with_layout(navbar::Layout::Simple)
Self::default().with_layout(navbar::Layout::Simple)
}
/// Crea una barra de navegación **simple pero colapsable**, con botón a la izquierda.
pub fn simple_toggle() -> Self {
Navbar::default().with_layout(navbar::Layout::SimpleToggle)
Self::default().with_layout(navbar::Layout::SimpleToggle)
}
/// Crea una barra de navegación **con marca a la izquierda**, siempre visible.
pub fn simple_brand_left(brand: navbar::Brand) -> Self {
Navbar::default().with_layout(navbar::Layout::SimpleBrandLeft(Typed::with(brand)))
Self::default().with_layout(navbar::Layout::SimpleBrandLeft(Typed::with(brand)))
}
/// Crea una barra de navegación con **marca a la izquierda** y **botón a la derecha**.
pub fn brand_left(brand: navbar::Brand) -> Self {
Navbar::default().with_layout(navbar::Layout::BrandLeft(Typed::with(brand)))
Self::default().with_layout(navbar::Layout::BrandLeft(Typed::with(brand)))
}
/// Crea una barra de navegación con **botón a la izquierda** y **marca a la derecha**.
pub fn brand_right(brand: navbar::Brand) -> Self {
Navbar::default().with_layout(navbar::Layout::BrandRight(Typed::with(brand)))
Self::default().with_layout(navbar::Layout::BrandRight(Typed::with(brand)))
}
/// Crea una barra de navegación cuyo contenido se muestra en un **offcanvas**.
pub fn offcanvas(oc: Offcanvas) -> Self {
Navbar::default().with_layout(navbar::Layout::Offcanvas(Typed::with(oc)))
Self::default().with_layout(navbar::Layout::Offcanvas(Typed::with(oc)))
}
/// Crea una barra de navegación con **marca a la izquierda** y contenido en **offcanvas**.
pub fn offcanvas_brand_left(brand: navbar::Brand, oc: Offcanvas) -> Self {
Navbar::default().with_layout(navbar::Layout::OffcanvasBrandLeft(
Self::default().with_layout(navbar::Layout::OffcanvasBrandLeft(
Typed::with(brand),
Typed::with(oc),
))
@ -207,7 +207,7 @@ impl Navbar {
/// Crea una barra de navegación con **marca a la derecha** y contenido en **offcanvas**.
pub fn offcanvas_brand_right(brand: navbar::Brand, oc: Offcanvas) -> Self {
Navbar::default().with_layout(navbar::Layout::OffcanvasBrandRight(
Self::default().with_layout(navbar::Layout::OffcanvasBrandRight(
Typed::with(brand),
Typed::with(oc),
))
@ -218,7 +218,7 @@ impl Navbar {
/// Establece el identificador único (`id`) de la barra de navegación.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self.id.alter_id(id);
self
}
@ -230,7 +230,7 @@ impl Navbar {
/// - Definir la apariencia del texto ([`classes::Text`]).
#[builder_fn]
pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
self.classes.alter_value(op, classes);
self.classes.alter_classes(op, classes);
self
}

View file

@ -26,7 +26,7 @@ pub enum Item {
impl Component for Item {
fn new() -> Self {
Item::default()
Self::default()
}
fn id(&self) -> Option<String> {

View file

@ -26,7 +26,7 @@ pub struct Offcanvas {
#[getters(skip)]
id: AttrId,
/// Devuelve las clases CSS asociadas al panel.
classes: AttrClasses,
classes: Classes,
/// Devuelve el título del panel.
title: L10n,
/// Devuelve el punto de ruptura configurado para cambiar el comportamiento del panel.
@ -45,7 +45,7 @@ pub struct Offcanvas {
impl Component for Offcanvas {
fn new() -> Self {
Offcanvas::default()
Self::default()
}
fn id(&self) -> Option<String> {
@ -73,14 +73,14 @@ impl Offcanvas {
/// Establece el identificador único (`id`) del panel.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self.id.alter_id(id);
self
}
/// Modifica la lista de clases CSS aplicadas al panel.
#[builder_fn]
pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
self.classes.alter_value(op, classes);
self.classes.alter_classes(op, classes);
self
}

View file

@ -42,7 +42,7 @@ impl<C: Component> AfterRender<C> {
/// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente
/// `C` con identificador `id`.
pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self {
self.referer_id.alter_value(id);
self.referer_id.alter_id(id);
self
}

View file

@ -42,7 +42,7 @@ impl<C: Component> BeforeRender<C> {
/// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente
/// `C` con identificador `id`.
pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self {
self.referer_id.alter_value(id);
self.referer_id.alter_id(id);
self
}

View file

@ -9,7 +9,7 @@ pub struct Block {
#[getters(skip)]
id: AttrId,
/// Devuelve las clases CSS asociadas al bloque.
classes: AttrClasses,
classes: Classes,
/// Devuelve el título del bloque.
title: L10n,
/// Devuelve la lista de componentes hijo del bloque.
@ -18,7 +18,7 @@ pub struct Block {
impl Component for Block {
fn new() -> Self {
Block::default()
Self::default()
}
fn id(&self) -> Option<String> {
@ -55,14 +55,14 @@ impl Block {
/// Establece el identificador único (`id`) del bloque.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id.alter_value(id);
self.id.alter_id(id);
self
}
/// Modifica la lista de clases CSS aplicadas al bloque.
#[builder_fn]
pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
self.classes.alter_value(op, classes);
self.classes.alter_classes(op, classes);
self
}

View file

@ -33,12 +33,13 @@ pub struct Html(Box<dyn Fn(&mut Context) -> Markup + Send + Sync>);
impl Default for Html {
fn default() -> Self {
Html::with(|_| html! {})
Self::with(|_| html! {})
}
}
impl Component for Html {
fn new() -> Self {
Html::default()
Self::default()
}
fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup {

View file

@ -106,7 +106,7 @@ impl Default for Intro {
impl Component for Intro {
fn new() -> Self {
Intro::default()
Self::default()
}
fn setup_before_prepare(&mut self, cx: &mut Context) {

View file

@ -10,7 +10,7 @@ pub struct ActionsList(RwLock<Vec<ActionBox>>);
impl ActionsList {
pub fn new() -> Self {
ActionsList::default()
Self::default()
}
pub fn add(&mut self, action: ActionBox) {

View file

@ -208,12 +208,12 @@ pub struct Children(Vec<Child>);
impl Children {
/// Crea una lista vacía.
pub fn new() -> Self {
Children::default()
Self::default()
}
/// Crea una lista con un componente hijo inicial.
pub fn with(child: Child) -> Self {
Children::default().with_child(ChildOp::Add(child))
Self::default().with_child(ChildOp::Add(child))
}
/// Fusiona varias listas de `Children` en una sola.

View file

@ -21,20 +21,11 @@ pub use logo::PageTopSvg;
// **< HTML ATTRIBUTES >****************************************************************************
mod attr_id;
pub use attr_id::AttrId;
mod attr;
pub use attr::{Attr, AttrId, AttrName, AttrValue};
mod attr_name;
pub use attr_name::AttrName;
mod attr_value;
pub use attr_value::AttrValue;
mod attr_l10n;
pub use attr_l10n::AttrL10n;
mod attr_classes;
pub use attr_classes::{AttrClasses, ClassesOp};
mod classes;
pub use classes::{Classes, ClassesOp};
mod unit;
pub use unit::UnitValue;

View file

@ -49,7 +49,7 @@ impl Favicon {
/// Equivalente a `Favicon::default()`. Se recomienda iniciar la secuencia de configuración
/// desde aquí.
pub fn new() -> Self {
Favicon::default()
Self::default()
}
// **< Favicon BUILDER >************************************************************************

View file

@ -88,7 +88,7 @@ impl JavaScript {
///
/// Equivale a `<script src="...">`.
pub fn from(path: impl Into<String>) -> Self {
JavaScript {
Self {
source: Source::From(path.into()),
..Default::default()
}
@ -100,7 +100,7 @@ impl JavaScript {
/// Equivale a `<script src="..." defer>`. Suele ser la opción recomendada para scripts no
/// críticos.
pub fn defer(path: impl Into<String>) -> Self {
JavaScript {
Self {
source: Source::Defer(path.into()),
..Default::default()
}
@ -111,7 +111,7 @@ impl JavaScript {
///
/// Equivale a `<script src="..." async>`. **No garantiza** el orden relativo con otros scripts.
pub fn asynchronous(path: impl Into<String>) -> Self {
JavaScript {
Self {
source: Source::Async(path.into()),
..Default::default()
}
@ -127,7 +127,7 @@ impl JavaScript {
where
F: Fn(&mut Context) -> String + Send + Sync + 'static,
{
JavaScript {
Self {
source: Source::Inline(name.into(), Box::new(f)),
..Default::default()
}
@ -147,7 +147,7 @@ impl JavaScript {
where
F: Fn(&mut Context) -> String + Send + Sync + 'static,
{
JavaScript {
Self {
source: Source::OnLoad(name.into(), Box::new(f)),
..Default::default()
}
@ -165,7 +165,7 @@ impl JavaScript {
where
F: Fn(&mut Context) -> String + Send + Sync + 'static,
{
JavaScript {
Self {
source: Source::OnLoadAsync(name.into(), Box::new(f)),
..Default::default()
}

View file

@ -91,7 +91,7 @@ impl StyleSheet {
///
/// Equivale a `<link rel="stylesheet" href="...">`.
pub fn from(path: impl Into<String>) -> Self {
StyleSheet {
Self {
source: Source::From(path.into()),
..Default::default()
}
@ -107,7 +107,7 @@ impl StyleSheet {
where
F: Fn(&mut Context) -> String + Send + Sync + 'static,
{
StyleSheet {
Self {
source: Source::Inline(name.into(), Box::new(f)),
..Default::default()
}

321
src/html/attr.rs Normal file
View file

@ -0,0 +1,321 @@
use crate::locale::{L10n, LangId};
use crate::{builder_fn, AutoDefault};
/// Valor opcional para atributos HTML.
///
/// `Attr<T>` encapsula un `Option<T>` y sirve como tipo base para representar atributos HTML
/// opcionales, uniformes y tipados.
///
/// Este tipo **no impone ninguna normalización ni semántica concreta**; dichas reglas se definen en
/// implementaciones concretas como `Attr<L10n>` y `Attr<String>`, o en tipos específicos como
/// [`AttrId`] y [`AttrName`].
#[derive(AutoDefault, Clone, Debug)]
pub struct Attr<T>(Option<T>);
impl<T> Attr<T> {
/// Crea un atributo vacío.
pub fn empty() -> Self {
Self(None)
}
/// Crea un atributo con valor.
pub fn some(value: T) -> Self {
Self(Some(value))
}
// **< Attr<T> BUILDER >************************************************************************
/// Establece un valor para el atributo.
#[builder_fn]
pub fn with_value(mut self, value: T) -> Self {
self.0 = Some(value);
self
}
/// Elimina el valor del atributo.
#[builder_fn]
pub fn with_none(mut self) -> Self {
self.0 = None;
self
}
// **< Attr<T> GETTERS >************************************************************************
/// Devuelve el valor (clonado), si existe.
pub fn get(&self) -> Option<T>
where
T: Clone,
{
self.0.clone()
}
/// Devuelve una referencia al valor, si existe.
pub fn as_ref(&self) -> Option<&T> {
self.0.as_ref()
}
/// Devuelve el valor (propiedad), si existe.
pub fn into_inner(self) -> Option<T> {
self.0
}
/// `true` si no hay valor.
pub fn is_empty(&self) -> bool {
self.0.is_none()
}
}
// **< Attr<L10n> >*********************************************************************************
/// Extiende [`Attr`] para [texto localizado](crate::locale) en atributos HTML.
///
/// Encapsula un [`L10n`] para manejar traducciones de forma segura en atributos.
///
/// # Ejemplo
///
/// ```rust
/// # use pagetop::prelude::*;
/// // Traducción por clave en las locales por defecto de PageTop.
/// let hello = Attr::<L10n>::new(L10n::l("test_hello_world"));
///
/// // Español disponible.
/// assert_eq!(
/// hello.lookup(&Locale::resolve("es-ES")),
/// Some("¡Hola mundo!".to_string())
/// );
///
/// // Japonés no disponible, traduce al idioma de respaldo (`"en-US"`).
/// assert_eq!(
/// hello.lookup(&Locale::resolve("ja-JP")),
/// Some("Hello world!".to_string())
/// );
///
/// // Uso típico en un atributo:
/// let title = hello.value(&Locale::resolve("es-ES"));
/// // Ejemplo: html! { a title=(title) { "Link" } }
/// ```
impl Attr<L10n> {
/// Crea una nueva instancia `Attr<L10n>`.
pub fn new(value: L10n) -> Self {
Self::some(value)
}
/// Devuelve la traducción para `language` si puede resolverse.
pub fn lookup(&self, language: &impl LangId) -> Option<String> {
self.0.as_ref()?.lookup(language)
}
/// Devuelve la traducción para `language` o una cadena vacía si no existe.
pub fn value(&self, language: &impl LangId) -> String {
self.lookup(language).unwrap_or_default()
}
}
// **< Attr<String> >*******************************************************************************
/// Extiende [`Attr`] para cadenas de texto.
impl Attr<String> {
/// Devuelve el texto como `&str` si existe.
pub fn as_str(&self) -> Option<&str> {
self.0.as_deref()
}
}
// **< AttrId >*************************************************************************************
/// Identificador normalizado para el atributo `id` o similar de HTML.
///
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
///
/// - Se eliminan los espacios al principio y al final.
/// - Se convierte a minúsculas.
/// - Se sustituyen los espacios (`' '`) intermedios por guiones bajos (`_`).
/// - Si el resultado es una cadena vacía, se guarda `None`.
///
/// # Ejemplo
///
/// ```rust
/// # use pagetop::prelude::*;
/// let id = AttrId::new(" main Section ");
/// assert_eq!(id.as_str(), Some("main_section"));
///
/// let empty = AttrId::default();
/// assert_eq!(empty.get(), None);
/// ```
#[derive(AutoDefault, Clone, Debug)]
pub struct AttrId(Attr<String>);
impl AttrId {
/// Crea un nuevo `AttrId` normalizando el valor.
pub fn new(id: impl AsRef<str>) -> Self {
Self::default().with_id(id)
}
// **< AttrId BUILDER >*************************************************************************
/// Establece un identificador nuevo normalizando el valor.
#[builder_fn]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
let id = id.as_ref().trim();
if id.is_empty() {
self.0 = Attr::default();
} else {
self.0 = Attr::some(id.to_ascii_lowercase().replace(' ', "_"));
}
self
}
// **< AttrId GETTERS >*************************************************************************
/// Devuelve el identificador normalizado, si existe.
pub fn get(&self) -> Option<String> {
self.0.get()
}
/// Devuelve el identificador normalizado (sin clonar), si existe.
pub fn as_str(&self) -> Option<&str> {
self.0.as_str()
}
/// Devuelve el identificador normalizado (propiedad), si existe.
pub fn into_inner(self) -> Option<String> {
self.0.into_inner()
}
/// `true` si no hay valor.
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
// **< AttrName >***********************************************************************************
/// Nombre normalizado para el atributo `name` o similar de HTML.
///
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
///
/// - Se eliminan los espacios al principio y al final.
/// - Se convierte a minúsculas.
/// - Se sustituyen los espacios (`' '`) intermedios por guiones bajos (`_`).
/// - Si el resultado es una cadena vacía, se guarda `None`.
///
/// # Ejemplo
///
/// ```rust
/// # use pagetop::prelude::*;
/// let name = AttrName::new(" DISplay name ");
/// assert_eq!(name.as_str(), Some("display_name"));
///
/// let empty = AttrName::default();
/// assert_eq!(empty.get(), None);
/// ```
#[derive(AutoDefault, Clone, Debug)]
pub struct AttrName(Attr<String>);
impl AttrName {
/// Crea un nuevo `AttrName` normalizando el valor.
pub fn new(name: impl AsRef<str>) -> Self {
Self::default().with_name(name)
}
// **< AttrName BUILDER >***********************************************************************
/// Establece un nombre nuevo normalizando el valor.
#[builder_fn]
pub fn with_name(mut self, name: impl AsRef<str>) -> Self {
let name = name.as_ref().trim();
if name.is_empty() {
self.0 = Attr::default();
} else {
self.0 = Attr::some(name.to_ascii_lowercase().replace(' ', "_"));
}
self
}
// **< AttrName GETTERS >***********************************************************************
/// Devuelve el nombre normalizado, si existe.
pub fn get(&self) -> Option<String> {
self.0.get()
}
/// Devuelve el nombre normalizado (sin clonar), si existe.
pub fn as_str(&self) -> Option<&str> {
self.0.as_str()
}
/// Devuelve el nombre normalizado (propiedad), si existe.
pub fn into_inner(self) -> Option<String> {
self.0.into_inner()
}
/// `true` si no hay valor.
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
// **< AttrValue >**********************************************************************************
/// Cadena normalizada para renderizar en atributos HTML.
///
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
///
/// - Se eliminan los espacios al principio y al final.
/// - Si el resultado es una cadena vacía, se guarda `None`.
///
/// # Ejemplo
///
/// ```rust
/// # use pagetop::prelude::*;
/// let s = AttrValue::new(" a new string ");
/// assert_eq!(s.as_str(), Some("a new string"));
///
/// let empty = AttrValue::default();
/// assert_eq!(empty.get(), None);
/// ```
#[derive(AutoDefault, Clone, Debug)]
pub struct AttrValue(Attr<String>);
impl AttrValue {
/// Crea un nuevo `AttrValue` normalizando el valor.
pub fn new(value: impl AsRef<str>) -> Self {
Self::default().with_str(value)
}
// **< AttrValue BUILDER >**********************************************************************
/// Establece una cadena nueva normalizando el valor.
#[builder_fn]
pub fn with_str(mut self, value: impl AsRef<str>) -> Self {
let value = value.as_ref().trim();
if value.is_empty() {
self.0 = Attr::default();
} else {
self.0 = Attr::some(value.to_string());
}
self
}
// **< AttrValue GETTERS >**********************************************************************
/// Devuelve la cadena normalizada, si existe.
pub fn get(&self) -> Option<String> {
self.0.get()
}
/// Devuelve la cadena normalizada (sin clonar), si existe.
pub fn as_str(&self) -> Option<&str> {
self.0.as_str()
}
/// Devuelve la cadena normalizada (propiedad), si existe.
pub fn into_inner(self) -> Option<String> {
self.0.into_inner()
}
/// `true` si no hay valor.
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}

View file

@ -1,62 +0,0 @@
use crate::{builder_fn, AutoDefault};
/// Identificador normalizado para el atributo `id` o similar de HTML.
///
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
///
/// - Se eliminan los espacios al principio y al final.
/// - Se convierte a minúsculas.
/// - Se sustituyen los espacios intermedios por guiones bajos (`_`).
/// - Si el resultado es una cadena vacía, se guarda `None`.
///
/// # Ejemplo
///
/// ```rust
/// # use pagetop::prelude::*;
/// let id = AttrId::new(" main Section ");
/// assert_eq!(id.as_str(), Some("main_section"));
///
/// let empty = AttrId::default();
/// assert_eq!(empty.get(), None);
/// ```
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
pub struct AttrId(Option<String>);
impl AttrId {
/// Crea un nuevo `AttrId` normalizando el valor.
pub fn new(value: impl AsRef<str>) -> Self {
AttrId::default().with_value(value)
}
// **< AttrId BUILDER >*************************************************************************
/// Establece un identificador nuevo normalizando el valor.
#[builder_fn]
pub fn with_value(mut self, value: impl AsRef<str>) -> Self {
let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_");
self.0 = if value.is_empty() { None } else { Some(value) };
self
}
// **< AttrId GETTERS >*************************************************************************
/// Devuelve el identificador normalizado, si existe.
pub fn get(&self) -> Option<String> {
self.0.as_ref().cloned()
}
/// Devuelve el identificador normalizado (sin clonar), si existe.
pub fn as_str(&self) -> Option<&str> {
self.0.as_deref()
}
/// Devuelve el identificador normalizado (propiedad), si existe.
pub fn into_inner(self) -> Option<String> {
self.0
}
/// `true` si no hay valor.
pub fn is_empty(&self) -> bool {
self.0.is_none()
}
}

View file

@ -1,60 +0,0 @@
use crate::locale::{L10n, LangId};
use crate::{builder_fn, AutoDefault};
/// Texto para [traducir](crate::locale) en atributos HTML.
///
/// Encapsula un [`L10n`] para manejar traducciones de forma segura en atributos.
///
/// # Ejemplo
///
/// ```rust
/// # use pagetop::prelude::*;
/// // Traducción por clave en las locales por defecto de PageTop.
/// let hello = AttrL10n::new(L10n::l("test_hello_world"));
///
/// // Español disponible.
/// assert_eq!(
/// hello.lookup(&Locale::resolve("es-ES")),
/// Some("¡Hola mundo!".to_string())
/// );
///
/// // Japonés no disponible, traduce al idioma de respaldo (`"en-US"`).
/// assert_eq!(
/// hello.lookup(&Locale::resolve("ja-JP")),
/// Some("Hello world!".to_string())
/// );
///
/// // Uso típico en un atributo:
/// let title = hello.value(&Locale::resolve("es-ES"));
/// // Ejemplo: html! { a title=(title) { "Link" } }
/// ```
#[derive(AutoDefault, Clone, Debug)]
pub struct AttrL10n(L10n);
impl AttrL10n {
/// Crea una nueva instancia `AttrL10n`.
pub fn new(value: L10n) -> Self {
AttrL10n(value)
}
// **< AttrL10n BUILDER >***********************************************************************
/// Establece una traducción nueva.
#[builder_fn]
pub fn with_value(mut self, value: L10n) -> Self {
self.0 = value;
self
}
// **< AttrL10n GETTERS >***********************************************************************
/// Devuelve la traducción para `language`, si existe.
pub fn lookup(&self, language: &impl LangId) -> Option<String> {
self.0.lookup(language)
}
/// Devuelve la traducción para `language` o una cadena vacía si no existe.
pub fn value(&self, language: &impl LangId) -> String {
self.0.lookup(language).unwrap_or_default()
}
}

View file

@ -1,62 +0,0 @@
use crate::{builder_fn, AutoDefault};
/// Nombre normalizado para el atributo `name` o similar de HTML.
///
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
///
/// - Se eliminan los espacios al principio y al final.
/// - Se convierte a minúsculas.
/// - Se sustituyen los espacios intermedios por guiones bajos (`_`).
/// - Si el resultado es una cadena vacía, se guarda `None`.
///
/// # Ejemplo
///
/// ```rust
/// # use pagetop::prelude::*;
/// let name = AttrName::new(" DISplay name ");
/// assert_eq!(name.as_str(), Some("display_name"));
///
/// let empty = AttrName::default();
/// assert_eq!(empty.get(), None);
/// ```
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
pub struct AttrName(Option<String>);
impl AttrName {
/// Crea un nuevo `AttrName` normalizando el valor.
pub fn new(value: impl AsRef<str>) -> Self {
AttrName::default().with_value(value)
}
// **< AttrName BUILDER >***********************************************************************
/// Establece un nombre nuevo normalizando el valor.
#[builder_fn]
pub fn with_value(mut self, value: impl AsRef<str>) -> Self {
let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_");
self.0 = if value.is_empty() { None } else { Some(value) };
self
}
// **< AttrName GETTERS >***********************************************************************
/// Devuelve el nombre normalizado, si existe.
pub fn get(&self) -> Option<String> {
self.0.as_ref().cloned()
}
/// Devuelve el nombre normalizado (sin clonar), si existe.
pub fn as_str(&self) -> Option<&str> {
self.0.as_deref()
}
/// Devuelve el nombre normalizado (propiedad), si existe.
pub fn into_inner(self) -> Option<String> {
self.0
}
/// `true` si no hay valor.
pub fn is_empty(&self) -> bool {
self.0.is_none()
}
}

View file

@ -1,64 +0,0 @@
use crate::{builder_fn, AutoDefault};
/// Cadena normalizada para renderizar en atributos HTML.
///
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
///
/// - Se eliminan los espacios al principio y al final.
/// - Si el resultado es una cadena vacía, se guarda `None`.
///
/// # Ejemplo
///
/// ```rust
/// # use pagetop::prelude::*;
/// let s = AttrValue::new(" a new string ");
/// assert_eq!(s.as_str(), Some("a new string"));
///
/// let empty = AttrValue::default();
/// assert_eq!(empty.get(), None);
/// ```
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
pub struct AttrValue(Option<String>);
impl AttrValue {
/// Crea un nuevo `AttrValue` normalizando el valor.
pub fn new(value: impl AsRef<str>) -> Self {
AttrValue::default().with_value(value)
}
// **< AttrValue BUILDER >**********************************************************************
/// Establece una cadena nueva normalizando el valor.
#[builder_fn]
pub fn with_value(mut self, value: impl AsRef<str>) -> Self {
let value = value.as_ref().trim();
self.0 = if value.is_empty() {
None
} else {
Some(value.to_string())
};
self
}
// **< AttrValue GETTERS >**********************************************************************
/// Devuelve la cadena normalizada, si existe.
pub fn get(&self) -> Option<String> {
self.0.as_ref().cloned()
}
/// Devuelve la cadena normalizada (sin clonar), si existe.
pub fn as_str(&self) -> Option<&str> {
self.0.as_deref()
}
/// Devuelve la cadena normalizada (propiedad), si existe.
pub fn into_inner(self) -> Option<String> {
self.0
}
/// `true` si no hay valor.
pub fn is_empty(&self) -> bool {
self.0.is_none()
}
}

View file

@ -1,16 +1,18 @@
use crate::{builder_fn, AutoDefault};
/// Operaciones disponibles sobre la lista de clases en [`AttrClasses`].
use std::borrow::Cow;
/// Operaciones disponibles sobre la lista de clases en [`Classes`].
pub enum ClassesOp {
/// Añade al final (si no existe).
Add,
/// Añade al principio.
Prepend,
/// Elimina coincidencias.
/// Elimina la(s) clase(s) indicada(s).
Remove,
/// Sustituye una o varias por las nuevas (`Replace("old other")`).
Replace(String),
/// Alterna presencia/ausencia.
/// Sustituye una o varias clases por otras nuevas (`Replace("old other".into())`).
Replace(Cow<'static, str>),
/// Alterna presencia/ausencia de una o más clases.
Toggle,
/// Sustituye toda la lista.
Set,
@ -23,34 +25,40 @@ pub enum ClassesOp {
///
/// # Normalización
///
/// - El [orden de las clases no es relevante](https://stackoverflow.com/a/1321712) en CSS.
/// - No se permiten clases duplicadas.
/// - El [orden de las clases no es relevante](https://stackoverflow.com/a/1321712) en CSS, pero
/// [`ClassesOp`] ofrece operaciones para controlar su orden de aparición.
/// - Las clases se convierten a minúsculas.
/// - No se permiten clases duplicadas.
/// - Las clases vacías se ignoran.
///
/// # Ejemplo
///
/// ```rust
/// # use pagetop::prelude::*;
/// let classes = AttrClasses::new("Btn btn-primary")
/// .with_value(ClassesOp::Add, "Active")
/// .with_value(ClassesOp::Remove, "btn-primary");
/// let classes = Classes::new("Btn btn-primary")
/// .with_classes(ClassesOp::Add, "Active")
/// .with_classes(ClassesOp::Remove, "btn-primary");
///
/// assert_eq!(classes.get(), Some("btn active".to_string()));
/// assert!(classes.contains("active"));
/// ```
#[derive(AutoDefault, Clone, Debug)]
pub struct AttrClasses(Vec<String>);
pub struct Classes(Vec<String>);
impl AttrClasses {
impl Classes {
/// Crea una nueva lista de clases a partir de la clase o clases proporcionadas en `classes`.
pub fn new(classes: impl AsRef<str>) -> Self {
AttrClasses::default().with_value(ClassesOp::Prepend, classes)
Self::default().with_classes(ClassesOp::Prepend, classes)
}
// **< AttrClasses BUILDER >********************************************************************
// **< Classes BUILDER >************************************************************************
/// Modifica la lista de clases según la operación indicada.
///
/// Realiza la operación indicada en `op` para las clases proporcionadas en `classes` sobre la
/// lista de clases actual.
#[builder_fn]
pub fn with_value(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
let classes = classes.as_ref().to_ascii_lowercase();
let classes: Vec<&str> = classes.split_ascii_whitespace().collect();
@ -114,7 +122,7 @@ impl AttrClasses {
}
}
// **< AttrClasses GETTERS >********************************************************************
// **< Classes GETTERS >************************************************************************
/// Devuelve la cadena de clases, si existe.
pub fn get(&self) -> Option<String> {
@ -127,7 +135,7 @@ impl AttrClasses {
/// Devuelve `true` si la clase está presente.
pub fn contains(&self, class: impl AsRef<str>) -> bool {
let class = class.as_ref();
self.0.iter().any(|c| c == class)
let class = class.as_ref().to_ascii_lowercase();
self.0.iter().any(|c| c == &class)
}
}

View file

@ -66,7 +66,7 @@ pub struct L10n {
impl L10n {
/// **n** = *“native”*. Crea una instancia con una cadena literal sin traducción.
pub fn n(text: impl Into<Cow<'static, str>>) -> Self {
L10n {
Self {
op: L10nOp::Text(text.into()),
..Default::default()
}
@ -75,7 +75,7 @@ impl L10n {
/// **l** = *“lookup”*. Crea una instancia para traducir usando una clave del conjunto de
/// traducciones predefinidas.
pub fn l(key: impl Into<Cow<'static, str>>) -> Self {
L10n {
Self {
op: L10nOp::Translate(key.into()),
..Default::default()
}
@ -84,7 +84,7 @@ impl L10n {
/// **t** = *“translate”*. Crea una instancia para traducir usando una clave de un conjunto de
/// traducciones específico.
pub fn t(key: impl Into<Cow<'static, str>>, locales: &'static Locales) -> Self {
L10n {
Self {
op: L10nOp::Translate(key.into()),
locales,
..Default::default()

View file

@ -24,8 +24,8 @@ use crate::core::component::{Context, ContextOp, Contextual};
use crate::core::theme::{DefaultRegion, Region, RegionRef, TemplateRef, ThemeRef};
use crate::html::{html, Markup, DOCTYPE};
use crate::html::{Assets, Favicon, JavaScript, StyleSheet};
use crate::html::{AttrClasses, ClassesOp};
use crate::html::{AttrId, AttrL10n};
use crate::html::{Attr, AttrId};
use crate::html::{Classes, ClassesOp};
use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier};
use crate::service::HttpRequest;
use crate::{builder_fn, AutoDefault};
@ -89,12 +89,12 @@ impl Region for ReservedRegion {
#[rustfmt::skip]
#[derive(AutoDefault)]
pub struct Page {
title : AttrL10n,
description : AttrL10n,
title : Attr<L10n>,
description : Attr<L10n>,
metadata : Vec<(&'static str, &'static str)>,
properties : Vec<(&'static str, &'static str)>,
body_id : AttrId,
body_classes: AttrClasses,
body_classes: Classes,
context : Context,
}
@ -106,12 +106,12 @@ impl Page {
#[rustfmt::skip]
pub fn new(request: HttpRequest) -> Self {
Page {
title : AttrL10n::default(),
description : AttrL10n::default(),
title : Attr::<L10n>::default(),
description : Attr::<L10n>::default(),
metadata : Vec::default(),
properties : Vec::default(),
body_id : AttrId::default(),
body_classes: AttrClasses::default(),
body_classes: Classes::default(),
context : Context::new(Some(request)),
}
}
@ -149,14 +149,14 @@ impl Page {
/// Establece el atributo `id` del elemento `<body>`.
#[builder_fn]
pub fn with_body_id(mut self, id: impl AsRef<str>) -> Self {
self.body_id.alter_value(id);
self.body_id.alter_id(id);
self
}
/// Modifica las clases CSS del elemento `<body>` con una operación sobre [`AttrClasses`].
/// Modifica las clases CSS del elemento `<body>` con una operación sobre [`Classes`].
#[builder_fn]
pub fn with_body_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
self.body_classes.alter_value(op, classes);
self.body_classes.alter_classes(op, classes);
self
}
@ -204,7 +204,7 @@ impl Page {
}
/// Devuelve las clases CSS del elemento `<body>`.
pub fn body_classes(&self) -> &AttrClasses {
pub fn body_classes(&self) -> &Classes {
&self.body_classes
}