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
+2 -2
View File
@@ -341,6 +341,6 @@ The special translations page is now one page named `wiki-translations`. It is p
Version 0.2.13 centers the wiki name in the sidebar and makes it a link to the first/start page. The sticky top chrome now starts without top padding (`padding-top: 0`).
## Version 0.2.14
## 0.2.15
Version 0.2.14 fixes the wiki-name/home navigation so clicking the wiki name, including while a special view such as Todo is open, always returns to the first/start page. It also adds a lightweight Wiki Graph view. The graph uses the existing pages and their internal Markdown links, requires no extra JavaScript dependency or database migration, and opens a page when its node is selected.
The page table of contents now includes a `(context)` link. It opens a graph containing the current page and all pages that link directly to it or are linked directly from it. The current page is highlighted. Heading anchors also reserve space for the sticky top navigation so a selected heading remains visible.
+1 -1
View File
@@ -1,7 +1,7 @@
#lang info
(define pkg-authors '(hnmdijkema))
(define version "0.2.14")
(define version "0.2.15")
(define license 'MIT)
(define collection "racket-wiki")
(define pkg-desc
+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: "{}" });
+2 -2
View File
@@ -16,7 +16,7 @@
(define english
(hash
'users "Users" 'translations "Translations" 'todo "Todo" 'todo-list "Todo list" 'graph "Graph" 'wiki-graph "Wiki graph" 'graph-summary "{pages} pages, {links} links" 'admin "Admin" 'role-reader "reader" 'role-editor "editor" 'role-admin "admin"
'users "Users" 'translations "Translations" 'todo "Todo" 'todo-list "Todo list" 'graph "Graph" 'wiki-graph "Wiki graph" 'graph-summary "{pages} pages, {links} links" 'context "context" 'context-graph "Context graph" 'context-graph-summary "{pages} related pages, {links} links" 'admin "Admin" 'role-reader "reader" 'role-editor "editor" 'role-admin "admin"
'search-wiki "Search wiki" 'contents "Contents" 'pages "Pages"
'edit "Edit" 'history "History" 'delete "Delete" 'page-not-found "Page not found"
'cancel "Cancel" 'save "Save" 'page-title "Page title" 'tags "Tags (comma separated)"
@@ -49,7 +49,7 @@
(define dutch
(hash
'users "Gebruikers" 'translations "Vertalingen" 'todo "Todo" 'todo-list "Todo-lijst" 'graph "Graph" 'wiki-graph "Wiki-graaf" 'graph-summary "{pages} pagina's, {links} links" 'admin "Admin" 'role-reader "lezer" 'role-editor "redacteur" 'role-admin "admin"
'users "Gebruikers" 'translations "Vertalingen" 'todo "Todo" 'todo-list "Todo-lijst" 'graph "Graph" 'wiki-graph "Wiki-graaf" 'graph-summary "{pages} pagina's, {links} links" 'context "context" 'context-graph "Contextgraaf" 'context-graph-summary "{pages} gerelateerde pagina's, {links} links" 'admin "Admin" 'role-reader "lezer" 'role-editor "redacteur" 'role-admin "admin"
'search-wiki "Wiki doorzoeken" 'contents "Inhoud" 'pages "Pagina's"
'edit "Bewerken" 'history "Geschiedenis" 'delete "Verwijderen" 'page-not-found "Pagina niet gevonden"
'cancel "Annuleren" 'save "Opslaan" 'page-title "Paginatitel" 'tags "Tags (komma-gescheiden)"