A political conference and discussion platform, in Rust and Dioxus
Something went wrong. Try again.
4.0 kB · 103 lines
Rust
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104use dioxus::prelude::*;
use crate::i18n::t;use crate::model::NodeWithChildren;use crate::route::Route;
use super::loader::{icon_el, visible_sorted};
/// ProgramApp — an agenda / programme view of a context (#60). Renders the/// context's ordered children as a numbered vertical timeline, each item linking/// into its node.#[component]pub fn ProgramApp(node: NodeWithChildren, path: Vec<String>) -> Element { let items = visible_sorted(&node.children);
rsx! { div { class: "card app-card", div { class: "card-header", div { class: "avatar", {icon_el("app/program")} } h3 { class: "title-medium", "{node.name}" } } if items.is_empty() { div { class: "card-content", p { class: "body-medium", class: "text-muted", "{t(\"program.empty\")}" } } } else { div { class: "program-timeline", for (i , item) in items.iter().enumerate() { { let mut full = path.clone(); full.push(item.key.clone()); let icon = super::loader::node_icon_el( item.mime_id.as_deref().unwrap_or(""), item.data.as_ref().map(|d| &d.0), ); let time = program_time(item.data.as_ref().map(|d| &d.0)); rsx! { Link { key: "{item.id.0}", to: Route::PathPage { segments: full, app: None }, class: "program-item", // Leading agenda time column (empty keeps the rail aligned). div { class: "program-time", if let Some(t) = time { "{t}" } } // The connected rail: a numbered dot over a vertical line. div { class: "program-marker", div { class: "program-dot", "{i + 1}" } } div { class: "program-body", div { class: "list-item-primary", span { class: "program-item-icon", {icon} } "{item.name}" } } } } } } } } } }}
/// A human agenda time from a node's data, if present (`time`, `start`, or/// `when` string fields).fn program_time(data: Option<&serde_json::Value>) -> Option<String> { let obj = data?.as_object()?; for key in ["when", "start", "time"] { if let Some(v) = obj.get(key).and_then(|v| v.as_str()) { if !v.is_empty() { return Some(v.to_string()); } } } None}
#[cfg(test)]mod tests { use super::*;
#[test] fn program_time_reads_known_fields() { assert_eq!( program_time(Some(&serde_json::json!({ "when": "10:00" }))), Some("10:00".to_string()) ); assert_eq!( program_time(Some(&serde_json::json!({ "start": "09:30" }))), Some("09:30".to_string()) ); assert_eq!(program_time(Some(&serde_json::json!({}))), None); assert_eq!(program_time(None), None); }}