use axum::extract::{Query, State}; use axum::response::IntoResponse; use axum::routing::get; use axum::Router; use futures_util::{stream, StreamExt}; use hemplate::Hemplate; use slhx::{CssClass, CssClasses, IntoEffect, RenderSlotExt, SafeHtml}; use slhx_axum::{ runtime_js, sse, DispatchRejection, EffectResponse, HandlerRegistry, InteractionForm, PageRequest, }; use slhx_techdemo::ui; use slhx_techdemo::ui::control_center::{classes, forms, handles, slots}; use slhx_techdemo::ui::issue_card::handles as card_handles; use slhx_techdemo::ui::issue_lane::handles as lane_handles; use std::collections::{BTreeMap, VecDeque}; use std::convert::Infallible; use std::net::SocketAddr; use std::sync::{Arc, Mutex}; use std::time::Duration; const LANES: [(&str, &str, &str); 3] = [ ("compiler", "Compiler", "Surface → generated API"), ("runtime", "Runtime", "EffectBatch → DOM"), ("product", "Product", "Native UX, zero app JS"), ]; #[derive(Clone)] struct WorkItem { id: u64, title: String, lane: usize, impact: u8, stage: Stage, } #[derive(Clone, Copy, Eq, PartialEq)] enum Stage { Draft, Active, Shipped, } impl Stage { fn advance(self) -> Self { match self { Self::Draft => Self::Active, Self::Active => Self::Shipped, Self::Shipped => Self::Shipped, } } fn label(self) -> &'static str { match self { Self::Draft => "Draft", Self::Active => "Active", Self::Shipped => "Shipped", } } } #[derive(Clone)] struct DemoState { next_id: u64, work: Vec, activity: VecDeque, spotlight: String, selected_id: Option, } impl Default for DemoState { fn default() -> Self { let mut state = Self { next_id: 4, work: vec![ WorkItem { id: 1, title: "Compile checked handles".into(), lane: 0, impact: 9, stage: Stage::Shipped }, WorkItem { id: 2, title: "Stream typed presence".into(), lane: 1, impact: 7, stage: Stage::Active }, WorkItem { id: 3, title: "Replace dashboard widgets".into(), lane: 2, impact: 8, stage: Stage::Draft }, ], activity: VecDeque::new(), spotlight: "No selectors. Generated resources address every target.".into(), selected_id: Some(2), }; state.log("Demo booted from server-rendered HTML"); state.log("Runtime attached one delegated listener per root"); state } } impl DemoState { fn log(&mut self, message: impl Into) { self.activity.push_front(message.into()); while self.activity.len() > 6 { self.activity.pop_back(); } } } struct Shared { demo: Mutex, } #[derive(Hemplate)] #[hemplate = "partials"] struct IssueLane { class: CssClass, lane_id: &'static str, title: &'static str, description: &'static str, cards: Vec, } #[derive(Hemplate)] #[hemplate = "partials"] struct IssueCard { class: CssClasses, id: u64, title: String, stage: &'static str, impact_style: String, } #[derive(Hemplate)] #[hemplate = "partials"] struct BoardLanes { lanes: Vec, } #[derive(Hemplate)] struct ControlCenter { hero: SafeHtml, board: SafeHtml, inspector: SafeHtml, activity: SafeHtml, island_snapshot: String, } #[derive(Hemplate)] struct AppShell { body: SafeHtml, } #[derive(Hemplate)] #[hemplate = "partials"] struct InspectorPanel { selected: String, spotlight: String, } #[derive(Hemplate)] #[hemplate = "partials"] struct InspectorSelected { title: String, lane: &'static str, stage: &'static str, impact: u8, } #[derive(Hemplate)] #[hemplate = "partials"] struct InspectorEmpty; #[derive(Hemplate)] #[hemplate = "partials"] struct LiveFeed { tick: u64, } #[derive(Hemplate)] #[hemplate = "partials"] struct ActivityFeed { items: Vec, } #[derive(Hemplate)] #[hemplate = "partials"] struct ArchitectureActivity; #[derive(Hemplate)] #[hemplate = "partials"] struct ArchitectureInspector; #[derive(Hemplate)] #[hemplate = "partials"] struct ArchitectureHero; #[derive(Hemplate)] #[hemplate = "partials"] struct ArchitectureBoard; #[derive(Hemplate)] #[hemplate = "partials"] struct HeroMetrics { resource_count: u64, active_count: usize, shipped_count: usize, impact_score: u64, } #[tokio::main] async fn main() { let state = Arc::new(Shared { demo: Mutex::new(DemoState::default()) }); let app = Router::new() .route("/", get(home).post(interact)) .route("/architecture", get(architecture)) .route("/events", get(events)) .route("/slhx.js", get(runtime)) .route("/app.css", get(app_css)) .route("/control_center.css", get(control_center_css)) .route("/island.js", get(island_js)) .with_state(state); let addr = std::env::var("SLHX_TECHDEMO_ADDR") .ok() .and_then(|addr| addr.parse().ok()) .unwrap_or_else(|| SocketAddr::from(([127, 0, 0, 1], 3002))); let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); println!("slhx techdemo: http://{addr}"); axum::serve(listener, app).await.unwrap(); } // req: examples/001 req: dx/008 req: public_api/001 async fn home(State(state): State>, request: PageRequest) -> impl IntoResponse { let demo = state.demo.lock().unwrap().clone(); request .page(page_html(&demo), shell) .title("slhx Techdemo") .fingerprint(ui::BUILD_FINGERPRINT) } // req: page_swap/001 req: page_swap/002 req: examples/001 async fn architecture(request: PageRequest) -> impl IntoResponse { let body = render_control_center(ControlCenter { hero: architecture_hero(), board: architecture_board(), inspector: architecture_inspector(), activity: architecture_activity(), island_snapshot: "2|3|21|architecture route · same opaque island bridge".to_owned(), }); request .page(body, shell) .title("slhx Architecture") .fingerprint(ui::BUILD_FINGERPRINT) } async fn runtime() -> impl IntoResponse { runtime_js() } async fn app_css() -> impl IntoResponse { ([("content-type", "text/css; charset=utf-8")], include_str!("../templates/app_shell.css")) } async fn control_center_css() -> impl IntoResponse { ([("content-type", "text/css; charset=utf-8")], include_str!("../templates/control_center.css")) } async fn island_js() -> impl IntoResponse { ([("content-type", "text/javascript; charset=utf-8")], include_str!("../templates/island.js")) } async fn interact( State(state): State>, form: InteractionForm, ) -> Result { registry(state).dispatch(form) } // req: push/001 req: push/003 req: examples/001 async fn events(Query(params): Query>) -> impl IntoResponse { if params.contains_key("once") { let effect = slots::live_feed.render(&LiveFeed { tick: 1 }); return sse(stream::iter([Ok::<_, Infallible>(effect.into_batch(ui::BUILD_FINGERPRINT))]).boxed()); } let batches = stream::unfold(1_u64, |tick| async move { tokio::time::sleep(Duration::from_secs(4)).await; let effect = slots::live_feed.render(&LiveFeed { tick }); Some((Ok::<_, Infallible>(effect.into_batch(ui::BUILD_FINGERPRINT)), tick + 1)) }) .boxed(); sse(batches) } fn registry(shared: Arc) -> HandlerRegistry { HandlerRegistry::new(ui::BUILD_FINGERPRINT) .register_handle(handles::launch_work, { let shared = shared.clone(); move |form| { // req: form/002 req: examples/001 let mut demo = shared.demo.lock().unwrap(); let title = form.value("title").unwrap_or("").trim(); let lane = parse_lane(form.value("lane")); let impact = form.value("impact").and_then(|value| value.parse::().ok()).unwrap_or(5).clamp(1, 9); if !title.is_empty() { let id = demo.next_id; demo.next_id += 1; demo.work.push(WorkItem { id, title: title.into(), lane, impact, stage: Stage::Draft }); demo.selected_id = Some(id); demo.spotlight = format!("Form data became typed Rust state; card #{id} was rendered by a generated slot."); demo.log(format!("Launched card #{id}: {title}")); } demo_effects(&demo, "Launch accepted · 4 targets updated") } }) .register_handle(card_handles::advance_work, { let shared = shared.clone(); move |form| { // req: list/003 req: examples/001 let mut demo = shared.demo.lock().unwrap(); let title = update_work(&mut demo, form.value("work_id"), |item| { item.stage = item.stage.advance(); if item.stage == Stage::Shipped { item.lane = LANES.len() - 1; } }); if let Some(title) = title { demo.spotlight = format!("{title} advanced without a selector: the server returned slot effects."); demo.log(format!("Advanced {title}")); } demo_effects(&demo, "Pipeline advanced") } }) .register_handle(lane_handles::move_to_lane, { let shared = shared.clone(); move |form| { // req: list/003 req: examples/001 let mut demo = shared.demo.lock().unwrap(); let lane = parse_lane(form.value("lane")); let title = update_work(&mut demo, form.value("work_id"), |item| { item.lane = lane; item.stage = match lane { 0 => Stage::Draft, 1 => Stage::Active, _ => Stage::Shipped, }; }); if let Some(title) = title { demo.selected_id = form.value("work_id").and_then(|value| value.parse().ok()); demo.spotlight = format!("{title} moved to {} by drag-and-drop; Rust re-rendered the board slot.", LANES[lane].1); demo.log(format!("Dragged {title} to {}", LANES[lane].1)); } demo_effects(&demo, "Drag-and-drop move persisted") } }) .register_handle(card_handles::delete_work, { let shared = shared.clone(); move |form| { // req: list/003 req: examples/001 let mut demo = shared.demo.lock().unwrap(); if let Some(id) = form.value("work_id").and_then(|value| value.parse::().ok()) { let before = demo.work.len(); demo.work.retain(|item| item.id != id); if demo.work.len() < before { if demo.selected_id == Some(id) { demo.selected_id = demo.work.first().map(|item| item.id); } demo.spotlight = format!("Card #{id} removed; the board, metrics, activity, and inspector updated together."); demo.log(format!("Deleted card #{id}")); } } demo_effects(&demo, "Card removed") } }) .register_handle(card_handles::spotlight_work, { let shared = shared.clone(); move |form| { // req: examples/001 let mut demo = shared.demo.lock().unwrap(); if let Some(id) = form.value("work_id").and_then(|value| value.parse::().ok()) { if let Some(item) = demo.work.iter().find(|item| item.id == id).cloned() { demo.selected_id = Some(id); demo.spotlight = format!("{} · lane={} · stage={} · impact={}", item.title, LANES[item.lane].1, item.stage.label(), item.impact); demo.log(format!("Inspected card #{id}")); } } demo_effects(&demo, "Inspector focused") } }) .register_handle(handles::simulate_push, { let shared = shared.clone(); move |_| { // req: push/003 req: examples/001 let mut demo = shared.demo.lock().unwrap(); demo.log("Simulated push event produced the same EffectBatch shape"); ( slots::live_feed.render(&LiveFeed { tick: demo.activity.len() as u64, }), slots::activity.render(&activity_view(&demo)), slots::notice.text("Push simulated · no client app code"), slhx::event("slhx:island-orbit", island_snapshot(&demo)), ) } }) .register_handle(handles::reset_demo, { let shared = shared.clone(); move |_| { // req: examples/001 let mut demo = shared.demo.lock().unwrap(); *demo = DemoState::default(); demo_effects(&demo, "Demo reset from Rust state") } }) } fn update_work(demo: &mut DemoState, id: Option<&str>, update: impl FnOnce(&mut WorkItem)) -> Option { let id = id.and_then(|value| value.parse::().ok())?; let item = demo.work.iter_mut().find(|item| item.id == id)?; let title = item.title.clone(); update(item); Some(title) } fn demo_effects(demo: &DemoState, notice: &'static str) -> impl IntoEffect { ( slots::hero_metrics.render(&hero_view(demo)), slots::board.html(render_board(demo)), slots::activity.render(&activity_view(demo)), slots::inspector.render(&inspector_view(demo)), slots::notice.text(notice), forms::launch_work.clear("title"), slhx::event("slhx:island-orbit", island_snapshot(demo)), ) } fn parse_lane(value: Option<&str>) -> usize { let value = value.unwrap_or(LANES[0].0); LANES.iter().position(|(id, _, _)| *id == value).unwrap_or(0) } fn island_snapshot(demo: &DemoState) -> String { // Opaque leaf-widget bridge: compact server snapshot in, native CustomEvent out. // req: interop/001 req: examples/001 let active = demo.work.iter().filter(|item| item.stage == Stage::Active).count(); let shipped = demo.work.iter().filter(|item| item.stage == Stage::Shipped).count(); let impact: u64 = demo.work.iter().map(|item| item.impact as u64).sum(); format!( "{}|{}|{}|{} active · {} shipped · {} activity rows", active + shipped, demo.work.len(), impact, active, shipped, demo.activity.len() ) } fn page_html(demo: &DemoState) -> String { // Explicit full-page composition boundary for already-rendered hemplate fragments. // req: html_safety/002 req: view/001 render_control_center(ControlCenter { hero: render_hero(demo), board: render_board(demo), inspector: render_inspector(demo), activity: render_activity(demo), island_snapshot: island_snapshot(demo), }) } fn shell(body: String) -> String { // Explicit full-page shell composition boundary for already-rendered hemplate fragments. // req: html_safety/002 req: view/001 render_template(&AppShell { body: SafeHtml::trusted(body) }) } fn hero_view(demo: &DemoState) -> HeroMetrics { // req: html_safety/002 req: view/001 let shipped = demo.work.iter().filter(|item| item.stage == Stage::Shipped).count(); let active = demo.work.iter().filter(|item| item.stage == Stage::Active).count(); let impact: u64 = demo.work.iter().map(|item| item.impact as u64).sum(); HeroMetrics { resource_count: 13, active_count: active, shipped_count: shipped, impact_score: impact, } } fn render_hero(demo: &DemoState) -> SafeHtml { // req: html_safety/002 req: view/001 slhx::render_html(&hero_view(demo)) } fn board_view(demo: &DemoState) -> BoardLanes { // req: html_safety/002 req: view/001 let lanes = LANES .iter() .enumerate() .map(|(idx, (lane_id, title, description))| IssueLane { class: classes::lane, lane_id, title, description, cards: demo .work .iter() .filter(|item| item.lane == idx) .map(|item| issue_card(item, demo.selected_id == Some(item.id))) .collect(), }) .collect::>(); BoardLanes { lanes } } fn render_board(demo: &DemoState) -> SafeHtml { // req: html_safety/002 req: view/001 req: component/003 ui::render_html(&board_view(demo)) } fn issue_card(item: &WorkItem, selected: bool) -> IssueCard { IssueCard { class: if selected { CssClasses::from([ classes::work_card, classes::is_selected, ]) } else { CssClasses::from(classes::work_card) }, id: item.id, title: item.title.clone(), stage: item.stage.label(), impact_style: format!("width:{}%", item.impact as usize * 11), } } fn activity_view(demo: &DemoState) -> ActivityFeed { // req: html_safety/002 req: view/001 ActivityFeed { items: demo.activity.iter().cloned().collect(), } } fn render_activity(demo: &DemoState) -> SafeHtml { // req: html_safety/002 req: view/001 slhx::render_html(&activity_view(demo)) } fn inspector_view(demo: &DemoState) -> InspectorPanel { // req: html_safety/002 req: view/001 let selected = demo .selected_id .and_then(|id| demo.work.iter().find(|item| item.id == id)); let selected = selected.map_or_else( || render_template(&InspectorEmpty), |item| { render_template(&InspectorSelected { title: item.title.clone(), lane: LANES[item.lane].1, stage: item.stage.label(), impact: item.impact, }) }, ); InspectorPanel { selected, spotlight: demo.spotlight.clone(), } } fn render_inspector(demo: &DemoState) -> SafeHtml { // req: html_safety/002 req: view/001 slhx::render_html(&inspector_view(demo)) } fn architecture_hero() -> SafeHtml { // req: html_safety/002 req: view/001 slhx::render_html(&ArchitectureHero) } fn architecture_board() -> SafeHtml { // req: html_safety/002 req: view/001 slhx::render_html(&ArchitectureBoard) } fn architecture_inspector() -> SafeHtml { // req: html_safety/002 req: view/001 slhx::render_html(&ArchitectureInspector) } fn architecture_activity() -> SafeHtml { // req: html_safety/002 req: view/001 slhx::render_html(&ArchitectureActivity) } fn render_control_center(page: ControlCenter) -> String { // req: html_safety/002 req: view/001 req: component/003 ui::render_html(&page).into_string() } fn render_template(template: &impl Hemplate) -> String { let mut html = String::new(); template .render_into(&mut html) .expect("techdemo hemplate partial renders"); html } #[cfg(test)] mod tests { use super::*; use scraper::{Html, Selector}; fn selector(value: &str) -> Selector { Selector::parse(value).expect("test selector parses") } // req: html_safety/002 req: view/001 req: test/005 #[test] fn shell_is_composed_by_a_hemplate_view() { let html = shell(page_html(&DemoState::default())); let document = Html::parse_document(&html); assert_eq!( document .select(&selector("title")) .next() .map(|title| title.text().collect::()), Some("slhx Techdemo".to_owned()) ); assert_eq!(document.select(&selector("script[src=\"/slhx.js\"]")).count(), 1); assert_eq!(document.select(&selector("link[rel=\"stylesheet\"]")).count(), 2); assert_eq!(document.select(&selector("link[href=\"/app.css\"]")).count(), 1); assert_eq!(document.select(&selector("link[href=\"/control_center.css\"]")).count(), 1); assert_eq!(document.select(&selector("main[data-slhx-root=\"techdemo\"]")).count(), 1); assert!(!html.contains("{+=")); } // req: html_safety/002 req: view/001 req: test/005 #[test] fn control_center_page_is_composed_by_hemplate_not_placeholders() { let html = page_html(&DemoState::default()); assert!(!html.contains("__HERO__")); assert!(!html.contains("__BOARD__")); assert!(!html.contains("__INSPECTOR__")); assert!(!html.contains("__ACTIVITY__")); let document = Html::parse_fragment(&html); assert_eq!(document.select(&selector("[data-slhx-root=\"techdemo\"]")).count(), 1); assert!(document.select(&selector("[data-sid]")).count() >= 7); assert!(document.select(&selector("[data-hid]")).count() >= 7); assert_eq!(document.select(&selector(".hero-panel .metrics")).count(), 1); assert_eq!(document.select(&selector(".board-card .lanes")).count(), 1); assert_eq!(document.select(&selector(".glass-card .inspector-hero")).count(), 1); assert_eq!(document.select(&selector(".glass-card ol.activity")).count(), 1); } // req: html_safety/002 req: view/001 req: test/005 #[test] fn hero_metrics_are_rendered_by_a_hemplate_view() { let html = render_hero(&DemoState::default()); let document = Html::parse_fragment(html.as_str()); let metrics = document.select(&selector(".metrics > .metric")).collect::>(); assert_eq!(metrics.len(), 4); assert_eq!( metrics[0] .select(&selector("span")) .next() .map(|span| span.text().collect::()), Some("generated resources on this page".to_owned()) ); assert!(metrics .iter() .any(|metric| metric.text().collect::().contains("aggregate impact score"))); } // req: style/001 req: style/002 req: style/003 req: test/005 #[test] fn generated_css_class_flows_through_hemplate_dynamic_attribute() { let board = render_board(&DemoState::default()); assert_eq!(classes::lane.as_str(), "lane"); assert_eq!(classes::work_card.as_str(), "work-card"); assert_eq!(classes::is_selected.as_str(), "is-selected"); let document = Html::parse_fragment(board.as_str()); assert_eq!(document.select(&selector(".lanes > section.lane")).count(), 3); let lane = document .select(&selector(r#"section.lane[data-lane="compiler"]"#)) .next() .expect("compiler lane renders"); assert_eq!(lane.value().attr("class"), Some("lane")); let selected_card = document .select(&selector(r#"article.work-card.is-selected[data-key="2"]"#)) .next() .expect("selected work card renders"); assert_eq!(selected_card.value().attr("class"), Some("work-card is-selected")); } // req: html_safety/002 req: view/001 req: test/005 #[test] fn inspector_payload_is_rendered_by_a_hemplate_view() { let html = render_inspector(&DemoState::default()); let document = Html::parse_fragment(html.as_str()); let hero = document .select(&selector(".inspector-hero")) .next() .expect("selected inspector hero renders"); assert_eq!( hero.select(&selector("span")) .next() .map(|span| span.text().collect::()), Some("Selected issue".to_owned()) ); assert_eq!(document.select(&selector(".inspector-row")).count(), 3); assert!(document .select(&selector("code")) .any(|code| code.text().collect::().contains("EffectBatch"))); } // req: html_safety/002 req: view/001 req: test/005 #[test] fn live_feed_payload_is_rendered_by_a_hemplate_view() { let html = slhx::render_html(&LiveFeed { tick: 7 }); let document = Html::parse_fragment(html.as_str()); let row = document .select(&selector(".live-row")) .next() .expect("live feed row renders"); let text = row.text().collect::(); assert!(text.contains("SSE tick #7")); assert!(row .select(&selector("code")) .any(|code| code.text().collect::() == "slots::live_feed")); } // req: html_safety/002 req: view/001 req: test/005 #[test] fn activity_payload_is_rendered_by_a_hemplate_view() { let mut demo = DemoState::default(); demo.activity.push_back("escaped activity".to_owned()); let html = render_activity(&demo); let document = Html::parse_fragment(html.as_str()); let list = document .select(&selector("ol.activity")) .next() .expect("activity list renders"); let items = list.select(&selector("li")).collect::>(); assert_eq!(items.len(), demo.activity.len()); assert!(items .last() .expect("activity item renders") .text() .collect::() .contains("escaped activity")); assert!(list.select(&selector("b")).next().is_none()); } // req: html_safety/002 req: view/001 req: test/005 #[test] fn architecture_activity_is_rendered_by_a_hemplate_view() { let html = architecture_activity(); let document = Html::parse_fragment(html.as_str()); let list = document .select(&selector("ol.activity")) .next() .expect("architecture activity list renders"); let items = list.select(&selector("li")).collect::>(); assert_eq!(items.len(), 3); assert_eq!( items[1].text().collect::(), "Fetched HTML with X-SLHX-Partial" ); } // req: html_safety/002 req: view/001 req: test/005 #[test] fn architecture_inspector_is_rendered_by_a_hemplate_view() { let html = architecture_inspector(); let document = Html::parse_fragment(html.as_str()); let row = document .select(&selector(".inspector-row")) .next() .expect("architecture inspector row renders"); assert_eq!( row.select(&selector("b")).next().map(|b| b.text().collect::()), Some("Page swap".to_owned()) ); assert!(row .text() .collect::() .contains("rendered through the same root")); } // req: html_safety/002 req: view/001 req: test/005 #[test] fn architecture_hero_is_rendered_by_a_hemplate_view() { let html = architecture_hero(); let document = Html::parse_fragment(html.as_str()); let metrics = document.select(&selector(".metric")).collect::>(); assert_eq!(metrics.len(), 3); assert_eq!( metrics[0] .select(&selector("span")) .next() .map(|span| span.text().collect::()), Some("template source of truth".to_owned()) ); assert!(document .select(&selector(".metrics .metric strong")) .any(|strong| strong.text().collect::() == "∞")); } // req: html_safety/002 req: view/001 req: test/005 #[test] fn architecture_board_is_rendered_by_a_hemplate_view() { let html = architecture_board(); let document = Html::parse_fragment(html.as_str()); let lanes = document.select(&selector(".lanes > section.lane")).collect::>(); assert_eq!(lanes.len(), 3); assert_eq!( lanes[0] .select(&selector("h3")) .next() .map(|heading| heading.text().collect::()), Some("hemplate".to_owned()) ); assert!(lanes.iter().any(|lane| { lane.select(&selector("p")) .next() .map(|paragraph| paragraph.text().collect::()) .is_some_and(|text| text.contains("EffectBatch ops")) })); } }