From 45485d634117c647f5e553ea92b30583828fed82 Mon Sep 17 00:00:00 2001
From: Shaun Struwig <41984034+Blargian@users.noreply.github.com>
Date: Tue, 18 Nov 2025 14:55:38 +0100
Subject: [PATCH 1/3] improvements to page versioning
---
.../ClientVersionDropdown.js | 95 ++++++++++++++++++-
src/theme/ClientVersionDropdown/Version.js | 47 +++++++++
2 files changed, 139 insertions(+), 3 deletions(-)
create mode 100644 src/theme/ClientVersionDropdown/Version.js
diff --git a/src/theme/ClientVersionDropdown/ClientVersionDropdown.js b/src/theme/ClientVersionDropdown/ClientVersionDropdown.js
index b85eef7bea5..39b30cefdc0 100644
--- a/src/theme/ClientVersionDropdown/ClientVersionDropdown.js
+++ b/src/theme/ClientVersionDropdown/ClientVersionDropdown.js
@@ -13,6 +13,22 @@ const ClientVersionDropdown = (props) => {
const buttonRef = useRef(null);
const dropdownRef = useRef(null);
+ // Store header IDs for each version
+ // Structure: { 0: ['header-1', 'header-2'], 1: ['header-3', 'header-4'] }
+ const [versionHeaders, setVersionHeaders] = useState({});
+
+ // Support both old API (snippet) and new API (children)
+ const usingChildren = props.children && React.Children.count(props.children) > 0;
+ const childrenArray = usingChildren ? React.Children.toArray(props.children) : [];
+
+ // Callback for Version components to report their headers
+ const handleHeadersCollected = (versionIndex, headerIds) => {
+ setVersionHeaders(prev => ({
+ ...prev,
+ [versionIndex]: headerIds
+ }));
+ };
+
// Find version from URL parameter on initial load
useEffect(() => {
const searchParams = new URLSearchParams(location.search);
@@ -135,8 +151,81 @@ const ClientVersionDropdown = (props) => {
const selectedVersion = props.versions[selectedVersionIndex];
- // Get the MDXContent component
- const MDXContent = selectedVersion.snippet;
+ // Effect to filter TOC based on selected version
+ useEffect(() => {
+ if (!usingChildren) return;
+
+ const filterTOC = () => {
+ // Get the header IDs for the currently selected version
+ const activeVersionHeaderIds = versionHeaders[selectedVersionIndex] || [];
+
+ if (activeVersionHeaderIds.length === 0) {
+ // Headers not collected yet, try again later
+ return;
+ }
+
+ // Find TOC - try multiple selectors for Docusaurus compatibility
+ const tocLinks = document.querySelectorAll(
+ '.table-of-contents a, .theme-doc-toc-desktop a, [class*="tocDesktop"] a, .toc a'
+ );
+
+ tocLinks.forEach(link => {
+ const href = link.getAttribute('href');
+ if (href && href.startsWith('#')) {
+ const headerId = href.substring(1);
+ const linkParent = link.parentElement; //
element
+
+ // Show TOC link only if its header ID is in the active version's headers
+ if (activeVersionHeaderIds.includes(headerId)) {
+ linkParent.style.display = '';
+ } else {
+ linkParent.style.display = 'none';
+ }
+ }
+ });
+ };
+
+ // Run immediately
+ filterTOC();
+
+ // Re-run after a delay to catch dynamically rendered TOC items
+ const timer = setTimeout(filterTOC, 200);
+
+ return () => clearTimeout(timer);
+ }, [selectedVersionIndex, usingChildren, versionHeaders]);
+
+ // Render content based on API being used
+ const renderContent = () => {
+ if (usingChildren) {
+ // New API: render children with show/hide based on selection
+ // Clone children and inject version props
+ return childrenArray.map((child, index) => {
+ const isVisible = index === selectedVersionIndex;
+
+ // Clone the child to add versionIndex and callback props
+ const clonedChild = React.cloneElement(child, {
+ versionIndex: index,
+ isVisible: isVisible,
+ onHeadersCollected: handleHeadersCollected
+ });
+
+ return (
+
+ {clonedChild}
+
+ );
+ });
+ } else {
+ // Old API: render snippet
+ const MDXContent = selectedVersion.snippet;
+ return MDXContent && typeof MDXContent === 'function' && ;
+ }
+ };
return (
<>
@@ -154,7 +243,7 @@ const ClientVersionDropdown = (props) => {
{renderDropdown()}
- {MDXContent && typeof MDXContent === 'function' && }
+ {renderContent()}
>
);
diff --git a/src/theme/ClientVersionDropdown/Version.js b/src/theme/ClientVersionDropdown/Version.js
new file mode 100644
index 00000000000..7f82d01ed1f
--- /dev/null
+++ b/src/theme/ClientVersionDropdown/Version.js
@@ -0,0 +1,47 @@
+import React, { useEffect, useRef } from 'react';
+
+/**
+ * Version wrapper component for use with ClientVersionDropdown.
+ * Collects all heading IDs within this version for TOC filtering.
+ * The parent ClientVersionDropdown component handles showing/hiding based on selection.
+ */
+const Version = ({ children, versionIndex, isVisible, onHeadersCollected }) => {
+ const containerRef = useRef(null);
+
+ useEffect(() => {
+ // Collect heading IDs from this version
+ const collectHeaders = () => {
+ if (containerRef.current && typeof versionIndex !== 'undefined') {
+ const headings = containerRef.current.querySelectorAll('h1, h2, h3, h4, h5, h6');
+ const headerIds = [];
+
+ headings.forEach(heading => {
+ if (heading.id) {
+ headerIds.push(heading.id);
+ // Mark heading with version index for reference
+ heading.setAttribute('data-version-index', versionIndex);
+ }
+ });
+
+ // Notify parent component of the headers in this version
+ if (onHeadersCollected && headerIds.length > 0) {
+ onHeadersCollected(versionIndex, headerIds);
+ }
+ }
+ };
+
+ // Run immediately and after a short delay to catch late-rendered content
+ collectHeaders();
+ const timer = setTimeout(collectHeaders, 100);
+
+ return () => clearTimeout(timer);
+ }, [versionIndex, children, onHeadersCollected]);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default Version;
\ No newline at end of file
From 64d3991cb7533e131f7131a0ee464917963bf0e7 Mon Sep 17 00:00:00 2001
From: Shaun Struwig <41984034+Blargian@users.noreply.github.com>
Date: Tue, 18 Nov 2025 15:02:36 +0100
Subject: [PATCH 2/3] update docs
---
contribute/style-guide.md | 56 +++++++++++++++++++++++++++++++++++----
1 file changed, 51 insertions(+), 5 deletions(-)
diff --git a/contribute/style-guide.md b/contribute/style-guide.md
index ae583549474..d9e5b69191a 100644
--- a/contribute/style-guide.md
+++ b/contribute/style-guide.md
@@ -331,7 +331,53 @@ which may need versioned documentation, we use the following custom
```
-### How to use it
+### How to use it
+
+The `ClientVersionDropdown` component supports two APIs:
+
+#### API 1: Inline Content (Recommended)
+
+This approach keeps all content in the main file, which allows Docusaurus to properly generate the table of contents (TOC) for all versions.
+
+```js
+import ClientVersionDropdown from '@theme/ClientVersionDropdown/ClientVersionDropdown'
+import Version from '@theme/ClientVersionDropdown/Version'
+
+
+
+
+## Environment requirements
+
+Your v0.8+ content here...
+
+
+
+## Environment requirements {#v07-environment-requirements}
+
+Your v0.7.x content here...
+
+
+
+```
+
+**Important Notes:**
+- All content is placed directly in the main `.mdx` file
+- Each `` block contains the content for one version
+- The order of `` blocks must match the order in the `versions` array
+- **Make header IDs unique** across versions using explicit anchor IDs (e.g., `{#v07-environment-requirements}`)
+- The TOC will show only headers from the currently selected version
+- The component will display the first version as 'selected' by default
+
+#### API 2: External Snippets (Legacy)
+
+This approach uses separate snippet files for each version. Note that this method has limitations with TOC generation.
Versioned folders are structured as follows:
@@ -352,9 +398,9 @@ Versioned folders are structured as follows:
```
* The content for each version is placed in a snippet. For example `_v0_7.mdx`
- * Snippets begin with `_`
+ * Snippets begin with `_`
* Snippets do not contain front-matter
- * These snippets import any components they may need (See `_v0_7.mdx` for example)
+ * These snippets import any components they may need
* They should be .mdx files
* There is a single page for all versions. For example `client.mdx`
* This page contains frontmatter
@@ -370,8 +416,8 @@ import ClientVersionDropdown from '@theme/ClientVersionDropdown/ClientVersionDro
Also import the two snippets:
```js
-import v07 from './_v0_7.mdx'
-import v08 from './_v0_8.mdx'
+import v07 from './_snippets/_v0_7.mdx'
+import v08 from './_snippets/_v0_8.mdx'
```
Pass it an array of objects representing versions and their respective snippets:
From 9c1718d0b578075d2e450059e601c843ee63039f Mon Sep 17 00:00:00 2001
From: Shaun Struwig <41984034+Blargian@users.noreply.github.com>
Date: Tue, 18 Nov 2025 15:19:37 +0100
Subject: [PATCH 3/3] newline
---
src/theme/ClientVersionDropdown/Version.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/theme/ClientVersionDropdown/Version.js b/src/theme/ClientVersionDropdown/Version.js
index 7f82d01ed1f..cfe2733c834 100644
--- a/src/theme/ClientVersionDropdown/Version.js
+++ b/src/theme/ClientVersionDropdown/Version.js
@@ -44,4 +44,4 @@ const Version = ({ children, versionIndex, isVisible, onHeadersCollected }) => {
);
};
-export default Version;
\ No newline at end of file
+export default Version;