Skip to content

Commit ca8718d

Browse files
committed
docs: add documentation versioning
1 parent dde5183 commit ca8718d

5 files changed

Lines changed: 257 additions & 5 deletions

File tree

.github/workflows/docs.yml

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ on:
55
types: [published]
66

77
permissions:
8-
contents: read
8+
contents: write
99
pages: write
1010
id-token: write
1111

@@ -16,19 +16,37 @@ jobs:
1616
url: ${{ steps.deployment.outputs.page_url }}
1717
runs-on: ubuntu-latest
1818
steps:
19-
- uses: actions/configure-pages@v5
20-
2119
- uses: actions/checkout@v6
20+
with:
21+
fetch-depth: 0
22+
23+
- name: Configure git
24+
run: |
25+
git config user.name "github-actions[bot]"
26+
git config user.email "github-actions[bot]@users.noreply.github.com"
2227
2328
- name: Install uv
2429
uses: astral-sh/setup-uv@v7
2530

2631
- name: Set up Python
2732
run: uv python install 3.13
2833

29-
- run: uv sync --group dev
34+
- run: uv sync --group docs
3035

31-
- run: uv run zensical build --clean
36+
- name: Install mkdocs shim
37+
run: cp scripts/mkdocs .venv/bin/mkdocs && chmod +x .venv/bin/mkdocs
38+
39+
- name: Deploy docs version
40+
run: |
41+
VERSION="${GITHUB_REF_NAME#v}"
42+
MINOR_VERSION="${VERSION%.*}"
43+
uv run mike deploy --push --update-aliases "$MINOR_VERSION" latest
44+
uv run mike set-default --push latest
45+
46+
- name: Prepare site artifact
47+
run: git worktree add site gh-pages
48+
49+
- uses: actions/configure-pages@v5
3250

3351
- uses: actions/upload-pages-artifact@v4
3452
with:
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{#-
2+
Override of partials/header.html — adds version selector slot missing in Zensical.
3+
-#}
4+
{% set class = "md-header" %}
5+
{% if "navigation.tabs.sticky" in features %}
6+
{% set class = class ~ " md-header--shadow md-header--lifted" %}
7+
{% elif "navigation.tabs" not in features %}
8+
{% set class = class ~ " md-header--shadow" %}
9+
{% endif %}
10+
<header class="{{ class }}" data-md-component="header">
11+
<nav class="md-header__inner md-grid" aria-label="{{ lang.t('header') }}">
12+
<a href="{{ config.extra.homepage | d(nav.homepage.url, true) | url }}" title="{{ config.site_name | e }}" class="md-header__button md-logo" aria-label="{{ config.site_name }}" data-md-component="logo">
13+
{% include "partials/logo.html" %}
14+
</a>
15+
<label class="md-header__button md-icon" for="__drawer">
16+
{% set icon = config.theme.icon.menu or "material/menu" %}
17+
{% include ".icons/" ~ icon ~ ".svg" %}
18+
</label>
19+
<div class="md-header__title" data-md-component="header-title">
20+
<div class="md-header__ellipsis">
21+
<div class="md-header__topic">
22+
<span class="md-ellipsis">
23+
{{ config.site_name }}
24+
</span>
25+
</div>
26+
<div class="md-header__topic" data-md-component="header-topic">
27+
<span class="md-ellipsis">
28+
{% if page.meta and page.meta.title %}
29+
{{ page.meta.title }}
30+
{% else %}
31+
{{ page.title }}
32+
{% endif %}
33+
</span>
34+
</div>
35+
</div>
36+
</div>
37+
{% if config.theme.palette %}
38+
{% if not config.theme.palette is mapping %}
39+
{% include "partials/palette.html" %}
40+
{% endif %}
41+
{% endif %}
42+
{% if not config.theme.palette is mapping %}
43+
{% include "partials/javascripts/palette.html" %}
44+
{% endif %}
45+
{% if config.extra.alternate %}
46+
{% include "partials/alternate.html" %}
47+
{% endif %}
48+
{% if "search" in config.plugins %}
49+
{% set search = config.plugins["search"] | attr("config") %}
50+
{% if search.enabled %}
51+
<label class="md-header__button md-icon" for="__search">
52+
{% set icon = config.theme.icon.search or "material/magnify" %}
53+
{% include ".icons/" ~ icon ~ ".svg" %}
54+
</label>
55+
{% include "partials/search.html" %}
56+
{% endif %}
57+
{% endif %}
58+
<div class="md-header__source">
59+
{% if config.repo_url %}
60+
{% include "partials/source.html" %}
61+
{% endif %}
62+
</div>
63+
</nav>
64+
{% if "navigation.tabs.sticky" in features %}
65+
{% if "navigation.tabs" in features %}
66+
{% include "partials/tabs.html" %}
67+
{% endif %}
68+
{% endif %}
69+
</header>

docs/stylesheets/version.css

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/* Version selector styles for Zensical modern theme (backported from classic theme).
2+
The JS appends .md-version into .md-header__topic, so we make that flex. */
3+
.md-header__topic:has(.md-version) {
4+
display: flex;
5+
align-items: center;
6+
}
7+
8+
9+
:root {
10+
--md-version-icon: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M140.3 376.8c12.6 10.2 31.1 9.5 42.8-2.2l128-128c9.2-9.2 11.9-22.9 6.9-34.9S301.4 192 288.5 192h-256c-12.9 0-24.6 7.8-29.6 19.8s-2.2 25.7 7 34.8l128 128z"/></svg>');
11+
}
12+
13+
.md-version {
14+
flex-shrink: 0;
15+
font-size: .8rem;
16+
height: 2.4rem;
17+
}
18+
19+
[dir=ltr] .md-version__current { margin-left: 1.4rem; margin-right: .4rem; }
20+
[dir=rtl] .md-version__current { margin-left: .4rem; margin-right: 1.4rem; }
21+
22+
.md-version__current {
23+
color: inherit;
24+
cursor: pointer;
25+
outline: none;
26+
position: relative;
27+
top: .05rem;
28+
}
29+
30+
[dir=ltr] .md-version__current:after { margin-left: .4rem; }
31+
[dir=rtl] .md-version__current:after { margin-right: .4rem; }
32+
33+
.md-version__current:after {
34+
background-color: currentcolor;
35+
content: "";
36+
display: inline-block;
37+
height: .6rem;
38+
-webkit-mask-image: var(--md-version-icon);
39+
mask-image: var(--md-version-icon);
40+
-webkit-mask-position: center;
41+
mask-position: center;
42+
-webkit-mask-repeat: no-repeat;
43+
mask-repeat: no-repeat;
44+
-webkit-mask-size: contain;
45+
mask-size: contain;
46+
width: .4rem;
47+
}
48+
49+
.md-version__alias {
50+
margin-left: .3rem;
51+
opacity: .7;
52+
}
53+
54+
.md-version__list {
55+
background-color: var(--md-default-bg-color);
56+
border-radius: .1rem;
57+
box-shadow: var(--md-shadow-z2);
58+
color: var(--md-default-fg-color);
59+
list-style-type: none;
60+
margin: .2rem .8rem;
61+
max-height: 0;
62+
opacity: 0;
63+
overflow: auto;
64+
padding: 0;
65+
position: absolute;
66+
scroll-snap-type: y mandatory;
67+
top: .15rem;
68+
transition: max-height 0ms .5s, opacity .25s .25s;
69+
z-index: 3;
70+
}
71+
72+
.md-version:focus-within .md-version__list,
73+
.md-version:hover .md-version__list {
74+
max-height: 10rem;
75+
opacity: 1;
76+
transition: max-height 0ms, opacity .25s;
77+
}
78+
79+
.md-version:hover .md-version__list { animation: hoverfix .25s forwards; }
80+
.md-version:focus-within .md-version__list { animation: none; }
81+
82+
.md-version__item { line-height: 1.8rem; }
83+
84+
[dir=ltr] .md-version__link { padding-left: .6rem; padding-right: 1.2rem; }
85+
[dir=rtl] .md-version__link { padding-left: 1.2rem; padding-right: .6rem; }
86+
87+
.md-version__link {
88+
cursor: pointer;
89+
display: block;
90+
outline: none;
91+
scroll-snap-align: start;
92+
transition: color .25s, background-color .25s;
93+
white-space: nowrap;
94+
width: 100%;
95+
}
96+
97+
.md-version__link:focus,
98+
.md-version__link:hover { color: var(--md-accent-fg-color); }
99+
100+
.md-version__link:focus { background-color: var(--md-default-fg-color--lightest); }

mkdocs.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Minimal stub for mike compatibility.
2+
# The actual build is handled by zensical (see scripts/mkdocs shim).
3+
site_name: FastAPI Toolsets
4+
docs_dir: docs
5+
site_dir: site

scripts/mkdocs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/usr/bin/env python3
2+
"""mkdocs shim for mike compatibility.
3+
4+
mike parses mkdocs.yml (valid YAML stub) for its Python internals, then calls
5+
`mkdocs build --config-file <mike-injected-temp.yml>` as a subprocess.
6+
7+
This shim intercepts that subprocess call, ignores the temp config, and
8+
delegates the actual build to `zensical build -f zensical.toml` instead.
9+
"""
10+
11+
from __future__ import annotations
12+
13+
import os
14+
import subprocess
15+
import sys
16+
17+
18+
def main() -> None:
19+
args = sys.argv[1:]
20+
21+
# mike calls `mkdocs --version` to embed in the commit message
22+
if args and args[0] == "--version":
23+
print("mkdocs, version 1.0.0 (zensical shim)")
24+
return
25+
26+
if not args or args[0] != "build":
27+
result = subprocess.run(["python3", "-m", "mkdocs"] + args)
28+
sys.exit(result.returncode)
29+
30+
config_file = "mkdocs.yml"
31+
clean = False
32+
33+
i = 1
34+
while i < len(args):
35+
if args[i] in ("-f", "--config-file") and i + 1 < len(args):
36+
config_file = args[i + 1]
37+
i += 2
38+
elif args[i] in ("-c", "--clean"):
39+
clean = True
40+
i += 1
41+
elif args[i] == "--dirty":
42+
i += 1
43+
else:
44+
i += 1
45+
46+
# mike creates a temp file prefixed with "mike-mkdocs"; always delegate
47+
# the actual build to zensical regardless of which config was passed.
48+
del config_file # unused — zensical auto-discovers zensical.toml
49+
50+
cmd = ["zensical", "build"]
51+
if clean:
52+
cmd.append("--clean")
53+
54+
env = os.environ.copy()
55+
result = subprocess.run(cmd, env=env)
56+
sys.exit(result.returncode)
57+
58+
59+
if __name__ == "__main__":
60+
main()

0 commit comments

Comments
 (0)