Files
ruin/lib/ruin_app/example/06_justify_content.rs
2026-05-22 23:46:05 -04:00

195 lines
7.1 KiB
Rust

//! Visual demonstration of every supported `justify_content` mode.
//!
//! The window arranges one labeled cell per mode in a two-column grid. Each
//! cell is a flex container of the same fixed width with four
//! identically-sized children, so the only visible difference between cells is
//! how `justify_content` distributes the leftover space along the main axis.
use ruin_app::prelude::*;
const TRACK_WIDTH: f32 = 360.0;
const ITEM_SIZE: f32 = 44.0;
#[ruin_runtime::async_main]
async fn main() -> ruin_app::Result<()> {
App::new()
.window(
Window::new()
.title("RUIN justify_content")
.app_id("dev.ruin.justify-content")
.size(960.0, 620.0),
)
.mount(view! {
JustifyContentGallery() {}
})
.run()
.await
}
#[component]
fn JustifyContentGallery() -> impl IntoView {
let canvas = Color::rgb(0x10, 0x16, 0x22);
let panel = Color::rgb(0x1A, 0x23, 0x33);
let accent = Color::rgb(0x71, 0xA7, 0xF7);
let text_color = Color::rgb(0xF5, 0xF7, 0xFB);
let muted = Color::rgb(0x9A, 0xA9, 0xC2);
view! {
column(gap = 18.0, padding = 24.0, background = canvas) {
text(role = TextRole::Heading(1), size = 28.0, weight = FontWeight::Semibold, color = text_color) {
"justify_content"
}
text(color = muted, wrap = TextWrap::Word) {
"Each cell below is the same width and contains the same four boxes. The only \
thing that changes between cells is `justify_content`, which controls how the \
leftover space along the main axis is distributed."
}
row(gap = 16.0, align_items = AlignItems::Start) {
column(gap = 14.0, flex = 1.0) {
JustifyRow(
label = "Start",
description = "Pack children at the start of the main axis (default).",
justify = JustifyContent::Start,
panel = panel,
accent = accent,
text_color = text_color,
muted = muted,
) {}
JustifyRow(
label = "End",
description = "Pack children at the end of the main axis.",
justify = JustifyContent::End,
panel = panel,
accent = accent,
text_color = text_color,
muted = muted,
) {}
JustifyRow(
label = "Center",
description = "Pack children as a group, centered on the main axis.",
justify = JustifyContent::Center,
panel = panel,
accent = accent,
text_color = text_color,
muted = muted,
) {}
}
column(gap = 14.0, flex = 1.0) {
JustifyRow(
label = "SpaceBetween",
description = "First child flush with the start, last with the end, equal gaps between.",
justify = JustifyContent::SpaceBetween,
panel = panel,
accent = accent,
text_color = text_color,
muted = muted,
) {}
JustifyRow(
label = "SpaceAround",
description = "Equal space around each child; end gaps are half the gap between children.",
justify = JustifyContent::SpaceAround,
panel = panel,
accent = accent,
text_color = text_color,
muted = muted,
) {}
JustifyRow(
label = "SpaceEvenly",
description = "Equal space between children and between children and both edges.",
justify = JustifyContent::SpaceEvenly,
panel = panel,
accent = accent,
text_color = text_color,
muted = muted,
) {}
}
}
}
}
}
#[component]
fn JustifyRow(
label: &'static str,
description: &'static str,
justify: JustifyContent,
panel: Color,
accent: Color,
text_color: Color,
muted: Color,
) -> impl IntoView {
view! {
column(
gap = 6.0,
padding = 12.0,
background = panel,
border_radius = 10.0,
border = (1.0, accent),
) {
row(gap = 10.0, align_items = AlignItems::Center) {
text(size = 16.0, weight = FontWeight::Semibold, color = text_color) { label }
text(color = muted) { description }
}
row(
width = TRACK_WIDTH,
height = ITEM_SIZE + 16.0,
padding = 8.0,
gap = 8.0,
background = Color::rgba(0xFF, 0xFF, 0xFF, 0x10),
border_radius = 6.0,
align_items = AlignItems::Center,
justify_content = justify,
) {
JustifyItem(label = "1", accent = accent, text_color = text_color) {}
JustifyItem(label = "2", accent = accent, text_color = text_color) {}
JustifyItem(label = "3", accent = accent, text_color = text_color) {}
JustifyItem(label = "4", accent = accent, text_color = text_color) {}
}
}
}
}
#[component]
fn JustifyItem(label: &'static str, accent: Color, text_color: Color) -> impl IntoView {
view! {
block(
width = ITEM_SIZE,
height = ITEM_SIZE,
background = accent,
border_radius = 6.0,
align_items = AlignItems::Center,
) {
row(
flex = 1.0,
align_items = AlignItems::Center,
justify_content = JustifyContent::Center,
) {
text(size = 18.0, weight = FontWeight::Semibold, color = text_color) { label }
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gallery_renders_all_labels() {
let root = JustifyContentGallery::builder().children(());
let view = ruin_app::__render_mountable_for_test(&root);
let snapshot = ruin_ui::layout_snapshot(1, UiSize::new(960.0, 620.0), view.element());
for label in ["Start", "End", "Center", "SpaceBetween", "SpaceAround", "SpaceEvenly"] {
assert!(
snapshot.scene.items.iter().any(|item| matches!(
item,
ruin_ui::DisplayItem::Text(text) if text.text.contains(label)
)),
"expected `{label}` label to appear in the rendered scene",
);
}
}
}