Wiki — Category / Portal Page
A dense, library-catalog category portal for a fictional distributed-systems wiki, built in a clean white knowledge-base palette. A header carries the category name, a serif description and live article counts, followed by a sticky A–Z jump bar, encyclopedic pages grouped under multi-column letter headings, a subcategory tile grid and a featured-article highlight card. The A–Z bar smooth-scrolls to letter groups, a search box live-filters every list, and a list/grid density toggle reflows the catalog. Inter, Source Serif 4, JetBrains Mono and vanilla JS only.
MCP
Codice
:root {
--bg: #ffffff;
--bg-2: #f7f8fa;
--panel: #ffffff;
--ink: #1a1a1f;
--ink-2: #3a3a42;
--muted: #6b7280;
--line: rgba(20, 20, 30, 0.10);
--line-2: rgba(20, 20, 30, 0.18);
--link: #2563eb;
--link-hover: #1d4ed8;
--accent: #2563eb;
--note: #2563eb;
--tip: #16a34a;
--warn: #d97706;
--danger: #dc2626;
--code-bg: #f4f4f6;
--kbd-bg: #eceef2;
--r-sm: 6px;
--r-md: 10px;
--r-lg: 14px;
--sans: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
--serif: "Source Serif 4", Georgia, "Times New Roman", serif;
--mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
--sidebar-w: 244px;
--shadow-sm: 0 1px 2px rgba(20, 20, 30, 0.06);
--shadow-md: 0 6px 22px rgba(20, 20, 30, 0.08);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font-family: var(--sans);
font-size: 15px;
line-height: 1.55;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
a { color: var(--link); text-decoration: none; }
a:hover { color: var(--link-hover); text-decoration: underline; }
:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
border-radius: var(--r-sm);
}
.skip-link {
position: absolute;
left: -999px;
top: 8px;
background: var(--ink);
color: #fff;
padding: 8px 14px;
border-radius: var(--r-sm);
z-index: 60;
}
.skip-link:focus { left: 12px; }
/* ---------- Topbar ---------- */
.topbar {
position: sticky;
top: 0;
z-index: 40;
display: flex;
align-items: center;
gap: 16px;
height: 56px;
padding: 0 18px;
background: rgba(255, 255, 255, 0.92);
backdrop-filter: saturate(1.4) blur(8px);
border-bottom: 1px solid var(--line);
}
.nav-toggle {
display: none;
flex-direction: column;
justify-content: center;
gap: 4px;
width: 38px;
height: 38px;
padding: 0 9px;
background: var(--bg-2);
border: 1px solid var(--line);
border-radius: var(--r-sm);
cursor: pointer;
}
.nav-toggle span {
display: block;
height: 2px;
background: var(--ink-2);
border-radius: 2px;
}
.brand {
display: flex;
align-items: center;
gap: 8px;
font-weight: 800;
font-size: 17px;
letter-spacing: -0.01em;
color: var(--ink);
}
.brand:hover { text-decoration: none; }
.brand-mark { color: var(--accent); font-size: 14px; }
.brand-dim { color: var(--muted); font-weight: 600; }
.topbar-search {
position: relative;
flex: 1;
max-width: 460px;
margin-left: auto;
}
.topbar-search input {
width: 100%;
height: 38px;
padding: 0 40px 0 14px;
font: inherit;
font-size: 14px;
color: var(--ink);
background: var(--bg-2);
border: 1px solid var(--line);
border-radius: 999px;
}
.topbar-search input:focus {
background: #fff;
border-color: var(--accent);
outline: none;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.14);
}
.topbar-search kbd {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
}
.topbar-links {
display: flex;
gap: 18px;
font-size: 14px;
font-weight: 500;
}
.topbar-links a { color: var(--ink-2); }
kbd {
font-family: var(--mono);
font-size: 11px;
line-height: 1;
padding: 3px 6px;
color: var(--ink-2);
background: var(--kbd-bg);
border: 1px solid var(--line-2);
border-bottom-width: 2px;
border-radius: var(--r-sm);
}
/* ---------- Layout ---------- */
.layout {
display: grid;
grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
max-width: 1320px;
margin: 0 auto;
}
.sidebar {
position: sticky;
top: 56px;
align-self: start;
height: calc(100vh - 56px);
overflow-y: auto;
padding: 22px 16px 40px;
border-right: 1px solid var(--line);
background: var(--bg);
}
.side-head {
margin: 18px 8px 6px;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
}
.side-head:first-child { margin-top: 0; }
.side-list { list-style: none; margin: 0; padding: 0; }
.side-list a {
display: block;
padding: 6px 10px;
border-radius: var(--r-sm);
font-size: 14px;
color: var(--ink-2);
}
.side-list a:hover { background: var(--bg-2); color: var(--ink); text-decoration: none; }
.side-list a[aria-current="page"] {
background: rgba(37, 99, 235, 0.10);
color: var(--link);
font-weight: 600;
}
.sidebar-scrim {
position: fixed;
inset: 0;
z-index: 30;
background: rgba(20, 20, 30, 0.4);
}
/* ---------- Content ---------- */
.content {
min-width: 0;
padding: 26px clamp(18px, 4vw, 56px) 80px;
}
.breadcrumb {
display: flex;
flex-wrap: wrap;
gap: 7px;
align-items: center;
font-size: 13px;
color: var(--muted);
margin-bottom: 18px;
}
.breadcrumb a { color: var(--ink-2); }
.breadcrumb [aria-current="page"] { color: var(--ink); font-weight: 600; }
.cat-header {
padding-bottom: 22px;
border-bottom: 1px solid var(--line);
margin-bottom: 30px;
}
.cat-kicker {
margin: 0 0 6px;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--accent);
}
.cat-title {
margin: 0 0 12px;
font-size: clamp(28px, 4vw, 40px);
font-weight: 800;
letter-spacing: -0.02em;
line-height: 1.1;
}
.cat-desc {
max-width: 720px;
margin: 0 0 18px;
font-family: var(--serif);
font-size: 17px;
line-height: 1.65;
color: var(--ink-2);
}
.cat-stats {
display: flex;
flex-wrap: wrap;
gap: 10px 24px;
list-style: none;
margin: 0;
padding: 0;
font-size: 13px;
color: var(--muted);
}
.cat-stats strong { color: var(--ink); font-weight: 700; }
.section-eyebrow {
margin: 0 0 14px;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
}
/* ---------- Featured ---------- */
.featured { margin-bottom: 38px; }
.featured-card {
display: grid;
grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
gap: 0;
background: linear-gradient(180deg, #fff, var(--bg-2));
border: 1px solid var(--line);
border-radius: var(--r-lg);
overflow: hidden;
box-shadow: var(--shadow-sm);
}
.featured-body { padding: 24px 26px; }
.badge {
display: inline-block;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.04em;
padding: 3px 9px;
border-radius: 999px;
}
.badge-star {
color: var(--warn);
background: rgba(217, 119, 6, 0.12);
border: 1px solid rgba(217, 119, 6, 0.25);
}
.featured-body h2 {
margin: 12px 0 10px;
font-size: 24px;
font-weight: 800;
letter-spacing: -0.01em;
}
.featured-body p {
margin: 0 0 12px;
max-width: 56ch;
font-family: var(--serif);
font-size: 16px;
line-height: 1.65;
color: var(--ink-2);
}
.featured-meta {
display: flex;
flex-wrap: wrap;
gap: 8px;
font-family: var(--sans) !important;
font-size: 12.5px !important;
color: var(--muted) !important;
}
.featured-link { font-weight: 600; }
.featured-aside {
display: flex;
align-items: stretch;
padding: 0;
background: #f3f4f8;
border-left: 1px solid var(--line);
}
.featured-aside pre {
margin: 0;
width: 100%;
padding: 20px;
overflow: auto;
}
.featured-aside code {
font-family: var(--mono);
font-size: 12.5px;
line-height: 1.7;
color: var(--ink-2);
white-space: pre;
}
/* ---------- Subcategories ---------- */
.subcats { margin-bottom: 38px; }
.subcat-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
gap: 12px;
}
.subcat {
display: flex;
flex-direction: column;
gap: 4px;
padding: 14px 16px;
background: var(--panel);
border: 1px solid var(--line);
border-radius: var(--r-md);
transition: border-color 0.14s ease, transform 0.14s ease, box-shadow 0.14s ease;
}
.subcat:hover {
text-decoration: none;
border-color: var(--line-2);
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.subcat-icon {
font-size: 18px;
color: var(--accent);
}
.subcat-name { font-weight: 600; color: var(--ink); }
.subcat-count { font-size: 12.5px; color: var(--muted); }
/* ---------- Articles ---------- */
.articles-bar {
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: space-between;
gap: 12px;
margin-bottom: 14px;
}
.articles-controls {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
}
.filter-box {
position: relative;
display: flex;
align-items: center;
gap: 8px;
}
.filter-box input {
height: 36px;
width: 220px;
max-width: 50vw;
padding: 0 12px;
font: inherit;
font-size: 14px;
background: var(--bg-2);
border: 1px solid var(--line);
border-radius: var(--r-sm);
color: var(--ink);
}
.filter-box input:focus {
background: #fff;
border-color: var(--accent);
outline: none;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.14);
}
.filter-count { font-size: 12.5px; color: var(--muted); }
.density-toggle {
display: inline-flex;
padding: 3px;
background: var(--bg-2);
border: 1px solid var(--line);
border-radius: var(--r-sm);
}
.density-toggle button {
font: inherit;
font-size: 13px;
font-weight: 600;
padding: 5px 12px;
border: none;
background: transparent;
color: var(--ink-2);
border-radius: 4px;
cursor: pointer;
}
.density-toggle button.is-active {
background: #fff;
color: var(--ink);
box-shadow: var(--shadow-sm);
}
/* A–Z bar */
.az-bar {
display: flex;
flex-wrap: wrap;
gap: 4px;
padding: 10px 12px;
margin-bottom: 24px;
background: var(--bg-2);
border: 1px solid var(--line);
border-radius: var(--r-md);
position: sticky;
top: 56px;
z-index: 20;
}
.az-bar button {
font-family: var(--mono);
font-size: 12.5px;
font-weight: 500;
width: 28px;
height: 28px;
display: inline-flex;
align-items: center;
justify-content: center;
border: 1px solid transparent;
background: transparent;
color: var(--ink-2);
border-radius: var(--r-sm);
cursor: pointer;
transition: background 0.12s ease, color 0.12s ease;
}
.az-bar button:hover:not(:disabled) {
background: #fff;
border-color: var(--line);
color: var(--link);
}
.az-bar button.is-active {
background: var(--accent);
border-color: var(--accent);
color: #fff;
}
.az-bar button:disabled {
color: var(--line-2);
cursor: default;
}
/* Letter groups */
.article-groups { display: flex; flex-direction: column; gap: 30px; }
.letter-group { scroll-margin-top: 100px; }
.letter-group.is-hidden { display: none; }
.letter-head {
display: flex;
align-items: baseline;
gap: 10px;
margin: 0 0 12px;
padding-bottom: 6px;
border-bottom: 2px solid var(--line);
}
.letter-head .letter {
font-size: 22px;
font-weight: 800;
color: var(--accent);
font-family: var(--mono);
}
.letter-head .letter-meta { font-size: 12.5px; color: var(--muted); }
.article-list {
list-style: none;
margin: 0;
padding: 0;
columns: 3;
column-gap: 28px;
}
.article-list li {
break-inside: avoid;
margin-bottom: 4px;
}
.article-list li.is-hidden { display: none; }
.article-list a {
display: block;
padding: 4px 8px;
border-radius: var(--r-sm);
color: var(--link);
line-height: 1.5;
}
.article-list a:hover { background: var(--bg-2); text-decoration: none; }
.article-list .art-tag {
font-family: var(--mono);
font-size: 10.5px;
color: var(--muted);
margin-left: 6px;
}
/* Grid density view */
.article-groups.is-grid .article-list {
columns: auto;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 8px;
}
.article-groups.is-grid .article-list a {
border: 1px solid var(--line);
background: var(--panel);
padding: 10px 12px;
border-radius: var(--r-md);
font-weight: 500;
}
.article-groups.is-grid .article-list a:hover {
border-color: var(--line-2);
box-shadow: var(--shadow-sm);
}
.no-results {
padding: 28px;
text-align: center;
color: var(--muted);
font-size: 15px;
background: var(--bg-2);
border: 1px dashed var(--line-2);
border-radius: var(--r-md);
}
.cat-footer {
margin-top: 56px;
padding-top: 20px;
border-top: 1px solid var(--line);
font-size: 12.5px;
color: var(--muted);
}
/* ---------- Toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 26px;
transform: translateX(-50%) translateY(16px);
background: var(--ink);
color: #fff;
font-size: 13.5px;
font-weight: 500;
padding: 10px 18px;
border-radius: 999px;
box-shadow: var(--shadow-md);
opacity: 0;
pointer-events: none;
transition: opacity 0.22s ease, transform 0.22s ease;
z-index: 70;
}
.toast.is-show {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
/* ---------- Responsive ---------- */
@media (max-width: 1040px) {
.article-list { columns: 2; }
}
@media (max-width: 820px) {
.nav-toggle { display: flex; }
.layout { grid-template-columns: minmax(0, 1fr); }
.sidebar {
position: fixed;
top: 56px;
left: 0;
z-index: 35;
width: 280px;
max-width: 84vw;
height: calc(100vh - 56px);
transform: translateX(-102%);
transition: transform 0.22s ease;
box-shadow: var(--shadow-md);
}
.sidebar.is-open { transform: translateX(0); }
.topbar-links { display: none; }
.featured-card { grid-template-columns: minmax(0, 1fr); }
.featured-aside { border-left: none; border-top: 1px solid var(--line); }
}
@media (max-width: 520px) {
.topbar { gap: 10px; padding: 0 12px; }
.brand-name { display: none; }
.article-list, .article-groups.is-grid .article-list { columns: auto; display: block; }
.article-groups.is-grid .article-list { display: flex; flex-direction: column; }
.az-bar { position: static; }
.articles-bar { flex-direction: column; align-items: stretch; }
.filter-box input { width: 100%; max-width: none; }
}
@media (prefers-reduced-motion: reduce) {
* { scroll-behavior: auto !important; transition: none !important; }
}(function () {
"use strict";
/* ---------- Data: fictional but real-feeling distributed-systems articles ---------- */
var ARTICLES = [
{ t: "Aurora DB", tag: "system" },
{ t: "Acceptor Quorum", tag: "concept" },
{ t: "Anti-Entropy Repair", tag: "concept" },
{ t: "Append-Only Log", tag: "concept" },
{ t: "Bloom Filter Index", tag: "structure" },
{ t: "Byzantine Fault Tolerance", tag: "concept" },
{ t: "Backpressure Control", tag: "concept" },
{ t: "Bucket Sharding", tag: "concept" },
{ t: "CAP Theorem", tag: "theorem" },
{ t: "Causal Consistency", tag: "model" },
{ t: "Chandy–Lamport Snapshot", tag: "algorithm" },
{ t: "Consistent Hashing", tag: "algorithm" },
{ t: "Compaction Strategy", tag: "concept" },
{ t: "Distributed Lock", tag: "primitive" },
{ t: "Dynamo Replication", tag: "system" },
{ t: "Delta CRDT", tag: "structure" },
{ t: "Epoch Fencing", tag: "concept" },
{ t: "Eventual Consistency", tag: "model" },
{ t: "Exactly-Once Delivery", tag: "concept" },
{ t: "Failure Detector", tag: "primitive" },
{ t: "Flow-Control Window", tag: "concept" },
{ t: "Gossip Protocol", tag: "protocol" },
{ t: "Gray Failure", tag: "concept" },
{ t: "Hinted Handoff", tag: "concept" },
{ t: "Heartbeat Lease", tag: "primitive" },
{ t: "Idempotency Key", tag: "concept" },
{ t: "Invariant Confluence", tag: "theory" },
{ t: "Jepsen Test Harness", tag: "tooling" },
{ t: "Kafka Partition Log", tag: "system" },
{ t: "Lamport Timestamp", tag: "concept" },
{ t: "Leaderless Replication", tag: "concept" },
{ t: "Linearizability", tag: "model" },
{ t: "Log-Structured Merge Tree", tag: "structure" },
{ t: "Merkle Tree Sync", tag: "structure" },
{ t: "Multi-Paxos", tag: "algorithm" },
{ t: "Membership Protocol", tag: "protocol" },
{ t: "Network Partition", tag: "concept" },
{ t: "Nimbus Scheduler", tag: "system" },
{ t: "Optimistic Concurrency", tag: "concept" },
{ t: "Operation Transform", tag: "algorithm" },
{ t: "Paxos", tag: "algorithm" },
{ t: "Phi Accrual Detector", tag: "algorithm" },
{ t: "Primary-Backup Replication", tag: "concept" },
{ t: "Quorum Reads", tag: "concept" },
{ t: "Quiescent Consistency", tag: "model" },
{ t: "Raft Consensus", tag: "algorithm" },
{ t: "Read Repair", tag: "concept" },
{ t: "Replication Lag", tag: "concept" },
{ t: "Saga Pattern", tag: "pattern" },
{ t: "Sequential Consistency", tag: "model" },
{ t: "Split-Brain", tag: "concept" },
{ t: "State Machine Replication", tag: "concept" },
{ t: "Two-Phase Commit", tag: "protocol" },
{ t: "Tunable Consistency", tag: "concept" },
{ t: "Vector Clock", tag: "structure" },
{ t: "Verdant Stack", tag: "system" },
{ t: "View Synchrony", tag: "concept" },
{ t: "Write-Ahead Log", tag: "structure" },
{ t: "Witness Replica", tag: "concept" },
{ t: "Zab Protocol", tag: "protocol" },
{ t: "Zone-Aware Routing", tag: "concept" }
];
var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
var groupsEl = document.getElementById("articleGroups");
var azBar = document.getElementById("azBar");
var filterInput = document.getElementById("articleFilter");
var filterCount = document.getElementById("filterCount");
var noResults = document.getElementById("noResults");
var statArticles = document.getElementById("statArticles");
/* ---------- Build grouped article lists ---------- */
var byLetter = {};
ALPHABET.forEach(function (l) { byLetter[l] = []; });
ARTICLES.forEach(function (a) {
var letter = a.t[0].toUpperCase();
if (!byLetter[letter]) byLetter[letter] = [];
byLetter[letter].push(a);
});
Object.keys(byLetter).forEach(function (l) {
byLetter[l].sort(function (x, y) { return x.t.localeCompare(y.t); });
});
statArticles.textContent = String(ARTICLES.length);
function buildGroups() {
var frag = document.createDocumentFragment();
ALPHABET.forEach(function (letter) {
var items = byLetter[letter];
if (!items || !items.length) return;
var group = document.createElement("section");
group.className = "letter-group";
group.id = "letter-" + letter;
group.setAttribute("aria-labelledby", "head-" + letter);
var head = document.createElement("div");
head.className = "letter-head";
head.id = "head-" + letter;
head.innerHTML =
'<span class="letter">' + letter + "</span>" +
'<span class="letter-meta">' + items.length +
(items.length === 1 ? " page" : " pages") + "</span>";
group.appendChild(head);
var ul = document.createElement("ul");
ul.className = "article-list";
items.forEach(function (a) {
var li = document.createElement("li");
var link = document.createElement("a");
link.href = "#";
link.dataset.title = a.t.toLowerCase();
link.innerHTML =
escapeHtml(a.t) +
'<span class="art-tag">' + escapeHtml(a.tag) + "</span>";
link.addEventListener("click", function (e) {
e.preventDefault();
toast("Opening “" + a.t + "”");
});
li.appendChild(link);
ul.appendChild(li);
});
group.appendChild(ul);
frag.appendChild(group);
});
groupsEl.appendChild(frag);
}
function escapeHtml(s) {
return s.replace(/[&<>"']/g, function (c) {
return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c];
});
}
/* ---------- A–Z jump bar ---------- */
function buildAzBar() {
var frag = document.createDocumentFragment();
var allBtn = document.createElement("button");
allBtn.type = "button";
allBtn.textContent = "All";
allBtn.style.width = "auto";
allBtn.style.padding = "0 10px";
allBtn.className = "is-active";
allBtn.dataset.letter = "ALL";
frag.appendChild(allBtn);
ALPHABET.forEach(function (letter) {
var btn = document.createElement("button");
btn.type = "button";
btn.textContent = letter;
btn.dataset.letter = letter;
if (!byLetter[letter] || !byLetter[letter].length) {
btn.disabled = true;
}
frag.appendChild(btn);
});
azBar.appendChild(frag);
azBar.addEventListener("click", function (e) {
var btn = e.target.closest("button");
if (!btn || btn.disabled) return;
setActiveLetter(btn.dataset.letter);
});
}
function setActiveLetter(letter) {
azBar.querySelectorAll("button").forEach(function (b) {
b.classList.toggle("is-active", b.dataset.letter === letter);
});
if (letter === "ALL") {
groupsEl.querySelector(".letter-group");
window.scrollTo({ top: groupsEl.offsetTop - 100, behavior: "smooth" });
return;
}
var target = document.getElementById("letter-" + letter);
if (target) {
target.scrollIntoView({ behavior: "smooth", block: "start" });
target.querySelector(".letter").animate(
[{ transform: "scale(1)" }, { transform: "scale(1.18)" }, { transform: "scale(1)" }],
{ duration: 360, easing: "ease-out" }
);
}
}
/* ---------- Live filter ---------- */
var filterTimer = null;
function applyFilter(q) {
q = q.trim().toLowerCase();
var shown = 0;
var groups = groupsEl.querySelectorAll(".letter-group");
groups.forEach(function (group) {
var visibleInGroup = 0;
group.querySelectorAll(".article-list li").forEach(function (li) {
var title = li.querySelector("a").dataset.title;
var match = !q || title.indexOf(q) !== -1;
li.classList.toggle("is-hidden", !match);
if (match) { visibleInGroup++; shown++; }
});
group.classList.toggle("is-hidden", visibleInGroup === 0);
});
noResults.hidden = shown !== 0;
if (q) {
filterCount.textContent = shown + (shown === 1 ? " match" : " matches");
} else {
filterCount.textContent = "";
}
// disable A–Z buttons whose group is now empty
azBar.querySelectorAll("button").forEach(function (b) {
var letter = b.dataset.letter;
if (letter === "ALL") return;
var g = document.getElementById("letter-" + letter);
var hasVisible = g && !g.classList.contains("is-hidden");
var emptyData = !byLetter[letter] || !byLetter[letter].length;
b.disabled = emptyData || !hasVisible;
});
}
filterInput.addEventListener("input", function () {
var v = filterInput.value;
clearTimeout(filterTimer);
filterTimer = setTimeout(function () { applyFilter(v); }, 80);
});
/* ---------- Density toggle ---------- */
var viewList = document.getElementById("viewList");
var viewGrid = document.getElementById("viewGrid");
function setDensity(grid) {
groupsEl.classList.toggle("is-grid", grid);
viewGrid.classList.toggle("is-active", grid);
viewList.classList.toggle("is-active", !grid);
viewGrid.setAttribute("aria-pressed", String(grid));
viewList.setAttribute("aria-pressed", String(!grid));
toast(grid ? "Grid view" : "List view");
}
viewList.addEventListener("click", function () { setDensity(false); });
viewGrid.addEventListener("click", function () { setDensity(true); });
/* ---------- Sidebar drawer ---------- */
var navToggle = document.getElementById("navToggle");
var sidebar = document.getElementById("sidebar");
var scrim = document.getElementById("scrim");
function openNav(open) {
sidebar.classList.toggle("is-open", open);
scrim.hidden = !open;
navToggle.setAttribute("aria-expanded", String(open));
}
navToggle.addEventListener("click", function () {
openNav(!sidebar.classList.contains("is-open"));
});
scrim.addEventListener("click", function () { openNav(false); });
sidebar.addEventListener("click", function (e) {
if (e.target.closest("a") && window.matchMedia("(max-width: 820px)").matches) {
openNav(false);
}
});
/* ---------- Toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer = null;
function toast(msg) {
toastEl.textContent = msg;
toastEl.classList.add("is-show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("is-show");
}, 1800);
}
/* ---------- Keyboard shortcuts ---------- */
var topSearch = document.getElementById("topSearch");
document.addEventListener("keydown", function (e) {
var typing = /^(INPUT|TEXTAREA)$/.test(document.activeElement.tagName);
if (e.key === "/" && !typing) {
e.preventDefault();
topSearch.focus();
topSearch.select();
} else if (e.key === "Escape") {
if (sidebar.classList.contains("is-open")) openNav(false);
if (document.activeElement === filterInput && filterInput.value) {
filterInput.value = "";
applyFilter("");
}
}
});
// mirror top search into the in-page filter for convenience
topSearch.addEventListener("input", function () {
filterInput.value = topSearch.value;
applyFilter(topSearch.value);
if (topSearch.value) {
document.getElementById("articleFilter")
.scrollIntoView({ behavior: "smooth", block: "center" });
}
});
/* ---------- Init ---------- */
buildGroups();
buildAzBar();
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Category: Distributed Systems — Codex Wiki</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Source+Serif+4:opsz,[email protected],400;8..60,500;8..60,600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip-link" href="#main">Skip to content</a>
<header class="topbar">
<button class="nav-toggle" id="navToggle" aria-label="Toggle navigation" aria-expanded="false" aria-controls="sidebar">
<span></span><span></span><span></span>
</button>
<a class="brand" href="#" aria-label="Codex Wiki home">
<span class="brand-mark" aria-hidden="true">◆</span>
<span class="brand-name">Codex<span class="brand-dim">Wiki</span></span>
</a>
<div class="topbar-search">
<input type="search" id="topSearch" placeholder="Search the wiki… (press /)" aria-label="Search the wiki" autocomplete="off" />
<kbd>/</kbd>
</div>
<nav class="topbar-links" aria-label="Utility">
<a href="#">Random</a>
<a href="#">Recent</a>
<a href="#">Help</a>
</nav>
</header>
<div class="layout">
<aside class="sidebar" id="sidebar" aria-label="Site navigation">
<nav>
<p class="side-head">Browse</p>
<ul class="side-list">
<li><a href="#">All categories</a></li>
<li><a href="#" aria-current="page">Distributed Systems</a></li>
<li><a href="#">Storage Engines</a></li>
<li><a href="#">Networking</a></li>
<li><a href="#">Cryptography</a></li>
<li><a href="#">Observability</a></li>
</ul>
<p class="side-head">Featured portals</p>
<ul class="side-list">
<li><a href="#">Aurora DB</a></li>
<li><a href="#">Project Nimbus</a></li>
<li><a href="#">The Verdant Stack</a></li>
</ul>
<p class="side-head">Tools</p>
<ul class="side-list">
<li><a href="#">What links here</a></li>
<li><a href="#">Category tree</a></li>
<li><a href="#">Export catalog</a></li>
</ul>
</nav>
</aside>
<div class="sidebar-scrim" id="scrim" hidden></div>
<main class="content" id="main">
<nav class="breadcrumb" aria-label="Breadcrumb">
<a href="#">Home</a>
<span aria-hidden="true">/</span>
<a href="#">Categories</a>
<span aria-hidden="true">/</span>
<span aria-current="page">Distributed Systems</span>
</nav>
<header class="cat-header">
<p class="cat-kicker">Category portal</p>
<h1 class="cat-title">Distributed Systems</h1>
<p class="cat-desc">
Articles on consensus, replication, partitioning, fault tolerance and the
engineering trade-offs of running software across many unreliable machines. This portal
collects encyclopedic entries, design notes and protocol references for systems such as
<a href="#">Aurora DB</a>, <a href="#">Project Nimbus</a> and the <a href="#">Verdant Stack</a>.
</p>
<ul class="cat-stats" aria-label="Category statistics">
<li><strong id="statArticles">42</strong> articles</li>
<li><strong>9</strong> subcategories</li>
<li><strong>1.2k</strong> revisions</li>
<li><strong>Updated</strong> 2 days ago</li>
</ul>
</header>
<section class="featured" aria-labelledby="featured-h">
<p class="section-eyebrow" id="featured-h">Featured article</p>
<article class="featured-card">
<div class="featured-body">
<span class="badge badge-star" aria-hidden="true">★ Featured</span>
<h2><a href="#">The Raft Consensus Protocol</a></h2>
<p>
Raft is a consensus algorithm designed to be more understandable than Paxos. It
decomposes the problem into <em>leader election</em>, <em>log replication</em> and
<em>safety</em>, and underpins the replication layer of Aurora DB. A single elected
leader accepts client writes, appends them to a durable log, and replicates entries to
follower nodes; an entry commits once a majority acknowledge it.
</p>
<p class="featured-meta">
<span>12,400 words</span><span aria-hidden="true">·</span>
<span>Reviewed by 6 editors</span><span aria-hidden="true">·</span>
<span>Last edited 2026-06-06</span>
</p>
<a class="featured-link" href="#">Read the full article →</a>
</div>
<div class="featured-aside" aria-hidden="true">
<pre><code>state := FOLLOWER
on election_timeout:
state := CANDIDATE
term := term + 1
vote_for_self()
request_votes()
if votes > quorum:
state := LEADER</code></pre>
</div>
</article>
</section>
<section class="subcats" aria-labelledby="subcats-h">
<p class="section-eyebrow" id="subcats-h">Subcategories</p>
<div class="subcat-grid">
<a class="subcat" href="#"><span class="subcat-icon" aria-hidden="true">⇄</span><span class="subcat-name">Consensus & Coordination</span><span class="subcat-count">8 articles</span></a>
<a class="subcat" href="#"><span class="subcat-icon" aria-hidden="true">⧉</span><span class="subcat-name">Replication</span><span class="subcat-count">7 articles</span></a>
<a class="subcat" href="#"><span class="subcat-icon" aria-hidden="true">▦</span><span class="subcat-name">Partitioning & Sharding</span><span class="subcat-count">6 articles</span></a>
<a class="subcat" href="#"><span class="subcat-icon" aria-hidden="true">⏱</span><span class="subcat-name">Clocks & Ordering</span><span class="subcat-count">5 articles</span></a>
<a class="subcat" href="#"><span class="subcat-icon" aria-hidden="true">⚠</span><span class="subcat-name">Fault Tolerance</span><span class="subcat-count">9 articles</span></a>
<a class="subcat" href="#"><span class="subcat-icon" aria-hidden="true">◷</span><span class="subcat-name">Latency & Scheduling</span><span class="subcat-count">4 articles</span></a>
</div>
</section>
<section class="articles-section" aria-labelledby="articles-h">
<div class="articles-bar">
<p class="section-eyebrow" id="articles-h">Pages in this category</p>
<div class="articles-controls">
<div class="filter-box">
<input type="search" id="articleFilter" placeholder="Filter pages…" aria-label="Filter pages in this category" autocomplete="off" />
<span class="filter-count" id="filterCount" aria-live="polite"></span>
</div>
<div class="density-toggle" role="group" aria-label="View density">
<button type="button" id="viewList" class="is-active" aria-pressed="true">List</button>
<button type="button" id="viewGrid" aria-pressed="false">Grid</button>
</div>
</div>
</div>
<nav class="az-bar" id="azBar" aria-label="Jump to letter">
<!-- buttons injected by script.js -->
</nav>
<div class="article-groups" id="articleGroups">
<!-- groups injected by script.js -->
</div>
<p class="no-results" id="noResults" hidden>No pages match that filter.</p>
</section>
<footer class="cat-footer">
<p>Codex Wiki · text available under a fictional open license · this is an illustrative demo.</p>
</footer>
</main>
</div>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Category / Portal Page
A complete wiki category portal for Distributed Systems, laid out in a crisp white docs palette with a persistent left sidebar, a readable centered column and a high-density, library-catalog feel. The header pairs the category name with a serif description and a row of live statistics — article count, subcategories, revisions and last-updated — above a featured-article highlight card and a grid of linked subcategory tiles. Below them, every page in the category is grouped alphabetically under large letter headings in multi-column lists, each entry tagged with its kind (algorithm, protocol, model, structure…).
The interactions are all vanilla JS. A sticky A–Z bar smooth-scrolls to the matching letter group and pulses the heading on arrival, with letters that have no pages disabled automatically. A search box live-filters every list as you type — hiding non-matching entries, collapsing empty letter groups, updating a match counter and disabling the A–Z buttons whose groups went empty. A list/grid toggle reflows the catalog between tight multi-column lists and a card grid, and the top-bar search mirrors straight into the in-page filter.
The layout is fully responsive: the sidebar collapses to a drawer with a scrim below 820px, the
multi-column lists step down to two and then one column, and the A–Z bar unsticks on the narrowest
screens. Keyboard shortcuts (/ to focus search, Esc to clear or close the drawer), visible focus
rings, semantic landmarks, a small toast() helper and prefers-reduced-motion support round it out —
no frameworks, no build step.
Illustrative UI only — fictional articles, products, and data.