Add version picker in the navbar (#2256)

Co-authored-by: Andrew Morgan <andrew@amorgan.xyz>
pull/2258/head
Johannes Marbach 3 days ago committed by GitHub
parent d28e05af87
commit a5afe542c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,106 @@
/*
Copyright 2025 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Determine the current version as defined in hugo.toml. This will either be
// "unstable" or "vX.X" and doesn't depend on the current URL.
//
// The oddity below is an attempt at producing a readable Hugo template while
// avoiding JS syntax errors in your IDE.
const currentVersion = `{{ if eq .Site.Params.version.status "unstable" }}
{{- /**/ -}}
unstable
{{- /**/ -}}
{{ else }}
{{- /**/ -}}
{{ printf "v%s.%s" .Site.Params.version.major .Site.Params.version.minor }}
{{- /**/ -}}
{{ end }}`;
// Determine the current version segment by regex matching the URL. This will either
// be "unstable", "latest", "vX.X" (production) or undefined (local & netlify).
const href = window.location.href;
const segmentMatches = href.match(/(?<=\/)unstable|latest|v\d+.\d+(?=\/)/);
const currentSegment = segmentMatches ? segmentMatches[0] : undefined;
// Determine the selected menu element. If we were able to obtain the version
// segment from the URL (production), use that. Otherwise (local & netlify),
// fall back to the version as defined in Hugo.
const selected = currentSegment ?? currentVersion;
function appendVersion(parent, name, url) {
// The list item
const li = document.createElement("li");
if (name === selected) {
li.classList.add("selected");
}
if (name === "latest") {
li.classList.add("latest");
}
parent.appendChild(li);
// The link
const a = document.createElement("a");
a.classList.add("dropdown-item");
a.setAttribute("href", url);
li.appendChild(a);
// Handle clicks manually to preserve the current path / fragment
a.addEventListener("click", (ev) => {
// If the URL is a relative link (i.e. the historical versions changelog), just
// let the browser load it
if (url.startsWith("/")) {
return;
}
// If we couldn't determine the current segment, we cannot safely replace
// it and have to let the browser load the (root) URL instead
if (!currentSegment) {
return;
}
// Otherwise, stop further event handling and replace the segment
ev.preventDefault();
ev.stopPropagation();
window.location.href = href.replace(`/${currentSegment}/`, `/${name}/`);
});
// The link text
const text = document.createTextNode(name);
a.appendChild(text);
}
fetch("/latest/versions.json")
.then(r => r.json())
.then(versions => {
// Find the surrounding list element
const ul = document.querySelector("ul#version-selector");
if (!ul) {
console.error("Cannot populate version selector: ul element not found");
return;
}
// Add a entries for the unstable version and the "latest" shortcut
appendVersion(ul, "unstable", "https://spec.matrix.org/unstable");
appendVersion(ul, "latest", "https://spec.matrix.org/latest");
// Add an entry for each proper version
for (const version of versions) {
appendVersion(ul, version.name, `https://spec.matrix.org/${version.name}`);
}
// For historical versions, simply link to the changelog
appendVersion(ul, "historical", '{{ (site.GetPage "changelog/historical").RelPermalink }}');
});

@ -50,6 +50,20 @@ Custom SCSS for the Matrix spec
a {
color: $black;
}
/* Make the version dropdown scroll if its too large */
ul#version-selector {
max-height: 80vh;
overflow-y: auto;
}
ul#version-selector li.selected a {
font-weight: bold;
}
ul#version-selector li.latest a {
color: $secondary;
}
}
/* Styles for the sidebar nav */

@ -0,0 +1 @@
Add version picker in the navbar.

@ -78,6 +78,10 @@ current_version_url = "https://spec.matrix.org/latest"
# major = "1"
# minor = "16"
[[params.versions]]
# We must include this parameter to enable docsy's version picker in the navbar. The picker
# is populated automatically in navbar-version-selector.html.
# User interface configuration
[params.ui]
# Collapse HTTP API and event <details> elements

@ -8,3 +8,10 @@
*/}}
{{ $toc := resources.Get "js/toc.js" -}}
<script defer src="{{ $toc.RelPermalink }}"></script>
{{- /* Load the versions script template, run and publish it */ -}}
{{ with resources.Get "js/versions.template.js" }}
{{ with resources.ExecuteAsTemplate "js/versions.js" $ . }}
<script defer src="{{ .RelPermalink }}"></script>
{{ end }}
{{ end }}

@ -0,0 +1,18 @@
{{- /*
A version of the navbar-version-selector.html partial in Docsy,
modified to read the versions from /versions.json.
*/ -}}
{{ $changelog := site.GetPage "changelog" }}
{{ $pages := $changelog.RegularPages.ByDate.Reverse }}
<div class="dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
All Versions
</a>
<ul class="dropdown-menu" id="version-selector">
{{- /* The menu is built by versions.template.js */ -}}
</ul>
</div>

@ -5,6 +5,25 @@
*/}}
{{/* Generate a static file versions.json that can be used to populate the version picker */}}
{{ if .IsHome }}
{{- /* Load all changelog subpages, sorted by release date */ -}}
{{ $changelog := site.GetPage "changelog" }}
{{ $pages := $changelog.RegularPages.ByDate.Reverse }}
{{- /* Collect proper versions and build metadata dicts */ -}}
{{ $versions := slice }}
{{ range $pages }}
{{ if findRE `^v[0-9]+\.[0-9]+$` .Params.linkTitle }}
{{ $versions = $versions | append (dict "name" .Params.linkTitle "date" .Params.date ) }}
{{ end }}
{{ end }}
{{- /* Generate the JSON */ -}}
{{ $json := jsonify $versions }}
{{ $noop := (resources.FromString "/versions.json" $json).Permalink }}
{{ end }}
<!doctype html>
<html itemscope itemtype="http://schema.org/WebPage"
{{- with .Site.Language.LanguageDirection }} dir="{{ . }}" {{- end -}}

Loading…
Cancel
Save