feat(techdemo): add opaque island bridge
Add a canvas leaf-widget island to the techdemo that receives server snapshots through Effect::event/CustomEvent while keeping slhx core and runtime semantics unchanged. req: interop/001 req: examples/001 req: examples/005
This commit is contained in:
@@ -133,6 +133,7 @@ struct ControlCenter {
|
||||
board: SafeHtml,
|
||||
inspector: SafeHtml,
|
||||
activity: SafeHtml,
|
||||
island_snapshot: String,
|
||||
}
|
||||
|
||||
#[derive(Hemplate)]
|
||||
@@ -207,6 +208,7 @@ async fn main() {
|
||||
.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")
|
||||
@@ -234,6 +236,7 @@ async fn architecture(request: PageRequest) -> impl IntoResponse {
|
||||
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)
|
||||
@@ -253,6 +256,10 @@ 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<Arc<Shared>>,
|
||||
form: InteractionForm,
|
||||
@@ -383,6 +390,7 @@ fn registry(shared: Arc<Shared>) -> HandlerRegistry {
|
||||
}),
|
||||
ui::control_center::slots::activity.render(&activity_view(&demo)),
|
||||
ui::control_center::slots::notice.text("Push simulated · no client app code"),
|
||||
slhx::event("slhx:island-orbit", island_snapshot(&demo)),
|
||||
)
|
||||
}
|
||||
})
|
||||
@@ -413,6 +421,7 @@ fn demo_effects(demo: &DemoState, notice: &'static str) -> impl IntoEffect {
|
||||
ui::control_center::slots::inspector.render(&inspector_view(demo)),
|
||||
ui::control_center::slots::notice.text(notice),
|
||||
ui::control_center::forms::launch_work.clear("title"),
|
||||
slhx::event("slhx:island-orbit", island_snapshot(demo)),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -421,6 +430,23 @@ fn parse_lane(value: Option<&str>) -> usize {
|
||||
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
|
||||
@@ -429,6 +455,7 @@ fn page_html(demo: &DemoState) -> String {
|
||||
board: render_board(demo),
|
||||
inspector: render_inspector(demo),
|
||||
activity: render_activity(demo),
|
||||
island_snapshot: island_snapshot(demo),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user