diff --git a/gen_viz.py b/gen_viz.py
index 41f37f8..b44d9b3 100644
--- a/gen_viz.py
+++ b/gen_viz.py
@@ -27,6 +27,12 @@ panel szczegółów renderuje `resource` jako klikalny odnośnik z
`target="_blank"` (viz.js:171-183) — to daje "klik otwiera URL w nowej
karcie" bez żadnej zmiany w viewerze.
+Węzły konceptów mają w `resource` ścieżkę do karty HTML w `pages/`
+(generowanej przez gen_pages.py) — ten sam mechanizm panelu szczegółów daje
+przejście z grafu do pełnej treści dokumentu. Jeśli koncept ma własne pole
+`resource` we frontmatterze, ląduje ono w danych węzła jako
+`resource_frontmatter`.
+
Skąd brane są adresy — cztery niezależne źródła, każde da się wyłączyć
osobno stałą `SOURCES`:
@@ -81,6 +87,9 @@ except ModuleNotFoundError as exc: # pragma: no cover
RESERVED = {"index.md", "log.md"}
+# Karty HTML konceptów generowane przez gen_pages.py.
+PAGES_DIRNAME = "pages"
+
# --- konfiguracja linków zewnętrznych ---------------------------------
SOURCES = ("md-link", "bare-url", "bare-domain", "frontmatter")
@@ -272,6 +281,33 @@ def _add_external(graph: dict, concepts: list) -> None:
graph["palette"] = {**graph.get("palette", {}), EXTERNAL_TYPE: EXTERNAL_COLOR}
+MISSING_PAGES: list[str] = []
+
+
+def _point_concepts_to_pages(graph: dict) -> None:
+ """Węzeł koncept → karta HTML w pages/.
+
+ Panel szczegółów renderuje `resource` jako klikalny odnośnik
+ (viz.js:171-183), więc ustawienie tam ścieżki karty daje przejście
+ z grafu do pełnej treści bez żadnej zmiany w viewerze. Ścieżka jest
+ względna wobec viz.html, czyli działa i lokalnie, i po deployu.
+
+ Wywoływane przed _add_external — na tym etapie w grafie są wyłącznie
+ węzły konceptów, więc URL-e węzłów external nie są nadpisywane.
+ """
+ for node in graph["nodes"]:
+ data = node["data"]
+ original = data.get("resource") or ""
+ if original:
+ # Koncept miał własny `resource` we frontmatterze — nie gubimy go,
+ # tylko przenosimy obok; `resource` węzła wskazuje kartę.
+ data["resource_frontmatter"] = original
+ page = f"{PAGES_DIRNAME}/{data['id']}.html"
+ data["resource"] = page
+ if not (BUNDLE_ROOT / page).is_file():
+ MISSING_PAGES.append(page)
+
+
# --- jedyna ingerencja w viewer ---------------------------------------
#
# Kolor węzła jest sterowany danymi ("background-color": "data(color)"),
@@ -358,8 +394,9 @@ def _walk_concepts(bundle_root: Path):
def _build_graph(concepts: list) -> dict:
- """Upstream + węzły/krawędzie linków zewnętrznych."""
+ """Upstream + karty HTML konceptów + węzły/krawędzie linków zewnętrznych."""
graph = _upstream_build_graph(concepts)
+ _point_concepts_to_pages(graph)
_add_external(graph, concepts)
return graph
@@ -380,6 +417,12 @@ def main() -> int:
f" węzły: {stats['concepts']} konceptów + {external} external, "
f"krawędzie: {stats['edges']}, rozmiar: {stats['bytes'] / 1024:.1f} KiB"
)
+ print(f" koncepty linkują do kart w {PAGES_DIRNAME}/ (pole resource)")
+ if MISSING_PAGES:
+ print(
+ f" UWAGA: brakuje {len(MISSING_PAGES)} kart — uruchom "
+ f"gen_pages.py: {', '.join(MISSING_PAGES)}"
+ )
print()
print(f"Linki zewnętrzne, które weszły do grafu ({external}):")
for url, origins, sources in REPORT["kept"]:
diff --git a/viz.html b/viz.html
index 414de22..12908a2 100644
--- a/viz.html
+++ b/viz.html
@@ -226,7 +226,7 @@ hr { border: none; border-top: 1px solid #e2e8f0; margin: 14px 0; }