From 94d50348396065f000777fce0bceefe02322b7ac Mon Sep 17 00:00:00 2001 From: Peter Feerick <5500713+pfeerick@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:59:37 +1000 Subject: [PATCH] feat: version banners for dev/legacy, per-branch edit links The legacy banner never rendered: it read extra.legacy_version from #__config, which Material doesn't populate. The banner script now works out the current version from the URL and mike's versions.json, showing a "Development version" notice on dev and a "Legacy version" notice (with a link to latest) on anything that isn't the latest alias. No per-version config is involved, so main can stay a straight copy of edgetx_2.12. Also turn on content.action.edit (Material hides the edit button without it) and take edit_uri from DOCS_EDIT_URI, which the publish workflow sets to the branch being built, so "Edit this page" on /dev/ opens main and on /2.12/ opens edgetx_2.12. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/publish-versioned-docs.yml | 3 + mkdocs.yml | 9 +- tools/import_legacy_gitbook.py | 7 +- tools/prepare_branch_site.py | 4 - .../javascripts/legacy-version-banner.js | 113 ++++++++++++++---- 5 files changed, 102 insertions(+), 34 deletions(-) diff --git a/.github/workflows/publish-versioned-docs.yml b/.github/workflows/publish-versioned-docs.yml index 041e95d0c..7745e26c5 100644 --- a/.github/workflows/publish-versioned-docs.yml +++ b/.github/workflows/publish-versioned-docs.yml @@ -124,6 +124,9 @@ jobs: git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - name: Publish docs with mike + env: + # "Edit this page" should open the branch this version is built from. + DOCS_EDIT_URI: edit/${{ github.ref_name }}/website/md-docs/ run: uv run mike deploy --push --update-aliases --title "${{ steps.version.outputs.title }}" ${{ steps.version.outputs.aliases }} - name: Set default docs version diff --git a/mkdocs.yml b/mkdocs.yml index 197349e52..839fedbf0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -3,7 +3,9 @@ site_description: Next-generation Lua API docs generated from EdgeTX source anno site_url: https://luadoc.edgetx.org/ repo_url: https://github.com/EdgeTX/lua-reference-guide repo_name: EdgeTX/lua-reference-guide -edit_uri: edit/edgetx_2.12/website/md-docs/ +# The publish workflow sets DOCS_EDIT_URI to the branch being built, so +# "Edit this page" on /dev/ points at main and on /2.12/ at edgetx_2.12. +edit_uri: !ENV [DOCS_EDIT_URI, "edit/edgetx_2.12/website/md-docs/"] docs_dir: website/md-docs site_dir: site exclude_docs: | @@ -40,6 +42,7 @@ theme: - search.suggest - search.highlight - content.code.copy + - content.action.edit plugins: - search: # Default separator only splits on whitespace/hyphens ([\s\-]+), so a @@ -60,10 +63,6 @@ extra: provider: mike default: latest alias: true - legacy_version: - enabled: false - label: Legacy version - message: This documentation version is preserved for reference and may not include later corrections or the newest docs structure. social: - icon: fontawesome/brands/github link: https://github.com/EdgeTX/lua-reference-guide diff --git a/tools/import_legacy_gitbook.py b/tools/import_legacy_gitbook.py index 319ada208..3087c4df7 100644 --- a/tools/import_legacy_gitbook.py +++ b/tools/import_legacy_gitbook.py @@ -590,12 +590,9 @@ def build_config( "javascripts/legacy-version-banner.js", ], "extra": { + # legacy-version-banner.js picks the notice from versions.json at + # runtime, so no per-version banner config is needed here. "version": {"provider": "mike", "default": "latest", "alias": True}, - "legacy_version": { - "enabled": True, - "label": "Legacy version", - "message": f"This documentation version preserves the original {version_name} GitBook content and structure for reference.", - }, }, "markdown_extensions": [ "tables", diff --git a/tools/prepare_branch_site.py b/tools/prepare_branch_site.py index 4507e930c..478187493 100644 --- a/tools/prepare_branch_site.py +++ b/tools/prepare_branch_site.py @@ -180,10 +180,6 @@ def build_config_text(site_name: str, docs_dir: Path, site_dir: Path, nav: list[ " provider: mike", " default: latest", " alias: true", - " legacy_version:", - " enabled: false", - " label: Legacy version", - " message: This documentation version is preserved for reference and may not include later corrections or the newest docs structure.", "markdown_extensions:", " - tables", " - admonition", diff --git a/website/md-docs/javascripts/legacy-version-banner.js b/website/md-docs/javascripts/legacy-version-banner.js index 3e235c5e0..aa99e476f 100644 --- a/website/md-docs/javascripts/legacy-version-banner.js +++ b/website/md-docs/javascripts/legacy-version-banner.js @@ -1,3 +1,13 @@ +// Shows a notice above the page content when the version being viewed is +// the development build ("dev") or anything other than the one mike aliases +// as "latest". The version is worked out at runtime from the URL and mike's +// versions.json rather than from per-version config, so every version can +// ship the same mkdocs.yml (main is a straight copy of the release branch). +// Material doesn't expose `extra` in #__config, so config can't drive this. + +const DEV_VERSION = "dev"; +const LATEST_ALIAS = "latest"; + function getSiteConfig() { const configNode = document.querySelector("#__config"); if (!configNode) return null; @@ -9,36 +19,99 @@ function getSiteConfig() { } } -function mountLegacyVersionBanner() { - const config = getSiteConfig(); - const legacyConfig = config?.extra?.legacy_version; - if (!legacyConfig?.enabled) return; +function getVersionRoot(config) { + // config.base is the relative path from this page to the version root, + // e.g. "../.." -- resolving it against the page URL gives //. + const base = config?.base; + if (typeof base !== "string") return null; + return new URL(base.endsWith("/") ? base : `${base}/`, window.location.href); +} - const container = document.querySelector(".md-content__inner"); - if (!container || container.querySelector(".legacy-version-banner")) return; +async function loadVersions(siteRoot) { + try { + const response = await fetch(new URL("versions.json", siteRoot)); + if (!response.ok) return null; + const versions = await response.json(); + return Array.isArray(versions) ? versions : null; + } catch { + return null; + } +} +function buildBanner({ label, message, linkText, linkHref }) { const banner = document.createElement("aside"); banner.className = "legacy-version-banner"; banner.setAttribute("role", "note"); - banner.setAttribute("aria-label", legacyConfig.label || "Legacy version"); + banner.setAttribute("aria-label", label); + + const labelNode = document.createElement("p"); + labelNode.className = "legacy-version-banner__label"; + labelNode.textContent = label; + + const messageNode = document.createElement("p"); + messageNode.className = "legacy-version-banner__message"; + messageNode.textContent = `${message} `; - const label = document.createElement("p"); - label.className = "legacy-version-banner__label"; - label.textContent = legacyConfig.label || "Legacy version"; + if (linkHref) { + const link = document.createElement("a"); + link.href = linkHref; + link.textContent = linkText; + messageNode.appendChild(link); + } + + banner.appendChild(labelNode); + banner.appendChild(messageNode); + return banner; +} + +async function mountVersionBanner() { + const container = document.querySelector(".md-content__inner"); + if (!container || container.querySelector(".legacy-version-banner")) return; - const message = document.createElement("p"); - message.className = "legacy-version-banner__message"; - message.textContent = - legacyConfig.message || - "This documentation version is preserved for reference and may not include later corrections or the newest docs structure."; + const versionRoot = getVersionRoot(getSiteConfig()); + if (!versionRoot) return; - banner.appendChild(label); - banner.appendChild(message); - container.insertBefore(banner, container.firstChild); + // Not served through mike (e.g. plain `mkdocs serve`): no versions.json + // one level up, so no banner. + const siteRoot = new URL("../", versionRoot); + const versions = await loadVersions(siteRoot); + if (!versions) return; + + const segment = decodeURIComponent(versionRoot.pathname.split("/").filter(Boolean).pop() || ""); + const current = versions.find( + (entry) => entry.version === segment || (entry.aliases || []).includes(segment), + ); + if (!current) return; + + const latest = versions.find((entry) => (entry.aliases || []).includes(LATEST_ALIAS)); + const latestHref = latest ? new URL(`${LATEST_ALIAS}/`, siteRoot).href : null; + const latestTitle = latest?.title || latest?.version; + + let banner = null; + if (current.version === DEV_VERSION) { + banner = buildBanner({ + label: "Development version", + message: + "These docs track EdgeTX development and may describe features or changes that are not in a released version yet.", + linkText: latest ? `View the ${latestTitle} release docs.` : "", + linkHref: latestHref, + }); + } else if (latest && current.version !== latest.version) { + banner = buildBanner({ + label: "Legacy version", + message: `You are viewing the documentation for EdgeTX ${current.title || current.version}. It is kept for reference and may not include later corrections.`, + linkText: `Go to the latest version (${latestTitle}).`, + linkHref: latestHref, + }); + } + + if (banner && !container.querySelector(".legacy-version-banner")) { + container.insertBefore(banner, container.firstChild); + } } if (document.readyState === "loading") { - document.addEventListener("DOMContentLoaded", mountLegacyVersionBanner, { once: true }); + document.addEventListener("DOMContentLoaded", mountVersionBanner, { once: true }); } else { - mountLegacyVersionBanner(); + mountVersionBanner(); }