Skip to content

Commit 75cca38

Browse files
authored
Merge pull request #1095 from altheaden/version-dropdown
Version dropdown
2 parents ecdb7c7 + 00cbd03 commit 75cca38

File tree

15 files changed

+209
-58
lines changed

15 files changed

+209
-58
lines changed

.github/workflows/build_workflow.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,5 @@ jobs:
8585
- if: ${{ steps.skip_check.outputs.should_skip != 'true' }}
8686
name: Build Sphinx Docs
8787
run: |
88-
# sphinx-multiversion expects at least a "main" branch
89-
git branch main || echo "branch main already exists."
9088
cd docs
91-
sphinx-multiversion . _build/html
92-
89+
DOCS_VERSION=test make versioned-html

.github/workflows/docs_workflow.yml

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ jobs:
6262
pip check
6363
mpas_analysis sync diags --help
6464
cd docs
65-
sphinx-multiversion . _build/html
65+
DOCS_VERSION=${{ github.ref_name }} make versioned-html
6666
- name: Copy Docs and Commit
6767
run: |
6868
set -e
@@ -71,17 +71,26 @@ jobs:
7171
cd docs
7272
# gh-pages branch must already exist
7373
git clone https://github.com/MPAS-Dev/MPAS-Analysis.git --branch gh-pages --single-branch gh-pages
74+
75+
# Only replace docs in a directory with the destination branch name with latest changes. Docs for
76+
# releases should be untouched.
77+
rm -rf gh-pages/${{ github.ref_name }}
78+
79+
# don't clobber existing release versions (in case we retroactively fixed them)
80+
cp -r _build/html/${{ github.ref_name }} gh-pages/
81+
82+
mkdir -p gh-pages/shared
83+
cp shared/version-switcher.js gh-pages/shared/version-switcher.js
84+
85+
# Update the list of versions with all versions in the gh-pages directory.
86+
python generate_versions_json.py
87+
7488
# Make sure we're in the gh-pages directory.
7589
cd gh-pages
7690
# Create `.nojekyll` (if it doesn't already exist) for proper GH Pages configuration.
7791
touch .nojekyll
7892
# Add `index.html` to point to the `develop` branch automatically.
7993
printf '<meta http-equiv="refresh" content="0; url=./develop/index.html" />' > index.html
80-
# Only replace docs in a directory with the destination branch name with latest changes. Docs for
81-
# releases should be untouched.
82-
rm -rf ${{ github.head_ref || github.ref_name }}
83-
# don't clobber existing release versions (in case we retroactively fixed them)
84-
cp -r -n ../_build/html/* .
8594
# Configure git using GitHub Actions credentials.
8695
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
8796
git config --local user.name "github-actions[bot]"

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,7 @@ developers". Then run:
294294
To generate the `sphinx` documentation, run:
295295
```
296296
cd docs
297-
make clean
298-
make html
297+
DOCS_VERSION=test make clean versioned-html
299298
```
300299
The results can be viewed in your web browser by opening:
301300
```

dev-spec.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,4 @@ m2r2>=0.3.3
4141
mistune<2
4242
sphinx
4343
sphinx_rtd_theme
44-
sphinx-multiversion
4544
tabulate

docs/Makefile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,23 @@ SPHINXPROJ = MPAS-Analysis
88
SOURCEDIR = .
99
BUILDDIR = _build
1010

11+
# Build into a versioned subdirectory
12+
versioned-html:
13+
@echo "Building version: $(DOCS_VERSION)"
14+
$(SPHINXBUILD) -b html "$(SOURCEDIR)" "$(BUILDDIR)/html/$(DOCS_VERSION)"
15+
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html/$(DOCS_VERSION)."
16+
@echo "Setting up shared version switcher for local preview..."
17+
mkdir -p _build/html/shared
18+
cp shared/version-switcher.js _build/html/shared/version-switcher.js
19+
python generate_versions_json.py --local
20+
21+
# Override html target to include local setup
22+
html:
23+
$(SPHINXBUILD) -b html "$(SOURCEDIR)" "$(BUILDDIR)/html"
24+
@echo
25+
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
26+
27+
1128
# Put it first so that "make" without argument is like "make help".
1229
help:
1330
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
@@ -16,6 +33,10 @@ clean:
1633
rm -rf users_guide/*obs_table.rst developers_guide/generated users_guide/obs
1734
@$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
1835

36+
clean-versioned-html:
37+
rm -rf $(BUILDDIR)/html/*
38+
@echo "Cleaned versioned HTML builds."
39+
1940
.PHONY: help Makefile
2041

2142
# Catch-all target: route all unknown targets to Sphinx using the new

docs/_static/style.css

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,29 @@
22
max-width: 1200px !important;
33
}
44

5+
#version-switcher select {
6+
background-color: #2980b9;
7+
color: white;
8+
border: none;
9+
border-radius: 4px;
10+
padding: 4px 30px 4px 10px;
11+
font-size: 0.9em;
12+
appearance: none; /* Remove default dropdown arrow */
13+
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg fill='white' height='10' viewBox='0 0 24 24' width='10' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M7 10l5 5 5-5z'/%3E%3C/svg%3E");
14+
background-repeat: no-repeat;
15+
background-position: right 10px center;
16+
background-size: 12px;
17+
}
18+
19+
#version-switcher select:focus {
20+
outline: none;
21+
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.4);
22+
background-color: #2c89c4; /* slightly lighter blue on focus */
23+
}
24+
25+
/* Selected item in the dropdown menu */
26+
#version-switcher option:checked {
27+
background-color: #dddddd; /* for selected */
28+
color: black;
29+
}
30+

docs/_templates/layout.html

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,26 @@
33
<link href="{{ pathto("_static/style.css", True) }}" rel="stylesheet" type="text/css">
44
{% endblock %}
55

6+
7+
{% block footer %}
8+
{{ super() }}
9+
10+
<!-- Meta tags for JS to use -->
11+
<meta name="doc-version" content="{{ current_version }}">
12+
<meta name="doc-site-root" content="{{ pathto('', 1) }}">
13+
14+
<!-- Create version switcher container -->
15+
<script>
16+
const sidebar = document.querySelector('.wy-side-nav-search');
17+
if (sidebar) {
18+
const versionDiv = document.createElement('div');
19+
versionDiv.id = 'version-switcher';
20+
versionDiv.style.marginTop = '1em';
21+
sidebar.appendChild(versionDiv);
22+
}
23+
</script>
24+
25+
<!-- Load version-switcher.js using the correct relative path -->
26+
<script src="{{ pathto('../shared/version-switcher.js', 1) }}"></script>
27+
{% endblock %}
28+

docs/_templates/versions.html

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

docs/conf.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
# ones.
3838
extensions = [
3939
'sphinx_rtd_theme',
40-
'sphinx_multiversion',
4140
'sphinx.ext.autodoc',
4241
'sphinx.ext.autosummary',
4342
'sphinx.ext.intersphinx',
@@ -222,14 +221,6 @@
222221
# so a file named "default.css" will overwrite the builtin "default.css".
223222
html_static_path = ["_static"]
224223

225-
html_sidebars = {
226-
"**": [
227-
"versions.html",
228-
],
224+
html_context = {
225+
"current_version": os.getenv("DOCS_VERSION", "main"),
229226
}
230-
231-
# -- Options sphinx-multiversion -------------------------------------------
232-
# Include tags like "tags/1.0.0" -- 1.7.2 doesn't build
233-
smv_tag_whitelist = r'^(?!1.7.2)\d+\.\d+.\d+$'
234-
smv_branch_whitelist = r'^(develop|main)$'
235-
smv_remote_whitelist = 'origin'

docs/generate_versions_json.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env python
2+
import argparse
3+
import json
4+
import os
5+
import re
6+
7+
8+
def version_key(name):
9+
"""Key function for sorting versions."""
10+
match = re.match(r'^(\d+)\.(\d+)\.(\d+)$', name)
11+
if match:
12+
# Sort by major, minor, patch
13+
return tuple(map(int, match.groups()))
14+
return ()
15+
16+
17+
# Mode: local or production
18+
parser = argparse.ArgumentParser(
19+
description='Generate versions.json for MPAS Analysis documentation.')
20+
parser.add_argument(
21+
'--local',
22+
action='store_true',
23+
help='Generate versions.json for local build.'
24+
)
25+
args = parser.parse_args()
26+
local = args.local
27+
base_dir = '_build/html' if local else 'gh-pages'
28+
shared_dir = os.path.join(base_dir, 'shared')
29+
30+
entries = []
31+
32+
if not os.path.exists(base_dir) or not os.listdir(base_dir):
33+
raise FileNotFoundError(
34+
f"Base directory '{base_dir}' does not exist or is empty.")
35+
36+
versions = os.listdir(base_dir)
37+
numeric_versions = []
38+
non_numeric_versions = []
39+
40+
for version in versions:
41+
# Check if it matches version pattern
42+
if re.match(r'^\d+\.\d+\.\d+$', version):
43+
numeric_versions.append(version)
44+
else:
45+
non_numeric_versions.append(version)
46+
47+
# Sort numeric versions by major, minor, patch in descending order
48+
numeric_versions.sort(key=version_key, reverse=True)
49+
# Sort non-numeric versions alphabetically
50+
non_numeric_versions.sort()
51+
52+
# Combine the sorted lists
53+
versions = non_numeric_versions + numeric_versions
54+
55+
if 'main' in versions:
56+
versions.insert(0, versions.pop(versions.index('main')))
57+
58+
for name in versions:
59+
path = os.path.join(base_dir, name)
60+
if os.path.isdir(path) and name not in ('shared', '.git'):
61+
entries.append({
62+
'version': name,
63+
'url': f'../{name}/' if local else f'/MPAS-Analysis/{name}/'
64+
})
65+
66+
os.makedirs(shared_dir, exist_ok=True)
67+
with open(os.path.join(shared_dir, 'versions.json'), 'w') as f:
68+
json.dump(entries, f, indent=2)
69+

0 commit comments

Comments
 (0)