Compare commits

..

No commits in common. "cf40af13bb1114526fdb95518cfd6e8b715af56e" and "180cb9c2f6bd8d17737ec072156f9cf21889c296" have entirely different histories.

20 changed files with 66 additions and 75 deletions

View file

@ -25,7 +25,7 @@ internos pueden omitirse si no afectan al uso del proyecto.
- [context] Generaliza los parámetros de contexto - [context] Generaliza los parámetros de contexto
- [context] Define un `trait` común de contexto - [context] Define un `trait` común de contexto
- Modifica tipos para atributos HTML a minúsculas - Modifica tipos para atributos HTML a minúsculas
- Renombra `with_component` por `add_child` - Renombra `with_component` por `add_component`
### Corregido ### Corregido

1
Cargo.lock generated
View file

@ -1593,7 +1593,6 @@ version = "0.0.18"
dependencies = [ dependencies = [
"pagetop", "pagetop",
"pagetop-build", "pagetop-build",
"serde",
] ]
[[package]] [[package]]

View file

@ -39,7 +39,7 @@ actix-web = { workspace = true, default-features = true }
actix-session = { version = "0.11", features = ["cookie-session"] } actix-session = { version = "0.11", features = ["cookie-session"] }
actix-web-files = { package = "actix-files", version = "0.6" } actix-web-files = { package = "actix-files", version = "0.6" }
serde.workspace = true serde = { version = "1.0", features = ["derive"] }
pagetop-macros.workspace = true pagetop-macros.workspace = true
pagetop-statics.workspace = true pagetop-statics.workspace = true
@ -78,7 +78,6 @@ authors = ["Manuel Cillero <manuel@cillero.es>"]
[workspace.dependencies] [workspace.dependencies]
actix-web = { version = "4.11", default-features = false } actix-web = { version = "4.11", default-features = false }
serde = { version = "1.0", features = ["derive"] }
# Helpers # Helpers
pagetop-build = { version = "0.3", path = "helpers/pagetop-build" } pagetop-build = { version = "0.3", path = "helpers/pagetop-build" }
pagetop-macros = { version = "0.2", path = "helpers/pagetop-macros" } pagetop-macros = { version = "0.2", path = "helpers/pagetop-macros" }

View file

@ -60,7 +60,7 @@ impl Extension for HelloWorld {
async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> {
Page::new(request) Page::new(request)
.add_child(Html::with(|_| html! { h1 { "Hello World!" } })) .add_component(Html::with(move |_| html! { h1 { "Hello World!" } }))
.render() .render()
} }
@ -102,7 +102,7 @@ El código se organiza en un *workspace* donde actualmente se incluyen los sigui
es un tema para demos y pruebas que muestra esquemáticamente la composición de las páginas HTML. es un tema para demos y pruebas que muestra esquemáticamente la composición de las páginas HTML.
* **[pagetop-bootsier](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-bootsier)**, * **[pagetop-bootsier](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-bootsier)**,
tema basado en [Bootstrap](https://getbootstrap.com) para integrar su catálogo de estilos y tema basado en [Bootstrap](https://getbootstrap.com) para ofrecer su catálogo de estilos y
componentes flexibles. componentes flexibles.

View file

@ -14,7 +14,7 @@ async fn hello_name(
) -> ResultPage<Markup, ErrorPage> { ) -> ResultPage<Markup, ErrorPage> {
let name = path.into_inner(); let name = path.into_inner();
Page::new(request) Page::new(request)
.add_child(Html::with(move |_| html! { h1 { "Hello " (name) "!" } })) .add_component(Html::with(move |_| html! { h1 { "Hello " (name) "!" } }))
.render() .render()
} }

View file

@ -10,7 +10,7 @@ impl Extension for HelloWorld {
async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> {
Page::new(request) Page::new(request)
.add_child(Html::with(|_| html! { h1 { "Hello World!" } })) .add_component(Html::with(move |_| html! { h1 { "Hello World!" } }))
.render() .render()
} }

View file

@ -67,10 +67,10 @@ use pagetop::prelude::*;
async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> {
Page::new(request) Page::new(request)
.with_theme("Aliner") .with_theme("Aliner")
.add_child( .add_component(
Block::new() Block::new()
.with_title(L10n::l("sample_title")) .with_title(L10n::l("sample_title"))
.add_child(Html::with(|cx| html! { .add_component(Html::with(|cx| html! {
p { (L10n::l("sample_content").using(cx)) } p { (L10n::l("sample_content").using(cx)) }
})), })),
) )

View file

@ -68,10 +68,10 @@ use pagetop::prelude::*;
async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> {
Page::new(request) Page::new(request)
.with_theme("Aliner") .with_theme("Aliner")
.add_child( .add_component(
Block::new() Block::new()
.with_title(L10n::l("sample_title")) .with_title(L10n::l("sample_title"))
.add_child(Html::with(|cx| html! { .add_component(Html::with(|cx| html! {
p { (L10n::l("sample_content").using(cx)) } p { (L10n::l("sample_content").using(cx)) }
})), })),
) )

View file

@ -4,7 +4,7 @@ version = "0.0.18"
edition = "2021" edition = "2021"
description = """ description = """
Tema de PageTop basado en Bootstrap para aplicar su catálogo de estilos y componentes flexibles. Tema de PageTop basado en Bootstrap para dar vida a tus diseños web.
""" """
categories = ["web-programming", "gui"] categories = ["web-programming", "gui"]
keywords = ["pagetop", "theme", "bootstrap", "css", "js"] keywords = ["pagetop", "theme", "bootstrap", "css", "js"]
@ -16,7 +16,6 @@ authors.workspace = true
[dependencies] [dependencies]
pagetop.workspace = true pagetop.workspace = true
serde.workspace = true
[build-dependencies] [build-dependencies]
pagetop-build.workspace = true pagetop-build.workspace = true

View file

@ -2,7 +2,7 @@
<h1>PageTop Bootsier</h1> <h1>PageTop Bootsier</h1>
<p>Tema de <strong>PageTop</strong> basado en Bootstrap para aplicar su catálogo de estilos y componentes flexibles.</p> <p>Tema de <strong>PageTop</strong> basado en Bootstrap para dar vida a tus diseños web.</p>
[![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier) [![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier)
[![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier) [![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier)
@ -67,10 +67,10 @@ use pagetop::prelude::*;
async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> {
Page::new(request) Page::new(request)
.with_theme("Bootsier") .with_theme("Bootsier")
.add_child( .add_component(
Block::new() Block::new()
.with_title(L10n::l("sample_title")) .with_title(L10n::l("sample_title"))
.add_child(Html::with(|cx| html! { .add_component(Html::with(|cx| html! {
p { (L10n::l("sample_content").using(cx)) } p { (L10n::l("sample_content").using(cx)) }
})), })),
) )

View file

@ -3,7 +3,7 @@
<h1>PageTop Bootsier</h1> <h1>PageTop Bootsier</h1>
<p>Tema de <strong>PageTop</strong> basado en Bootstrap para aplicar su catálogo de estilos y componentes flexibles.</p> <p>Tema de <strong>PageTop</strong> basado en Bootstrap para ofrecer su catálogo de estilos y componentes flexibles.</p>
[![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier) [![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier)
[![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier) [![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier)

View file

@ -71,7 +71,7 @@ impl Block {
} }
/// Añade un nuevo componente hijo al bloque. /// Añade un nuevo componente hijo al bloque.
pub fn add_child(mut self, component: impl Component) -> Self { pub fn add_component(mut self, component: impl Component) -> Self {
self.children self.children
.alter_child(ChildOp::Add(Child::with(component))); .alter_child(ChildOp::Add(Child::with(component)));
self self

View file

@ -65,10 +65,10 @@ pub enum IntroOpening {
/// ```rust /// ```rust
/// # use pagetop::prelude::*; /// # use pagetop::prelude::*;
/// let intro = Intro::default() /// let intro = Intro::default()
/// .add_child( /// .add_component(
/// Block::new() /// Block::new()
/// .with_title(L10n::l("intro_custom_block_title")) /// .with_title(L10n::l("intro_custom_block_title"))
/// .add_child(Html::with(move |cx| { /// .add_component(Html::with(move |cx| {
/// html! { /// html! {
/// p { (L10n::l("intro_custom_paragraph_1").using(cx)) } /// p { (L10n::l("intro_custom_paragraph_1").using(cx)) }
/// p { (L10n::l("intro_custom_paragraph_2").using(cx)) } /// p { (L10n::l("intro_custom_paragraph_2").using(cx)) }
@ -301,7 +301,7 @@ impl Intro {
/// Añade un nuevo componente hijo a la intro. /// Añade un nuevo componente hijo a la intro.
/// ///
/// Si es un bloque ([`Block`]) aplica estilos específicos para destacarlo. /// Si es un bloque ([`Block`]) aplica estilos específicos para destacarlo.
pub fn add_child(mut self, component: impl Component) -> Self { pub fn add_component(mut self, component: impl Component) -> Self {
self.children self.children
.alter_child(ChildOp::Add(Child::with(component))); .alter_child(ChildOp::Add(Child::with(component)));
self self

View file

@ -26,22 +26,22 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> {
Page::new(request) Page::new(request)
.with_title(L10n::l("welcome_title")) .with_title(L10n::l("welcome_title"))
.add_child( .add_component(
Intro::new() Intro::new()
.add_child( .add_component(
Block::new() Block::new()
.with_title(L10n::l("welcome_status_title")) .with_title(L10n::l("welcome_status_title"))
.add_child(Html::with(move |cx| { .add_component(Html::with(move |cx| {
html! { html! {
p { (L10n::l("welcome_status_1").using(cx)) } p { (L10n::l("welcome_status_1").using(cx)) }
p { (L10n::l("welcome_status_2").using(cx)) } p { (L10n::l("welcome_status_2").using(cx)) }
} }
})), })),
) )
.add_child( .add_component(
Block::new() Block::new()
.with_title(L10n::l("welcome_support_title")) .with_title(L10n::l("welcome_support_title"))
.add_child(Html::with(move |cx| { .add_component(Html::with(move |cx| {
html! { html! {
p { (L10n::l("welcome_support_1").using(cx)) } p { (L10n::l("welcome_support_1").using(cx)) }
p { (L10n::l("welcome_support_2").with_arg("app", app).using(cx)) } p { (L10n::l("welcome_support_2").with_arg("app", app).using(cx)) }

View file

@ -10,9 +10,4 @@ pub use children::{Typed, TypedOp};
mod context; mod context;
pub use context::{Context, ContextError, ContextOp, Contextual}; pub use context::{Context, ContextError, ContextOp, Contextual};
/// Alias de función (*callback*) para **resolver una URL** según el contexto de renderizado.
///
/// Se usa para generar enlaces dinámicos en función del contexto (petición, idioma, etc.). Debe
/// devolver una referencia válida durante el renderizado.
pub type FnPathByContext = fn(cx: &Context) -> &str; pub type FnPathByContext = fn(cx: &Context) -> &str;

View file

@ -145,9 +145,9 @@ impl UnitValue {
impl fmt::Display for UnitValue { impl fmt::Display for UnitValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
UnitValue::None => Ok(()), UnitValue::None => write!(f, ""),
UnitValue::Auto => f.write_str("auto"), UnitValue::Auto => write!(f, "auto"),
UnitValue::Zero => f.write_str("0"), UnitValue::Zero => write!(f, "0"),
// Valor absoluto. // Valor absoluto.
UnitValue::Cm(av) => write!(f, "{av}cm"), UnitValue::Cm(av) => write!(f, "{av}cm"),
UnitValue::In(av) => write!(f, "{av}in"), UnitValue::In(av) => write!(f, "{av}in"),

View file

@ -61,7 +61,7 @@ impl Extension for HelloWorld {
async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> {
Page::new(request) Page::new(request)
.add_child(Html::with(|_| html! { h1 { "Hello World!" } })) .add_component(Html::with(move |_| html! { h1 { "Hello World!" } }))
.render() .render()
} }

View file

@ -93,28 +93,29 @@ impl Page {
self self
} }
/// **Obsoleto desde la versión 0.4.0**: usar [`add_child()`](Self::add_child) en su lugar. /// **Obsoleto desde la versión 0.4.0**: usar [`add_component()`](Self::add_component) en su
#[deprecated(since = "0.4.0", note = "Use `add_child()` instead")]
pub fn with_component(self, component: impl Component) -> Self {
self.add_child(component)
}
/// **Obsoleto desde la versión 0.4.0**: usar [`add_child_in()`](Self::add_child_in) en su
/// lugar. /// lugar.
#[deprecated(since = "0.4.0", note = "Use `add_child_in()` instead")] #[deprecated(since = "0.4.0", note = "Use `add_component()` instead")]
pub fn with_component_in(self, region_key: &'static str, component: impl Component) -> Self { pub fn with_component(self, component: impl Component) -> Self {
self.add_child_in(region_key, component) self.add_component(component)
} }
/// Añade un componente hijo a la región de contenido por defecto. /// **Obsoleto desde la versión 0.4.0**: usar [`add_component_in()`](Self::add_component_in) en
pub fn add_child(mut self, component: impl Component) -> Self { /// su lugar.
#[deprecated(since = "0.4.0", note = "Use `add_component_in()` instead")]
pub fn with_component_in(self, region_key: &'static str, component: impl Component) -> Self {
self.add_component_in(region_key, component)
}
/// Añade un componente a la región de contenido por defecto.
pub fn add_component(mut self, component: impl Component) -> Self {
self.context self.context
.alter_child_in(REGION_CONTENT, ChildOp::Add(Child::with(component))); .alter_child_in(REGION_CONTENT, ChildOp::Add(Child::with(component)));
self self
} }
/// Añade un componente hijo en una región (`region_key`) de la página. /// Añade un componente en una región (`region_key`) de la página.
pub fn add_child_in(mut self, region_key: &'static str, component: impl Component) -> Self { pub fn add_component_in(mut self, region_key: &'static str, component: impl Component) -> Self {
self.context self.context
.alter_child_in(region_key, ChildOp::Add(Child::with(component))); .alter_child_in(region_key, ChildOp::Add(Child::with(component)));
self self

View file

@ -24,9 +24,9 @@ impl Display for ErrorPage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
// Error 304. // Error 304.
ErrorPage::NotModified(_) => f.write_str("Not Modified"), ErrorPage::NotModified(_) => write!(f, "Not Modified"),
// Error 400. // Error 400.
ErrorPage::BadRequest(_) => f.write_str("Bad Client Data"), ErrorPage::BadRequest(_) => write!(f, "Bad Client Data"),
// Error 403. // Error 403.
ErrorPage::AccessDenied(request) => { ErrorPage::AccessDenied(request) => {
let mut error_page = Page::new(request.clone()); let mut error_page = Page::new(request.clone());
@ -34,12 +34,12 @@ impl Display for ErrorPage {
if let Ok(page) = error_page if let Ok(page) = error_page
.with_title(L10n::n("Error FORBIDDEN")) .with_title(L10n::n("Error FORBIDDEN"))
.with_layout("error") .with_layout("error")
.add_child(Html::with(move |_| error403.clone())) .add_component(Html::with(move |_| error403.clone()))
.render() .render()
{ {
write!(f, "{}", page.into_string()) write!(f, "{}", page.into_string())
} else { } else {
f.write_str("Access Denied") write!(f, "Access Denied")
} }
} }
// Error 404. // Error 404.
@ -49,20 +49,20 @@ impl Display for ErrorPage {
if let Ok(page) = error_page if let Ok(page) = error_page
.with_title(L10n::n("Error RESOURCE NOT FOUND")) .with_title(L10n::n("Error RESOURCE NOT FOUND"))
.with_layout("error") .with_layout("error")
.add_child(Html::with(move |_| error404.clone())) .add_component(Html::with(move |_| error404.clone()))
.render() .render()
{ {
write!(f, "{}", page.into_string()) write!(f, "{}", page.into_string())
} else { } else {
f.write_str("Not Found") write!(f, "Not Found")
} }
} }
// Error 412. // Error 412.
ErrorPage::PreconditionFailed(_) => f.write_str("Precondition Failed"), ErrorPage::PreconditionFailed(_) => write!(f, "Precondition Failed"),
// Error 500. // Error 500.
ErrorPage::InternalError(_) => f.write_str("Internal Error"), ErrorPage::InternalError(_) => write!(f, "Internal Error"),
// Error 504. // Error 504.
ErrorPage::Timeout(_) => f.write_str("Timeout"), ErrorPage::Timeout(_) => write!(f, "Timeout"),
} }
} }
} }

View file

@ -70,12 +70,14 @@ macro_rules! join {
}; };
} }
/// Concatena los fragmentos **no vacíos** en un [`Option<String>`] con un separador opcional. /// Concatena los fragmentos no vacíos en un [`Option<String>`] con un separador opcional.
/// ///
/// Acepta cualquier número de fragmentos que implementen [`AsRef<str>`]. Si todos los fragmentos /// Esta macro acepta cualquier número de fragmentos que implementen [`AsRef<str>`] para concatenar
/// están vacíos, devuelve `None`. /// todos los fragmentos no vacíos usando opcionalmente un separador.
/// ///
/// # Ejemplos /// Si todos los fragmentos están vacíos, devuelve [`None`].
///
/// # Ejemplo
/// ///
/// ```rust /// ```rust
/// # use pagetop::prelude::*; /// # use pagetop::prelude::*;
@ -88,7 +90,7 @@ macro_rules! join {
/// assert_eq!(result_without_separator, Some("HelloWorld".to_string())); /// assert_eq!(result_without_separator, Some("HelloWorld".to_string()));
/// ///
/// // Devuelve `None` si todos los fragmentos están vacíos. /// // Devuelve `None` si todos los fragmentos están vacíos.
/// let result_empty = join_opt!(["", "", ""]; ","); /// let result_empty = join_opt!(["", "", ""]);
/// assert_eq!(result_empty, None); /// assert_eq!(result_empty, None);
/// ``` /// ```
#[macro_export] #[macro_export]
@ -98,16 +100,12 @@ macro_rules! join_opt {
(!s.is_empty()).then_some(s) (!s.is_empty()).then_some(s)
}}; }};
([$($arg:expr),* $(,)?]; $separator:expr) => {{ ([$($arg:expr),* $(,)?]; $separator:expr) => {{
let sep = ($separator).as_ref(); let s = [$($arg),*]
let mut s = String::new(); .iter()
for part in [ $( ($arg).as_ref() ),* ] { .filter(|&item| !item.is_empty())
if !(part as &str).is_empty() { .cloned()
if !s.is_empty() { .collect::<Vec<_>>()
s.push_str(sep); .join($separator);
}
s.push_str(part);
}
}
(!s.is_empty()).then_some(s) (!s.is_empty()).then_some(s)
}}; }};
} }
@ -155,7 +153,7 @@ macro_rules! join_pair {
}}; }};
} }
/// Concatena varios fragmentos en un [`Option<String>`] **si ninguno está vacío**. /// Concatena varios fragmentos en un [`Option<String>`] si ninguno está vacío.
/// ///
/// Si alguno de los fragmentos, que deben implementar [`AsRef<str>`], está vacío, devuelve /// Si alguno de los fragmentos, que deben implementar [`AsRef<str>`], está vacío, devuelve
/// [`None`]. Opcionalmente se puede indicar un separador entre los fragmentos concatenados. /// [`None`]. Opcionalmente se puede indicar un separador entre los fragmentos concatenados.