♻️ (bootsier): Mueve Container al core de PageTop
`Container` y `Kind` pasan a `pagetop::base::component` como componente genérico reutilizable por cualquier tema. Bootsier conserva `Width` y añade el *trait* `ContainerBootsier`, que guarda el ancho como valor extra en `Props`.
This commit is contained in:
parent
654618aa68
commit
771f61bf29
15 changed files with 268 additions and 274 deletions
|
|
@ -144,14 +144,15 @@ impl Theme for Bootsier {
|
||||||
) -> Option<Result<Markup, ComponentError>> {
|
) -> Option<Result<Markup, ComponentError>> {
|
||||||
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),
|
||||||
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),
|
||||||
});
|
});
|
||||||
render_component!(component, {
|
render_component!(component, {
|
||||||
form::input::Field => |c| theme::bs::form::input::render(c, cx),
|
form::input::Field => |c| theme::bs::form::input::render(c, cx),
|
||||||
form::select::Field => |c| theme::bs::form::select::render(c, cx),
|
form::select::Field => |c| theme::bs::form::select::render(c, cx),
|
||||||
form::Textarea => |c| theme::bs::form::textarea::render(c, cx),
|
form::Textarea => |c| theme::bs::form::textarea::render(c, cx),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,17 +168,17 @@ impl Theme for Bootsier {
|
||||||
.alter_assets(AssetsOp::AddStyleSheet(
|
.alter_assets(AssetsOp::AddStyleSheet(
|
||||||
StyleSheet::from("/bootsier/css/bootsier.min.css")
|
StyleSheet::from("/bootsier/css/bootsier.min.css")
|
||||||
.with_version(ADMINLTE_VERSION)
|
.with_version(ADMINLTE_VERSION)
|
||||||
.with_weight(-90),
|
.with_weight(-99),
|
||||||
))
|
))
|
||||||
.alter_assets(AssetsOp::AddJavaScript(
|
.alter_assets(AssetsOp::AddJavaScript(
|
||||||
JavaScript::defer("/bootsier/js/bootsier.bundle.min.js")
|
JavaScript::defer("/bootsier/js/bootsier.bundle.min.js")
|
||||||
.with_version(BOOTSTRAP_VERSION)
|
.with_version(BOOTSTRAP_VERSION)
|
||||||
.with_weight(-90),
|
.with_weight(-99),
|
||||||
))
|
))
|
||||||
.alter_assets(AssetsOp::AddJavaScript(
|
.alter_assets(AssetsOp::AddJavaScript(
|
||||||
JavaScript::defer("/bootsier/js/bootsier.extended.min.js")
|
JavaScript::defer("/bootsier/js/bootsier.extended.min.js")
|
||||||
.with_version(ADMINLTE_VERSION)
|
.with_version(ADMINLTE_VERSION)
|
||||||
.with_weight(-90),
|
.with_weight(-99),
|
||||||
))
|
))
|
||||||
.alter_child_in(
|
.alter_child_in(
|
||||||
&DefaultRegion::Footer,
|
&DefaultRegion::Footer,
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,4 @@
|
||||||
//! Tipos y componentes disponibles.
|
//! Componentes proporcionados por el tema.
|
||||||
//!
|
|
||||||
//! A continuación, el apartado **Modules** incluye las definiciones necesarias para los componentes
|
|
||||||
//! que se muestran en el apartado **Structs**, mientras que en **Enums** se listan los elementos
|
|
||||||
//! auxiliares del tema utilizados en clases y componentes.
|
|
||||||
|
|
||||||
mod attrs;
|
|
||||||
pub use attrs::*;
|
|
||||||
|
|
||||||
mod classes;
|
|
||||||
pub use classes::*;
|
|
||||||
|
|
||||||
// Button.
|
// Button.
|
||||||
mod button;
|
mod button;
|
||||||
|
|
@ -18,6 +8,8 @@ pub use button::{Button, ButtonAction};
|
||||||
pub mod container;
|
pub mod container;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use container::Container;
|
pub use container::Container;
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use container::ContainerBootsier;
|
||||||
|
|
||||||
// Dropdown.
|
// Dropdown.
|
||||||
pub mod dropdown;
|
pub mod dropdown;
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,99 @@
|
||||||
//! Definiciones para crear contenedores de componentes ([`Container`]).
|
//! Definiciones para crear contenedores de componentes ([`Container`]).
|
||||||
//!
|
|
||||||
//! Cada contenedor envuelve contenido usando la etiqueta semántica indicada por
|
|
||||||
//! [`container::Kind`](crate::theme::bs::container::Kind).
|
|
||||||
//!
|
|
||||||
//! Con [`container::Width`](crate::theme::bs::container::Width) se puede definir el ancho y el
|
|
||||||
//! comportamiento *responsive* del contenedor. También permite aplicar utilidades de estilo para el
|
|
||||||
//! fondo, texto, borde o esquinas redondeadas.
|
|
||||||
|
|
||||||
mod props;
|
use pagetop::prelude::*;
|
||||||
pub use props::{Kind, Width};
|
|
||||||
|
|
||||||
mod component;
|
use crate::theme::*;
|
||||||
pub use component::Container;
|
|
||||||
|
pub use pagetop::base::component::container::{Container, Kind};
|
||||||
|
|
||||||
|
const EXTRA_WIDTH: &str = "bootsier.container.width";
|
||||||
|
|
||||||
|
/// Extensión de Bootsier para [`Container`].
|
||||||
|
///
|
||||||
|
/// Permite definir el comportamiento del ancho del contenedor usando el método
|
||||||
|
/// [`with_width()`](Self::with_width). También acepta clases predefinidas para:
|
||||||
|
///
|
||||||
|
/// - Modificar el color de fondo ([`Background`](crate::theme::class::Background)).
|
||||||
|
/// - Definir la apariencia del texto ([`Text`](crate::theme::class::Text)).
|
||||||
|
/// - Establecer bordes ([`Border`](crate::theme::class::Border)).
|
||||||
|
/// - Redondear las esquinas ([`Rounded`](crate::theme::class::Rounded)).
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// use pagetop::prelude::*;
|
||||||
|
/// use pagetop_bootsier::theme::*;
|
||||||
|
///
|
||||||
|
/// let main = bs::Container::main()
|
||||||
|
/// .with_id("main-page")
|
||||||
|
/// .with_width(bs::container::Width::From(token::BreakPoint::LG))
|
||||||
|
/// .with_prop(PropsOp::add_classes(class::Background::with(token::Color::Light)))
|
||||||
|
/// .with_prop(PropsOp::add_classes(class::Text::with(token::Color::Dark)))
|
||||||
|
/// .with_prop(PropsOp::add_classes(class::Border::with(token::ScaleSize::One)))
|
||||||
|
/// .with_prop(PropsOp::add_classes(class::Rounded::with(token::RoundedRadius::Default)));
|
||||||
|
/// ```
|
||||||
|
pub trait ContainerBootsier {
|
||||||
|
/// Establece el comportamiento del ancho para el contenedor.
|
||||||
|
///
|
||||||
|
/// Determina si el contenedor aplica los anchos máximos predefinidos para cada punto de
|
||||||
|
/// ruptura, o si ocupa siempre el 100% del ancho disponible, o lo hace hasta un ancho máximo
|
||||||
|
/// explícito. Ver [`Width`] para las variantes disponibles.
|
||||||
|
fn with_width(self, width: Width) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContainerBootsier for Container {
|
||||||
|
fn with_width(self, width: Width) -> Self {
|
||||||
|
self.with_prop(PropsOp::set_extra(EXTRA_WIDTH, width))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< Width >**************************************************************************************
|
||||||
|
|
||||||
|
/// Define cómo se comporta el ancho de un contenedor ([`Container`]).
|
||||||
|
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum Width {
|
||||||
|
/// Comportamiento por defecto, aplica los anchos máximos predefinidos para cada punto de
|
||||||
|
/// ruptura. Por debajo del menor punto de ruptura ocupa el 100% del ancho disponible.
|
||||||
|
#[default]
|
||||||
|
Default,
|
||||||
|
/// Aplica los anchos máximos predefinidos a partir del punto de ruptura indicado. Por debajo de
|
||||||
|
/// ese punto de ruptura ocupa el 100% del ancho disponible.
|
||||||
|
From(token::BreakPoint),
|
||||||
|
/// Ocupa el 100% del ancho disponible siempre.
|
||||||
|
Fluid,
|
||||||
|
/// Ocupa el 100% del ancho disponible hasta un ancho máximo explícito.
|
||||||
|
FluidMax(UnitValue),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Width {
|
||||||
|
const CONTAINER: &str = "container";
|
||||||
|
|
||||||
|
/// Añade la clase asociada al ancho del contenedor a la cadena de clases.
|
||||||
|
#[inline]
|
||||||
|
pub fn push_to(self, classes: &mut String) {
|
||||||
|
match self {
|
||||||
|
Self::Default => token::BreakPoint::None.push_to(classes, Self::CONTAINER, ""),
|
||||||
|
Self::From(bp) => bp.push_to(classes, Self::CONTAINER, ""),
|
||||||
|
Self::Fluid | Self::FluidMax(_) => {
|
||||||
|
token::BreakPoint::None.push_to(classes, Self::CONTAINER, "fluid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Devuelve la clase asociada al ancho del contenedor.
|
||||||
|
pub fn to_class(self) -> String {
|
||||||
|
let mut class = String::new();
|
||||||
|
self.push_to(&mut class);
|
||||||
|
class
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< Container SETUP >****************************************************************************
|
||||||
|
|
||||||
|
pub(crate) fn setup(container: &mut Container) {
|
||||||
|
let width = container.props().extra_or(EXTRA_WIDTH, Width::default());
|
||||||
|
container.alter_prop(PropsOp::prepend_classes(width.to_class()));
|
||||||
|
if let Width::FluidMax(w) = width
|
||||||
|
&& w.is_measurable()
|
||||||
|
{
|
||||||
|
container.alter_prop(PropsOp::add_style("max-width", w.to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,172 +0,0 @@
|
||||||
use pagetop::prelude::*;
|
|
||||||
|
|
||||||
use crate::theme::*;
|
|
||||||
|
|
||||||
/// Componente para crear un **contenedor de componentes**
|
|
||||||
/// ([`container`](crate::theme::bs::container)).
|
|
||||||
///
|
|
||||||
/// Envuelve un conjunto de componentes en un contenedor establecido que se crea aplicando uno de
|
|
||||||
/// los tipos definidos en [`container::Kind`](crate::theme::bs::container::Kind).
|
|
||||||
///
|
|
||||||
/// Si no contiene elementos, el componente **no se renderiza**.
|
|
||||||
///
|
|
||||||
/// # Ejemplo
|
|
||||||
///
|
|
||||||
/// ```rust,no_run
|
|
||||||
/// use pagetop_bootsier::theme::*;
|
|
||||||
///
|
|
||||||
/// let main = bs::Container::main()
|
|
||||||
/// .with_id("main-page")
|
|
||||||
/// .with_width(bs::container::Width::From(token::BreakPoint::LG));
|
|
||||||
/// ```
|
|
||||||
#[derive(AutoDefault, Clone, Debug, Getters)]
|
|
||||||
pub struct Container {
|
|
||||||
/// Devuelve identificador, clases CSS, atributos HTML y valores extra del componente.
|
|
||||||
props: Props,
|
|
||||||
/// Devuelve el tipo semántico del contenedor.
|
|
||||||
container_kind: bs::container::Kind,
|
|
||||||
/// Devuelve el comportamiento para el ancho del contenedor.
|
|
||||||
container_width: bs::container::Width,
|
|
||||||
/// Devuelve la lista de componentes (`children`) del contenedor.
|
|
||||||
children: Children,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl Component for Container {
|
|
||||||
fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn id(&self) -> Option<String> {
|
|
||||||
self.props.get_id()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup(&mut self, _cx: &Context) {
|
|
||||||
self.alter_prop(PropsOp::prepend_classes(self.container_width().to_class()));
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn prepare(&self, cx: &mut Context) -> Result<Markup, ComponentError> {
|
|
||||||
let output = self.children().render(cx).await;
|
|
||||||
if output.is_empty() {
|
|
||||||
return Ok(html! {});
|
|
||||||
}
|
|
||||||
let style = match self.container_width() {
|
|
||||||
bs::container::Width::FluidMax(w) if w.is_measurable() => {
|
|
||||||
Some(util::join!("max-width: ", w.to_string(), ";"))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
Ok(match self.container_kind() {
|
|
||||||
bs::container::Kind::Default => html! {
|
|
||||||
div (self.props()) style=[style] {
|
|
||||||
(output)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
bs::container::Kind::Main => html! {
|
|
||||||
main (self.props()) style=[style] {
|
|
||||||
(output)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
bs::container::Kind::Header => html! {
|
|
||||||
header (self.props()) style=[style] {
|
|
||||||
(output)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
bs::container::Kind::Footer => html! {
|
|
||||||
footer (self.props()) style=[style] {
|
|
||||||
(output)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
bs::container::Kind::Section => html! {
|
|
||||||
section (self.props()) style=[style] {
|
|
||||||
(output)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
bs::container::Kind::Article => html! {
|
|
||||||
article (self.props()) style=[style] {
|
|
||||||
(output)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Container {
|
|
||||||
/// Crea un contenedor de tipo `Main` (`<main>`).
|
|
||||||
pub fn main() -> Self {
|
|
||||||
Self {
|
|
||||||
container_kind: bs::container::Kind::Main,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Crea un contenedor de tipo `Header` (`<header>`).
|
|
||||||
pub fn header() -> Self {
|
|
||||||
Self {
|
|
||||||
container_kind: bs::container::Kind::Header,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Crea un contenedor de tipo `Footer` (`<footer>`).
|
|
||||||
pub fn footer() -> Self {
|
|
||||||
Self {
|
|
||||||
container_kind: bs::container::Kind::Footer,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Crea un contenedor de tipo `Section` (`<section>`).
|
|
||||||
pub fn section() -> Self {
|
|
||||||
Self {
|
|
||||||
container_kind: bs::container::Kind::Section,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Crea un contenedor de tipo `Article` (`<article>`).
|
|
||||||
pub fn article() -> Self {
|
|
||||||
Self {
|
|
||||||
container_kind: bs::container::Kind::Article,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// **< Container BUILDER >**********************************************************************
|
|
||||||
|
|
||||||
/// Establece el identificador único del componente; igual a `with_prop(PropsOp::set_id(id))`.
|
|
||||||
#[builder_fn]
|
|
||||||
pub fn with_id(mut self, id: impl Into<CowStr>) -> Self {
|
|
||||||
self.props.alter_id(id);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Modifica identificador, clases CSS, atributos HTML o valores extra del componente.
|
|
||||||
///
|
|
||||||
/// También acepta clases predefinidas para:
|
|
||||||
///
|
|
||||||
/// - Modificar el color de fondo ([`Background`]).
|
|
||||||
/// - Definir la apariencia del texto ([`Text`]).
|
|
||||||
/// - Establecer bordes ([`Border`]).
|
|
||||||
/// - Redondear las esquinas ([`Rounded`]).
|
|
||||||
#[builder_fn]
|
|
||||||
pub fn with_prop(mut self, op: PropsOp) -> Self {
|
|
||||||
self.props.alter_prop(op);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Establece el comportamiento del ancho para el contenedor.
|
|
||||||
#[builder_fn]
|
|
||||||
pub fn with_width(mut self, width: bs::container::Width) -> Self {
|
|
||||||
self.container_width = width;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Añade un nuevo componente al contenedor o modifica la lista de componentes (`children`) con
|
|
||||||
/// una operación [`ChildOp`].
|
|
||||||
#[builder_fn]
|
|
||||||
pub fn with_child(mut self, op: impl Into<ChildOp>) -> Self {
|
|
||||||
self.children.alter_child(op.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
use pagetop::prelude::*;
|
|
||||||
|
|
||||||
use crate::theme::*;
|
|
||||||
|
|
||||||
// **< Kind >***************************************************************************************
|
|
||||||
|
|
||||||
/// Tipo de contenedor ([`Container`](crate::theme::bs::Container)).
|
|
||||||
///
|
|
||||||
/// Permite aplicar la etiqueta HTML apropiada (`<main>`, `<header>`, etc.) manteniendo una API
|
|
||||||
/// común a todos los contenedores.
|
|
||||||
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
|
|
||||||
pub enum Kind {
|
|
||||||
/// Contenedor genérico (`<div>`).
|
|
||||||
#[default]
|
|
||||||
Default,
|
|
||||||
/// Contenido principal de la página (`<main>`).
|
|
||||||
Main,
|
|
||||||
/// Encabezado de la página o de sección (`<header>`).
|
|
||||||
Header,
|
|
||||||
/// Pie de la página o de sección (`<footer>`).
|
|
||||||
Footer,
|
|
||||||
/// Sección de contenido (`<section>`).
|
|
||||||
Section,
|
|
||||||
/// Artículo de contenido (`<article>`).
|
|
||||||
Article,
|
|
||||||
}
|
|
||||||
|
|
||||||
// **< Width >**************************************************************************************
|
|
||||||
|
|
||||||
/// Define cómo se comporta el ancho de un contenedor ([`Container`](crate::theme::bs::Container)).
|
|
||||||
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
|
|
||||||
pub enum Width {
|
|
||||||
/// Comportamiento por defecto, aplica los anchos máximos predefinidos para cada punto de
|
|
||||||
/// ruptura. Por debajo del menor punto de ruptura ocupa el 100% del ancho disponible.
|
|
||||||
#[default]
|
|
||||||
Default,
|
|
||||||
/// Aplica los anchos máximos predefinidos a partir del punto de ruptura indicado. Por debajo de
|
|
||||||
/// ese punto de ruptura ocupa el 100% del ancho disponible.
|
|
||||||
From(token::BreakPoint),
|
|
||||||
/// Ocupa el 100% del ancho disponible siempre.
|
|
||||||
Fluid,
|
|
||||||
/// Ocupa el 100% del ancho disponible hasta un ancho máximo explícito.
|
|
||||||
FluidMax(UnitValue),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Width {
|
|
||||||
const CONTAINER: &str = "container";
|
|
||||||
|
|
||||||
/// Añade la clase asociada al ancho del contenedor a la cadena de clases.
|
|
||||||
#[inline]
|
|
||||||
pub fn push_to(self, classes: &mut String) {
|
|
||||||
match self {
|
|
||||||
Self::Default => token::BreakPoint::None.push_to(classes, Self::CONTAINER, ""),
|
|
||||||
Self::From(bp) => bp.push_to(classes, Self::CONTAINER, ""),
|
|
||||||
Self::Fluid | Self::FluidMax(_) => {
|
|
||||||
token::BreakPoint::None.push_to(classes, Self::CONTAINER, "fluid")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Devuelve la clase asociada al ancho del contenedor.
|
|
||||||
pub fn to_class(self) -> String {
|
|
||||||
let mut class = String::new();
|
|
||||||
self.push_to(&mut class);
|
|
||||||
class
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,7 +3,7 @@ use pagetop::prelude::*;
|
||||||
use crate::LOCALES_BOOTSIER;
|
use crate::LOCALES_BOOTSIER;
|
||||||
use crate::theme::*;
|
use crate::theme::*;
|
||||||
|
|
||||||
/// Componente para crear un **menú desplegable** ([`dropdown`](crate::theme::bs::dropdown)).
|
/// Componente para crear un **menú desplegable**.
|
||||||
///
|
///
|
||||||
/// Renderiza un botón (único o desdoblado, ver [`with_button_split()`](Self::with_button_split))
|
/// Renderiza un botón (único o desdoblado, ver [`with_button_split()`](Self::with_button_split))
|
||||||
/// con un menú desplegable de elementos [`dropdown::Item`](crate::theme::bs::dropdown::Item), que
|
/// con un menú desplegable de elementos [`dropdown::Item`](crate::theme::bs::dropdown::Item), que
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,17 @@ pub use pagetop::base::component::form::check;
|
||||||
pub use pagetop::base::component::form::radio;
|
pub use pagetop::base::component::form::radio;
|
||||||
|
|
||||||
pub mod select;
|
pub mod select;
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use select::SelectBootsier;
|
||||||
|
|
||||||
pub mod input;
|
pub mod input;
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use input::InputBootsier;
|
||||||
|
|
||||||
pub mod textarea;
|
pub mod textarea;
|
||||||
pub use textarea::Textarea;
|
pub use textarea::Textarea;
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use textarea::TextareaBootsier;
|
||||||
|
|
||||||
pub use pagetop::base::component::form::Range;
|
pub use pagetop::base::component::form::Range;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use pagetop::prelude::*;
|
||||||
|
|
||||||
use crate::theme::*;
|
use crate::theme::*;
|
||||||
|
|
||||||
/// Componente para renderizar una **imagen** ([`image`](crate::theme::bs::image)).
|
/// Componente para renderizar una **imagen**.
|
||||||
///
|
///
|
||||||
/// A una imagen se le puede:
|
/// A una imagen se le puede:
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use pagetop::prelude::*;
|
||||||
|
|
||||||
use crate::theme::*;
|
use crate::theme::*;
|
||||||
|
|
||||||
/// Componente para crear un **menú** ([`nav`](crate::theme::bs::nav)).
|
/// Componente para crear un **menú**.
|
||||||
///
|
///
|
||||||
/// Presenta un menú con una lista de elementos usando una vista básica, o alguna de sus variantes
|
/// Presenta un menú con una lista de elementos usando una vista básica, o alguna de sus variantes
|
||||||
/// ([`nav::Kind`](crate::theme::bs::nav::Kind)) como *pestañas* (`Tabs`), *botones* (`Pills`) o
|
/// ([`nav::Kind`](crate::theme::bs::nav::Kind)) como *pestañas* (`Tabs`), *botones* (`Pills`) o
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::theme::*;
|
||||||
const TOGGLE_COLLAPSE: &str = "collapse";
|
const TOGGLE_COLLAPSE: &str = "collapse";
|
||||||
const TOGGLE_OFFCANVAS: &str = "offcanvas";
|
const TOGGLE_OFFCANVAS: &str = "offcanvas";
|
||||||
|
|
||||||
/// Componente para crear una **barra de navegación** ([`navbar`](crate::theme::bs::navbar)).
|
/// Componente para crear una **barra de navegación**.
|
||||||
///
|
///
|
||||||
/// Permite mostrar enlaces, menús y una marca de identidad en distintas disposiciones (simples, con
|
/// Permite mostrar enlaces, menús y una marca de identidad en distintas disposiciones (simples, con
|
||||||
/// botón de despliegue o dentro de un [`Offcanvas`](crate::theme::bs::Offcanvas)), controladas por
|
/// botón de despliegue o dentro de un [`Offcanvas`](crate::theme::bs::Offcanvas)), controladas por
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use pagetop::prelude::*;
|
||||||
use crate::LOCALES_BOOTSIER;
|
use crate::LOCALES_BOOTSIER;
|
||||||
use crate::theme::*;
|
use crate::theme::*;
|
||||||
|
|
||||||
/// Componente para crear un **panel lateral deslizante** ([`offcanvas`](crate::theme::bs::offcanvas)).
|
/// Componente para crear un **panel lateral deslizante**.
|
||||||
///
|
///
|
||||||
/// Útil para navegación, filtros, formularios o menús contextuales. Incluye las siguientes
|
/// Útil para navegación, filtros, formularios o menús contextuales. Incluye las siguientes
|
||||||
/// características principales:
|
/// características principales:
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,10 @@ pub use block::Block;
|
||||||
mod button;
|
mod button;
|
||||||
pub use button::{Button, ButtonAction};
|
pub use button::{Button, ButtonAction};
|
||||||
|
|
||||||
|
pub mod container;
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use container::Container;
|
||||||
|
|
||||||
pub mod form;
|
pub mod form;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use form::Form;
|
pub use form::Form;
|
||||||
|
|
|
||||||
145
src/base/component/container.rs
Normal file
145
src/base/component/container.rs
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
//! Definiciones para crear contenedores de componentes ([`Container`]).
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
// **< Kind >***************************************************************************************
|
||||||
|
|
||||||
|
/// Tipo de contenedor (`Container`).
|
||||||
|
///
|
||||||
|
/// Permite aplicar la etiqueta HTML apropiada (`<main>`, `<header>`, etc.) manteniendo una API
|
||||||
|
/// común a todos los contenedores.
|
||||||
|
#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum Kind {
|
||||||
|
/// Contenedor genérico (`<div>`).
|
||||||
|
#[default]
|
||||||
|
Default,
|
||||||
|
/// Contenido principal de la página (`<main>`).
|
||||||
|
Main,
|
||||||
|
/// Encabezado de la página o de sección (`<header>`).
|
||||||
|
Header,
|
||||||
|
/// Pie de la página o de sección (`<footer>`).
|
||||||
|
Footer,
|
||||||
|
/// Sección de contenido (`<section>`).
|
||||||
|
Section,
|
||||||
|
/// Artículo de contenido (`<article>`).
|
||||||
|
Article,
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< Container >**********************************************************************************
|
||||||
|
|
||||||
|
/// Componente para crear un **contenedor de componentes**.
|
||||||
|
///
|
||||||
|
/// Envuelve un conjunto de componentes en un contenedor establecido que se crea aplicando uno de
|
||||||
|
/// los tipos definidos en [`Kind`].
|
||||||
|
///
|
||||||
|
/// Si no contiene elementos, el componente **no se renderiza**.
|
||||||
|
///
|
||||||
|
/// # Ejemplo
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// use pagetop::prelude::*;
|
||||||
|
///
|
||||||
|
/// let main = Container::main().with_id("main-page");
|
||||||
|
/// ```
|
||||||
|
#[derive(AutoDefault, Clone, Debug, Getters)]
|
||||||
|
pub struct Container {
|
||||||
|
/// Devuelve identificador, clases CSS, atributos HTML y valores extra del componente.
|
||||||
|
props: Props,
|
||||||
|
/// Devuelve el tipo semántico del contenedor.
|
||||||
|
kind: Kind,
|
||||||
|
/// Devuelve la lista de componentes (`children`) del contenedor.
|
||||||
|
children: Children,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Component for Container {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id(&self) -> Option<String> {
|
||||||
|
self.props.get_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
async fn prepare(&self, cx: &mut Context) -> Result<Markup, ComponentError> {
|
||||||
|
let output = self.children().render(cx).await;
|
||||||
|
if output.is_empty() {
|
||||||
|
return Ok(html! {});
|
||||||
|
}
|
||||||
|
Ok(match self.kind() {
|
||||||
|
Kind::Default => html! { div (self.props()) { (output) } },
|
||||||
|
Kind::Main => html! { main (self.props()) { (output) } },
|
||||||
|
Kind::Header => html! { header (self.props()) { (output) } },
|
||||||
|
Kind::Footer => html! { footer (self.props()) { (output) } },
|
||||||
|
Kind::Section => html! { section (self.props()) { (output) } },
|
||||||
|
Kind::Article => html! { article (self.props()) { (output) } },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Container {
|
||||||
|
/// Crea un contenedor de tipo `Main` (`<main>`).
|
||||||
|
pub fn main() -> Self {
|
||||||
|
Self {
|
||||||
|
kind: Kind::Main,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Crea un contenedor de tipo `Header` (`<header>`).
|
||||||
|
pub fn header() -> Self {
|
||||||
|
Self {
|
||||||
|
kind: Kind::Header,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Crea un contenedor de tipo `Footer` (`<footer>`).
|
||||||
|
pub fn footer() -> Self {
|
||||||
|
Self {
|
||||||
|
kind: Kind::Footer,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Crea un contenedor de tipo `Section` (`<section>`).
|
||||||
|
pub fn section() -> Self {
|
||||||
|
Self {
|
||||||
|
kind: Kind::Section,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Crea un contenedor de tipo `Article` (`<article>`).
|
||||||
|
pub fn article() -> Self {
|
||||||
|
Self {
|
||||||
|
kind: Kind::Article,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< Container BUILDER >**********************************************************************
|
||||||
|
|
||||||
|
/// Establece el identificador único del componente; igual a `with_prop(PropsOp::set_id(id))`.
|
||||||
|
#[builder_fn]
|
||||||
|
pub fn with_id(mut self, id: impl Into<CowStr>) -> Self {
|
||||||
|
self.props.alter_id(id);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modifica identificador, clases CSS, atributos HTML o valores extra del componente.
|
||||||
|
#[builder_fn]
|
||||||
|
pub fn with_prop(mut self, op: PropsOp) -> Self {
|
||||||
|
self.props.alter_prop(op);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Añade un nuevo componente al contenedor o modifica la lista de componentes (`children`) con
|
||||||
|
/// una operación [`ChildOp`].
|
||||||
|
#[builder_fn]
|
||||||
|
pub fn with_child(mut self, op: impl Into<ChildOp>) -> Self {
|
||||||
|
self.children.alter_child(op.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
//! Componentes y tipos para crear formularios HTML ([`Form`]).
|
//! Definiciones para crear formularios ([`Form`]).
|
||||||
|
|
||||||
mod props;
|
mod props;
|
||||||
pub use props::{Autocomplete, AutofillField, CheckboxKind, Method};
|
pub use props::{Autocomplete, AutofillField, CheckboxKind, Method};
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use crate::prelude::*;
|
||||||
|
|
||||||
use crate::base::component::form;
|
use crate::base::component::form;
|
||||||
|
|
||||||
/// Componente para crear un **formulario** HTML ([`form`]).
|
/// Componente para crear un **formulario**.
|
||||||
///
|
///
|
||||||
/// Renderiza un formulario estándar con soporte para los atributos más habituales:
|
/// Renderiza un formulario estándar con soporte para los atributos más habituales:
|
||||||
///
|
///
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue