pagetop/examples/intro-responsive.rs
Manuel Cillero 3c3ffc91e6 ♻️ (pagetop): with_prop() acepta impl Into<PropsOp>
`FlexItem`, `Margin` y `Padding` se pasan directamente gracias a `From`
 hacia `PropsOp`, sin `PropsOp::flex_item()`/`margin()`/`padding()` ni
`.into()` explícito. Revisadas todas las llamadas en el código para
simplificarlas.
2026-09-13 01:38:33 +02:00

267 lines
9.3 KiB
Rust

use pagetop::prelude::*;
include_locales!(LOC from "examples/locale");
struct IntroResponsive;
#[async_trait]
impl Extension for IntroResponsive {
fn dependencies(&self) -> Vec<ExtensionRef> {
vec![&pagetop_bootsier::Bootsier]
}
fn configure_router(&self, router: Router) -> Router {
router.route("/", web::get(intro_responsive))
}
}
async fn intro_responsive(request: HttpRequest) -> Result<Markup, ErrorPage> {
Page::new(request)
.with_assets(demo_box_styles())
.with_assets(demo_row_styles())
.with_assets(demo_code_styles())
.with_child(
Intro::default()
.with_opening(IntroOpening::Custom)
.with_title(Lc::n("PageTop"))
.with_slogan(Lc::t("responsive_slogan", &LOC))
.with_button(None::<(Lc, Route)>)
.with_child(Html::with(|cx| {
html! {
p class="intro-text-lead" {
(Lc::t("responsive_note", &LOC).using(cx))
}
}
}))
.with_child(activation_block())
.with_child(direction_block())
.with_child(grid_block())
.with_child(justify_align_block())
.with_child(order_block())
.with_child(gap_grow_block()),
)
.render()
.await
}
fn activation_block() -> Block {
Block::new()
.with_title(Lc::t("responsive_block_title_activation", &LOC))
.with_child(caption(
Lc::t("responsive_title_activation", &LOC),
Lc::n("Flex::at(Breakpoint::Md)"),
))
.with_child(
demo_row(Flex::at(Breakpoint::Md).with_gap(flex::Gap::Both(UnitValue::RelRem(0.5))))
.with_child(demo_box(Lc::t("responsive_box_nav_home", &LOC)))
.with_child(demo_box(Lc::t("responsive_box_nav_products", &LOC)))
.with_child(demo_box(Lc::t("responsive_box_nav_about", &LOC)))
.with_child(demo_box(Lc::t("responsive_box_nav_contact", &LOC))),
)
}
fn direction_block() -> Block {
Block::new()
.with_title(Lc::t("responsive_block_title_direction", &LOC))
.with_child(caption(
Lc::t("responsive_title_direction", &LOC),
Lc::n(concat!(
"Flex::new()",
".with_direction(Direction::Column)",
".with_direction_at(Breakpoint::Md, Direction::RowReverse)",
)),
))
.with_child(
demo_row(
Flex::new()
.with_direction(flex::Direction::Column)
.with_direction_at(Breakpoint::Md, flex::Direction::RowReverse)
.with_gap(flex::Gap::Both(UnitValue::RelRem(0.5))),
)
.with_child(sized_box(
Lc::t("responsive_box_image", &LOC),
"2.5rem 1rem",
))
.with_child(demo_box(Lc::t("responsive_box_text", &LOC))),
)
}
fn grid_block() -> Block {
let mut row = demo_row(Flex::new().with_wrap(flex::Behavior::Wrap));
for n in 1..=6 {
row = row.with_child(
Container::new()
.with_prop(PropsOp::add_style("padding", "0.25rem"))
.with_prop(
FlexItem::new()
.with_size(flex::ItemSize::Percent100)
.with_size_at(Breakpoint::Sm, flex::ItemSize::Percent50)
.with_size_at(Breakpoint::Md, flex::ItemSize::Percent33),
)
.with_child(demo_box(card_label(n))),
);
}
Block::new()
.with_title(Lc::t("responsive_block_title_grid", &LOC))
.with_child(caption(
Lc::t("responsive_title_grid", &LOC),
Lc::n(concat!(
"FlexItem::new()",
".with_size(ItemSize::Percent100)",
".with_size_at(Breakpoint::Sm, ItemSize::Percent50)",
".with_size_at(Breakpoint::Md, ItemSize::Percent33)",
)),
))
.with_child(row)
}
fn justify_align_block() -> Block {
Block::new()
.with_title(Lc::t("responsive_block_title_justify_align", &LOC))
.with_child(caption(
Lc::t("responsive_title_justify_align", &LOC),
Lc::n(concat!(
"Flex::new()",
".with_justify(ContentJustify::Center)",
".with_justify_at(Breakpoint::Md, ContentJustify::SpaceBetween)",
".with_align(Align::Center)",
)),
))
.with_child(
demo_row(
Flex::new()
.with_justify(flex::ContentJustify::Center)
.with_justify_at(Breakpoint::Md, flex::ContentJustify::SpaceBetween)
.with_align(flex::Align::Center)
.with_gap(flex::Gap::Both(UnitValue::RelRem(0.5))),
)
.with_child(demo_box(Lc::t("responsive_box_logo", &LOC)))
.with_child(demo_box(Lc::t("responsive_box_menu", &LOC))),
)
}
fn order_block() -> Block {
Block::new()
.with_title(Lc::t("responsive_block_title_order", &LOC))
.with_child(caption(
Lc::t("responsive_title_order", &LOC),
Lc::n(concat!(
"Flex::at(Breakpoint::Lg)",
" + FlexItem::new().with_order_at(Breakpoint::Lg, ItemOrder::First)",
)),
))
.with_child(
demo_row(Flex::at(Breakpoint::Lg).with_gap(flex::Gap::Both(UnitValue::RelRem(0.5))))
.with_child(demo_box(Lc::t("responsive_box_content", &LOC)))
.with_child(demo_box(Lc::t("responsive_box_sidebar", &LOC)).with_prop(
FlexItem::new().with_order_at(Breakpoint::Lg, flex::ItemOrder::First),
)),
)
}
fn gap_grow_block() -> Block {
Block::new()
.with_title(Lc::t("responsive_block_title_gap_grow", &LOC))
.with_child(caption(
Lc::t("responsive_title_gap_grow", &LOC),
Lc::n(concat!(
"Flex::new()",
".with_gap(Gap::Both(RelRem(0.5)))",
".with_gap_at(Breakpoint::Md, Gap::Both(RelRem(1.5)))",
" + FlexItem::new().with_grow_at(Breakpoint::Md, ItemGrow::Is1)",
)),
))
.with_child(
demo_row(
Flex::new()
.with_gap(flex::Gap::Both(UnitValue::RelRem(0.5)))
.with_gap_at(Breakpoint::Md, flex::Gap::Both(UnitValue::RelRem(1.5))),
)
.with_child(demo_box(Lc::t("responsive_box_file", &LOC)))
.with_child(demo_box(Lc::t("responsive_box_edit", &LOC)))
.with_child(
demo_box(Lc::t("responsive_box_search", &LOC))
.with_prop(FlexItem::new().with_grow_at(Breakpoint::Md, flex::ItemGrow::Is1)),
),
)
}
// **< HELPERS >************************************************************************************
// Aspecto fijo de las cajas de muestra.
fn demo_box_styles() -> AssetsOp {
AssetsOp::add_responsive_styles(
None,
"flex-demo-box",
[
("background-color", "#0d6efd"),
("color", "#fff"),
("min-width", "3rem"),
("width", "auto"),
("max-width", "none"),
("margin", "0"),
("border-radius", "0.375rem"),
("text-align", "center"),
],
)
}
// Aspecto fijo de las filas de muestra.
fn demo_row_styles() -> AssetsOp {
AssetsOp::add_responsive_styles(
None,
"flex-demo-row",
[
("background-color", "#f1f3f5"),
("width", "100%"),
("max-width", "none"),
("margin", "0 0 1.5rem"),
("padding", "0.75rem"),
],
)
}
// Evita que los fragmentos de código largos desborden su contenedor.
fn demo_code_styles() -> AssetsOp {
AssetsOp::add_responsive_styles(None, "flex-demo-code", [("overflow-wrap", "anywhere")])
}
// Caja con fondo azul y relleno vertical configurable, para mostrar diferencias de altura.
fn sized_box(label: Lc, padding: &'static str) -> Container {
Container::new()
.with_prop(PropsOp::add_classes("flex-demo-box"))
.with_prop(PropsOp::add_style("padding", padding))
.with_child(Html::with(move |cx| html! { (label.using(cx)) }))
}
// Caja con el relleno vertical estandar del resto de ejemplos.
fn demo_box(label: Lc) -> Container {
sized_box(label, "0.5rem 1rem")
}
// Etiqueta "Tarjeta N" para las cajas de la rejilla responsive.
fn card_label(n: usize) -> Lc {
Lc::t("responsive_box_card", &LOC).with_arg("n", n.to_string())
}
// Fila de demostracion con fondo gris para visualizar los limites del propio contenedor flex.
fn demo_row(flex: Flex) -> Container {
Container::new()
.with_prop(PropsOp::add_classes("flex-demo-row"))
.with_flex(flex)
}
// Titulo y fragmento de codigo que introducen cada demostracion.
fn caption(title: Lc, code: Lc) -> Html {
Html::with(move |cx| {
html! {
h3 { (title.using(cx)) }
p { code class="flex-demo-code" { (code.using(cx)) } }
}
})
}
#[pagetop::main]
async fn main() -> std::io::Result<()> {
Application::prepare(&IntroResponsive).await.run().await
}