Skip to content

Commit 4fc8882

Browse files
Kludexclaudemaxisbey
authored
docs: replace MkDocs with Zensical (#3073)
Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
1 parent 74a242a commit 4fc8882

17 files changed

Lines changed: 1185 additions & 612 deletions

.github/workflows/deploy-docs.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ on:
1414
- src/mcp/**
1515
- src/mcp-types/**
1616
- scripts/build-docs.sh
17+
- scripts/docs/**
1718
- pyproject.toml
1819
- uv.lock
1920
- .github/workflows/deploy-docs.yml
@@ -49,9 +50,6 @@ jobs:
4950

5051
- name: Build combined docs (v1.x at /, main at /v2/)
5152
run: bash scripts/build-docs.sh site
52-
env:
53-
# Silence mkdocs-material's MkDocs 2.0 warning banner in CI logs.
54-
NO_MKDOCS_2_WARNING: "1"
5553

5654
- name: Configure Pages
5755
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0

.github/workflows/shared.yml

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,16 @@ jobs:
139139
- name: Check README snippets are up to date
140140
run: uv run --frozen scripts/update_readme_snippets.py --check
141141

142-
# `mkdocs.yml` sets `strict: true` and `pymdownx.snippets: check_paths: true`,
143-
# but until this job existed the docs were only ever built post-merge by
144-
# `deploy-docs.yml`, so a broken link, a missing nav target, or a deleted
145-
# `docs_src/` include went green on the PR and broke the next deploy of main.
146-
# This is the check path; `deploy-docs.yml` stays the deploy path.
142+
# `scripts/docs/build.sh` is the whole gauntlet: build_config.py fails on
143+
# nav entries without a page and pages without a nav entry, `zensical build
144+
# --strict` fails on broken .md links, `pymdownx.snippets: check_paths:
145+
# true` fails on a deleted `docs_src/` include, and the post-build steps
146+
# fail on unresolved cross-references, inventory download failures, and
147+
# broken non-markdown link targets.
148+
# Until this job existed the docs were only ever built post-merge by
149+
# `deploy-docs.yml`, so those failures went green on the PR and broke the next
150+
# deploy of main. This is the check path; `deploy-docs.yml` stays the deploy
151+
# path.
147152
docs:
148153
runs-on: ubuntu-latest
149154
steps:
@@ -168,11 +173,5 @@ jobs:
168173
enable-cache: true
169174
version: 0.9.5
170175

171-
- name: Install dependencies
172-
run: uv sync --frozen --all-extras --python 3.10
173-
174176
- name: Build the docs in strict mode
175-
run: uv run --frozen --no-sync mkdocs build --strict
176-
env:
177-
# Silence mkdocs-material's MkDocs 2.0 warning banner in CI logs.
178-
NO_MKDOCS_2_WARNING: "1"
177+
run: bash scripts/docs/build.sh

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,13 @@ venv.bak/
141141
# Rope project settings
142142
.ropeproject
143143

144-
# mkdocs documentation
144+
# documentation
145145
/site
146146
/.worktrees/
147+
# Generated at build time by scripts/docs/ (the API reference tree and the
148+
# concrete Zensical config spliced from mkdocs.yml).
149+
/docs/api/
150+
/mkdocs.gen.yml
147151

148152
# mypy
149153
.mypy_cache/

docs/extra.css

Lines changed: 70 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,42 @@
1-
/* Sidebar hierarchy + density for MkDocs Material 9.7.x.
2-
All rules scoped to the desktop sidebar breakpoint (>= 76.25em), matching
3-
Material's own scoping for navigation.sections, so the mobile drill-down
4-
drawer keeps stock styling. Colors use Material tokens, so the light and
5-
slate schemes both work without extra palette handling. */
1+
/* Sidebar hierarchy + density for Zensical's UI (Material-compatible md-*
2+
DOM, but different stock spacing: nav links are 8px-radius pills with
3+
7px 16px padding). All rules scoped to the desktop sidebar breakpoint
4+
(>= 76.25em) so the mobile drill-down drawer keeps stock styling. Colors
5+
use the md-* tokens, so the light and slate schemes both work without
6+
extra palette handling. */
67

78
@media screen and (min-width: 76.25em) {
8-
/* Section labels: smaller, uppercase, letter-spaced, muted. Covers both the
9-
clickable index-page headers and the bare API Reference label. */
9+
/* The sidebar is one coordinate system derived from the pill inset:
10+
every row — page links, group rows, section labels — is a direct
11+
.md-nav__link child of its item with the same 10px horizontal padding,
12+
so all text shares one column, and hover/active pills always paint
13+
10px of breathing room inside the scroll container (never clipped).
14+
The padding lives on the elements Zensical paints hover/active pills
15+
on (.md-nav__link[href] anchors and [for] labels — leaf links, bare
16+
section labels, and the inner anchor of an .md-nav__container
17+
wrapper); wrappers stay geometry-neutral, as stock. The 10px inset
18+
also stays >= the 0.4rem pill radius, so the corner curve never
19+
crowds the text. Vertical rhythm has a single knob: the nav list's
20+
flex gap (stock 0.2rem reads airy; 2px matches the density the site
21+
shipped with on Material, ~30px row pitch). */
22+
.md-sidebar--primary .md-nav__list {
23+
gap: 2px;
24+
}
25+
.md-sidebar--primary .md-nav__item > .md-nav__link:not(.md-nav__container),
26+
.md-sidebar--primary .md-nav__container > .md-nav__link {
27+
padding: 3px 10px;
28+
margin: 0;
29+
}
30+
.md-sidebar--primary .md-nav__item > .md-nav__container {
31+
padding: 0;
32+
margin: 0;
33+
}
34+
35+
/* Section labels: typography only — geometry comes from the row rule
36+
above, so no specificity coordination is needed. */
37+
.md-sidebar--primary .md-nav__item--section {
38+
margin: 0.8em 0;
39+
}
1040
.md-sidebar--primary .md-nav__item--section > .md-nav__link {
1141
font-size: 0.62rem;
1242
font-weight: 700;
@@ -15,39 +45,19 @@
1545
color: var(--md-default-fg-color--light);
1646
}
1747

18-
/* Indent section children and hang a guide line. Material outdents section
19-
children with [dir=ltr] ... margin-left: -0.6rem, which is why they sit
20-
flush under the header; restoring the margin re-exposes the stock 0.6rem
21-
list padding. The logical property ties Material's physical one at
22-
(0,3,0) specificity and wins on source order (extra_css loads last),
23-
while staying direction-agnostic. */
48+
/* Guide lines: 12px from the item box = 2px right of the label text
49+
(which sits at box + 10px pill inset); children indent past them. */
2450
.md-sidebar--primary .md-nav__item--section > .md-nav {
25-
margin-inline-start: 0.1rem;
51+
margin-inline-start: 12px;
2652
border-inline-start: 0.05rem solid var(--md-default-fg-color--lightest);
2753
}
28-
29-
/* Same guide line for collapsible groups inside the API Reference subtree
30-
(section items also carry --nested, so exclude them). */
3154
.md-sidebar--primary .md-nav__item--nested:not(.md-nav__item--section) > .md-nav {
55+
margin-inline-start: 12px;
3256
border-inline-start: 0.05rem solid var(--md-default-fg-color--lightest);
3357
}
3458

35-
/* Tighten vertical rhythm (stock: 0.625em link margins, 1.25em sections).
36-
The child combinator keeps this off anchors inside md-nav__container,
37-
which carry their own margin-top: 0 stock rule. */
38-
.md-sidebar--primary .md-nav__item > .md-nav__link {
39-
margin-top: 0.45em;
40-
}
41-
.md-sidebar--primary .md-nav__item--section {
42-
margin: 1em 0;
43-
}
44-
.md-sidebar--primary .md-nav__item--section > .md-nav__link {
45-
margin-top: 0;
46-
}
47-
48-
/* The current page stands out from its siblings. 700 because Material only
49-
loads Inter at 300/400/700; a 600 would silently substitute the 700 face
50-
anyway, but render lighter on the system-font fallback stack. */
59+
/* The current page stands out from its siblings (on top of the stock
60+
pill highlight). 700 because only Inter 300/400/700 are loaded. */
5161
.md-sidebar--primary .md-nav__link--active {
5262
font-weight: 700;
5363
}
@@ -60,10 +70,33 @@
6070
}
6171
}
6272

63-
/* Headings: Material's 300-weight light-gray defaults read washed out; use
64-
the full foreground color and a solid weight instead. 700, not 600: the
65-
Google Fonts request only carries Inter 300/400/700 (see the nav__link
66-
note above). */
73+
/* Dark scheme: Zensical's slate canvas is near-black (hsla(225,15%,5%)),
74+
harsher than the Material slate this site shipped with; restore that
75+
blue-grey. Code blocks and other surfaces keep Zensical's own tokens. */
76+
@media screen {
77+
[data-md-color-scheme="slate"] {
78+
--md-default-bg-color: #1e2129;
79+
}
80+
}
81+
82+
/* Inline code inside admonitions: the chip token is an absolute dark
83+
surface designed for the page canvas, so on a tinted admonition panel it
84+
sits as an opaque slab (Zensical's own docs share this bug). Re-tint it
85+
tone-on-tone instead — translucent foreground, composited over whatever
86+
the panel color is — the same pattern Starlight and Docusaurus ship for
87+
code inside callouts. Prose chips keep the block-matching dark surface;
88+
block code inside admonitions keeps its own surface too. The first
89+
declaration is the fallback where color-mix is unsupported. */
90+
.md-typeset .admonition :not(pre) > code,
91+
.md-typeset details :not(pre) > code {
92+
background-color: var(--md-default-fg-color--lightest);
93+
background-color: color-mix(in srgb, currentcolor 11%, transparent);
94+
color: inherit;
95+
}
96+
97+
/* Headings: the 300-weight light-gray defaults read washed out; use the
98+
full foreground color and a solid weight instead. 700, not 600: only
99+
Inter 300/400/700 are loaded (see the nav__link note above). */
67100
.md-typeset h1,
68101
.md-typeset h2 {
69102
font-weight: 700;

docs/hooks/gen_ref_pages.py

Lines changed: 0 additions & 40 deletions
This file was deleted.

0 commit comments

Comments
 (0)