From dbc897370c8be6c12d55e06c1bac603ed704f324 Mon Sep 17 00:00:00 2001 From: Zaine Date: Fri, 8 May 2026 12:28:07 +0100 Subject: [PATCH] adding sitemap style --- .../blogs/2026-05-08-time-to-100m-pic.webp | Bin authoring_server.py | 130 ++++++++++++++++-- posts/posts-list.org | 2 +- 3 files changed, 119 insertions(+), 13 deletions(-) mode change 100644 => 100755 assets/images/blogs/2026-05-08-time-to-100m-pic.webp diff --git a/assets/images/blogs/2026-05-08-time-to-100m-pic.webp b/assets/images/blogs/2026-05-08-time-to-100m-pic.webp old mode 100644 new mode 100755 diff --git a/authoring_server.py b/authoring_server.py index c184ae8..56d6282 100755 --- a/authoring_server.py +++ b/authoring_server.py @@ -704,7 +704,7 @@ APP_HTML = r""" button { border: 1px solid var(--line); background: #fff; color: var(--ink); min-height: 38px; padding: 0 12px; border-radius: 6px; cursor: pointer; } button.primary { background: var(--accent); color: white; border-color: var(--accent); } button.icon { min-width: 38px; padding: 0 10px; font-weight: 700; } - .app { min-height: 100vh; display: grid; grid-template-columns: minmax(260px, 360px) 1fr; } + .app { min-height: 100vh; display: grid; grid-template-columns: minmax(300px, 420px) 1fr; } aside { border-right: 1px solid var(--line); background: #eee8dc; padding: 18px; overflow: auto; max-height: 100vh; } main { padding: 20px clamp(18px, 3vw, 42px); overflow: auto; max-height: 100vh; } .topbar { display: flex; align-items: center; gap: 10px; justify-content: space-between; margin-bottom: 16px; } @@ -716,10 +716,23 @@ APP_HTML = r""" .status.fail { border-color: #a12a2a; } .quick-link { display: inline-block; color: var(--accent); font-size: 13px; margin: -6px 0 14px; } .filters { display: grid; gap: 8px; margin-bottom: 14px; } - .page-list { display: grid; gap: 7px; } - .page-item { width: 100%; text-align: left; min-height: auto; padding: 9px 10px; background: var(--panel); } + .page-list { display: grid; gap: 3px; } + .tree-dir { margin: 1px 0; } + .tree-dir summary { list-style: none; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 8px; align-items: center; min-height: 34px; padding: 6px 8px; border-radius: 6px; cursor: pointer; color: var(--ink); } + .tree-dir summary::-webkit-details-marker { display: none; } + .tree-dir summary:hover, .page-item:hover { background: rgba(255, 253, 248, 0.78); } + .tree-dir summary::before { content: ">"; display: inline-block; width: 14px; color: var(--muted); } + .tree-dir[open] > summary::before { content: "v"; } + .tree-label { display: flex; align-items: baseline; gap: 6px; min-width: 0; } + .tree-label strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; } + .tree-label span { color: var(--muted); font-size: 12px; white-space: nowrap; } + .tree-children { display: grid; gap: 2px; margin-left: 15px; padding-left: 10px; border-left: 1px solid var(--line); } + .tree-add { min-height: 28px; padding: 0 8px; font-size: 12px; color: var(--accent); background: transparent; } + .page-item { width: 100%; text-align: left; min-height: auto; padding: 8px 10px; background: transparent; } + .page-item.active { border-color: var(--accent); background: var(--panel); } .page-item strong { display: block; font-size: 14px; margin-bottom: 2px; overflow-wrap: anywhere; } .page-item span { display: block; color: var(--muted); font-size: 12px; overflow-wrap: anywhere; } + .page-item .filename { color: var(--ink); } form { display: grid; gap: 14px; } .grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; } .toolbar { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; border: 1px solid var(--line); background: var(--panel); border-radius: 6px; padding: 7px; } @@ -924,21 +937,113 @@ APP_HTML = r""" const matches = state.pages .filter((page) => (!type || page.pageType === type)) .filter((page) => `${page.title} ${page.path} ${page.tags.join(" ")}`.toLowerCase().includes(query)) - .slice(0, 120); + .sort((a, b) => a.path.localeCompare(b.path)); if (!matches.length) { pagesBox.innerHTML = `
No files matched.
`; + renderStatus(); + return; } - matches.forEach((page) => { - const btn = document.createElement("button"); - btn.type = "button"; - btn.className = "page-item"; - btn.innerHTML = `${html(page.title)}${html(page.path)}${page.tags.map((tag) => `${html(tag)}`).join("")}`; - btn.onclick = () => loadPage(page.path); - pagesBox.appendChild(btn); - }); + const tree = buildPageTree(matches); + renderTree(tree, pagesBox, query !== ""); renderStatus(); } + function buildPageTree(pages) { + const root = { dirs: new Map(), pages: [], path: "" }; + pages.forEach((page) => { + const parts = page.path.split("/"); + const filename = parts.pop(); + let node = root; + let dirPath = ""; + parts.forEach((part) => { + dirPath = dirPath ? `${dirPath}/${part}` : part; + if (!node.dirs.has(part)) node.dirs.set(part, { dirs: new Map(), pages: [], path: dirPath }); + node = node.dirs.get(part); + }); + node.pages.push({ ...page, filename }); + }); + return root; + } + + function renderTree(node, container, expandAll = false) { + [...node.dirs.entries()] + .sort(([a], [b]) => a.localeCompare(b)) + .forEach(([name, child]) => container.appendChild(renderDirectory(name, child, expandAll))); + node.pages + .sort((a, b) => a.filename.localeCompare(b.filename)) + .forEach((page) => container.appendChild(renderPageButton(page))); + } + + function renderDirectory(name, node, expandAll) { + const details = document.createElement("details"); + details.className = "tree-dir"; + details.open = expandAll || node.path.split("/").length <= 2 || containsCurrentPath(node); + + const summary = document.createElement("summary"); + const label = document.createElement("span"); + label.className = "tree-label"; + label.innerHTML = `${html(name)}${countPages(node)} files`; + const add = document.createElement("button"); + add.type = "button"; + add.className = "tree-add"; + add.textContent = "New"; + add.title = `New file in ${node.path}`; + add.onclick = (event) => { + event.preventDefault(); + event.stopPropagation(); + newPageInDirectory(node.path); + }; + summary.append(label, add); + + const children = document.createElement("div"); + children.className = "tree-children"; + renderTree(node, children, expandAll); + details.append(summary, children); + return details; + } + + function renderPageButton(page) { + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = `page-item${page.path === state.currentPath ? " active" : ""}`; + btn.innerHTML = `${html(page.title)}${html(page.filename || page.path)}${html(page.path)}${page.tags.length ? `${page.tags.map((tag) => `${html(tag)}`).join("")}` : ""}`; + btn.onclick = () => loadPage(page.path); + return btn; + } + + function countPages(node) { + let count = node.pages.length; + node.dirs.forEach((child) => { count += countPages(child); }); + return count; + } + + function containsCurrentPath(node) { + return Boolean(state.currentPath && (state.currentPath.startsWith(`${node.path}/`) || node.pages.some((page) => page.path === state.currentPath))); + } + + function newPageInDirectory(dirPath) { + const pageType = pageTypeForDirectory(dirPath); + setForm({ pageType, date: currentOrgDate(), comments: true }); + editor.section.value = pageType === "post" ? postSectionForDirectory(dirPath) : ""; + editor.targetPath.value = `${dirPath}/`; + state.pathManual = true; + updateEditorMode(); + saveMessage.textContent = `New file will be created in ${dirPath}.`; + editor.title.focus(); + } + + function pageTypeForDirectory(dirPath) { + if (dirPath === "lima" || dirPath.startsWith("lima/")) return "lima"; + if (dirPath === "posts" || dirPath.startsWith("posts/")) return "post"; + if (dirPath === "blogs" || dirPath.startsWith("blogs/")) return "blog"; + return "page"; + } + + function postSectionForDirectory(dirPath) { + if (!dirPath.startsWith("posts/")) return ""; + return dirPath.slice("posts/".length); + } + function html(value) { return String(value).replace(/[&<>"']/g, (char) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[char])); } @@ -1034,6 +1139,7 @@ APP_HTML = r""" updateEditorMode(); updateSuggestedPath(); updateMarkdownPreview(); + if (state.pages.length) renderPages(); saveMessage.textContent = ""; } diff --git a/posts/posts-list.org b/posts/posts-list.org index c2a545b..1456f82 100755 --- a/posts/posts-list.org +++ b/posts/posts-list.org @@ -4,7 +4,7 @@ See the categories: @@html:Categories@@ * Posts: -- [[file:career/career-list.org][Career List]] @@html:08-05-2026 12:09@@ +- [[file:career/career-list.org][Career List]] @@html:08-05-2026 12:27@@ - [[file:posts-list.sync-conflict-20260417-233432-VT6366A.org][Posts List]] @@html:14-04-2026 16:36@@ - [[file:career/ha-dr.org][High Availability, Disaster Recovery and Business Continuity]] @@html:11-03-2026 17:18@@ @@html:@@ @@html:@@ - [[file:career/javascript.org][Understands the Javascript language]] @@html:11-03-2026 16:52@@ @@html:@@ @@html:@@