diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 6f3c9ef0c..17e6812f9 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -5,6 +5,7 @@ const path = require('path'); const {themes} = require('prism-react-renderer'); const lightCodeTheme = themes.github; const darkCodeTheme = themes.dracula; +const shouldShowBanner = true; /** @type {import('@docusaurus/types').Config} */ const config = { @@ -55,12 +56,25 @@ const config = { { indexBlog: false, }, - ] + ], + [ + path.join(__dirname, "plugins", "versioning"), + {}, + ], ], themeConfig: /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ + announcementBar: shouldShowBanner + ? { + id: 'announcement_banner', + content: 'Go to our latest Stable release', + backgroundColor: '#ffcc00', + textColor: '#000', + isCloseable: true, + } + : undefined, docs: { sidebar: { hideable: true, @@ -80,6 +94,10 @@ const config = { label: 'Akuity.io', position: 'left', }, + { + type: 'custom-navbar-dropdown', + position: 'right', + }, { href: 'https://kargo.io/', label: 'Kargo.io', diff --git a/docs/plugins/versioning/index.js b/docs/plugins/versioning/index.js new file mode 100644 index 000000000..7e569f6dc --- /dev/null +++ b/docs/plugins/versioning/index.js @@ -0,0 +1,25 @@ +import path from 'path' +module.exports = function (context, options) { + console.log("Index.js called") + return { + name: 'my-custom-navbar-plugin', + getThemePath() { + return './ui/components'; + }, + contentLoaded({ actions }) { + }, + // Aliasing the NavbarItem type for custom mapping + configureWebpack() { + return { + resolve: { + alias: { + '@theme/NavbarItem/ComponentTypes': path.resolve( + __dirname, + './ui/components/NavbarItemTypes' + ), + }, + }, + }; + }, + }; +}; diff --git a/docs/plugins/versioning/src/index.ts b/docs/plugins/versioning/src/index.ts new file mode 100644 index 000000000..7ae9aaa3b --- /dev/null +++ b/docs/plugins/versioning/src/index.ts @@ -0,0 +1,21 @@ +import { LoadContext, Plugin } from '@docusaurus/types'; +import * as path from 'path'; + +export default function versioningPlugin(context: LoadContext): Plugin { + return { + name: 'versioning', + async loadContent() { + return { }; + }, + getThemePath() { + return path.resolve(__dirname, './theme'); + }, + + getTypeScriptThemePath() { + return path.resolve(__dirname, './theme'); + }, + getClientModules() { + return [path.resolve(__dirname, './theme/NavbarItem/VersionSwitcher')]; + } + }; +} diff --git a/docs/plugins/versioning/src/theme/NavbarItem/ComponentTypes.js b/docs/plugins/versioning/src/theme/NavbarItem/ComponentTypes.js new file mode 100644 index 000000000..5d6763704 --- /dev/null +++ b/docs/plugins/versioning/src/theme/NavbarItem/ComponentTypes.js @@ -0,0 +1,18 @@ +import { ComponentTypes } from '@theme-original/NavbarItem/ComponentTypes'; +import VersionSwitcher from './VersionSwitcher'; +import ComponentTypesObject from '@theme-original/NavbarItem/ComponentTypesObject'; +const ComponentTypes: ComponentTypesObject = { + 'custom-myAwesomeNavbarItem': VersionSwitcher, + }; + + export default ComponentTypes;'custom-myAwesomeNavbarItem': VersionDropdown, +// }; + +import { ComponentTypes } from '@theme-original/NavbarItem/ComponentTypes'; +import VersionSwitcher from './VersionSwitcher'; +import ComponentTypesObject from '@theme/NavbarItem/ComponentTypesObject'; +const ComponentTypes: ComponentTypesObject = { + 'custom-myAwesomeNavbarItem': VersionSwitcher, + }; + + export default ComponentTypes; \ No newline at end of file diff --git a/docs/plugins/versioning/src/theme/NavbarItem/VersionSwitcher.tsx b/docs/plugins/versioning/src/theme/NavbarItem/VersionSwitcher.tsx new file mode 100644 index 000000000..eaf0b6b96 --- /dev/null +++ b/docs/plugins/versioning/src/theme/NavbarItem/VersionSwitcher.tsx @@ -0,0 +1,95 @@ +import React, { useEffect, useState } from 'react'; + +interface Branch { + name: string; +} + +interface Version { + version: string; + url: string; +} + +const GITHUB_API = 'https://api.github.com/repos/akuity/kargo/branches'; +const CACHE_KEY = 'kargo-docs-versions'; +const CACHE_DURATION = 1000 * 60 * 60; // 1 hour + +const VersionDropdown: React.FC = () => { + const [versions, setVersions] = useState([]); + const [currentVersion, setCurrentVersion] = useState('current'); + + const parseVersionFromHostname = (hostname: string): string => { + const match = hostname.match(/^release-(\d+-\d+)\.docs\.kargo\.io$/); + if (match) { + return match[1].replace('-', '.'); + } + if (hostname === 'docs.kargo.io') { + return 'current'; + } + return 'unknown'; + }; + + const fetchVersions = async () => { + try { + const cachedData = localStorage.getItem(CACHE_KEY); + if (cachedData) { + const { data, timestamp } = JSON.parse(cachedData); + if (Date.now() - timestamp < CACHE_DURATION) { + setVersions(data); + return; + } + } + + const response = await fetch(GITHUB_API); + const branches: Branch[] = await response.json(); + + const versionData = branches + .map(branch => { + const match = branch.name.match(/^release-(\d+\.\d+)$/); + if (match) { + const version = match[1]; + return { + version, + url: `https://release-${version.replace('.', '-')}.docs.kargo.io` + }; + } + return null; + }) + .filter((v): v is Version => v !== null) + .sort((a, b) => b.version.localeCompare(a.version, undefined, { numeric: true })); + + localStorage.setItem(CACHE_KEY, JSON.stringify({ + data: versionData, + timestamp: Date.now() + })); + + setVersions(versionData); + } catch (error) { + console.error('Failed to fetch versions:', error); + } + }; + + useEffect(() => { + fetchVersions(); + setCurrentVersion(parseVersionFromHostname(window.location.hostname)); + }, []); + + const handleVersionChange = (event: React.ChangeEvent) => { + const selectedVersion = event.target.value; + if (selectedVersion === 'current') { + window.location.href = 'https://docs.kargo.io'; + } else { + const version = versions.find(v => v.version === selectedVersion); + if (version) { + window.location.href = version.url; + } + } + }; + + return ( +
+ {/* Version dropdown implementation can go here */} +
+ ); +}; + +export default VersionDropdown; \ No newline at end of file diff --git a/docs/plugins/versioning/src/theme/NavbarItem/index.jsx b/docs/plugins/versioning/src/theme/NavbarItem/index.jsx new file mode 100644 index 000000000..b0b7d4742 --- /dev/null +++ b/docs/plugins/versioning/src/theme/NavbarItem/index.jsx @@ -0,0 +1,7 @@ +import React from 'react'; +import NavbarItem from '@theme-original/NavbarItem'; +import ComponentTypes from './ComponentTypes'; + +export default function NavbarItemWrapper(props) { + return ; +} diff --git a/docs/plugins/versioning/src/theme/VersionDropdown/index.tsx b/docs/plugins/versioning/src/theme/VersionDropdown/index.tsx new file mode 100644 index 000000000..eaf0b6b96 --- /dev/null +++ b/docs/plugins/versioning/src/theme/VersionDropdown/index.tsx @@ -0,0 +1,95 @@ +import React, { useEffect, useState } from 'react'; + +interface Branch { + name: string; +} + +interface Version { + version: string; + url: string; +} + +const GITHUB_API = 'https://api.github.com/repos/akuity/kargo/branches'; +const CACHE_KEY = 'kargo-docs-versions'; +const CACHE_DURATION = 1000 * 60 * 60; // 1 hour + +const VersionDropdown: React.FC = () => { + const [versions, setVersions] = useState([]); + const [currentVersion, setCurrentVersion] = useState('current'); + + const parseVersionFromHostname = (hostname: string): string => { + const match = hostname.match(/^release-(\d+-\d+)\.docs\.kargo\.io$/); + if (match) { + return match[1].replace('-', '.'); + } + if (hostname === 'docs.kargo.io') { + return 'current'; + } + return 'unknown'; + }; + + const fetchVersions = async () => { + try { + const cachedData = localStorage.getItem(CACHE_KEY); + if (cachedData) { + const { data, timestamp } = JSON.parse(cachedData); + if (Date.now() - timestamp < CACHE_DURATION) { + setVersions(data); + return; + } + } + + const response = await fetch(GITHUB_API); + const branches: Branch[] = await response.json(); + + const versionData = branches + .map(branch => { + const match = branch.name.match(/^release-(\d+\.\d+)$/); + if (match) { + const version = match[1]; + return { + version, + url: `https://release-${version.replace('.', '-')}.docs.kargo.io` + }; + } + return null; + }) + .filter((v): v is Version => v !== null) + .sort((a, b) => b.version.localeCompare(a.version, undefined, { numeric: true })); + + localStorage.setItem(CACHE_KEY, JSON.stringify({ + data: versionData, + timestamp: Date.now() + })); + + setVersions(versionData); + } catch (error) { + console.error('Failed to fetch versions:', error); + } + }; + + useEffect(() => { + fetchVersions(); + setCurrentVersion(parseVersionFromHostname(window.location.hostname)); + }, []); + + const handleVersionChange = (event: React.ChangeEvent) => { + const selectedVersion = event.target.value; + if (selectedVersion === 'current') { + window.location.href = 'https://docs.kargo.io'; + } else { + const version = versions.find(v => v.version === selectedVersion); + if (version) { + window.location.href = version.url; + } + } + }; + + return ( +
+ {/* Version dropdown implementation can go here */} +
+ ); +}; + +export default VersionDropdown; \ No newline at end of file diff --git a/docs/plugins/versioning/src/theme/styles.css b/docs/plugins/versioning/src/theme/styles.css new file mode 100644 index 000000000..8cf3de743 --- /dev/null +++ b/docs/plugins/versioning/src/theme/styles.css @@ -0,0 +1,21 @@ +.version-dropdown-container { + margin-left: auto; + padding: 0 1rem; + } + + .version-select { + padding: 0.5rem; + border-radius: 4px; + border: 1px solid var(--ifm-color-emphasis-300); + background-color: var(--ifm-background-color); + color: var(--ifm-color-content); + font-size: 0.9rem; + } + + .version-banner { + background-color: var(--ifm-color-primary); + color: white; + text-align: center; + padding: 0.5rem; + font-size: 0.9rem; + } \ No newline at end of file diff --git a/docs/plugins/versioning/ui/components/NavbarDropdown.js b/docs/plugins/versioning/ui/components/NavbarDropdown.js new file mode 100644 index 000000000..d4dffb2a7 --- /dev/null +++ b/docs/plugins/versioning/ui/components/NavbarDropdown.js @@ -0,0 +1,90 @@ +import React, { useState, useEffect } from 'react'; +import styles from './NavbarDropdown.module.css'; + + + +const CACHE_KEY = 'kargo-docs-versions'; +const CACHE_DURATION = 1000 * 60 * 30; // 30 minutes +const githubApiUrl = 'https://api.github.com/repos/akuity/kargo/branches'; + +function NavbarDropdown() { + console.log("Navbar dropdown initialized"); + const [versions, setVersions] = useState([]); + const [loading, setLoading] = useState(true); + const [currentVersion, setCurrentVersion] = useState(""); + + useEffect(() => { + fetchVersions(); + }, []); + + const fetchVersions = async () => { + try { + console.log("Before fetching versions") + const response = await fetch(githubApiUrl); + const branches = await response.json(); + console.log("fetched branches are: ", branches); + + const releaseBranches = branches + .map(branch => branch.name) + .filter(name => /^release-1/.test(name)) + .map(name => { + const [major, minor] = name.split('.'); + return { + version: `${major}-${minor}`, + url: `https://${major}-${minor}.docs.kargo.io${window.location.pathname}` + }; + }); + console.log("These are release branches before unshifting: ", releaseBranches) + // Add current version + releaseBranches.unshift({ + version: 'current', + url: `https://docs.kargo.io${window.location.pathname}` + }); + console.log("These are release branches: ", releaseBranches) + + localStorage.setItem(CACHE_KEY, JSON.stringify({ + versions: releaseBranches, + timestamp: Date.now() + })); + + setVersions(releaseBranches); + setLoading(false); + } catch (error) { + console.error('Error fetching versions:', error); + setLoading(false); + } + }; + + const handleVersionChange = (event) => { + const selectedVersion = versions.find(v => v.version === event.target.value); + if (selectedVersion) { + window.location.href = selectedVersion.url; + } + }; + + if (loading) return null; + + return ( +
+ +
+ ); +} + +export default NavbarDropdown; diff --git a/docs/plugins/versioning/ui/components/NavbarDropdown.module.css b/docs/plugins/versioning/ui/components/NavbarDropdown.module.css new file mode 100644 index 000000000..96355e956 --- /dev/null +++ b/docs/plugins/versioning/ui/components/NavbarDropdown.module.css @@ -0,0 +1,34 @@ +.dropdown { + position: relative; + display: inline-block; + } + + .dropdownButton { + background-color: #008cba; + color: white; + padding: 10px 16px; + font-size: 16px; + border: none; + cursor: pointer; + } + + .dropdownContent { + display: block; + position: absolute; + background-color: white; + min-width: 160px; + box-shadow: 0px 8px 16px rgba(0, 0, 0, 0.2); + z-index: 1; + } + + .dropdownContent a { + color: black; + padding: 12px 16px; + text-decoration: none; + display: block; + } + + .dropdownContent a:hover { + background-color: #ddd; + } + \ No newline at end of file diff --git a/docs/plugins/versioning/ui/components/NavbarItemTypes.js b/docs/plugins/versioning/ui/components/NavbarItemTypes.js new file mode 100644 index 000000000..b4cbe7d63 --- /dev/null +++ b/docs/plugins/versioning/ui/components/NavbarItemTypes.js @@ -0,0 +1,8 @@ +import NavbarDropdown from './NavbarDropdown'; +import DefaultComponentTypes from '@theme-original/NavbarItem/ComponentTypes'; + +console.log("REached the navbaritemtypes.js file") +export default { + ...DefaultComponentTypes, + 'custom-navbar-dropdown': NavbarDropdown, +};