From 3f378d31d961e8514f48dbef2f19a9b029e4db03 Mon Sep 17 00:00:00 2001 From: Michael Harp Date: Thu, 11 Jun 2026 07:32:54 -0400 Subject: [PATCH] Add a per-product documentation version selector Render a version picker at the top of the sidebar, driven by _data/products.yml. For the current product it lists the versions (newest first), marks the one being viewed, and badges the version that `latest` aliases. Version links point at each version's root; switching is an infrequent, deliberate jump, and root links stay correct in the theme's persistent (Turbo-navigated) sidebar without per-page rewriting (keeping the reader on the same page across a switch is a possible later enhancement). - _includes/version-selector.html renders a block per qualifying product (2+ versions, not single_version) so the picker survives Turbo navigation between products. The wrapper is only emitted when at least one product qualifies, so nothing shows while every product still has a single version. - layout_end.html gains syncVersionPicker, which on each Turbo frame load shows the block matching the current collection and marks the active version (with a fallback to the `latest`-aliased version on //latest/ pages), mirroring the existing nav-group sync. - custom.css styles the picker to match the theme. Verified against a local two-version test bed (OpenVox 8.x + a 9.0.0-alpha1 9.x): correct active marking and latest badge on direct loads of 8.x, 9.x and the latest alias; correct group swap and active marking across Turbo navigation between products; OpenVox Containers (single_version) excluded; and no picker rendered while all products have one version. Part of #325. Co-Authored-By: Claude Opus 4.8 Signed-off-by: Michael Harp --- _includes/jekyll_vitepress/layout_end.html | 29 ++++++++++ _includes/sidebar.html | 2 + _includes/version-selector.html | 66 +++++++++++++++++++++ assets/css/custom.css | 67 ++++++++++++++++++++++ 4 files changed, 164 insertions(+) create mode 100644 _includes/version-selector.html diff --git a/_includes/jekyll_vitepress/layout_end.html b/_includes/jekyll_vitepress/layout_end.html index 2a16c0684..e10e7bf2d 100644 --- a/_includes/jekyll_vitepress/layout_end.html +++ b/_includes/jekyll_vitepress/layout_end.html @@ -9,9 +9,38 @@ group.hidden = collections.indexOf(currentCollection) < 0; }); } + // Show the version picker for the current product and mark the active version. + // The sidebar persists across Turbo navigation, so this re-runs per frame load. + function syncVersionPicker() { + var frameState = document.getElementById('vp-page-state'); + if (!frameState) return; + var currentCollection = frameState.getAttribute('data-collection') || ''; + document.querySelectorAll('.VPVersionPickerGroup').forEach(function (group) { + var collections = (group.getAttribute('data-collections') || '').split('|'); + var isCurrent = collections.indexOf(currentCollection) >= 0; + group.hidden = !isCurrent; + if (!isCurrent) return; + // The _latest alias collection has no version link of its own; fall back + // to the version `latest` points at. + var target = currentCollection; + if (!group.querySelector('.VPVersionPickerItem[data-collection="' + currentCollection + '"]')) { + target = group.getAttribute('data-latest-collection') || ''; + } + group.querySelectorAll('.VPVersionPickerItem').forEach(function (link) { + var active = link.getAttribute('data-collection') === target; + link.classList.toggle('is-active', active); + if (active) { + link.setAttribute('aria-current', 'true'); + } else { + link.removeAttribute('aria-current'); + } + }); + }); + } document.addEventListener('turbo:frame-load', function (event) { if (!event.target || event.target.id !== 'vp-content-frame') return; syncSidebarNavGroups(); + syncVersionPicker(); }); })(); diff --git a/_includes/sidebar.html b/_includes/sidebar.html index d41a4583c..03f82e626 100644 --- a/_includes/sidebar.html +++ b/_includes/sidebar.html @@ -11,6 +11,8 @@