From cb5d83b1f7b4510452c1b72a34282b6aa567300d Mon Sep 17 00:00:00 2001 From: Sergio Date: Sat, 23 May 2026 14:40:35 +0000 Subject: [PATCH] gioser-web: integrate gioser-graph-web widget below page content - Add gioser-graph-web dependency to gioser-web - After markdown loads, mount SVG semantic graph below content - Graph fetches from api.gioser.net/graph endpoint - Uses Qdrant k-NN edges, colored by camino - Callback navigation placeholder (will be wired in next commit) --- crates/apps/gioser-web/Cargo.toml | 1 + crates/apps/gioser-web/src/lib.rs | 62 ++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/crates/apps/gioser-web/Cargo.toml b/crates/apps/gioser-web/Cargo.toml index c9d0cf6..d537ae2 100644 --- a/crates/apps/gioser-web/Cargo.toml +++ b/crates/apps/gioser-web/Cargo.toml @@ -14,6 +14,7 @@ gioser-canvas-web = { path = "../../modules/gioser/gioser-canvas-web" } fana-md-reader-web = { path = "../../modules/fana/fana-md-reader-web" } revista-web = { path = "../../modules/revista/revista-web" } barra-web = { path = "../../modules/barra/barra-web" } +gioser-graph-web = { path = "../../modules/gioser/gioser-graph-web" } wasm-bindgen.workspace = true wasm-bindgen-futures.workspace = true js-sys.workspace = true diff --git a/crates/apps/gioser-web/src/lib.rs b/crates/apps/gioser-web/src/lib.rs index 9a22053..8382c01 100644 --- a/crates/apps/gioser-web/src/lib.rs +++ b/crates/apps/gioser-web/src/lib.rs @@ -21,6 +21,7 @@ use std::rc::Rc; use barra_web::{Task, TaskList}; use gioser_canvas_web::{tips, Renderer}; +use gioser_graph_web::GraphWidget; use fana_md_reader_web::Reader; use revista_web::Deck; use wasm_bindgen::prelude::*; @@ -272,13 +273,53 @@ impl AppState { if inner.contains("pluma-doc") { return; // ya hidratado } - let reader = Reader::new(content); + let document_clone = self.document.clone(); let element_owned = element.to_string(); let url_owned = md_url.to_string(); wasm_bindgen_futures::spawn_local(async move { + let content_clone = content.clone(); if let Err(e) = reader.open_url(&url_owned, &element_owned).await { web_sys::console::warn_1(&e); } + // Después de cargar el md, montar el grafo debajo + let graph_container_id = format!("graph-{}-container", element_owned); + // Si ya existe, no lo duplicamos + if document_clone.get_element_by_id(&graph_container_id).is_some() { + return; + } + // Crear contenedor debajo del content + let wrapper: HtmlElement = document_clone + .create_element("div") + .ok() + .and_then(|e| e.dyn_into::().ok()) + .unwrap(); + wrapper.set_id(&graph_container_id); + wrapper.style().set_property("margin-top", "1rem").ok(); + wrapper.style().set_property("padding-top", "1rem").ok(); + wrapper.style().set_property("border-top", "1px solid rgba(255,255,255,0.08)").ok(); + // Label + let label: HtmlElement = document_clone + .create_element("div") + .ok() + .and_then(|e| e.dyn_into::().ok()) + .unwrap(); + label.set_inner_html( + " + · grafo semántico · + " + ); + wrapper.append_child(&label).ok(); + content_clone.append_child(&wrapper).ok(); + // Cargar el grafo + let mut graph = GraphWidget::new( + wrapper, + "https://api.gioser.net", + None, // callback simplificado por ahora + ); + if let Err(e) = graph.load().await { + web_sys::console::warn_1(&format!("grafo: error al cargar: {:?}", e)); + } }); } @@ -639,6 +680,25 @@ fn position_tips(document: &Document, canvas: &HtmlCanvasElement, renderer: &Ren } } +/// Mapea un doc_id de Qdrant al nombre del elemento (aire/fuego/tierra/agua) +/// y su ruta md. Los doc_ids se generan con uuid5 en el indexador, pero +/// podemos inferir por el nombre del camino o del elemento. +fn map_doc_id_to_element(doc_id: &str) -> (String, String) { + // Inferir del doc_id: contiene el nombre del elemento + let el = if doc_id.contains("aire") || doc_id.contains("logos") { + "aire" + } else if doc_id.contains("fuego") || doc_id.contains("nomos") { + "fuego" + } else if doc_id.contains("tierra") || doc_id.contains("kay") { + "tierra" + } else if doc_id.contains("agua") || doc_id.contains("uku") { + "agua" + } else { + "aire" + }; + (el.to_string(), format!("./md/{}.md", el)) +} + fn install_panic_hook() { static SET: std::sync::Once = std::sync::Once::new(); SET.call_once(|| {