113 lines
3.3 KiB
Rust
113 lines
3.3 KiB
Rust
//! Aspirational RUIN app API for typed children, slots, and builder finalization.
|
|
//!
|
|
//! Intentionally non-compiling; this is a design sketch.
|
|
|
|
use ruin::prelude::*;
|
|
|
|
#[ruin_runtime::async_main]
|
|
async fn main() -> ruin::Result<()> {
|
|
App::new()
|
|
.window(Window::new().title("RUIN Children Contracts").size(1100.0, 760.0))
|
|
.mount::<ChildrenContractsExample>()
|
|
.run()
|
|
.await
|
|
}
|
|
|
|
#[component]
|
|
fn ChildrenContractsExample() -> impl View {
|
|
let projects = projects();
|
|
|
|
view! {
|
|
column(fill = true, gap = 20, padding = 24) {
|
|
text(role = TextRole::Heading(1), size = 30, weight = FontWeight::Semibold) {
|
|
"Typed children and slots"
|
|
}
|
|
|
|
text(color = colors::muted()) {
|
|
"This sketch focuses on declaration-side child contracts. The `view!` syntax stays \
|
|
uniform for all components, while the generated builder enforces props first and \
|
|
`children` as the finalizing step."
|
|
}
|
|
|
|
SplitLayout(sidebar = view! {
|
|
block(gap = 12, width = 280) {
|
|
text(role = TextRole::Heading(2), size = 22, weight = FontWeight::Semibold) {
|
|
"Filters"
|
|
}
|
|
FilterChip(selected = true) { "All projects" }
|
|
FilterChip(selected = false) { "Recent" }
|
|
}
|
|
}) {
|
|
column(gap = 12) {
|
|
text(role = TextRole::Heading(2), size = 22, weight = FontWeight::Semibold) {
|
|
"Projects"
|
|
}
|
|
|
|
ForEach(items = projects, key = |project| project.id) { |project|
|
|
ProjectRow(project = project.clone()) {}
|
|
}
|
|
}
|
|
}
|
|
|
|
Dialog(
|
|
open = true,
|
|
title = view! {
|
|
text(role = TextRole::Heading(2), size = 22, weight = FontWeight::Semibold) {
|
|
"Dialog with custom title and actions"
|
|
}
|
|
},
|
|
actions = view! {
|
|
button(kind = ButtonKind::Secondary) { "Cancel" }
|
|
button(kind = ButtonKind::Primary) { "Delete" }
|
|
},
|
|
) {
|
|
text(color = colors::muted()) {
|
|
"A dialog can declare exactly one main child body plus separately typed \
|
|
title/actions slots."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[component]
|
|
fn FilterChip(children: impl InlineChildren, selected: bool) -> impl View {
|
|
let background = if selected {
|
|
colors::accent()
|
|
} else {
|
|
colors::muted().with_alpha(0.12)
|
|
};
|
|
|
|
view! {
|
|
block(
|
|
padding = (8, 16),
|
|
background = background,
|
|
corner_radius = 1000,
|
|
) {
|
|
children
|
|
}
|
|
}
|
|
}
|
|
|
|
#[component]
|
|
fn ForEach<T, C>(
|
|
items: impl IntoIterator<Item = T>,
|
|
key: impl Fn(&T) -> u64,
|
|
children: impl Fn(T) -> C,
|
|
) -> impl View
|
|
where
|
|
C: Children,
|
|
{
|
|
todo!("The framework would lower this into a keyed mapper primitive or composite")
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
struct Project {
|
|
id: u64,
|
|
name: String,
|
|
}
|
|
|
|
fn projects() -> Vec<Project> {
|
|
Vec::new()
|
|
}
|