graph functionality

This commit is contained in:
2026-08-15 00:51:51 +02:00
parent caa16a0ce8
commit b3afd64769
6 changed files with 79 additions and 9 deletions
+34
View File
@@ -1014,3 +1014,37 @@ body.editor-mode .editor-metadata-row {
fill: #1e2f6d;
stroke: #1e2f6d;
}
/* 0.2.15 context navigation and sticky-anchor correction ---------------- */
.context-link {
color: var(--wiki-link);
font-size: .76rem;
font-weight: 400;
letter-spacing: normal;
text-transform: none;
text-decoration: none;
}
.context-link:hover {
text-decoration: underline;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
scroll-margin-top: 82px;
}
.wiki-graph-node-focus circle {
r: 15px;
fill: #1e2f6d;
stroke: #1e2f6d;
}
.wiki-graph-node-focus text {
font-weight: 700;
}
+2 -2
View File
@@ -22,7 +22,7 @@
<input id="search-input" type="search" placeholder="Search wiki" data-tr-placeholder="search-wiki" autocomplete="off" aria-label="Search wiki">
</form>
<section class="sidebar-section toc-section">
<div class="sidebar-heading" data-tr="contents">Contents</div>
<div class="sidebar-heading"><span data-tr="contents">Contents</span> <a id="context-link" class="context-link hidden" href="#">(<span data-tr="context">context</span>)</a></div>
<nav id="toc-list" class="toc-list"></nav>
</section>
<details class="sidebar-section pages-section">
@@ -110,7 +110,7 @@
<section id="graph-view" class="hidden">
<header class="page-header">
<h1 data-tr="wiki-graph">Wiki graph</h1>
<h1 id="graph-title" data-tr="wiki-graph">Wiki graph</h1>
<div id="graph-summary" class="muted"></div>
</header>
<div class="wiki-graph-shell">
+38 -2
View File
@@ -23,6 +23,7 @@
$(id).classList.toggle("hidden", id !== viewId);
}
$("page-action-links").classList.toggle("hidden", viewId !== "page-view");
$("context-link").classList.toggle("hidden", !(state.currentPage && ["page-view", "editor-view", "history-view"].includes(viewId)));
document.body.classList.toggle("editor-mode", viewId === "editor-view");
}
@@ -1182,7 +1183,7 @@
return { nodes: state.pages, edges };
}
function renderWikiGraph(data) {
function renderWikiGraph(data, focusSlug = null) {
const svg = $("wiki-graph");
svg.replaceChildren();
@@ -1222,7 +1223,7 @@
for (const page of nodes) {
const position = positions.get(page.slug);
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
group.setAttribute("class", "wiki-graph-node");
group.setAttribute("class", page.slug === focusSlug ? "wiki-graph-node wiki-graph-node-focus" : "wiki-graph-node");
group.setAttribute("transform", `translate(${position.x} ${position.y})`);
group.setAttribute("tabindex", "0");
group.setAttribute("role", "link");
@@ -1259,6 +1260,7 @@
]);
renderToc([], () => {});
show("graph-view");
$("graph-title").textContent = tr("wiki-graph", "Wiki graph");
const data = await loadGraphData();
$("graph-summary").textContent = tr("graph-summary", "{pages} pages, {links} links")
@@ -1267,6 +1269,39 @@
renderWikiGraph(data);
}
async function showContextGraph() {
if (!state.currentPage) return;
const page = state.currentPage;
state.previousView = "page-view";
renderBreadcrumbs([
{ label: state.siteTitle, href: "/" },
{ label: page.title, href: `#/${encodeURIComponent(page.slug)}` },
{ label: tr("context", "context") }
]);
renderToc([], () => {});
show("graph-view");
$("graph-title").textContent = tr("context-graph", "Context graph");
const data = await loadGraphData();
const relatedSlugs = new Set([page.slug]);
const contextEdges = [];
for (const edge of data.edges) {
if (edge.from === page.slug || edge.to === page.slug) {
relatedSlugs.add(edge.from);
relatedSlugs.add(edge.to);
contextEdges.push(edge);
}
}
const contextNodes = data.nodes.filter((node) => relatedSlugs.has(node.slug));
$("graph-summary").textContent = tr("context-graph-summary", "{pages} related pages, {links} links")
.replace("{pages}", String(Math.max(0, contextNodes.length - 1)))
.replace("{links}", String(contextEdges.length));
renderWikiGraph({ nodes: contextNodes, edges: contextEdges }, page.slug);
}
function setConnectionStatus(status) {
const node = $("connection-status");
node.classList.remove("hidden", "online", "offline");
@@ -1339,6 +1374,7 @@
});
$("todo-link").addEventListener("click", (event) => { event.preventDefault(); showTodos().catch((error) => console.error(error)); });
$("graph-link").addEventListener("click", (event) => { event.preventDefault(); showGraph().catch((error) => console.error(error)); });
$("context-link").addEventListener("click", (event) => { event.preventDefault(); showContextGraph().catch((error) => console.error(error)); });
$("logout-link").addEventListener("click", async (event) => {
event.preventDefault();
await api("/api/logout", { method: "POST", body: "{}" });