♻️ (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>> {
|
||||
setup_component!(component, {
|
||||
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::select::Field => |c| theme::bs::form::select::setup(c),
|
||||
form::Textarea => |c| theme::bs::form::textarea::setup(c),
|
||||
});
|
||||
render_component!(component, {
|
||||
form::input::Field => |c| theme::bs::form::input::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::input::Field => |c| theme::bs::form::input::render(c, cx),
|
||||
form::select::Field => |c| theme::bs::form::select::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(
|
||||
StyleSheet::from("/bootsier/css/bootsier.min.css")
|
||||
.with_version(ADMINLTE_VERSION)
|
||||
.with_weight(-90),
|
||||
.with_weight(-99),
|
||||
))
|
||||
.alter_assets(AssetsOp::AddJavaScript(
|
||||
JavaScript::defer("/bootsier/js/bootsier.bundle.min.js")
|
||||
.with_version(BOOTSTRAP_VERSION)
|
||||
.with_weight(-90),
|
||||
.with_weight(-99),
|
||||
))
|
||||
.alter_assets(AssetsOp::AddJavaScript(
|
||||
JavaScript::defer("/bootsier/js/bootsier.extended.min.js")
|
||||
.with_version(ADMINLTE_VERSION)
|
||||
.with_weight(-90),
|
||||
.with_weight(-99),
|
||||
))
|
||||
.alter_child_in(
|
||||
&DefaultRegion::Footer,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,4 @@
|
|||
//! Tipos y componentes disponibles.
|
||||
//!
|
||||
//! 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::*;
|
||||
//! Componentes proporcionados por el tema.
|
||||
|
||||
// Button.
|
||||
mod button;
|
||||
|
|
@ -18,6 +8,8 @@ pub use button::{Button, ButtonAction};
|
|||
pub mod container;
|
||||
#[doc(inline)]
|
||||
pub use container::Container;
|
||||
#[doc(inline)]
|
||||
pub use container::ContainerBootsier;
|
||||
|
||||
// Dropdown.
|
||||
pub mod dropdown;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,99 @@
|
|||
//! 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;
|
||||
pub use props::{Kind, Width};
|
||||
use pagetop::prelude::*;
|
||||
|
||||
mod component;
|
||||
pub use component::Container;
|
||||
use crate::theme::*;
|
||||
|
||||
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::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))
|
||||
/// 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 mod select;
|
||||
#[doc(inline)]
|
||||
pub use select::SelectBootsier;
|
||||
|
||||
pub mod input;
|
||||
#[doc(inline)]
|
||||
pub use input::InputBootsier;
|
||||
|
||||
pub mod textarea;
|
||||
pub use textarea::Textarea;
|
||||
#[doc(inline)]
|
||||
pub use textarea::TextareaBootsier;
|
||||
|
||||
pub use pagetop::base::component::form::Range;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use pagetop::prelude::*;
|
|||
|
||||
use crate::theme::*;
|
||||
|
||||
/// Componente para renderizar una **imagen** ([`image`](crate::theme::bs::image)).
|
||||
/// Componente para renderizar una **imagen**.
|
||||
///
|
||||
/// A una imagen se le puede:
|
||||
///
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use pagetop::prelude::*;
|
|||
|
||||
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
|
||||
/// ([`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_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
|
||||
/// 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::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
|
||||
/// características principales:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue