diff --git a/src/css/custom.css b/src/css/custom.css index 3039cf530..4d021cd91 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -167,4 +167,34 @@ gap: 0.75rem; /* space between icons */ align-items: center; } +} + +.kmesh-version-badge { + display: inline-block; + margin-left: 0.5rem; + background: transparent; + color: inherit; + font-weight: 600; + padding: 0.08rem 0.28rem; + border-radius: 0.25rem; + font-size: 0.85rem; + line-height: 1; + box-shadow: none; + border: 1px solid rgba(0,0,0,0.06); + vertical-align: middle; +} + +[data-theme="dark"] .kmesh-version-badge { + border-color: rgba(255,255,255,0.06); +} + +.kmesh-version-container { + display: inline-flex; + align-items: center; + margin: 0; + padding: 0; +} + +@media (max-width: 996px) { + .kmesh-version-badge { display: none; } } \ No newline at end of file diff --git a/src/theme/Navbar/index.js b/src/theme/Navbar/index.js new file mode 100644 index 000000000..3b0a73479 --- /dev/null +++ b/src/theme/Navbar/index.js @@ -0,0 +1,95 @@ +import React, { useEffect, useState } from 'react'; +import ReactDOM from 'react-dom'; +import OriginalNavbar from '@theme-original/Navbar'; + +export default function Navbar(props) { + const [version, setVersion] = useState(null); + + const [containerEl, setContainerEl] = useState(null); + + useEffect(() => { + let mounted = true; + // fetch latest release tag + fetch('https://api.github.com/repos/kmesh-net/kmesh/releases/latest') + .then((res) => res.json()) + .then((data) => { + if (!mounted) return; + if (data && data.tag_name) setVersion(data.tag_name); + }) + .catch(() => { + // network or API error + }); + + if (typeof document !== 'undefined') { + const searchEl = document.querySelector('.navbar__search, .DocSearch-Button'); + const navRight = document.querySelector('.navbar__items--right'); + if (searchEl) { + const searchItem = searchEl.closest('.navbar__item') || searchEl.parentNode; + const container = navRight || (searchItem && searchItem.parentNode); + if (container && searchItem) { + + let existing = container.querySelector('.kmesh-version-container'); + if (!existing) { + const wrapper = document.createElement('div'); + wrapper.className = 'kmesh-version-container'; + wrapper.style.display = 'inline-flex'; + wrapper.style.alignItems = 'center'; + wrapper.style.margin = '0 0.5rem 0 0'; + wrapper.style.padding = '0'; + container.insertBefore(wrapper, searchItem); + setContainerEl(wrapper); + } else { + setContainerEl(existing); + } + } else if (navRight) { + + let existing = navRight.querySelector('.kmesh-version-container'); + if (!existing) { + const wrapper = document.createElement('div'); + wrapper.className = 'kmesh-version-container'; + wrapper.style.display = 'inline-flex'; + wrapper.style.alignItems = 'center'; + wrapper.style.margin = '0 0.5rem 0 0'; + wrapper.style.padding = '0'; + navRight.appendChild(wrapper); + setContainerEl(wrapper); + } else { + setContainerEl(existing); + } + } + } else if (navRight) { + + let existing = navRight.querySelector('.kmesh-version-container'); + if (!existing) { + const wrapper = document.createElement('div'); + wrapper.className = 'kmesh-version-container'; + wrapper.style.display = 'inline-flex'; + wrapper.style.alignItems = 'center'; + wrapper.style.margin = '0 0.5rem 0 0'; + wrapper.style.padding = '0'; + navRight.appendChild(wrapper); + setContainerEl(wrapper); + } else { + setContainerEl(existing); + } + } + } + + return () => { + mounted = false; + }; + }, []); + + return ( + <> + + {version && containerEl && + ReactDOM.createPortal( +
+ {version} +
, + containerEl + )} + + ); +}